全部产品
存储与CDN 数据库 安全 应用服务 数加·人工智能 数加·大数据基础服务 互联网中间件 视频服务 开发者工具 解决方案 物联网
移动推送

阿里云移动推送+ReactNative最佳实践

更新时间:2017-07-07 15:19:23

React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的UI框架 React 在原生移动应用平台的衍生产物,目前支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。

近年来Web化已成为移动端开发的一大趋势,越来越多的开发者倾向于使用ReactNative等web框架来开发App,而阿里云移动推送同样支持ReactNative开发模式,接下来为大家介绍如何在ReactNative工程中集成阿里云推送。

1. 构建您的ReactNative

如果您已有构建好的ReactNative工程,可直接跳过本节。如果您是第一次接触ReactNative,可以参考官方教程创建自己的第一个ReactNative应用。

2. 接入移动推送Android SDK

本节以ReactNative实例工程AwesomeProject作为实例工程为大家介绍Android推送SDK的接入步骤。可先下载Demo示例工程,再结合本教程效果更佳。

2.1 接入推送SDK

ReactNative模式下接入移动推送SDK的方式和传统Android开发模式下接入SDK一样,相关接入方式可以参考:移动推送SDK接入指南

2.2 JavaScript调用推送SDK Native接口

ReactNative模式下常常需要通过JavaScript调用推送SDK native接口,完整调用过程包含以下三步。

2.2.1 创建PushModule模块

创建PushModule,继承自ReactContextBaseJavaModule,可参考以下代码:

  1. public class PushModule extends ReactContextBaseJavaModule {
  2. private static ReactContext context;
  3. public PushModule(ReactApplicationContext reactContext) {
  4. super(reactContext);
  5. context = reactContext;
  6. }
  7. public static ReactContext getContext() {
  8. return context;
  9. }
  10. //模块名,在JavaScript中调用相关方法时需要首先引入MPush模块
  11. @Override
  12. public String getName() {
  13. return "MPush";
  14. }
  15. @ReactMethod
  16. public void getDeviceId(Callback callback) {
  17. callback.invoke(PushServiceFactory.getCloudPushService().getDeviceId());
  18. }
  19. @ReactMethod
  20. public void bindAccount(String account, final Callback callback) {
  21. PushServiceFactory.getCloudPushService().bindAccount(account, new CommonCallback() {
  22. @Override
  23. public void onSuccess(String s) {
  24. callback.invoke("bind account success");
  25. }
  26. @Override
  27. public void onFailed(String s, String s1) {
  28. callback.invoke("bind account failed. errorCode:" + s + ", errorMsg:" + s1);
  29. }
  30. });
  31. }
  32. ......
  33. }
  • getName(): 这个方法用于在JavaScript 端标记这个模块。这里我们把这个模块命名为 MPush,这样就可以在 JavaScript 中通过 NativeModules.MPush 访问到这个模块
  • @ReactMethod:要导出一个方法给 JavaScript 使用,Java 方法需要使用注解 @ReactMethod,方法的返回类型必须为 void。React Native 的跨语言访问是异步进行的,所以想要给 JavaScript 返回一个值的唯一办法是使用回调函数或者发送事件
2.2.2 注册模块

创建一个 Package 类 PushPackage 并实现 ReactPackage,在 createNativeModules 方法中添加这个模块

  1. public class PushPackage implements ReactPackage {
  2. @Override
  3. public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
  4. List<NativeModule> modules = new ArrayList<>();
  5. modules.add(new PushModule(reactContext));
  6. return modules;
  7. }
  8. @Override
  9. public List<Class<? extends JavaScriptModule>> createJSModules() {
  10. return Collections.emptyList();
  11. }
  12. @Override
  13. public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
  14. return Collections.emptyList();
  15. }
  16. }
2.2.3 添加模块

在 Application 中的 ReactNativeHost 实例里 getPackages 方法添加 PushPackage 实例

  1. @Override
  2. protected List<ReactPackage> getPackages() {
  3. return Arrays.<ReactPackage>asList(
  4. new MainReactPackage(),
  5. new PushPackage()
  6. );
  7. }
2.2.4 在JavaScript中调用Native方法
  1. //引入MPush模块
  2. var {NativeModules}=require('react-native');
  3. var mPush = NativeModules.MPush;
  4. export default class AwesomeProject extends Component {
  5. ......
  6. //调用Native方法
  7. getDeviceId() {
  8. var that = this;
  9. mPush.getDeviceId(function(args) {
  10. that.setState({
  11. deviceIdBtnTitle: args
  12. });
  13. });
  14. }
  15. ......
  16. }

