更新时间:2020-10-27 19:02
React Native(简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的UI框架React在原生移动应用平台的衍生产物,目前支持Android和iOS两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。
近年来Web化已成为移动端开发的一大趋势,越来越多的开发者倾向于使用ReactNative等web框架来开发App,而阿里云移动推送同样支持ReactNative开发模式,接下来为大家介绍如何在ReactNative工程中集成阿里云移动推送服务。
如果您已有构建好的ReactNative工程,可直接跳过本节。如果您是第一次接触ReactNative,可以参考官方教程创建自己的第一个ReactNative应用。
本节以ReactNative实例工程AwesomeProject
作为实例工程为大家介绍移动推送Android SDK的接入步骤。
可先下载Demo示例工程,再结合本教程效果更佳。
ReactNative模式下接入移动推送SDK的方式和传统Android开发模式下接入SDK一样,相关接入方式可以参考:移动推送Android SDK接入指南,SDK版本号以接入指南为准,这里介绍Maven远程依赖具体写法,手动依赖参见接入指南。
在Android工程根目录(比如\AwesomeProject\android\)下build.gradle文件中配置maven库URL:
allprojects {
repositories {
jcenter()
maven {
url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
}
}
}
在Android工程对应的module(比如\AwesomeProject\android\app\)下的build.gradle文件中添加对应依赖:
android {
......
defaultConfig {
applicationId "com.xxx.xxx" //包名,与控制台包名一直
......
ndk {
//选择要添加的对应cpu类型的.so库。
//推送支持'arm64-v8a', 'armeabi', 'armeabi-v7a', 'x86', 'x86_64', 'mips', 'mips64'七种。
abiFilters 'armeabi', 'x86'
}
......
}
......
}
dependencies {
......
compile 'com.aliyun.ams:alicloud-android-push:3.1.12@aar'
compile 'com.aliyun.ams:alicloud-android-utdid:2.5.1-proguard'
compile 'com.aliyun.ams:alicloud-android-utils:1.1.6.4'
compile 'com.aliyun.ams:alicloud-android-ut:5.4.3'
compile 'com.aliyun.ams:alicloud-android-beacon:1.0.4.3'
// 或
compile 'com.aliyun.ams:alicloud-android-push:3.1.12'
......
}
注意:如果在添加以上abiFilter配置之后编译或其他场景出现以下提示:
NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin.
则在Android工程根目录(比如\AwesomeProject\android\)的gradle.properties文件中添加:
android.useDeprecatedNdk=true
在Android工程的对应module目录(比如\AwesomeProject\android\app\src\main\)的AndroidManifest.xml中,application标签下设置appKey,appSecret:
<application android:name="*****">
<meta-data android:name="com.alibaba.app.appkey" android:value="*****"/> <!-- 请填写你自己的- appKey -->
<meta-data android:name="com.alibaba.app.appsecret" android:value="****"/> <!-- 请填写你自己的appSecret -->
</application>
ReactNative模式下常常需要通过JavaScript调用推送SDK native接口,完整调用过程包含以下三步。
在Android工程目录的java代码目录中(比如\AwesomeProject\android\app\src\main\java\com\awesomeproject\),创建PushModule,继承自ReactContextBaseJavaModule
,可参考以下代码:
public class PushModule extends ReactContextBaseJavaModule {
private static ReactContext context;
public PushModule(ReactApplicationContext reactContext) {
super(reactContext);
context = reactContext;
}
public static ReactContext getContext() {
return context;
}
//模块名,在JavaScript中调用相关方法时需要首先引入MPush模块
@Override
public String getName() {
return "MPush";
}
@ReactMethod
public void getDeviceId(Callback callback) {
callback.invoke(PushServiceFactory.getCloudPushService().getDeviceId());
}
@ReactMethod
public void bindAccount(String account, final Callback callback) {
PushServiceFactory.getCloudPushService().bindAccount(account, new CommonCallback() {
@Override
public void onSuccess(String s) {
callback.invoke("bind account success");
}
@Override
public void onFailed(String s, String s1) {
callback.invoke("bind account failed. errorCode:" + s + ", errorMsg:" + s1);
}
});
}
......
}
getName()
: 这个方法用于在JavaScript端标记这个模块。这里我们把这个模块命名为MPush,这样就可以在JavaScript中通过NativeModules.MPush访问到这个模块。@ReactMethod
:要导出一个方法给JavaScript使用,Java方法需要使用注解 @ReactMethod,方法的返回类型必须为void。React Native的跨语言访问是异步进行的,所以想要给JavaScript返回一个值的唯一办法是使用回调函数或者发送事件。在Android工程目录的java代码目录中(比如\AwesomeProject\android\app\src\main\java\com\awesomeproject\),创建一个Package类 PushPackage并实现ReactPackage,在createNativeModules方法中添加这个模块。
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<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
在Android工程目录的java代码目录(比如\AwesomeProject\android\app\src\main\java\com\awesomeproject),Application(比如默认创建的是MainApplication extends Application implements ReactApplication)中的ReactNativeHost实例里getPackages方法添加PushPackage实例。
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new PushPackage()
);
}
//引入MPush模块
var {NativeModules}=require('react-native');
var mPush = NativeModules.MPush;
export default class AwesomeProject extends Component {
......
//调用Native方法
getDeviceId() {
var that = this;
mPush.getDeviceId(function(args) {
that.setState({
deviceIdBtnTitle: args
});
});
}
......
}
当终端接收到推送消息时需要将对应的消息发送到JavaScript,此时需要用到ReactNative的事件机制。
在消息接收回调函数中添加事件发送逻辑,先在Android工程目录的java代码目录中(比如\AwesomeProject\android\app\src\main\java\com\awesomeproject\),创建自定义接收器,比如MyMessageReceiver,继承com.alibaba.sdk.android.push.MessageReceiver:(这里举例通知类型接收到时触发的onNotification,以及消息类型接收到时触发的onMessage,全部回调接口参见SDK API介绍)
public class MyMessageReceiver extends MessageReceiver {
public MyMessageReceiver() {
super();
}
@Override
protected void onMessage(Context context, CPushMessage cPushMessage) {
super.onMessage(context, cPushMessage);
WritableMap params = Arguments.createMap();
params.putString("messageId", cPushMessage.getMessageId());
params.putString("content", cPushMessage.getContent());
params.putString("title", cPushMessage.getTitle());
PushModule.sendEvent(getReactContext(), "onMessage", params);
}
@Override
protected void onNotification(Context context, String s, String s1, Map<String, String> map) {
super.onNotification(context, s, s1, map);
WritableMap params = Arguments.createMap();
params.putString("content", s1);
params.putString("title", s);
for (Map.Entry<String, String> entry: map.entrySet()) {
params.putString(entry.getKey(), entry.getValue());
}
sendEvent(getReactContext(), "onNotification", params);
}
private void sendEvent(ReactContext context, String eventName, @Nullable WritableMap params) {
if (context == null) {
Log.i(TAG, "reactContext==null");
}else{
context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
}
}
将该receiver添加到Android工程中对应module目录(比如\AwesomeProject\android\app\src\main\)的AndroidManifest.xml中:
<!-- 消息接收监听器(用户可自主扩展)-->
<receiver
android:name=".MyMessageReceiver"
android:exported="false"> <!-- 为保证receiver安全,建议设置不可导出,如需对其他应用开放可通过android:permission进行限制 -->
<intent-filter>
<action android:name="com.alibaba.push2.action.NOTIFICATION_OPENED" />
</intent-filter>
<intent-filter>
<action android:name="com.alibaba.push2.action.NOTIFICATION_REMOVED" />
</intent-filter>
<intent-filter>
<action android:name="com.alibaba.sdk.android.push.RECEIVE" />
</intent-filter>
</receiver>
//导入相关模块
import {
AppRegistry,
MPush,
DeviceEventEmitter,
......
} from 'react-native';
export default class AwesomeProject extends Component {
......
//绑定事件
componentDidMount() {
DeviceEventEmitter.addListener('onMessage', this.onMessage);
DeviceEventEmitter.addListener('onNotification', this.onNotification);
}
//解绑事件
componentWillUnmount() {
DeviceEventEmitter.removeListener('onMessage', this.onMessage);
DeviceEventEmitter.removeListener('onNotification', this.onNotification);
}
//事件处理逻辑
onMessage(e){
alert("Message Received. Title:" + e.title + ", Content:" + e.content);
}
onNotification(e){
alert("Notification Received.Title:" + e.title + ", Content:" + e.content);
}
}
public class MainApplication extends Application implements ReactApplication {
private static final String TAG = MainApplication.class.getName();
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage()
new PushPackage()
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
this.initCloudChannel();
}
private void initCloudChannel() {
PushServiceFactory.init(this.getApplicationContext());
CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.register(this.getApplicationContext(), new CommonCallback() {
@Override
public void onSuccess(String s) {
Log.e(TAG, "init cloudchannel success");
}
@Override
public void onFailed(String s, String s1) {
Log.e(TAG, "init cloudchannel failed. errorCode:" + s + ". errorMsg:" + s1);
}
});
}
}
Android 8+系统需要单独进行适配,客户端和服务端都有设备,详情参见常见问题:Android 8.0以上设备通知接收不到。
详细参见常见问题:只在Android9+系统报errorCode为10109的错误
本节以ReactNative实例工程AwesomeProject
作为实例工程为大家介绍iOS推送手动集成 SDK的步骤。
参考:移动研发平台 EMAS > 快速入门的下载SDK章节。
AwesomeProject/ios/AwesomeProject.xcodeproj
,将推送iOS SDK拖进工程中。注意:Targets -> Build Settings -> Linking -> Other Linker Flags,请加上-ObjC这个属性,否则推送服务无法正常使用。如果之前已经设置了
force_load
,需要设置-force_load <framework_path>/CloudPushSDK.framework/CloudPushSDK
。
Xcode 8 打开推送开关,TARGETS > Capabilitie > Push Notifications,并会自动在项目中生成.entitlement
文件。
- (void)initCloudPush {
[CloudPushSDK asyncInit:@"*****" appSecret:@"*****" callback:^(CloudPushCallbackResult *res) {
if (res.success) {
NSLog(@"Push SDK init success, deviceId: %@.", [CloudPushSDK getDeviceId]);
} else {
NSLog(@"Push SDK init failed, error: %@", res.error);
}
}];
}
/**
* 注册苹果推送,获取deviceToken用于推送
*
* @param application
*/
- (void)registerAPNS:(UIApplication *)application {
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
// iOS 8 Notifications
[application registerUserNotificationSettings:
[UIUserNotificationSettings settingsForTypes:
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge)
categories:nil]];
[application registerForRemoteNotifications];
}
else {
// iOS < 8 Notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
}
}
/*
* 苹果推送注册成功回调,将苹果返回的deviceToken上传到CloudPush服务器
*/
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[CloudPushSDK registerDevice:deviceToken withCallback:^(CloudPushCallbackResult *res) {
if (res.success) {
NSLog(@"Register deviceToken success.");
} else {
NSLog(@"Register deviceToken failed, error: %@", res.error);
}
}];
}
/*
* 苹果推送注册失败回调
*/
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"didFailToRegisterForRemoteNotificationsWithError %@", error);
}
/**
* 注册推送消息到来监听
*/
- (void)registerMessageReceive {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMessageReceived:) name:@"CCPDidReceiveMessageNotification" object:nil];
}
/**
* 处理到来推送消息
*
* @param notification
*/
- (void)onMessageReceived:(NSNotification *)notification {
CCPSysMessage *message = [notification object];
NSString *title = [[NSString alloc] initWithData:message.title encoding:NSUTF8StringEncoding];
NSString *body = [[NSString alloc] initWithData:message.body encoding:NSUTF8StringEncoding];
NSLog(@"Receive message title: %@, content: %@.", title, body);
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 点击通知将App从关闭状态启动时,将通知打开回执上报
// [CloudPushSDK handleLaunching:launchOptions];(Deprecated from v1.8.1)
[CloudPushSDK sendNotificationAck:launchOptions];
return YES;
}
/*
* App处于启动状态时,通知打开回调
*/
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo {
NSLog(@"Receive one notification.");
// 取得APNS通知内容
NSDictionary *aps = [userInfo valueForKey:@"aps"];
// 内容
NSString *content = [aps valueForKey:@"alert"];
// badge数量
NSInteger badge = [[aps valueForKey:@"badge"] integerValue];
// 播放声音
NSString *sound = [aps valueForKey:@"sound"];
// 取得Extras字段内容
NSString *Extras = [userInfo valueForKey:@"Extras"]; //服务端中Extras字段,key是自己定义的
NSLog(@"content = [%@], badge = [%ld], sound = [%@], Extras = [%@]", content, (long)badge, sound, Extras);
// iOS badge 清0
application.applicationIconBadgeNumber = 0;
// 通知打开回执上报
// [CloudPushSDK handleReceiveRemoteNotification:userInfo];(Deprecated from v1.8.1)
[CloudPushSDK sendNotificationAck:userInfo];
}
// 新创建 一个继承 RCTEventEmitter 的类
// SREventEmitter.h 文件
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
NS_ASSUME_NONNULL_BEGIN
@interface SREventEmitter : RCTEventEmitter <RCTBridgeModule>
+ (void)postNotiToReactNative:(NSString *)str withDic:(NSDictionary *)dic;
@end
NS_ASSUME_NONNULL_END
// SREventEmitter.m 文件
#import "SREventEmitter.h"
@implementation SREventEmitter
RCT_EXPORT_MODULE();
- (NSArray<NSString *> *)supportedEvents {
return @[@"AliyunPush"]; // 这里返回的将是你要发送的消息名的数组
}
- (void)startObserving {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(emitEventInternal:)
name:@"event-emitted"
object:nil];
}
- (void)stopObserving {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)emitEventInternal:(NSNotification *)notification {
NSLog(@"\n ===== notification %@",notification);
dispatch_async(dispatch_get_main_queue(), ^{
[self sendEventWithName:@"AliyunPush"
body:notification.object];
});
}
+ (void)postNotiToReactNative:(NSString *)str withDic:(NSDictionary *)dic {
NSMutableDictionary *tempDic = [NSMutableDictionary dictionary];
tempDic[@"str"] = str;
tempDic[@"dic"] = dic;
[[NSNotificationCenter defaultCenter] postNotificationName:@"event-emitted" object:tempDic];
}
@end
// AppDelegate.m 文件
- (void)onMessageReceived:(NSNotification *)notification {
CCPSysMessage *message = [notification object];
NSString *title = [[NSString alloc] initWithData:message.title encoding:NSUTF8StringEncoding];
NSString *body = [[NSString alloc] initWithData:message.body encoding:NSUTF8StringEncoding];
[SREventEmitter postNotiToReactNative:@"MessageReminder" withDic:@{ @"title" : title,@"body" : body }];
}
// index.ios.js 文件
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Alert,
NativeModules,
NativeEventEmitter
} from 'react-native';
var nativeBridge = NativeModules.SREventEmitter;
const NativeModule = new NativeEventEmitter(nativeBridge);
export default class MyApp extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
This is Push iOS Demo!
</Text>
<Text style={styles.instructions}>
To get started, edit index.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
</View>
);
}
componentDidMount(){
console.log('here2')
this.subscription = NativeModule.addListener(
'AliyunPush',
(reminder) => {
console.log('here1')
alert(reminder.str)
}
);
}
componentWillUnmount() {
this.subscription.remove()
}
}
在文档使用中是否遇到以下问题
更多建议
匿名提交