项目背景
最近开发的一款人脸识别终端管理系统,主要包括运营平台、企业后台管理系统、APP 端、智能人脸识别终端模块。
下图是系统的架构图:
其中各个模块之间都需要即时通讯,比如:
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 的项目(有项目的请忽略这一步)
第二步:配置 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:
第三步:配置清单文件
在 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 端接收通知
打开极光推送后台,“发送通知”页面,输入标题和内容,点击发送预览即可。
此时 APP 端能收到以下信息说明集成成功:
测试 Android 端接收自定义消息
打开极光推送后台,“自定义消息”页面,输入通知内容,点击发送预览即可。
此时 APP 端能收到以下信息说明接收自定义消息成功:
消息接收正常,只需要根据消息内容来处理相应的逻辑即可,所以只需要前后端商量好消息的协议即可,倒数第二章会给出一些消息协议的定制建议以便于前端解析协议。
服务端快速集成极光推送
你可能已经发现,发送消息是通过极光推送的后台管理页面发送的,实际业务中总不能跑他们官网一条消息一条消息的发吧!
是的,极光推送是提供得有服务端推送 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()); } } }
此时服务端控制台输入以下消息说明推送成功:
Android 控制台输入以下信息说明接收消息成功:
发送自定义消息
发送自定义消息,只需调用方法 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 端接收到以下消息说明发送自定义消息成功:
模拟新增人员信息消息
先来看看人员信息实体类:
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 端会收到以下消息:
自定义消息推送协议的制定
此处只作为参考,最终还是得根据你们的实际情况来制定。
协议使用 json 来制定,分为公共参数和可变参数部分(或者叫扩展参数):
{ "type":"消息类型编号", "msg":"消息说明", "data":根据消息的类型传递不同的json对象 }
此处的 type 定义,建议后端使用字典来管理或者使用枚举也行,类型的编号建议有一定的编码信息,便于业务的统计与分析,如下图:
当服务端新增人脸消息时,需要及时下发消息给相应的人脸识别终端下载最新的人脸信息,此时消息协议可以这么定:
{ "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
关于极光
极光(Aurora Mobile,纳斯达克股票代码:JG)成立于2011年,是中国领先的开发者服务提供商。极光专注于为移动应用开发者提供稳定高效的消息推送、即时通讯、统计分析、极光分享、短信、一键认证、深度链接等开发者服务。截止到2019年12月份,极光已经为超过50万移动开发者和145.2万款移动应用提供服务,其开发工具包(SDK)安装量累计336亿,月度独立活跃设备13.6亿部。同时,极光持续赋能开发者和传统行业客户,推出精准营销、金融风控、市场洞察、商业地理服务产品,致力于为社会和各行各业提高运营效率,优化决策制定。