2.3 将推送消息传递到JavaScript

当终端接收到推送消息时需要将对应的消息发送到JavaScript,此时需要用到ReactNative的事件机制。

2.3.1 消息接收Receiver改造

在消息接收回调函数中添加事件发送逻辑:

  1. public class MyMessageReceiver extends MessageReceiver {
  2. public MyMessageReceiver() {
  3. super();
  4. }
  5. @Override
  6. protected void onMessage(Context context, CPushMessage cPushMessage) {
  7. super.onMessage(context, cPushMessage);
  8. WritableMap params = Arguments.createMap();
  9. params.putString("messageId", cPushMessage.getMessageId());
  10. params.putString("content", cPushMessage.getContent());
  11. params.putString("title", cPushMessage.getTitle());
  12. PushModule.sendEvent(getReactContext(), "onMessage", params);
  13. }
  14. @Override
  15. protected void onNotification(Context context, String s, String s1, Map<String, String> map) {
  16. super.onNotification(context, s, s1, map);
  17. WritableMap params = Arguments.createMap();
  18. params.putString("content", s1);
  19. params.putString("title", s);
  20. for (Map.Entry<String, String> entry: map.entrySet()) {
  21. params.putString(entry.getKey(), entry.getValue());
  22. }
  23. sendEvent(getReactContext(), "onNotification", params);
  24. }
  25. private void sendEvent(ReactContext context, String eventName, @Nullable WritableMap params) {
  26. if (context == null) {
  27. Log.i(TAG, "reactContext==null");
  28. }else{
  29. context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
  30. .emit(eventName, params);
  31. }
  32. }
  33. }
2.3.2 JavaScript监听相关事件
  1. //导入相关模块
  2. import {
  3. AppRegistry,
  4. MPush,
  5. DeviceEventEmitter,
  6. ......
  7. } from 'react-native';
  8. export default class AwesomeProject extends Component {
  9. ......
  10. //绑定事件
  11. componentDidMount() {
  12. DeviceEventEmitter.addListener('onMessage', this.onMessage);
  13. DeviceEventEmitter.addListener('onNotification', this.onNotification);
  14. }
  15. //解绑事件
  16. componentWillUnmount() {
  17. DeviceEventEmitter.removeListener('onMessage', this.onMessage);
  18. DeviceEventEmitter.removeListener('onNotification', this.onNotification);
  19. }
  20. //事件处理逻辑
  21. onMessage(e){
  22. alert("Message Received. Title:" + e.title + ", Content:" + e.content);
  23. }
  24. onNotification(e){
  25. alert("Notification Received.Title:" + e.title + ", Content:" + e.content);
  26. }
  27. }

2.4 初始化

在Application中初始化推送SDK:

  1. public class MainApplication extends Application implements ReactApplication {
  2. private static final String TAG = MainApplication.class.getName();
  3. private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
  4. @Override
  5. public boolean getUseDeveloperSupport() {
  6. return BuildConfig.DEBUG;
  7. }
  8. @Override
  9. protected List<ReactPackage> getPackages() {
  10. return Arrays.<ReactPackage>asList(
  11. new MainReactPackage()
  12. );
  13. }
  14. };
  15. @Override
  16. public ReactNativeHost getReactNativeHost() {
  17. return mReactNativeHost;
  18. }
  19. @Override
  20. public void onCreate() {
  21. super.onCreate();
  22. SoLoader.init(this, /* native exopackage */ false);
  23. this.initCloudChannel();
  24. }
  25. private void initCloudChannel() {
  26. PushServiceFactory.init(this.getApplicationContext());
  27. CloudPushService pushService = PushServiceFactory.getCloudPushService();
  28. pushService.register(this.getApplicationContext(), new CommonCallback() {
  29. @Override
  30. public void onSuccess(String s) {
  31. Log.e(TAG, "init cloudchannel success");
  32. }
  33. @Override
  34. public void onFailed(String s, String s1) {
  35. Log.e(TAG, "init cloudchannel failed. errorCode:" + s + ". errorMsg:" + s1);
  36. }
  37. });
  38. }
  39. }

3 接入移动推送iOS SDK

本节以ReactNative实例工程AwesomeProject作为实例工程为大家介绍iOS推送 手动集成 SDK 的步骤。

3.1 控制台下载SDK

参考:推送SDK下载

3.2 SDK集成

  • 打开 AwesomeProject/ios/AwesomeProject.xcodeproj,将推送iOS SDK拖进工程中。
  • Build Phases -> Link Binary With Libraries中,引入下列的公共包:
    • libz.tbd
    • libresolv.tbd
    • CoreTelephony.framework
    • SystemConfiguration.framework
    • libsqlite3.tbd(阿里云平台下载的SDK无需依赖,百川平台下载的SDK需要依赖)

