极光推送 请检查参数合法性_极光小课堂 | 极光推送在人脸识别终端管理系统中的应用...

项目背景

最近开发的一款人脸识别终端管理系统,主要包括运营平台、企业后台管理系统、APP 端、智能人脸识别终端模块。

下图是系统的架构图:

98d413cb0d7c0617e5943d331dabf5b5.png

其中各个模块之间都需要即时通讯,比如:

  • APP 端用户注册完成之后,企业管理员在后台管理系统中将用户邀请进入企业,此时需要及时通知用户已加入企业;

  • 当管理员将该用户加入到指定的用户组时,需要将该用户的人脸信息下发到关联了该用户组的智能人脸识别终端中;

  • 管理员更改用户或者设备信息时都需要及时通知到相关的设备同步最新的数据;

  • 用户 APP 远程开门需要发送实时消息给到门禁(或者闸机),门禁(或闸机)收到开门消息后方可开门;

  • 当管理员发布广告或者公告时,需要通知到指定的门禁设备播放最新的消息;

...大概十多项通知都离不开消息的推送,此时最先想到的自然是集成第三方稳定高效的即时推送方案(APP  端还需要有强大的离线推送功能)。

为什么选择极光推送

集成第三方推送无非出于以下几点考虑:推送稳定高效、方便集成、APP 离线模式支持更多的机型(通道)、APP 进程互相拉起、有效的数据统计,最重要的一点要免费,无疑极光推送都满足了这几方面。

本人是极光推送几年的老用户,并且在几年前写过一篇【(快速搞定)2分钟集成极光推送(极光推送 Android 端集成)】的文章,当时使用极光推送的时候还没有几家推送 SDK,可以说极光推送是较早的一批推送方案了,这么多年的积累稳定性方面毋庸置疑。

Android 快速集成极光推送

下面一步一步教大家快速集成极光推送(尽量按下面的方式进行,说不定可以少走很多弯路哦):

官方可能要考虑一些额外的情况加了个一个手动集成的教程,现在都2020年了当然得用依赖 jcenter 项目的方式来集成啦,如需手动集成请移步官方稳定。

开发环境:

  • Android Studio 3.0.1 正式版

  • gradle v3.0.1

  • compileSdkVersion 26

  • targetSdkVersion 22 (减少不必要的动态权限请求)

开发者账号注册、创建应用这些就不说了哈,根据官网提示即可创建完成。

第一步:创建项目名叫 smart_face_jpush 的项目(有项目的请忽略这一步)

7e951fcace7abfd8e0ec8258bbc7ee52.png

第二步:配置 app/build.gradle 文件

