React Native如今是愈来愈火,一套代码同时构建iOS、Android两种应用真的是太爽了,并且有了ES6和React的加成开发效率出奇的高。 虽然坑奇多无比可是仍是阻挡不了市场对它的热爱。可是使用React Native也并不是老是那么舒服,尤为涉及到须要用objective-c或者java实现某些原生功能的时候,让广大前端出生没有原生App开发经验的同窗们苦不堪言,可是没有办法,硬着头皮写下去总比丢工做强。因此React Native开发者们真的是痛并快乐着,爽并纠结着。然而能力就是在这个过程当中快速提升的,因此你们加油,如今只不过是黎明前的黑暗!html
今天要分享的是我在React Native开发过程当中征服的一个小小领域:消息推送。前端
其实作手机App就绕不开消息推送,没有消息推送的App就像一个没有漂亮前台的公司(就像咱们公司,嘿嘿),让人没有进去看看的欲望。。怎么可能火呢。java
说正经的,虽然我作完React Native版的消息推送以后发现其实也并不难,可是一路上踩过大大小小的坑、尝试过无数的解决方案,到最终大功告成仍是有点小成就感的(笨人得到知足感相对比较容易)。实现React Native App的消息推送可预见的难点在于:react
结下来我就针对以上的难点,并结合实际的项目来详细分析如何实现消息推送。ios
市场上的推送服务提供商有不少,好比友盟、极光推送、Leancloud、个推、环信、融云等等。这么多的选择咱们不可能都用过,因此应该从哪些方面去考量呢?git
下面是我整理的一些主流的推送服务提供商的对比,可能不是那么完善和客观,欢迎纠错,没有提到的厂商很差意思啦。。github
服务商 | React Native支持否 | 文档质量 | 官方Demo | 价格 |
---|---|---|---|---|
友盟 | 是 | 差,放弃 | 未调查 | 未调查 |
极光 | 是 | 缺乏 | Demo | 价格 |
Leancloud | 是 | 高 | iOS | 价格 |
腾讯信鸽 | 否(未找到相关文档) | / | / | / |
阿里云推送 | 否(未找到相关文档) | / | / | / |
百度云推送 | 否(未找到相关文档) | / | / | / |
网易云信 | 是 | 缺乏 | Demo | 价格 |
云巴 | 否(未找到相关文档) | / | / | / |
个推 | 是 | 缺乏 | Demo | 价格 |
环信 | 否(只支持IM) | / | / | / |
融云 | 否(未找到相关文档) | / | / | / |
以上全部的厂商里面只有4家是支持React Native消息推送的,BAT跟商量好了似的都不支持,难道集体看衰React Native吗?在仅有的4家厂商中,文档方面只有Leancloud一家是我以为文档质量比较好的,其余厂商都缺乏接入React Native的相关文档。个推只有一个小Demo,并且Demo的文档也很简陋,因此先排除。极光的Demo应该是作的最好的,star数最多,Demo文档看起来也写的挺好的,虽然没有明码标价,可是免费版貌似就够用了,推送次数没有上限,二十万条/秒的推送速度也够用了,作通常应用应该足够了。网易的Demo看起来也挺完善,文档也说的过去,关键是价格太贵啦,商用版1800/月。。为了只作一个推送不值得,放弃!最后Leancloud是我我的比较喜欢的,由于以前有项目用到过,不论是文档、SDK的易用性、服务的可靠性和速度仍是网站的审美均可以算得上同行中的佼佼者,并且商用版30/天的价格也能够接收(30/天包含了除推送外其余更多的功能和服务)。因此总结下来,只有极光推送和Leancloud值得一用(欢迎极光和Leancloud联系我打赏,嘿嘿),因为个人我的偏好,最终选择了使用Leancloud。objective-c
咱们在实现具体项目以前仍是有必要了解一下消息推送的相应机制和基本概念的,这里我就不赘述了,欢迎阅读Leancloud的 消息推送服务总览。npm
首先咱们建立一个React Native项目(本文Demo地址):segmentfault
react-native init LeancloudPushDemo
并在Leancloud建立一个同名应用,开发版就好:
安装完成后,咱们须要安装Leancloud推送相关的js sdk:
$ npm install leancloud-storage --save $ npm install leancloud-installation --save
咱们在项目根目录下建立services文件夹,并在其中添加PushService.js文件,用于管理消息推送的主要逻辑,初始内容以下:
import AV from 'leancloud-storage'; const appId = 'ppdriT1clcnRoda0okCPaB48-gzGzoHsz'; const appKey = 'Qzarq5cMdWzAMjwDW4umWpBL'; AV.init({ appId: appId, appKey: appKey }); const Installation = require('leancloud-installation')(AV); class PushService { } export default new PushService();
目前PushService仍是一个空的class,稍后咱们会逐渐丰富它的功能。
Leancloud的AppId,AppKey能够在以下页面获取:
因为iOS、Android推送方式的差别,接下来咱们将分别进行实现。
在React Native中实现iOS的消息推送相对Android简单一些,由于官方已经给出了PushNotificationIOS
这样现成的组件。
首先,根据,在iOS 项目中引入 RCTPushNotification,可参考:Linking Libraries - React Native docs
而后,修改AppDelegate.m,增长推送相关事件代理,可参考:PushNotificationIOS - React Native docs,。
Leancloud须要根据iOS设备的deviceToken来决定推送到哪台设备,因此须要把deviceToken保存到_Installation表。而保存的最佳时机就在App刚刚启动的时候,在PushService下添加以下代码:
//引用PushNotificationIOS const PushNotificationIOS = require('react-native').PushNotificationIOS; ... class PushService { //获取iOS消息通知权限 _iOS_initPush = () => { PushNotificationIOS.addEventListener('register', this._iOS_onRegister); PushNotificationIOS.requestPermissions(); } //权限获取成功回调 _iOS_onRegister = (deviceToken) => { if (deviceToken) { this._iOS_saveInstallation(deviceToken); } } //保存deviceToken到Installation _iOS_saveInstallation = (deviceToken) => { const info = { apnsTopic: 'com.example', deviceType: 'ios', deviceToken: deviceToken }; Installation.getCurrent() .then(installation => installation.save(info)) .then(result => console.log(result)) .catch(error => console.error(error)) } } ...
修改App.js,在componentDidMount
时执行初始化:
import React, { Component } from 'react'; import { Text, View } from 'react-native'; import PushService from './services/PushService'; type Props = {}; export default class App extends Component<Props> { componentDidMount() { PushService._iOS_initPush(); } render() { return ( <View> <Text>Leancloud Push Demo</Text> </View> ); } }
如今咱们来运行一下项目(须使用真机,模拟器获取不到deviceToken),看是否能获取到deviceToken并保存。
保存成功后发现_Installation表中多了一条记录:
成功保存deviceToken意味着咱们已经成功了一半了,但若是要让iOS设备能收到通知,还须要配置推送证书,详细步骤请参考 iOS推送证书设置指南。推荐使用Token Authentication。
推送证书设置完成以后,就能够测试手机是否能收到消息通知了。Leancloud提供在线发送消息的功能:
在线发送以后,手机就能够收到通知了(不当心暴露个人起床时间了。。):
到目前为止咱们已经成功了一大半了,可是咱们还想作得更多一点,一款成熟的应用还应该包括如下功能:
当App在前台运行时收到通知iOS默认是不会提醒的(iOS 10开始支持在前台显示,请参考 stackoverflow),所以咱们须要本身实现接收通知并显示的逻辑。
咱们选择用 react-native-message-bar来展现通知,先安装react-native-message-bar:
npm install react-native-message-bar --save
而后,在App.js中引入并注册MessageBar:
... const MessageBarAlert = require('react-native-message-bar').MessageBar; const MessageBarManager = require('react-native-message-bar').MessageBarManager; ... componentDidMount() { PushService._iOS_initPush(); MessageBarManager.registerMessageBar(this.refs.alert); } componentWillUnmount() { PushNotificationIOS.removeEventListener('register'); MessageBarManager.unregisterMessageBar(); } render() { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text style={{ fontSize: 24 }}>Leancloud Push Demo</Text> <MessageBarAlert ref="alert" /> </View> ); } ...
接着,修改PushService,增长对notification
事件的监听,和显示自定义Alert的方法:
... _iOS_initPush = () => { PushNotificationIOS.addEventListener('register', this._iOS_onRegister); PushNotificationIOS.addEventListener('notification', this._iOS_onNotification); PushNotificationIOS.requestPermissions(); } _iOS_onNotification = (notification) => { //若是app在前台则显示alert if (AppState.currentState === 'active') { this._showAlert(notification._alert); } } ... _showAlert = (message) => { const MessageBarManager = require('react-native-message-bar').MessageBarManager; MessageBarManager.showAlert({ title: '您有一条新的消息', message: message, alertType: 'success', stylesheetSuccess: { backgroundColor: '#7851B3', titleColor: '#fff', messageColor: '#fff' }, viewTopInset : 20 }); } ...
最后从新运行App,而后在线发送一条通知,App打开状态下也能显示通知了:
要实现badge显示并能随着通知个数递增很是简单,只须要在Leancloud控制台中勾选Increment iOS badges
,而后发送通知后App图标上就会出现红色的badge了:
添加badge以后,咱们须要在合适的时间点再将其清除,Leancloud将每一个设备上badge的数量也保存在_Installation表中,因此清除设备的badge同时须要修改Installation表:
_iOS_cleanBadge = () => { Installation.getCurrent() .then((installation) => { installation.set('badge', 0); return installation.save(); }) .then((result) => { PushNotificationIOS.setApplicationIconBadgeNumber(0); }) .catch(error => console.log(error)); }
点击通知又分为点击iOS系统弹出的通知提醒和点击咱们自定义的MessageBar。而点击iOS系统的通知又可分为App在后台运行和App处于关闭状态。接下来咱们就分别讨论这三种状态下如何处理:
react-native-message-bar提供了onTapped
的callback,因此咱们只须要传入咱们想要执行的方法就好了,咱们将PushService进行以下修改:
... _iOS_onNotificationTapped = () => { Alert.alert('Notification Tapped'); } _showAlert = (message) => { const MessageBarManager = require('react-native-message-bar').MessageBarManager; MessageBarManager.showAlert({ ... onTapped: this._iOS_onNotificationTapped }); } ...
实现思路是,当app在后台运行时收到通知,点击通知会触发notification
事件,咱们用一个临时变量记录下当前的通知,再经过监听app状态的变化,当app从后台切换到前台后临时变量是否有值判断是不是点击通知打开的app,若是是经过点击通知打开app,执行咱们想要的逻辑。说的有点绕,让咱们来看代码:
... class PushService { //用于记录通知的临时变量 backgroundNotification = null; _iOS_initPush = () => { ... //监听app状态的改变 AppState.addEventListener('change', (newState) => { if (newState === 'active') { if (this.backgroundNotification != null) { this._iOS_onNotificationTapped(); this.backgroundNotification = null; this._iOS_cleanBadge(); } } }); } ... _iOS_onNotification = (notification) => { ... } else if (AppState.currentState === 'background') { //app在后台运行时点击通知 this.backgroundNotification = notification; } } ...
直接调用PushNotificationIOS.getInitialNotification
判断app关闭时,是否经过点击系统消息打开:
... _iOS_initPush = () => { ... //app关闭时,是否经过点击系统通知打开 PushNotificationIOS.getInitialNotification() .then((notification) => { if (notification) { this._iOS_onNotificationTapped(); } }); } ...
至此,使用Leancloud实现iOS的消息推送已实现完成,并涵盖了主要的应用场景。出于控制篇幅的缘由,Android的实现单独写了一篇文章分享给你们:
Android篇地址:使用Leancloud实现React Native App的消息推送(Push Notification)- Android篇
本文Demo Github地址:https://github.com/MudOnTire/LeancloudPushDemo,若是对你有帮助,star一下吧。