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一下吧。