apply plugin: 'com.android.application'  android {     compileSdkVersion 26   defaultConfig {         applicationId "com.hdl.smartface"//JPush 上注册的包名.   minSdkVersion 17   targetSdkVersion 22   versionCode 1   versionName "1.0"   testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"   //极光推送配置----------开始-----------   ndk {             //一般armeabi-v7a已能适配绝大部分机型   abiFilters 'armeabi-v7a'   // 还可以添加 'armeabi', 'arm64-v8a', 'x86', 'x86_64', 'mips', 'mips64'  }         manifestPlaceholders = [                 JPUSH_PKGNAME: applicationId,                 JPUSH_APPKEY : "307d4e883d70b727687597fb", //JPush 上注册的包名对应的 Appkey.  JPUSH_CHANNEL: "developer-default", //暂时填写默认值即可.   ]         //极光推送配置----------结束-----------   }     buildTypes {         release {             minifyEnabled false   proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'   }     }  }  dependencies {     implementation fileTree(dir: 'libs', include: ['*.jar'])     implementation 'com.android.support:appcompat-v7:26.1.0'   testImplementation 'junit:junit:4.12'   androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {         exclude group: 'com.android.support', module: 'support-annotations'   })     //极光推送相关库   implementation 'cn.jiguang.sdk:jpush:3.5.4'    implementation 'cn.jiguang.sdk:jcore:2.2.6' //日志库implementation 'com.hdl:elog:v2.0.2'}

配置完成之后需要同步仓库,如图 Try Again:

dd85f5fc79e94087f77f8c62f5b1a402.png

第三步:配置清单文件

在 AndroidManifest.xml 的 application 中加入极光推送必要的配置:

<?xml version="1.0" encoding="utf-8"?>  <manifest xmlns:android="http://schemas.android.com/apk/res/android"   xmlns:tools="http://schemas.android.com/tools"   package="com.hdl.smartface">  <application  android:name=".base.MyApp"   android:allowBackup="true"   android:icon="@mipmap/ic_launcher"   android:label="@string/app_name"   android:roundIcon="@mipmap/ic_launcher_round"   android:supportsRtl="true"   android:theme="@style/AppTheme">  <activity android:name=".MainActivity">  <intent-filter> <action android:name="android.intent.action.MAIN" />  <category android:name="android.intent.category.LAUNCHER" />  intent-filter> activity>       <activity   android:name="cn.jpush.android.ui.PopWinActivity"   android:exported="true"   android:theme="@style/MyDialogStyle"   tools:node="replace">  <intent-filter> <category android:name="android.intent.category.DEFAULT" />  <action android:name="cn.jpush.android.ui.PopWinActivity" />  <category android:name="${applicationId}" />  intent-filter> activity>      <activity   android:name="cn.jpush.android.ui.PushActivity"   android:configChanges="orientation|keyboardHidden"   android:exported="true"   android:theme="@android:style/Theme.NoTitleBar"   tools:node="replace">  <intent-filter> <action android:name="cn.jpush.android.ui.PushActivity" />  <category android:name="android.intent.category.DEFAULT" />  <category android:name="${applicationId}" />  intent-filter> activity>     <receiver   android:name=".receiver.JpushReceiver"   android:enabled="true"   android:exported="false">  <intent-filter> <action android:name="cn.jpush.android.intent.REGISTRATION" />    <action android:name="cn.jpush.android.intent.MESSAGE_RECEIVED" />    <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED" />    <action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED" />    <action android:name="cn.jpush.android.intent.CONNECTION" />  <category android:name="com.hdl.smartface" />  intent-filter> receiver>     <receiver android:name=".receiver.MyJpushMessageReceiver">  <intent-filter> <action android:name="cn.jpush.android.intent.RECEIVE_MESSAGE" />  <category android:name="com.hdl.smartface">category>  intent-filter> receiver>     <receiver   android:name="cn.jpush.android.service.PushReceiver"   android:enabled="true"   android:exported="false">  <intent-filter android:priority="1000">  <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED_PROXY" />    <category android:name="com.hdl.smartface" />  intent-filter> <intent-filter> <action android:name="android.intent.action.USER_PRESENT" />  <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />  intent-filter>     <intent-filter>  <action android:name="android.intent.action.PACKAGE_ADDED" />  <action android:name="android.intent.action.PACKAGE_REMOVED" />  <data android:scheme="package" />  intent-filter> receiver>      <receiver   android:name="cn.jpush.android.service.AlarmReceiver"   android:exported="false" />      <service   android:name="cn.jpush.android.service.PushService"   android:exported="false"   android:process=":pushcore">  <intent-filter> <action android:name="cn.jpush.android.intent.REGISTER" />  <action android:name="cn.jpush.android.intent.REPORT" />  <action android:name="cn.jpush.android.intent.PushService" />  <action android:name="cn.jpush.android.intent.PUSH_TIME" />  intent-filter> service>     <service   android:name=".services.PushService"   android:process=":pushcore">  <intent-filter> <action android:name="cn.jiguang.user.service.action" />  intent-filter> service>     application>  manifest>

第四步:混淆配置

在 proguard-rules.pro 文件中加入以下配置:

#极光推送混淆配置-------------开始------------  -dontoptimize  -dontpreverify  -dontwarn cn.jpush.**  -keep class cn.jpush.** { *; }  -keep class * extends cn.jpush.android.helpers.JPushMessageReceiver { *; }  -dontwarn cn.jiguang.**  -keep class cn.jiguang.** { *; }  #极光推送混淆配置-------------结束------------

第五步:创建接收消息的广播接收器 JpushReceiver

package com.hdl.smartface.receiver;  import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.Intent;  import android.os.Bundle;  import android.text.TextUtils;  import com.hdl.elog.ELog;  import org.json.JSONException;  import org.json.JSONObject;  import java.util.Iterator;  import cn.jpush.android.api.JPushInterface;  import cn.jpush.android.helper.Logger;  /**  * 自定义接收器   *  * 如果不定义这个 Receiver,则: * 1) 默认用户会打开主界面   * 2) 接收不到自定义消息   *  * @author Admin  */public class JpushReceiver extends BroadcastReceiver {     private static final String TAG = "JpushReceiver";   @Override   public void onReceive(Context context, Intent intent) {         try {             Bundle bundle = intent.getExtras();   ELog.e(TAG, "[JpushReceiver] onReceive - " + intent.getAction() + ", extras: " + printBundle(bundle));  if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) {                 String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID);   ELog.e(TAG, "[JpushReceiver] 接收Registration Id : " + regId);   //send the Registration Id to your server...   } else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {                 ELog.e(TAG, "[JpushReceiver] 接收到推送下来的自定义消息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE));  //          processCustomMessage(context, bundle);   } else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) {                 ELog.e(TAG, "[JpushReceiver] 接收到推送下来的通知");  int notifactionId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID);   ELog.e(TAG, "[JpushReceiver] 接收到推送下来的通知的ID: " + notifactionId);   } else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) {                 ELog.e(TAG, "[JpushReceiver] 用户点击打开了通知");   //打开自定义的Activity  //          Intent i = new Intent(context, TestActivity.class);  //          i.putExtras(bundle);  //i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//          i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP );  //          context.startActivity(i);   } else if (JPushInterface.ACTION_RICHPUSH_CALLBACK.equals(intent.getAction())) {                 ELog.e(TAG, "[JpushReceiver] 用户收到到RICH PUSH CALLBACK: " + bundle.getString(JPushInterface.EXTRA_EXTRA));   //在这里根据 JPushInterface.EXTRA_EXTRA 的内容处理代码,比如打开新的Activity, 打开一个网页等..   } else if (JPushInterface.ACTION_CONNECTION_CHANGE.equals(intent.getAction())) {                 boolean connected = intent.getBooleanExtra(JPushInterface.EXTRA_CONNECTION_CHANGE, false);   Logger.w(TAG, "[JpushReceiver]" + intent.getAction() + " connected state change to " + connected);   } else {                 ELog.e(TAG, "[JpushReceiver] Unhandled intent - " + intent.getAction());   }         } catch (Exception e) {         }     }     /**  * 打印所有的 intent extra 数据   *  * @param bundle   * @return   */   private static String printBundle(Bundle bundle) {         StringBuilder sb = new StringBuilder();  for (String key : bundle.keySet()) {             if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) {                 sb.append("\nkey:" + key + ", value:" + bundle.getInt(key));   } else if (key.equals(JPushInterface.EXTRA_CONNECTION_CHANGE)) {                 sb.append("\nkey:" + key + ", value:" + bundle.getBoolean(key));   } else if (key.equals(JPushInterface.EXTRA_EXTRA)) {                 if (TextUtils.isEmpty(bundle.getString(JPushInterface.EXTRA_EXTRA))) {                     Logger.i(TAG, "This message has no Extra data");  continue;  }                 try {                     JSONObject json = new JSONObject(bundle.getString(JPushInterface.EXTRA_EXTRA));   Iterator<String> it = json.keys();  while (it.hasNext()) {                         String myKey = it.next();   sb.append("\nkey:" + key + ", value: [" +                                 myKey + " - " + json.optString(myKey) + "]");   }                 } catch (JSONException e) {                     Logger.e(TAG, "Get message extra JSON error!");   }             } else {                 sb.append("\nkey:" + key + ", value:" + bundle.get(key));   }         }         return sb.toString();   }  }

第六步:创建继承至 JPushMessageReceiver 的广播接收器 MyJpushMessageReceiver

package com.hdl.smartface.receiver;  import android.content.Context;  import android.util.Log;  import cn.jpush.android.api.JPushMessage;  import cn.jpush.android.service.JPushMessageReceiver;  /**  * 自定义JPush message 接收器,包括操作tag/alias的结果返回(仅仅包含tag/alias新接口部分)  * * @author Admin  */public class MyJpushMessageReceiver extends JPushMessageReceiver {     private static final String TAG = "MyJpushMessageReceiver";   @Override   public void onTagOperatorResult(Context context, JPushMessage jPushMessage) {         super.onTagOperatorResult(context, jPushMessage);   Log.e(TAG, "onTagOperatorResult: code = " + jPushMessage.getErrorCode());   }     @Override   public void onCheckTagOperatorResult(Context context, JPushMessage jPushMessage) {         super.onCheckTagOperatorResult(context, jPushMessage);   Log.e(TAG, "onCheckTagOperatorResult: code = " + jPushMessage.getErrorCode());   }     @Override   public void onAliasOperatorResult(Context context, JPushMessage jPushMessage) {         super.onAliasOperatorResult(context, jPushMessage);   Log.e(TAG, "onAliasOperatorResult: code = " + jPushMessage.getErrorCode());   }     @Override   public void onMobileNumberOperatorResult(Context context, JPushMessage jPushMessage) {         super.onMobileNumberOperatorResult(context, jPushMessage);   Log.e(TAG, "onMobileNumberOperatorResult: code = " + jPushMessage.getErrorCode());   }  }

第七步:初始化 SDK

新建应用启动类 MyApp(继承至 Application 的类--如已有此类请忽略新建过程)并在 onCreate 中初始化极光推送。package com.hdl.smartface.base;  import android.app.Application;  import cn.jpush.android.api.JPushInterface;  /**  * 应用启动类   * Created by Admin on 2020/1/11.  * * @author Admin  */  public class MyApp extends Application {     @Override   public void onCreate() {         super.onCreate();   initJpush();   }     /**  * 初始化极光推送   */   private void initJpush() {         //调试模式开关,正式版需设置未false   JPushInterface.setDebugMode(true);   //初始化极光推送   JPushInterface.init(this);   }  }  同时AndroidMenifest.xml中的application标签加入:......   android:name=".base.MyApp"   ...>....

测试

本项目中智能人脸识别终端都是使用的自定义消息(不用弹出通知),通知主要是针对用户 APP 端(会在手机通知栏弹出通知信息)。

测试 Android 端接收通知

打开极光推送后台,“发送通知”页面,输入标题和内容,点击发送预览即可。

a2996456c862d548612e3dc8459389ef.png

此时 APP 端能收到以下信息说明集成成功:

8621593f4e496672da78bb6ce4d22dc7.png

测试 Android 端接收自定义消息

打开极光推送后台,“自定义消息”页面,输入通知内容,点击发送预览即可。

767a00c1314a25006afcbc31be7e0f47.png

此时 APP 端能收到以下信息说明接收自定义消息成功:

943d94954c186ef12eb81b1b2129fa1c.png

消息接收正常,只需要根据消息内容来处理相应的逻辑即可,所以只需要前后端商量好消息的协议即可,倒数第二章会给出一些消息协议的定制建议以便于前端解析协议。

服务端快速集成极光推送

你可能已经发现,发送消息是通过极光推送的后台管理页面发送的,实际业务中总不能跑他们官网一条消息一条消息的发吧!

是的,极光推送是提供得有服务端推送 SDK 的,我们只需要集成他们的 SDK 来发送消息,APP 端负责接收消息即可。

本项目的服务端是基于 Java 开发的,所以使用极光推送服务端 SDK for Java 版来做示例。

创建一个 maven 项目,加入极光推送相关推送:

<?xml version="1.0" encoding="UTF-8"?>  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">  <modelVersion>4.0.0modelVersion>  <parent> <groupId>org.springframework.bootgroupId>  <artifactId>spring-boot-starter-parentartifactId>  <version>2.2.2.RELEASEversion>  <relativePath/>    parent>  <groupId>com.hdlgroupId>  <artifactId>smartfaceartifactId>  <version>0.0.1-SNAPSHOTversion>  <name>smartfacename>  <description>Demo project for Spring Bootdescription>  <properties> <java.version>1.8java.version>  properties>  <dependencies> <dependency> <groupId>org.springframework.bootgroupId>  <artifactId>spring-boot-starterartifactId>  dependency>  <dependency> <groupId>org.springframework.bootgroupId>  <artifactId>spring-boot-starter-testartifactId>  <scope>testscope>  <exclusions> <exclusion> <groupId>org.junit.vintagegroupId>  <artifactId>junit-vintage-engineartifactId>  exclusion> exclusions> dependency>     <dependency>  <groupId>cn.jpush.apigroupId>  <artifactId>jpush-clientartifactId>  <version>3.4.3version>  dependency> <dependency> <groupId>cn.jpush.apigroupId>  <artifactId>jiguang-commonartifactId>  <version>1.1.4version>  dependency> <dependency> <groupId>io.nettygroupId>  <artifactId>netty-allartifactId>  <version>4.1.6.Finalversion>  <scope>compilescope>  dependency> <dependency> <groupId>com.google.code.gsongroupId>  <artifactId>gsonartifactId>  <version>2.3version>  dependency> <dependency> <groupId>org.slf4jgroupId>  <artifactId>slf4j-apiartifactId>  <version>1.7.7version>  dependency>      <dependency>  <groupId>org.slf4jgroupId>  <artifactId>slf4j-log4j12artifactId>  <version>1.7.7version>  dependency> <dependency> <groupId>log4jgroupId>  <artifactId>log4jartifactId>  <version>1.2.17version>  dependency>     dependencies>  <build> <plugins> <plugin> <groupId>org.springframework.bootgroupId>  <artifactId>spring-boot-maven-pluginartifactId>  plugin> plugins> build>  project>

测试服务端下发通知

同步完成,接下来开始测试消息发送:

package com.hdl.smartface;  import cn.jiguang.common.ClientConfig;  import cn.jiguang.common.resp.APIConnectionException;  import cn.jiguang.common.resp.APIRequestException;  import cn.jpush.api.JPushClient;  import cn.jpush.api.push.PushResult;  import cn.jpush.api.push.model.PushPayload;  import org.junit.jupiter.api.Test;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory;  import static cn.jpush.api.push.model.notification.PlatformNotification.ALERT;  public class JPushTest {     protected static final Logger LOG = LoggerFactory.getLogger(SmartfaceApplicationTests.class);   /**  * 极光推送应用管理中获取   */   private static final String MASTER_SECRET = "6031870790216966f74410d1";   /**  * 极光推送应用管理中获取   */   private static final String APP_KEY = "307d4e883d70b727687597fb";  public static PushPayload buildPushObject_all_all_alert() {         return PushPayload.alertAll(ALERT);   }     @Test   public void testPushMsg() {         JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, ClientConfig.getInstance());   // For push, all you need do is to build PushPayload object.   PushPayload payload = buildPushObject_all_all_alert();  try {             PushResult result = jpushClient.sendPush(payload);   LOG.info("Got result - " + result);   } catch (APIConnectionException e) {             // Connection error, should retry later   LOG.error("Connection error, should retry later", e);   } catch (APIRequestException e) {             // Should review the error, and fix the request   LOG.error("Should review the error, and fix the request", e);   LOG.info("HTTP Status: " + e.getStatus());   LOG.info("Error Code: " + e.getErrorCode());   LOG.info("Error Message: " + e.getErrorMessage());   }     }  }

此时服务端控制台输入以下消息说明推送成功:

b0f614809bae80bddb9852f3e756f08c.png

Android 控制台输入以下信息说明接收消息成功:

feabee5f38a04240c2c6dbb160c161cd.png

发送自定义消息

发送自定义消息,只需调用方法 PushPayload.Builder.setMessage(Message.content ("要发送的自定义消息"))即可

/**  * 测试推送自定义消息   */  @Test  public void testPushCustomMsg() {     JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, ClientConfig.getInstance());   PushPayload pushPayload = PushPayload.newBuilder()             .setPlatform(Platform.all())             .setAudience(Audience.all())             .setMessage(Message.content("This is a custom msg"))             .build();  try {         PushResult result = jpushClient.sendPush(pushPayload);   LOG.info("Got result - " + result);   } catch (APIConnectionException e) {         // Connection error, should retry later   LOG.error("Connection error, should retry later", e);   } catch (APIRequestException e) {         // Should review the error, and fix the request   LOG.error("Should review the error, and fix the request", e);   LOG.info("HTTP Status: " + e.getStatus());   LOG.info("Error Code: " + e.getErrorCode());   LOG.info("Error Message: " + e.getErrorMessage());   }  }

APP 端接收到以下消息说明发送自定义消息成功:

b4cfcfd4d95ce7b5843f5ef6d9cbfbf6.png

模拟新增人员信息消息

先来看看人员信息实体类:

package com.hdl.smartface.model;  /**  * 人脸用户信息   */  public class FaceUser {     /**  * 姓名   */   private String name;   /**  * 手机号   */   private String phone;   /**  * 人脸特征值   */   private String featrue;   /**  * 人脸图片   */   private String pic;  ...省略getter setter  toString  }

公共自定义消息实体类(定义说明请看下一节介绍)

package com.hdl.smartface.base;  /**  * 公共自定义消息返回体   */  public class BaseCustomMessage {     /**  * 消息类型   */   private String type;   /**  * 消息简介   */   private String msg;   /**  * 可变参数【扩展参数】   */   private T data;  public String getType() {         return type;   }     public void setType(String type) {         this.type = type;   }     public String getMsg() {         return msg;   }     public void setMsg(String msg) {         this.msg = msg;   }     public T getData() {         return data;   }     public void setData(T data) {         this.data = data;   }     @Override   public String toString() {         return "BaseCustomMessage{" +                 "type='" + type + '\'' +                 ", msg='" + msg + '\'' +                 ", data=" + data +                 '}';   }  }

服务端发送测试消息:

/**  * 测试发送新增人脸信息消息   */  @Test  public void testSendAddFaceUserMessage() {     JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, ClientConfig.getInstance());   //模拟构建需要下发的人员信息   FaceUser faceUser = new FaceUser();   faceUser.setName("大力哥");   faceUser.setPhone("155959595959");   faceUser.setFeatrue("http://face.hdl.com/featrue/155959595959.data");   faceUser.setPic("http://face.hdl.com/pic/155959595959.png");   //模拟构建自定义消息体   BaseCustomMessage faceUserMessage = new BaseCustomMessage<>();   faceUserMessage.setType("1001001");//方便测试,这里写死,type和msg建议按下一章的建议来制定   faceUserMessage.setMsg("新人脸更新");   faceUserMessage.setData(faceUser);   PushPayload pushPayload = PushPayload.newBuilder()             .setPlatform(Platform.all())             .setAudience(Audience.all())             .setMessage(Message.content(new Gson().toJson(faceUserMessage)))//使用gson将对象转成json   .build();  try {         PushResult result = jpushClient.sendPush(pushPayload);   LOG.info("Got result - " + result);   } catch (APIConnectionException e) {         // Connection error, should retry later   LOG.error("Connection error, should retry later", e);   } catch (APIRequestException e) {         // Should review the error, and fix the request   LOG.error("Should review the error, and fix the request", e);   LOG.info("HTTP Status: " + e.getStatus());   LOG.info("Error Code: " + e.getErrorCode());   LOG.info("Error Message: " + e.getErrorMessage());   }  }

此时 APP 端会收到以下消息:

faa5000f2f341815177324031701472c.png

自定义消息推送协议的制定

此处只作为参考,最终还是得根据你们的实际情况来制定。

协议使用 json 来制定,分为公共参数和可变参数部分(或者叫扩展参数):

{     "type":"消息类型编号",     "msg":"消息说明",     "data":根据消息的类型传递不同的json对象  }  

此处的 type 定义,建议后端使用字典来管理或者使用枚举也行,类型的编号建议有一定的编码信息,便于业务的统计与分析,如下图:

3796da31d8c8d7e5ef6a45d2cc06aedf.png

当服务端新增人脸消息时,需要及时下发消息给相应的人脸识别终端下载最新的人脸信息,此时消息协议可以这么定:

{    "type":"1001001",    "msg":"新人脸更新",    "data":{        "name":"大力哥",        "phone":"155959595959",        "featrue":"http://face.hdl.com/featrue/155959595959.data",        "pic":"http://face.hdl.com/pic/155959595959.png"   }}

data 是可变参数字段(或者叫扩展参数字段),根据不同的 type 放回不同的实体即可,再来一个下发人脸识别终端广告的协议:

{    "type":"20010658",    "msg":"广告更新通知",    "data":[       {            "url":"http://face.hdl.com/adv/qhkhk3g523424aqat.png",            "sourceType":"img",            "duration":5,            "title":"恭祝大家新春快乐"       },       {            "url":"http://face.hdl.com/adv/ioweybzgkshywet12b34.mp4",            "sourceType":"vedio",            "duration":-1,            "title":"给大家拜年啦"       },       {            "url":"http://face.hdl.com/adv/shdgwsgsd124sgs.png",            "sourceType":"img",            "duration":5,            "title":"年货节火热进行中"       }   ]}

此时的 data 可以是一个集合,表示下发三条广告信息。

写在最后的话

阅读完本文相信您已经基本了解到如何将极光推送应用到实际项目中,并且能够快速集成 Android 端 SDK 和 Java 服务端 SDK,限于篇幅很多功能未能一一介绍,如看完本文还有疑问可评论留言或者移步官方网站。

下面给出本文的 demo 地址:

极光推送 Android 端集成 Demo:

https://github.com/huangdali/smart_face_jpush

极光推送 Java 服务端集成 Demo:

https://github.com/huangdali/jpush_java_sdk_demo

fff6f77407dae50a4d90a29a6b15bdfc.png

关于极光

极光(Aurora Mobile,纳斯达克股票代码:JG)成立于2011年,是中国领先的开发者服务提供商。极光专注于为移动应用开发者提供稳定高效的消息推送、即时通讯、统计分析、极光分享、短信、一键认证、深度链接等开发者服务。截止到2019年12月份,极光已经为超过50万移动开发者和145.2万款移动应用提供服务,其开发工具包(SDK)安装量累计336亿,月度独立活跃设备13.6亿部。同时,极光持续赋能开发者和传统行业客户,推出精准营销、金融风控、市场洞察、商业地理服务产品,致力于为社会和各行各业提高运营效率,优化决策制定。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/512912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实时数仓入门训练营:Hologres性能调优实践

简介&#xff1a; 《实时数仓入门训练营》由阿里云研究员王峰、阿里云资深技术专家金晓军、阿里云高级产品专家刘一鸣等实时计算 Flink 版和 Hologres 的多名技术/产品一线专家齐上阵&#xff0c;合力搭建此次训练营的课程体系&#xff0c;精心打磨课程内容&#xff0c;直击当下…

re:Invent大会第十年,亚马逊云科技推出了哪些底层自研技术

编辑 | 宋慧 出品 | CSDN云计算 头图 | 付费下载于视觉中国 一转眼&#xff0c; 亚马逊云科技的云计算已经推出了十五年&#xff0c;亚马逊云科技的年度大会 re:Invent 也举办到了第十年。 今年 re:Invent全球 大会上&#xff0c;亚马逊云科技继续向前&#xff0c;发布系列重…

微信小程序(uniapp)api讲解

Uniapp是一个基于Vue.js的跨平台开发框架&#xff0c;可以同时开发微信小程序、H5、App等多个平台的应用。下面是Uniapp常用的API讲解&#xff1a; Vue.js的API Uniapp采用了Vue.js框架&#xff0c;因此可以直接使用Vue.js的API。例如&#xff1a;v-show、v-if、v-for、comput…

mysql 5.7 binlog 压缩_mysql binlog压缩处理

前一段时间系统mysql压力较大&#xff0c;产生大量binlog&#xff0c;大量的binlog删除后又担心后期出现问题难以调查&#xff0c;保存后又占用本身的空间存储。每天产生的binlog可以多达5-6G。因此考虑是否扩容机器达到目的&#xff1f;经过运维同学 建议&#xff0c;可以压缩…

高度为5的3阶b树含有的关键字个数_第15期:索引设计(索引组织方式 B+ 树)

谈到索引&#xff0c;大家并不陌生。索引本身是一种数据结构&#xff0c;存在的目的主要是为了缩短数据检索的时间&#xff0c;最大程度减少磁盘 IO。任何有数据的场景几乎都有索引&#xff0c;比如手机通讯录、文件系统&#xff08;ext4xfsntfs)、数据库系统&#xff08;MySQL…

ARMS企业级场景被集成场景介绍

简介&#xff1a; ARMS企业级场景被集成场景介绍 通过本次最佳实践内容&#xff0c;您可以看到ARMS OpenAPI可以灵活的被集成到客户链路监控场景&#xff0c;并对其进行可视化图形展示监控信息。 1. 背景信息 应用实时监控服务ARMS&#xff08;Application Real-Time Monitor…

千万并发连接下,如何保障网络性能

过去几十年互联网呈爆发式的增长&#xff0c;内容的丰富以及层出不穷的DDoS攻击等&#xff0c;对网络性能提出了极大的挑战&#xff0c;也同样促进了网络基础设施的快速发展。运营商的带宽越来越大&#xff0c;CPU/网卡等硬件的性能也会越来越强。但在很长时间内&#xff0c;软…

kafka window 启动_Apache Flink结合Kafka构建端到端的Exactly-Once处理

Apache Flink自2017年12月发布的1.4.0版本开始&#xff0c;为流计算引入了一个重要的里程碑特性&#xff1a;TwoPhaseCommitSinkFunction&#xff08;相关的Jira&#xff09;。它提取了两阶段提交协议的通用逻辑&#xff0c;使得通过Flink来构建端到端的Exactly-Once程序成为可…

浅谈云原生架构的 7 个原则

简介&#xff1a; 作为一种架构模式&#xff0c;云原生架构通过若干原则来对应用架构进行核心控制。这些原则可以帮助技术主管和架构师在进行技术选型时更加高效、准确&#xff0c;下面将展开具体介绍。 服务化原则 在软件开发过程中&#xff0c;当代码数量与开发团队规模都扩…

深入浅出FlatBuffers原理

简介&#xff1a; FlatBuffers 是一个开源的、跨平台的、高效的、提供了多种语言接口的序列化工具库。实现了与 Protocal Buffers 类似的序列化格式。主要由 Wouter van Oortmerssen 编写&#xff0c;并由 Google 开源。本文将基于高德地图数据编译增量发布使用了FlatBuffers序…

java 反编译class文件_用Java实现JVM第三章《解析class文件》

解析class文件案例介绍本案例主要介绍通过java代码从class文件中解析&#xff1b;class文件、常量池、属性表&#xff1b;作为类(或者接口)信息的载体&#xff0c;每个class文件都完整地定义了一个类。为了使java程序可以“编写一次&#xff0c;处处运行”&#xff0c;Java虚拟…

解放人与设备距离,5G时代的远程操控该如何完成

物联网这个概念早在十多年前便已提出&#xff0c;其主要依托于移动通讯网络来实现其功能的传输。在过去物联网领域的一些设备控制场景中&#xff0c;我们或多或少都见到过远程控制技术的身影&#xff0c;但受限于当时的网络条件和技术场景&#xff0c;大部分应用都属于对设备的…

Spark 大数据处理最佳实践

开源大数据社区 & 阿里云 EMR 系列直播 第十一期 主题&#xff1a;Spark 大数据处理最佳实践 讲师&#xff1a;简锋&#xff0c;阿里云 EMR 数据开发平台 负责人 内容框架&#xff1a; 大数据概览如何摆脱技术小白Spark SQL 学习框架EMR Studio 上的大数据最佳实践 直播…

CNCF TOC 委员张磊:不断演进的云原生给我们带来了什么?

简介&#xff1a; 任何一种云原生技术&#xff0c;它不再是某种能力的弥补&#xff0c;而是更多地将云的能力以某种方式更简单、更高效地透出给我的应用去使用。无论是容器、K8s 还是 Service Mesh&#xff0c;他们都是在不同的环节帮助应用本身能够更好地去使用云服务。 作者…

php url传递参数_互联网系统(APP、网站等)通信基石——会话(PHP版)

一、会话概述1.1、技术背景互联网通信中采用的Http协议(建立TCP连接->Http请求->Http应答->断开TCP连接)本身是无状态的&#xff0c;即Http各请求之间是相互独立、互不相关的&#xff0c;而大量应用需要将各请求关联起来(如&#xff1a;用户登录系统购物、多次购买行为…

十年探索,云上明灯,re:Invent再启掀产业风暴

15年前&#xff0c;IT基础设施有着太多的限制&#xff0c;成本高、反应慢、灵活度低&#xff0c;对于企业的创新与发展有着很大的伤害。当亚马逊推出全球第一个云计算服务简单存储 Amazon S3时&#xff0c;可能没有太多人相信&#xff0c;这些内容将会开启一个新世界的大门&…

用手机「3D探店」是种什么体验?

简介&#xff1a; 未来场景尽在眼前&#xff01;阿里云3D全景网站通过云端算法技术自动建模&#xff0c;将线下场景1:1真实还原到线上&#xff0c;让用户足不出户就可以感受到真实的3D空间漫游效果。 在手机里用3D探店打卡是种什么样的体验&#xff1f; 走进商场&#xff0c;每…

mysql bin oct_python 讲解进制转换 int、bin、oct、hex

相关免费学习推荐&#xff1a;python视频教程原理十进制转n进制都可以使用倒除法&#xff1a;对十进制进行除n的运算&#xff0c;直到商为0为止&#xff0c;然后将各个步骤中得到的余数倒着写出来.n进制转十进制&#xff1a;(例子&#xff1a;二进制转十进制)101001 > 2^5 …

java设置字体大小和颜色_Java 设置Excel图表背景填充(颜色、图片填充)

本文介绍通过Java程序来设置Excel图表背景填充的方法&#xff0c;填充时&#xff0c;可设置颜色填充或者加载图片填充&#xff1b;填充区域可设置整个图表区域或者绘图区域。设置方法参考以下内容。使用工具&#xff1a;Free Spire.XLS for Java&#xff08;免费版&#xff09;…

英特尔TCI技术落地,锐捷网络发布OCS终端云化新品

编辑 | 宋慧 出品 | CSDN 云计算 2021 年 6 月&#xff0c;国内一直深耕桌面虚拟化的厂商锐捷正式发布了新一代云桌面解决方案——锐捷三擎云桌面解决方案&#xff08; “精耕细作”桌面云市场的锐捷&#xff0c;重磅发布三擎云桌面 &#xff09;&#xff0c;其中三擎指的是终端…