iOS远程推送原理及实现过程

该文章是我16年在公司博客上写的,除了证书注册的过程大致没有改变,像接收通知的方法都有所改变,所以将iOS 10 之后的接收通知及注册通知的方法在文章中补全,希望对正在处理远程推送的伙伴们有所帮助

一 、推送原理

推送通知,是现在的应用必不可少的功能。那么在 iOS 中,我们是如何实现远程推送的呢?iOS 的远程推送原理又是什么呢?在做 iOS 远程推送时,我们会遇到各种各样的问题。 那么首先让我们准备一些做推送需要的东西。我们需要一个付费的苹果开发者账号(免费的不可以做远程推送),有了开发者账号,我们可以去苹果开发者网站,配置自己所需要的推送的相关证书。然后下载证书,供我们后面使用,详细的证书配置过程,我们下面再说。
首先我们要说说iOS推送通知的基本原理:
苹果的推送服务通知是由自己专门的推送服务器APNs (Apple Push Notification service)来完成的,其过程是 APNs 接收到我们自己的应用服务器发出的被推送的消息,将这条消息推送到指定的 iOS 的设备上,然后再由 iOS设备通知到我们的应用程序,我们将会以通知或者声音的形式收到推送回来的消息。 iOS 远程推送的前提是,装有我们应用程序的 iOS 设备,需要向 APNs 服务器注册,注册成功后,APNs 服务器将会给我们返回一个 devicetoken,我们获取到这个 token 后会将这个 token 发送给我们自己的应用服务器。当我们需要推送消息时,我们的应用服务器将消息按照指定的格式进行打包,然后结合 iOS 设备的 devicetoken 一起发给 APNs 服务器。我们的应用会和 APNs 服务器维持一个基于 TCP 的长连接,APNs 服务器将新消息推送到iOS 设备上,然后在设备屏幕上显示出推送的消息。

设备注册APNs的流程图:
注册APNs的流程图.png

上图完成了如下步骤:

  1. Device(设备)连接APNs服务器并携带设备序列号(UUID)

  2. 连接成功,APNs经过打包和处理产生devicetoken并返回给注册的Device(设备)

  3. Device(设备)携带获取的devicetoken发送到我们自己的应用服务器

  4. 完成需要被推送的Device(设备)在APNs服务器和我们自己的应用服务器的注册

推送过程图:
在这里插入图片描述

推送的过程经过如下步骤:

  1. 首先,我们的设备安装了具有推送功能的应用(应用程序要用代码注册消息推动),我们的 iOS设备在有网络的情况下会连接APNs推送服务器,连接过程中,APNS 服务器会验证devicetoken,连接成功后维持一个基于TCP 的长连接;

  2. Provider(我们自己的应用服务器)收到需要被推送的消息并结合被推送的 iOS设备的devicetoken一起打包发送给APNS服务器;

  3. APNS服务器将推送信息推送给指定devicetoken的iOS设备;

  4. iOS设备收到推送消息后通知我们的应用程序并显示和提示用户(声音、弹出框)

比较直观的流程图:
直观的流程图.png

信息包结构图:
信息包结构图.png

上图显示的这个消息体就是我们的应用服务器(Provider)发送给APNs服务器的消息结构,APNs验证这个结构正确并提取其中的信息后,再将消息推送到指定的iOS设备。这个结构体包括五个部分,第一个部分是命令标示符,第二个部分是我们的devicetoken的长度,第三部分是我们的devicetoken字符串,第四部分是推送消 息体(Payload)的长度,最后一部分也就是真正的消息内容了,里面包含了推送消息的基本信息,比如消息内容,应用Icon右上角显示多少数字以及推送消息到达时所播放的声音等

Payload(消息体)的结构:

{
“aps”:{
“alert”:“CSDN给您发送了新消息”,
“badge”:1,
“sound”:“default”
},
}

这其实就是个JSON结构体,alert标签的内容就是会显示在用户手机上的推送信息,badge显示的数量(注意是整型)是会在应用Icon右上角显示的数量,提示有多少条未读消息等,sound就是当推送信息送达是手机播放的声音,传defalut就标明使用系统默认声音。

