Using Leancloud to realize push notification of React Native App-android chapter

Preface

InLast articleWe have explained in detail the process of implementing iOS message push with Leancloud, and today this article will continue to explain the implementation of Android message push.

Access to Leancloud

Before accessing the Leancoud, it is recommended to read the Leancoud official first.Android Message Push Development Guide.

Install Leancloud SDK

There are many ways to install SDK, please refer toAndroid SDK installation guide. I chose to install with Gradle, first in the root directorybuild.gradleMaven warehouse address for adding Leancloud to:

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"
 }
 }
 }

Then open thebuild.gradleMake the following configuration:

android {
//To solve the problem that some third-party libraries have repeatedly packaged META-INF
packagingOptions{
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
lintOptions {
abortOnError false
}
...
}

...

dependencies {
...

// LeanCloud foundation package
compile ('cn.leancloud.android:avoscloud-sdk:v4.6.4')
//Push the packages needed for real-time chat
compile ('cn.leancloud.android:avoscloud-push:v4.6.4@aar'){transitive = true}
}

Initialize Leancloud

We need to initialize and modify the App with the AppId and AppKey of Leancloud after the app is created.MainApplicationAs follows:

@Override
 public void onCreate() {
 super.onCreate();
 ...
 //initialize leancloud
 AVOSCloud.initialize(this,"ppdriT1clcnRoda0okCPaB48-gzGzoHsz","Qzarq5cMdWzAMjwDW4umWpBL");
 }

Next, inAndroidManifest.xmlThe permissions required to configure the Leancloud SDK and the service and receiver required for message push in:

...

<!  -basic module (following declaration must be added) 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" />
<!  -basic module END -- >

<application
...
android:name=".MainApplication" >
...

<!  -real-time communication module, push (all need to add the following statement) START -- >
<!  -push service should be used for real-time communication module and push->
<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>
<!  -real-time communication module, push END -- >
</application>

At this point, the access to the Leancloud SDK is complete, and we need to test whether the SDK can be used normally. We areMainActivity.javaTheonCreateMethod to see if the data can be saved to the Leancloud database:

@Override
protected void onCreate(Bundle savedInstanceState) {
...
//code to test whether SDK works properly
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!"  );
}
}
});

...
}

Start the App and go to the Leancoud console to see if there is an additional TestObject record in the database. If there is any indication that the Leancloud SDK has been successfully accessed:

image

Save Installation

Like iOS, Android needs to save installation to allow Leancloud to determine which devices to push.However, what is more shocking is that Leancloud officially provided it.leancloud-installationInstallation of iOS devices can only be saved correctly.Therefore, we can only use Android SDK to save installation, and we’d better package this method as a native module and expose it to js calls, so as to facilitate the corresponding operation after the save succeeds or fails.

Incom.leancloudpushdemoCreate in folderPushModule.java,PushDemoInherit fromReactContextBaseJavaModuleAnd realizeActivityEventListenerInterface, add the following code:

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) {}

/**
* Save installation
*/
@ReactMethod
public void saveInstaillation(final Callback resultCallback) {
AVInstallation.getCurrentInstallation().saveInBackground(new SaveCallback() {
public void done(AVException e) {
if (e == null) {
//Save Successfully
String installationId = AVInstallation.getCurrentInstallation().getInstallationId();
resultCallback.invoke(installationId);
} else {
resultCallback.invoke();
}
}
});
}
}

Then add it under the same directory.PushPackage.javaFor registrationPushModuleModule, code is as follows:

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();
 }
 }

Then, inMainApplication.javahit the targetgetPackagesAdded in methodPushPackage

@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
...
new PushPackage()
);
}

Then, in ourPushService.jsIntroduction ofPushModuleAnd save the 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) {
Log ('android installation saved successfully!'  );
}
})
}
...
}

Finally, inApp.jsTo perform Android initialization in:

componentDidMount() {
 if (Platform.OS === 'ios') {
 PushService._iOS_initPush();
 } else {
 PushService._an_initPush();
 }
 MessageBarManager.registerMessageBar(this.refs.alert);
 }

Restart App and go to Leancloud console to see if there is an installation record in the database. If there is any explanation, save successfully:

image

If there is no problem with the confirmation code, but it is still not saved successfully, I suggest:

  1. Restart Android Studio
  2. Restart reactive packager
  3. Restart the computer and mobile phone. .
  4. If you have any questions, please contact me.

Implementation of system push

Start push service

First call Leancloud SDK to start push service:

PushService.setDefaultPushCallback(getReactApplicationContext(), PushHandlerActivity.class);

PushHandlerActivityIn order to receive the activity that is opened by default upon notification, we will implement it next.

PushHandlerActivity implementation

The activity is positioned to receive and initially parse notification data. We arecom.leancloudpushdemoAdd under folderPushHandlerActivity.java, which reads as follows:

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 (!  Isactive ()) {//todo: judge whether PushModule is instantiated or not.
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: handle notifications
} catch (Exception e) {
PushModule.onError(e);  // todo: handle errors
}
}

private void relaunchActivity() {
PackageManager pm = getPackageManager();
Intent launchIntent = pm.getLaunchIntentForPackage(getApplicationContext().getPackageName());
startActivity(launchIntent);
}
}

Don’t forget to be inAndroidManifest.xml

<activity android:name=".PushHandlerActivity"></activity>

Main processing logic implementation

PushHandlerActivityThere are three places in the codetodoPushModuleThe logic implemented in. As for how to deal with after receiving the notification, my thinking is that when the native module receives the notification, it will passTrigger corresponding events, monitor these events in js, respond and modify themPushModuleAs follows:

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;
 }
 
 ...

Finally, we are inPushService.jsTo increase the logic of monitoring and processing related events of message notification, I choose to increase monitoring after the installation is successfully saved:

...

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');
}
}
...

image

image

The push in the App open state is realized

So far, we have implemented system-level push. Like iOS, we hope Android App can pop up a notification reminder when it is open. Leancloud offers the possibility that we canCustom ReceiverTo achieve.

Custom Receiver

We areCustomPushReceiver.java, code is as follows:

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");
//Get the message content
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: handle notifications
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;
}
}

todoThe method will be available later.PushModuleTo be realized in. Then, inAndroidManifest.xmlAdd custom receiver to:

<receiver android:name="com.leancloudpushdemo.CustomPushReceiver">
 <intent-filter>
 <action android:name="com.cnuip.INNER_NOTI" />
 </intent-filter>
 </receiver>

Notification processing

As follows:

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, increase the rightON_CUSTOM_RECEIVEMonitoring of events:

...
 _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 {
 ...
 }
 })
 }
 ...

At the same time, the notification message needs to be modified to be received by custom receiver. We can use Postman to send the message:

image

After the message was sent out, the App successfully popped up a message reminder, perfect.

image

Conclusion

After unremitting efforts, we have successfully implemented message notification on iOS and Android using Leancloud. It is still a bit tiring to write such a long article for the first time. . If it is helpful to you, welcome to praise! And although all the functions have been realized, I think there may be a better way to realize it. Welcome to share it with your classmates. Thank you!

Related links

IOS article address:Using Leancloud to realize Push Notification)- iOS React Native App-ios

This article Demo Github address:https://github.com/MudOnTire/LeancloudPushDemo)