iOS及Android消息推送方案安装使用入门
iOS消息推送直接使用苹果消息推送协议,服务器端采用easy apns: http://www.easyapns.com/
Android消息推送采用MQTT协议,服务器端采用mosquito+PhpMQTTClient
mosquito: http://mosquitto.org/
PhpMQTTClient : https://github.com/tokudu/PhpMQTTClient
1 、 iOS 消息推送
1.0 、消息推送证书生成
在apple官网分别生成消息推送的development和production证书,这里只使用development证书,假定为push.p12
1.1 、生成 easy apns 所需要的 pem 格式的证书
openssl pkcs12 -clcerts -nokeys -out cert.pem -in push.p12
openssl pkcs12 -nocerts -out key.pem -in push.p12
cat cert.pem key.unencrypted.pem > apns-dev-cert.pem
对production证书重复以上类似步骤,生成apns-cert.pem
1.2 、 easy apns 安装配置
由于easy apns使用了mysqli来连接mysql,因此记得在安装php时候在php.ini启用mysqli
1.2.1 、 easy apns 下载
从 https://github.com/manifestinteractive/easyapns下载easy apns代码
unzip manifestinteractive-easyapns-6f5731a.zip
1.2.2 、 easy apns 数据库初始化
创建数据库apns
用manifestinteractive-easyapns-6f5731a/manifestinteractive-easyapns-6f5731a/src/sql/apns.sql建立所需要的数据库表
1.2.3 、 easy apns php 应用
将manifestinteractive-easyapns-6f5731a/manifestinteractive-easyapns-6f5731a/src/php下的代码拷贝到服务器对应的目录下,假设为/var/www/html/apns
将1.1生成的apns-dev-cert.pem 和apns-cert.pem 拷贝到/var/www/html/apns下
修改classes/class_APNS.php如下参数:
private $logPath = ‘/var/www/html/apns/apns.log’;
private $certificate = ‘/var/www/html/apns/apns-cert.pem’;
private $sandboxCertificate = ‘/var/www/html/apns/apns-dev-cert.pem’; // change this to your development certificate absolute path
将证书权限修改为644
修改apns.php如下参数
$db = new DbConnect(‘localhost’, ‘apnsuser’, ‘apnspassword’, ‘apnsdb’);
将localhost、apnsuser、apnspassword、apnsdb改成对应的参数
1.2.4 、 crontab 配置
* * * * * nice /usr/bin/php -f /var/www/html/apns/apns.php fetch > /var/www/html/apns/apns.log 2>&1 &
1.2.5 、测试
在manifestinteractive-easyapns-6f5731a/manifestinteractive-easyapns-6f5731a/src/delegate/Delegate.m基础上,建立iPhone测试Demo程序
修改Delegate.m中的:
NSString *host = @" www.mywebsite.com"; //修改为指向实际消息推送的Web服务器的地址和端口
NSString *urlString = [NSString stringWithFormat:@" /apns.php?task=%@&appname=%@&appversion=%@&deviceuid=%@&devicetoken=%@&devicename=%@&devicemodel=%@&deviceversion=%@&pushbadge=%@&pushalert=%@&pushsound=%@", @"register", appName,appVersion, deviceUuid, deviceToken, deviceName, deviceModel, deviceSystemVersion, pushBadge, pushAlert, pushSound];
将/apns.php? 修改为easy apns实际的url访问路径,此处为:/apns/apns.php
修改samples.php
$db = new DbConnect(‘localhost’, ‘apnsuser’, ‘apnspassword’, ‘apnsdb’);
将localhost、apnsuser、apnspassword、apnsdb改成对应的参数
在iPhone上运行Demo程序,查看服务器数据库apns_devices表,看Demo程序是否成功注册
如果在apns_devices表中已有iPhone客户端的设备信息,则修改对应的development字段为:sandbox
运行发送消息的例子: http://ip:port/apns/samples.php,应该就会有消息推送
备注:
a 、如果要向所有已注册的设备推送消息,可以将samples.php 中的例子修改为
$apns->newMessage(NULL);
$apns->addMessageAlert(‘所有设备推送测试消息’);
$apns->addMessageCustom(‘acme2′, array(‘bang’, ‘whiz’));
$apns->queueMessage();
b 、如果要支持推送表情消息,可以参考: http://www.easyapns.com/category/just-for-fun
c 、查看classes/class_APNS.php 的_fetchMessages() 可知,easy apns 缺省每次只处理100 条记录,为提高发送效率,可适当提高此参数
1.2.6 、其他问题
a 、消息大批量发送问题
目前由于APNS(Apple Push Notification Service)机制原因,目前easy apns的消息发送机制为:
对每一条发送的消息,为所有需要推送的设备都在数据库中apns_messages创建一条消息,然后通过轮训数据库表来一条一条向苹果消息推送服务器发送消息
在需要推送的设备较多的情况下,由于存在大量的网络链接,导致存在较长时间的延迟。
解决方案:
1、做批量消息推送时候,保持与苹果消息推送服务器的长链接
2、使用批量发送机制
具体可参考: http://bit.ly/QUNRJ6
You should also retain connections with APNs across multiple notifications. APNs may consider connections that are rapidly and repeatedly established and torn down as a denial-of-service attack. Upon error, APNs closes the connection on which the error occurred.
As a provider, you are responsible for the following aspects of push notifications:
You must compose the notification payload (see “The Notification Payload”).
You are responsible for supplying the badge number to be displayed on the application icon.
You should regularly connect with the feedback web server and fetch the current list of those devices that have repeatedly reported failed-delivery attempts. Then you should cease sending notifications to the devices associated with those applications. See “The Feedback Service” for more information.
b 、数据库轮询效率问题
由于目前easy apns是采用数据库轮询的方式来进行消息推送,效率并不高,后期可以修改为Redis这样的NOSQL方案
1.3 、参考文档:
http://1j2.com/tutorial-implementing-push-notifications-with-easy-apns/
2 、 Android 消息推送
MQTT服务器采用mosquito http://mosquitto.org/
PHP管理包采用phpmqttclient: https://github.com/tokudu/PhpMQTTClient
2.1 、 mosquito 安装
cd /etc/yum.repos.d
wget http://download.opensuse.org/repositories/home:/oojah:/mqtt/CentOS_CentOS-5/home:oojah:mqtt.repo
yum update
yum install mosquitto
2.2 、 mosquito 命令行使用
mosquito安装主要包含三个部分:
mosquitto mosquitto服务器主程序,实现了MQTT协议
mosquitto_pub mosquitto发布消息的命令行程序
mosquitto_sub mosquitto订阅消息的命令行程序
启动mosquitto在前台运行
mosquitto
启动mosquitto在后台运行
mosquitto -d
启动订阅:
mosquitto_sub -t hello/world //订阅topic为hello/world的消息,使用默认地址和端口1883
发布消息
mosquitto_pub -t hello/world -m "hello,world" //发布topic 为hello/world的消息 "hello,world"
更多mosquitto命令可以参考
http://mosquitto.org/documentation/
2.3 、 PhpMQTTClient 安装
2.3.1 、从 https://github.com/tokudu/PhpMQTTClient下载
将tokudu-PhpMQTTClient-ba4e494/tokudu-PhpMQTTClient-ba4e494拷贝到服务器对应目录下
假设为/var/www/html/mqtt,可以通过 http://host:port/mqtt访问phpmqttclient
2.3.2 、将 index.php 的 $result = $conn->connect(SAM_MQTT, array(SAM_HOST => ’127.0.0.1′, SAM_PORT => 1883)); 修改为
$result = $conn->connect(SAM_MQTT, array(‘SAM_HOST’ => ’127.0.0.1′, ‘SAM_PORT’ => 1883));
备注:如果phpmqttclient的http服务器与mosquitto没有安装在同一台服务器,注意将index.php中的127.0.0.1和send_mqtt.php修改成mosquitto的ip地址
2.3.3 、将 SAM/MQTT/sam_mqtt.php 的 SAM_PORT 和 SAM_HOST 也都加上 ”
if ($options['SAM_PORT'] == ”) {
$this->port = 1883;
} else {
$this->port = $options['SAM_PORT'];
}
if ($options['SAM_HOST'] == ”) {
$this->host = ‘localhost’;
} else {
$this->host = $options['SAM_HOST'];
2.3.4 、服务器测试,测试 PhpMQTTClient 安装成功
启动mosquitto在前台运行,以方便获取连接客户端的信息
mosquitto
在服务器另外一终端上启动订阅消息的进程,订阅所有tokudu开头topic
mosquitto_sub –t tokudu /+
注意,此处之所以要使用tokudu,可以看index.php的182行 var target = ‘tokudu/’ + $(‘#messageTarget’).val();
在mosquitto的终端获得mosquitto_sub客户端的id
1350006978: New client connected from 127.0.0.1 as mosqsub/8491-localhost..
访问 http://host:port/mqtt ,push notification target字段填写8491-localhost,push notification text填写需要推送的测试消息
在在mosquitto的终端查看是否收到了推送的消息,如果收到,说明phpmqttclient已经安装配置成功
2.3.5 、 android Demo 程序安装
从 https://github.com/tokudu/AndroidPushNotificationsDemo 下载Android客户端例子,安装到Android,启动后获取客户端的Device Target
2.3.6 、先客户端推送消息
访问 http://host:port/mqtt ,push notification target字段填写Android客户端的Device Target,push notification text填写需要推送的测试消息
2.4 、问题
1、 需要在客户端增加向服务器端上报Device Target的通信报文,服务器端获取客户端的设备信息后存入到数据库中。需要发送消息时候从设备信息表中获取Device Target,然后调用推送接口发送消息,可参考send_mqtt.php
2、 消息队列的持久化及轮询机制,初期可存放到数据库中(参考easy apns),后期放到NOSQL数据库中。需要程序轮询消息队列,获取mosquitto消息队列状态、对未成功发送的消息重试等
3、大批量消息推送:可能的瓶颈应该主要在mosquitto的处理性能 ,由于是使用C++写的,性能应该可以支撑需要,可以先通过调整mosquitto.conf参数来优化mosquitto的性能。
4、除了MQTT+Mosquitto外,Apache ActiveMQ/Apollo+MQTT也是值得考虑的方案,ActiveMQ 5.6开始也支持MQTT协议了
5、之所以选择MQTT而非XMPP协议,可以参考 http://slidesha.re/PrXJvb,值得注意的Facebook Messenger也采用了MQTT协议。有空再单独写一篇关于移动终端消息推送整体架构及选型的方案
2.5 、参考文档
http://tokudu.com/2010/how-to-implement-push-notifications-for-android/
http://ceit.uq.edu.au/content/installing-mosquitto-under-centos