二、证书及推送实现过程

  1. 首先我们要新建一个Certificate Signing Request(也就是CSR)的请求文件
  • 在应用程序里的使用工具中找到钥匙串访问,选择从证书颁发机构请求证书

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 保存位置在 tingyun(指定自己的文件夹,这里我选择的是我的文件夹),点击存储。

  • 然后点击完成后我们会在 tingyun 里看到一个CertificateSigningRequest.certSigningRequest的请求文件,也就是我们说的CSR文件。在我们生成CSR文件的同时,会在钥匙串访问中生成一对秘钥,名称为刚才我们填写的常用名。

  1. 配置AppID
  • 到苹果开发者网站https://developer.apple.com

  • 点击Account
    在这里插入图片描述

  • 选择 Certificates,identifiers&Profiles
    在这里插入图片描述

  • 选择 Identifiers ->App IDs 点击上方的+号创建一个 App ID.
    在这里插入图片描述

  • Name: 填写 App 的名字就行

  • App ID Suffix 选择不用通配符的及 Explicit App ID

  • Bundle ID:填写自己应用的 Bundle ID 一定要和自己应用的一致.
    在这里插入图片描述

  • 在下面的 App Services 中选择自己需要的服务,我们需要推送服务,所以在Push Notifications上打勾,然后点击continue。
    在这里插入图片描述

  1. 创建证书
  • 证书需要创建两种,一种是开发的、一种是发布的,开发的是做测试用的。

  • 选择Development 点击右上角的+号,创建证书,我们首先创建开发证书
    在这里插入图片描述

  • 选择Apple Push Notification service SSL (Sandbox),创建推送服务证书点击下一步
    在这里插入图片描述

  • 这儿的 App ID 选择我们刚才创建的 App ID,然后点击下一步,下一步

在这里插入图片描述

  • 这儿点击 Choose File,选择我们刚才创建的 CSR 文件,然后点击生成(Generate)。最后点击下载,下载证书。将下载的证书,放到指定位置。

  • 发布证书的创建和开发证书一样,选择Production->Apple Push Notification service SSL (Production),后面和开发证书一样。
    在这里插入图片描述
  1. 添加 Devices (一个公司账号、企业账号或者个人账号,可添加100个设备):
  • 首先选中你要添加哪种设备,然后在左上角点击“+”号。
    在这里插入图片描述

  • Name 填写一个设备名字,UDID 填写自己需要加入测试的设备的 UDID,然后点击下一步。

在这里插入图片描述

  • 然后点击 Register 即可

在这里插入图片描述

  • 点击Done。
    在这里插入图片描述
  1. 查找设备的 UDID:
  • 用自己的 iOS 设备连接到电脑上,打开 iTunes。在设备摘要处可以看见一个序列号,点击序列号就会变成 UDID。

在这里插入图片描述

  1. 生成配置文件
  • 配置文件也有两种,一种是开发的,一种是发布的,开发的使我们做测试需要的,发布的是我们在 Appstore 上发布时需要的,我们都需要生成。

  • 我们先生成开发配置文件,选择Provisioning Profiles->Development点击右上角的+号。

在这里插入图片描述

  • 选择iOS App Development 点击下一步
    在这里插入图片描述

  • 这儿的 App ID 仍然选择我们刚才创建的 App ID
    在这里插入图片描述
    在这里插入图片描述

  • 这儿选择我们开发者的证书,如果不知道是哪个选择全部即可
    在这里插入图片描述

  • 这儿选择我们的测试设备,如果没有则在前面的Devices里面添加即可
    在这里插入图片描述
    在这里插入图片描述

  • 随便取个名字即可,然后下载下来
    在这里插入图片描述

  • 发布配置文件和开发配置文件一样创建,选择Distribution->Ad Hoc即可,后面与发布配置文件一样。

在这里插入图片描述
在这里插入图片描述

三、证书配置完成,打开我们创建的应用项目

打开AppDelegate.m 文件,在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法中添加下面代码,注册消息推送

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
/*
注册通知(推送)
申请App需要接受来自服务商提供推送消息
*/

if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
//iOS10特有
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
// 必须写代理,不然无法监听通知的接收与点击
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
// 点击允许
//NSLog(@"注册成功");
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
//NSLog(@"%@", settings);
}];
} else {
// 点击不允许
// NSLog(@"注册失败");
}
}];
}
else if ([[UIDevice currentDevice].systemVersion floatValue] >8.0){
//iOS8 - iOS10
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge categories:nil]];

}
else
{
UIRemoteNotificationType apn_type = (UIRemoteNotificationType)(UIRemoteNotificationTypeAlert |UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeBadge);
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:apn_type];
}
// 注册获得device Token
[[UIApplication sharedApplication] registerForRemoteNotifications];
return YES;
}

//下面方法是返回 ANPs 苹果推送服务器生成的唯一标识
/** 接收服务器传回的设备唯一标识 token */
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{

// 第一次运行获取到DeviceToken时间会比较长!
// 将deviceToken转换成字符串,以便后续使用
NSString *token = [deviceToken description];
NSLog(@"description %@", token);
}