注意:Targets -> Build Settings -> Linking -> Other Linker Flags,请加上-ObjC这个属性,否则推送服务无法正常使用。如果之前已经设置了force_load,需要设置-force_load <framework_path>/CloudPushSDK.framework/CloudPushSDK

3.3 Xcode 设置

Xcode 8 打开推送开关,TARGETS > Capabilitie > Push Notifications,并会自动在项目中生成 .entitlement)文件。

3.4 SDK配置

  1. - (void)initCloudPush {
  2. [CloudPushSDK asyncInit:@"*****" appSecret:@"*****" callback:^(CloudPushCallbackResult *res) {
  3. if (res.success) {
  4. NSLog(@"Push SDK init success, deviceId: %@.", [CloudPushSDK getDeviceId]);
  5. } else {
  6. NSLog(@"Push SDK init failed, error: %@", res.error);
  7. }
  8. }];
  9. }
  • 向苹果APNs注册获取deviceToken并上报到阿里云推送服务器;
  1. /**
  2. * 注册苹果推送,获取deviceToken用于推送
  3. *
  4. * @param application
  5. */
  6. - (void)registerAPNS:(UIApplication *)application {
  7. if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
  8. // iOS 8 Notifications
  9. [application registerUserNotificationSettings:
  10. [UIUserNotificationSettings settingsForTypes:
  11. (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge)
  12. categories:nil]];
  13. [application registerForRemoteNotifications];
  14. }
  15. else {
  16. // iOS < 8 Notifications
  17. [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
  18. (UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
  19. }
  20. }
  21. /*
  22. * 苹果推送注册成功回调,将苹果返回的deviceToken上传到CloudPush服务器
  23. */
  24. - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  25. [CloudPushSDK registerDevice:deviceToken withCallback:^(CloudPushCallbackResult *res) {
  26. if (res.success) {
  27. NSLog(@"Register deviceToken success.");
  28. } else {
  29. NSLog(@"Register deviceToken failed, error: %@", res.error);
  30. }
  31. }];
  32. }
  33. /*
  34. * 苹果推送注册失败回调
  35. */
  36. - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  37. NSLog(@"didFailToRegisterForRemoteNotificationsWithError %@", error);
  38. }
  • 推送消息到来监听;
  1. /**
  2. * 注册推送消息到来监听
  3. */
  4. - (void)registerMessageReceive {
  5. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMessageReceived:) name:@"CCPDidReceiveMessageNotification" object:nil];
  6. }
  7. /**
  8. * 处理到来推送消息
  9. *
  10. * @param notification
  11. */
  12. - (void)onMessageReceived:(NSNotification *)notification {
  13. CCPSysMessage *message = [notification object];
  14. NSString *title = [[NSString alloc] initWithData:message.title encoding:NSUTF8StringEncoding];
  15. NSString *body = [[NSString alloc] initWithData:message.body encoding:NSUTF8StringEncoding];
  16. NSLog(@"Receive message title: %@, content: %@.", title, body);
  17. }
  • 通知打开监听;
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  2. // 点击通知将App从关闭状态启动时,将通知打开回执上报
  3. // [CloudPushSDK handleLaunching:launchOptions];(Deprecated from v1.8.1)
  4. [CloudPushSDK sendNotificationAck:launchOptions];
  5. return YES;
  6. }
  7. /*
  8. * App处于启动状态时,通知打开回调
  9. */
  10. - (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo {
  11. NSLog(@"Receive one notification.");
  12. // 取得APNS通知内容
  13. NSDictionary *aps = [userInfo valueForKey:@"aps"];
  14. // 内容
  15. NSString *content = [aps valueForKey:@"alert"];
  16. // badge数量
  17. NSInteger badge = [[aps valueForKey:@"badge"] integerValue];
  18. // 播放声音
  19. NSString *sound = [aps valueForKey:@"sound"];
  20. // 取得Extras字段内容
  21. NSString *Extras = [userInfo valueForKey:@"Extras"]; //服务端中Extras字段,key是自己定义的
  22. NSLog(@"content = [%@], badge = [%ld], sound = [%@], Extras = [%@]", content, (long)badge, sound, Extras);
  23. // iOS badge 清0
  24. application.applicationIconBadgeNumber = 0;
  25. // 通知打开回执上报
  26. // [CloudPushSDK handleReceiveRemoteNotification:userInfo];(Deprecated from v1.8.1)
  27. [CloudPushSDK sendNotificationAck:userInfo];
  28. }
本文导读目录