在上一篇文章 中咱們詳細講解了用Leancloud實現iOS消息推送的流程,今天本文將繼續講解實現Android的消息推送。html
在接入Leancloud以前,仍是推薦先閱讀Leancloud官方的 Android消息推送開發指南。java
SDK有多種安裝方式,詳情請參考Android SDK安裝指南。我選擇用Gradle安裝,先在根目錄下的build.gradle
中添加Leancloud的maven倉庫地址:node
buildscript { repositories { jcenter() maven { url 'https://maven.google.com/' name 'Google' } maven { url "http://mvn.leancloud.cn/nexus/content/repositories/public" } } dependencies { classpath 'com.android.tools.build:gradle:2.3.3' } } allprojects { repositories { mavenLocal() jcenter() maven { url "$rootDir/../node_modules/react-native/android" } maven { url 'https://maven.google.com/' name 'Google' } maven { url "http://mvn.leancloud.cn/nexus/content/repositories/public" } } }
而後打開 app 目錄下的 build.gradle
進行以下配置:react
android { //爲了解決部分第三方庫重複打包了META-INF的問題 packagingOptions{ exclude 'META-INF/LICENSE.txt' exclude 'META-INF/NOTICE.txt' } lintOptions { abortOnError false } ... } ... dependencies { ... // LeanCloud 基礎包 compile ('cn.leancloud.android:avoscloud-sdk:v4.6.4') // 推送與實時聊天須要的包 compile ('cn.leancloud.android:avoscloud-push:v4.6.4@aar'){transitive = true} }
咱們須要在App建立後用Leancloud的AppId,AppKey進行初始化,修改MainApplication
以下:android
@Override public void onCreate() { super.onCreate(); ... //初始化leancloud AVOSCloud.initialize(this,"ppdriT1clcnRoda0okCPaB48-gzGzoHsz","Qzarq5cMdWzAMjwDW4umWpBL"); }
接下來,在AndroidManifest.xml
中配置Leancloud SDK所需的權限以及消息推送所需的service和receiver:ios
... <!-- 基礎模塊(必須加入如下聲明)START --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 基礎模塊 END --> <application ... android:name=".MainApplication" > ... <!-- 實時通訊模塊、推送(均須要加入如下聲明) START --> <!-- 實時通訊模塊、推送都要使用 PushService --> <service android:name="com.avos.avoscloud.PushService"/> <receiver android:name="com.avos.avoscloud.AVBroadcastReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.USER_PRESENT"/> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> </intent-filter> </receiver> <!-- 實時通訊模塊、推送 END --> </application>
到此,Leancloud SDK的接入完成,咱們須要測試一下SDK能不能正常使用。咱們在MainActivity.java
的onCreate
方法中添加代碼看能不能保存數據到Leancloud數據庫:git
@Override protected void onCreate(Bundle savedInstanceState) { ... // 測試 SDK 是否正常工做的代碼 AVObject testObject = new AVObject("TestObject"); testObject.put("words","Hello World!"); testObject.saveInBackground(new SaveCallback() { @Override public void done(AVException e) { if(e == null){ Log.d("saved","success!"); } } }); ... }
啓動App,前往Leancloud控制檯,查看數據庫中是否多了一條TestObject的記錄,若是有說明Leancloud SDK接入成功:github
和iOS同樣,Android也須要保存installation才能讓Leancloud肯定推送到哪些設備。可是比較坑的是:Leancloud官方提供的 leancloud-installation只能正確保存iOS設備的installation。 所以咱們只能使用Android的SDK保存installation,並且咱們最好把這個方法封裝成一個native模塊暴露給js調用,以方便在保存成功或失敗後執行相應操做。數據庫
在com.leancloudpushdemo
文件夾中建立PushModule.java
,PushDemo
繼承於ReactContextBaseJavaModule
並實現ActivityEventListener
接口,添加以下代碼:npm
package com.leancloudpushdemo; import android.app.Activity; import android.content.Intent; import com.avos.avoscloud.AVException; import com.avos.avoscloud.AVInstallation; import com.avos.avoscloud.SaveCallback; import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; public class PushModule extends ReactContextBaseJavaModule implements ActivityEventListener { public PushModule(ReactApplicationContext reactContext) { super(reactContext); } @Override public String getName() { return "androidPushModule"; } @Override public void onNewIntent(Intent intent) {} @Override public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {} /** * 保存installation */ @ReactMethod public void saveInstaillation(final Callback resultCallback) { AVInstallation.getCurrentInstallation().saveInBackground(new SaveCallback() { public void done(AVException e) { if (e == null) { // 保存成功 String installationId = AVInstallation.getCurrentInstallation().getInstallationId(); resultCallback.invoke(installationId); } else { resultCallback.invoke(); } } }); } }
接着在同一目錄下面添加PushPackage.java
用於註冊PushModule
模塊,代碼以下:
package com.leancloudpushdemo; import com.facebook.react.ReactPackage; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.ViewManager; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class PushPackage implements ReactPackage { @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); modules.add(new PushModule(reactContext)); return modules; } @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); } }
而後,在MainApplication.java
中的getPackages
方法中增長PushPackage
:
@Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( ... new PushPackage() ); }
接着,在咱們的PushService.js
中引入PushModule
並保存installation:
... import { NativeModules } from 'react-native'; const AndroidPush = NativeModules.androidPushModule; ... class PushService { ... //Android _an_initPush = () => { this._an_saveInstallation(); } _an_saveInstallation = () => { AndroidPush.saveInstaillation((installationId) => { if (installationId) { console.log('Android installation 保存成功!'); } }) } ... }
最後,在App.js
中執行Android的初始化:
componentDidMount() { if (Platform.OS === 'ios') { PushService._iOS_initPush(); } else { PushService._an_initPush(); } MessageBarManager.registerMessageBar(this.refs.alert); }
重啓App,前往Leancloud控制檯中查看數據庫中是否多了一條installation記錄,若是有說明保存成功:
若是確認代碼沒問題,可是仍是保存不成功,我建議:
首先調用Leancloud SDK啓動推送服務:
PushService.setDefaultPushCallback(getReactApplicationContext(), PushHandlerActivity.class);
PushHandlerActivity
爲收到通知默認打開的activity,咱們接下來實現。
該activity的定位爲接收並初步解析通知數據。咱們在com.leancloudpushdemo
文件夾下添加PushHandlerActivity.java
,內容以下:
package com.leancloudpushdemo; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import java.util.HashMap; import java.util.Map; public class PushHandlerActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); processPush(); finish(); if (!PushModule.isActive()) { //todo:判斷PushModule是否實例化 relaunchActivity(); } } private void processPush() { try { Intent intent = getIntent(); String action = intent.getAction(); String channel = intent.getExtras().getString("com.avos.avoscloud.Channel"); String data = intent.getExtras().getString("com.avos.avoscloud.Data"); Map<String, String> map = new HashMap<String, String>(); map.put("action", action); map.put("channel", channel); map.put("data", data); PushModule.onReceive(map); //todo:處理通知 } catch (Exception e) { PushModule.onError(e); // todo:處理錯誤 } } private void relaunchActivity() { PackageManager pm = getPackageManager(); Intent launchIntent = pm.getLaunchIntentForPackage(getApplicationContext().getPackageName()); startActivity(launchIntent); } }
別忘了在AndroidManifest.xml
中加上該activity:
<activity android:name=".PushHandlerActivity"></activity>
PushHandlerActivity
代碼中有三處todo
是咱們接下來要在PushModule
中實現的邏輯。關於接收到通知後如何處理,個人思路是當native module收到通知時,經過RCTDeviceEventEmitter
觸發相應的Event,在js中監聽這些Event並響應,修改PushModule
以下:
public class PushModule extends ReactContextBaseJavaModule implements ActivityEventListener { private static PushModule singleton; private static String ON_RECEIVE = "leancloudPushOnReceive"; private static String ON_ERROR = "leancloudPushOnError"; public PushModule(ReactApplicationContext reactContext) { super(reactContext); singleton = this; } ... protected static boolean isActive() { return singleton != null; } private static WritableMap getWritableMap(Map<String, String> map) { WritableMap writableMap = Arguments.createMap(); writableMap.putString("action", map.get("action")); writableMap.putString("channel", map.get("channel")); writableMap.putString("data", map.get("data")); return writableMap; } protected static void onReceive(Map<String, String> map) { if (singleton != null) { WritableMap pushNotification = getWritableMap(map); DeviceEventManagerModule.RCTDeviceEventEmitter emitter = singleton.getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class); emitter.emit(ON_RECEIVE, pushNotification); } } protected static void onError(Exception e) { if (singleton != null) { WritableMap error = Arguments.createMap(); error.putString("message", e.getLocalizedMessage()); DeviceEventManagerModule.RCTDeviceEventEmitter emitter = singleton.getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class); emitter.emit(ON_ERROR, error); } } @Override public Map<String, Object> getConstants() { final Map<String, Object> constants = new HashMap<>(); constants.put("ON_RECEIVE", ON_RECEIVE); constants.put("ON_ERROR", ON_ERROR); return constants; } ...
最後,咱們在PushService.js
增長對消息通知相關事件的監聽和處理的邏輯,我選擇在保存installation成功後增長監聽:
... import { DeviceEventEmitter } from 'react-native'; ... class PushService { ... _an_saveInstallation = () => { AndroidPush.saveInstaillation((installationId, error) => { if (installationId) { DeviceEventEmitter.addListener(AndroidPush.ON_RECEIVE, (notification) => { console.log('receive android notification'); this._an_onNotificationTapped(notification); }); DeviceEventEmitter.addListener(AndroidPush.ON_ERROR, (res) => { console.log('android notification error'); console.log(res); }); } else { console.log(error); } }) } _an_onNotificationTapped = (notification) => { Alert.alert('Android Notification Tapped'); } } ...
如今咱們在Leancloud控制檯發送一條通知,手機應該能收到消息:
當點擊通知的時候,App打開並執行咱們自定義的邏輯:
到目前爲止,咱們已經實現了系統級的推送,和iOS同樣,咱們但願Android App打開狀態下也能彈出通知提醒。Leancloud提供了這樣的可能,咱們能夠經過 自定義Receiver 來實現。
咱們在com.leancloudpushdemo
路徑下添加CustomPushReceiver.java
,代碼以下:
package com.leancloudpushdemo; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import java.util.HashMap; import java.util.Map; public class CustomPushReceiver extends BroadcastReceiver { private static final String TAG = "CustomPushReceiver"; private HandleMessage handleMessage; @Override public void onReceive(Context context, Intent intent) { try { String action = intent.getAction(); String channel = intent.getExtras().getString("com.avos.avoscloud.Channel"); //獲取消息內容 String data = intent.getExtras().getString("com.avos.avoscloud.Data"); JSONObject jsonObject = JSON.parseObject(data); if (jsonObject != null) { Map<String, String> map = new HashMap<String, String>(); map.put("action", action); map.put("channel", channel); map.put("data", data); PushModule.onCustomReceive(map); //todo: 處理通知 if (handleMessage!=null){ handleMessage.receiveMessage(jsonObject); } } } catch (JSONException e) { PushModule.onError(e); } } interface HandleMessage{ public void receiveMessage(JSONObject jsonObject); } public void setHandleMessage(HandleMessage handleMessage) { this.handleMessage = handleMessage; } }
todo
的方法待會兒在PushModule
中實現。接着,在AndroidManifest.xml
中添加custom receiver:
<receiver android:name="com.leancloudpushdemo.CustomPushReceiver"> <intent-filter> <action android:name="com.cnuip.INNER_NOTI" /> </intent-filter> </receiver>
而後修改PushModule
以下:
public class PushModule extends ReactContextBaseJavaModule implements ActivityEventListener { ... private static String ON_CUSTOM_RECEIVE = "leancloudPushOnCustomReceive"; ... protected static void onCustomReceive(Map<String, String> map) { if (singleton != null) { WritableMap pushNotification = getWritableMap(map); DeviceEventManagerModule.RCTDeviceEventEmitter emitter = singleton.getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class); emitter.emit(ON_CUSTOM_RECEIVE, pushNotification); } } ... @Override public Map<String, Object> getConstants() { final Map<String, Object> constants = new HashMap<>(); constants.put("ON_RECEIVE", ON_RECEIVE); constants.put("ON_CUSTOM_RECEIVE", ON_CUSTOM_RECEIVE); constants.put("ON_ERROR", ON_ERROR); return constants; } }
最後,修改PushService.js
,增長對ON_CUSTOM_RECEIVE
事件的監聽:
... _an_saveInstallation = () => { AndroidPush.saveInstaillation((installationId, error) => { if (installationId) { ... DeviceEventEmitter.addListener(AndroidPush.ON_CUSTOM_RECEIVE, (notification) => { console.log('receive custom android notification'); this._showAlert(JSON.parse(notification.data).alert); }); ... } else { ... } }) } ...
同時通知的消息提也須要作相應修改,才能讓custom receiver接收到,咱們能夠用Postman來發送消息:
消息發出後,App中成功彈出消息提醒,完美。
通過不懈的努力,咱們已經成功使用Leancloud實現了iOS和Android上的消息通知,第一次寫這麼長的文章仍是有點累的。。若是對你有幫助歡迎點贊!還有雖然功能都實現了,可是我想可能還會有更好的實現方式,歡迎找到的同窗分享,謝謝!
iOS篇地址:使用Leancloud實現React Native App的消息推送(Push Notification)- iOS篇
本文Demo Github地址:https://github.com/MudOnTire/LeancloudPushDemo)