//下面方法是当注册推送服务失败时,接收错误信息
/** 注册推送服务失败 */
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
NSLog(@"注册失败 %@",error);
}

//下面方法是当有消息推送回来时,接收推送消息
/** 设备接收到来自苹果推送服务器的消息时触发的,用来显示推送消息 */

// iOS 10收到通知(前台)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
NSDictionary * userInfo = notification.request.content.userInfo;
UNNotificationRequest *request = notification.request; // 收到推送的请求
UNNotificationContent *content = request.content; // 收到推送的消息内容
NSNumber *badge = content.badge;  // 推送消息的角标
NSString *body = content.body;    // 推送消息体
UNNotificationSound *sound = content.sound;  // 推送消息的声音
NSString *subtitle = content.subtitle;  // 推送消息的副标题
NSString *title = content.title;  // 推送消息的标题

if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
NSLog(@"iOS10 前台收到远程通知:%@", [self logDic:userInfo]);

}
else {
// 判断为本地通知
NSLog(@"iOS10 前台收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
}
completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以设置
}

//iOS 10  通知的点击事件(点击通知)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{

NSDictionary * userInfo = response.notification.request.content.userInfo;
UNNotificationRequest *request = response.notification.request; // 收到推送的请求
UNNotificationContent *content = request.content; // 收到推送的消息内容
NSNumber *badge = content.badge;  // 推送消息的角标
NSString *body = content.body;    // 推送消息体
UNNotificationSound *sound = content.sound;  // 推送消息的声音
NSString *subtitle = content.subtitle;  // 推送消息的副标题
NSString *title = content.title;  // 推送消息的标题
if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
NSLog(@"iOS10 收到远程通知:%@", [self logDic:userInfo]);

}
else {
// 判断为本地通知
NSLog(@"iOS10 收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
}

// Warning: UNUserNotificationCenter delegate received call to -userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: but the completion handler was never called.
completionHandler();  // 系统要求执行这个方法

}

//iOS 6 及以下系统通知
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(@"iOS6及以下系统,收到通知:%@",userInfo);
}

//iOS 7 及以上系统通知(前台/后台)
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {

NSLog(@"iOS7及以上系统,收到通知:%@",userInfo);
completionHandler(UIBackgroundFetchResultNewData);
}

四、服务器端(Java服务器)

服务器端我们需要,一个后缀为. p12的证书,以及需要的 jar 包

服务器端的证书生成方式:

1、打开我们前面下载的证书,在钥匙串中找到它
在这里插入图片描述

2、点击鼠标右键选择导出
在这里插入图片描述

3、导出后缀为.p12的文件保存到自己的电脑上,需要输入一个密码,在 Java 服务器端要用到
在这里插入图片描述

4、Java服务器端需要的 Jar 包

在这里插入图片描述

5、Java 服务器端代码:

import javapns.back.PushNotificationManager;
import javapns.back.SSLConnectionHelper;
import javapns.data.Device;
import javapns.data.PayLoad;
public class pushService {
public static void main(String[] args) {


try {

//这个token  就是客户端从APNs服务器获取到的devicetoken
String deviceToken = "eab6df47eb4f81e0aaa93bb208cffd7dc3884fd346ea0743fcf93288018cfcb6";
//被推送的iphone应用程序标示符
PayLoad payLoad = new PayLoad();
payLoad.addAlert("测试我的push消息");
payLoad.addBadge(1);
payLoad.addSound("default");

PushNotificationManager pushManager = PushNotificationManager.getInstance();
pushManager.addDevice("iphone", deviceToken);

//测试推送服务器地址:gateway.sandbox.push.apple.com /2195
//产品推送服务器地址:gateway.push.apple.com / 2195
String host="gateway.sandbox.push.apple.com";  //测试用的苹果推送服务器
int port = 2195;
String certificatePath = "/Users/hsw/Desktop/PushTest/PushTest.p12"; //刚才在mac系统下导出的证书

String certificatePassword= "123456";

pushManager.initializeConnection(host, port, certificatePath,certificatePassword, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);

//Send Push
Device client = pushManager.getDevice("iphone");
pushManager.sendNotification(client, payLoad); //推送消息
pushManager.stopConnection();
pushManager.removeDevice("iphone");
}
catch (Exception e) {
e.printStackTrace();
System.out.println("push faild!");
return;
}
System.out.println("push succeed!");
}

}

