使用Leancloud实现React Native App的消息推送(Push Notification)- iOS篇

前言

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

  1. 在众多的第三方推送服务提供商中选择哪个最合适
  2. 须要同时实现Android和IOS两个系统的推送,须要对两个系统的推送机制都很是熟悉
  3. 哪些部分须要用原生实现,哪些须要用js实现,如何实现桥接
  4. 如何实现App在后台或者关闭(inactive)状态下的推送,又如何实现App打开(active)状态下的消息推送

结下来我就针对以上的难点,并结合实际的项目来详细分析如何实现消息推送。ios

选择服务提供商

市场上的推送服务提供商有不少,好比友盟、极光推送、Leancloud、个推、环信、融云等等。这么多的选择咱们不可能都用过,因此应该从哪些方面去考量呢?git

  1. 首先,必须支持React Native。为了验证这些第三方服务是否支持React Native,没有特别好的办法,我只能一个个的看他们的官网文档。若是文档里面都没有提到React Native那么果断放弃(有些厂商都不提供文档搜索功能,那也不建议选择,之后出问题都很差找)。
  2. 推送服务要稳定、可靠、快速,这一点不太好判断,由于你们都说本身可靠快速,因此须要实际使用后才能判断。
  3. 文档完善、清晰、准确、更新及时,能提供官方的React Native推送Demo。
  4. 价格合理(咱们仍是要想办法为公司省点钱滴)。

下面是我整理的一些主流的推送服务提供商的对比,可能不是那么完善和客观,欢迎纠错,没有提到的厂商很差意思啦。。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

接入Leancloud

首先咱们建立一个React Native项目(本文Demo地址):segmentfault

react-native init LeancloudPushDemo

并在Leancloud建立一个同名应用,开发版就好:

image

安装完成后,咱们须要安装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能够在以下页面获取:

image

因为iOS、Android推送方式的差别,接下来咱们将分别进行实现。

iOS消息推送

在React Native中实现iOS的消息推送相对Android简单一些,由于官方已经给出了PushNotificationIOS这样现成的组件。

配置

首先,根据,在iOS 项目中引入 RCTPushNotification,可参考:Linking Libraries - React Native docs

步骤1:将PushNotification项目拖到当前iOS主项目

image

步骤2:添加libRCTPushNotification静态库

image

步骤3: 开启Push Notification功能

image

而后,修改AppDelegate.m,增长推送相关事件代理,可参考:PushNotificationIOS - React Native docs,。

获取devideToken,更新_Installation表

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表中多了一条记录:

image

推送证书设置

成功保存deviceToken意味着咱们已经成功了一半了,但若是要让iOS设备能收到通知,还须要配置推送证书,详细步骤请参考 iOS推送证书设置指南。推荐使用Token Authentication。

推送证书设置完成以后,就能够测试手机是否能收到消息通知了。Leancloud提供在线发送消息的功能:
image

在线发送以后,手机就能够收到通知了(不当心暴露个人起床时间了。。):

image

通知的接收和处理

到目前为止咱们已经成功了一大半了,可是咱们还想作得更多一点,一款成熟的应用还应该包括如下功能:

  • App在前台、后台运行或者关闭状态都能看到通知消息
  • App在后台或者关闭状态收到通知,App图标能显示通知个数的badge
  • 点击通知可以进行自定义的操做,好比跳转到具体页面

App打开时通知的显示

当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打开状态下也能显示通知了:

image

收到通知显示Badge

要实现badge显示并能随着通知个数递增很是简单,只须要在Leancloud控制台中勾选Increment iOS badges,而后发送通知后App图标上就会出现红色的badge了:

image

image

清除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处于关闭状态。接下来咱们就分别讨论这三种状态下如何处理:

1. App打开,点击MessageBar

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

...

2. App在后台运行,点击系统通知

实现思路是,当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;
        }
    }
    
    ...

3. App关闭状态下,点击系统通知

直接调用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一下吧。

相关文章
相关标签/搜索