注意,我有看到转载的提问,服务端是否需要deviceToken,这个肯定是需要的,在上面Java的代码中也有写到。deviceToken是设备唯一的推送标识,服务端只有知道这个标识,才能够将通知推送到你的设备上。 注意:iOS 13后获取token的规则有变化

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论
### 回答1: iOS消息推送 APNs 是指苹果公司提供的一种用于向移动设备发送远程通知的服务。而使用 Java 实现 HTTP/2 协议发送推送消息可以通过以下步骤完成。 首先,我们需要使用 Java 开发一个 HTTP/2 客户端,以实现与 APNs 服务器的通信。我们可以使用 okhttp、netty 或者 java-http-client 等库来实现这个客户端。 其次,我们需要获取 APNs 服务器的推送地址和凭证认证信息。推送地址常见的有两个,分别是开发环境和生产环境。在获取推送地址之后,我们还需要生成一个包含认证信息的 JWT(JSON Web Tokens),以进行身份验证。 然后,我们可以使用 Java 客户端向 APNs 服务器发送 HTTP/2 请求。请求的内容应包括推送通知的 payload 和设备的设备标识符(Device Token)等信息。设备标识符是由 APNs 服务器为每个设备生成的唯一标识符,用于指定接收消息的设备。 最后,我们可以根据 APNs 服务器的响应来判断推送是否成功。APNs 服务器会返回一个包含推送结果的响应,其中包括推送是否成功以及失败的原因。 总之,使用 Java 实现 HTTP/2 协议发送 iOS 消息推送 APNs,需要开发一个符合 HTTP/2 协议的客户端,生成凭证信息并发送请求。通过与 APNs 服务器的通信,可以将推送消息发送到指定的 iOS 设备上。 ### 回答2: iOS消息推送(APNs)是苹果公司提供的一种服务,用于将推送通知发送到iOS设备上的应用程序。实现APNs推送的一种方法是使用HTTP/2协议发送请求。 在Java中,可以使用一些第三方库来实现使用HTTP/2协议发送APNs消息推送。其中,使用Netty库是一个常见的选择。 首先,你需要引入Netty库的相关依赖项,并创建一个Netty的客户端连接。 然后,你需要创建APNs推送的请求和消息内容。APNs消息使用JSON格式进行发送,你需要构建一个JSON对象来包含推送的内容。这个内容可以包括通知标题、内容、图标等。 接下来,你需要将JSON对象编码为二进制数据,并发送给APNs服务器。此时,你可以使用Netty库提供的HTTP/2的客户端请求来发送。 发送请求的过程包括建立连接、发送帧、处理响应等步骤。你需要设置请求的方法、URL、Headers以及Payload(即消息内容的二进制数据)。 最后,你需要在接收到APNs服务器的响应后,进行对应的处理和错误处理。常见的响应包括成功响应和错误响应。 总结起来,实现使用HTTP/2协议发送APNs消息推送过程,包括建立连接、构建JSON消息、编码为二进制数据、发送请求、处理响应等步骤。通过使用Netty库,可以简化这个实现过程,并提供了更好的性能和可扩展性。 ### 回答3: 在iOS中,APNS(Apple Push Notification Service)是一种用于向苹果设备(如iPhone、iPad、iPod Touch等)推送消息的服务。而在Java中,可以使用HTTP/2协议来实现发送APNS通知。 HTTP/2是一种基于HTTP/1.1的进化版本,其在性能和效率上有所提升。使用Java实现HTTP/2协议发送APNS通知的步骤如下: 1. 首先,需要准备APNS证书。在苹果开发者账号中创建一个推送证书,并将其导出为.p12文件。 2. 将.p12文件转换为Java可用的密钥和证书形式。可以使用Java的KeyTool工具来完成此步骤。 3. 使用Java的HTTP/2库,如Jetty或Netty,建立与APNS服务器的HTTP/2连接。这些库可提供与APNS服务器之间的双向通信。 4. 在建立连接后,可以使用HTTP/2的帧和流的概念向APNS服务器发送推送通知。可以使用Jetty或Netty提供的API来创建和发送HTTP/2帧。 5. 在发送通知时,需要将推送的相关信息,如设备令牌、推送内容等,封装为HTTP/2的帧数据发送到APNS服务器。 6. APNS服务器收到推送请求后,会根据设备令牌等信息将通知推送给相应的设备。 总之,使用Java实现HTTP/2协议发送APNS通知需要准备证书、使用HTTP/2库建立连接,并利用API创建和发送HTTP/2帧,最后将推送信息发送给APNS服务器。这样就可以通过HTTP/2协议向iOS设备推送消息了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

假装自己很用心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值