大家好,系统自动推送功能详解(一)—— 初识集成流程(一)相信很多的网友都不是很明白,包括也是一样,不过没有关系,接下来就来为大家分享关于系统自动推送功能详解(一)—— 初识集成流程(一)和的一些知识点,大家可以关注收藏,免得下次来找不到哦,下面我们开始吧!
几个需要提前知道的问题
1. 推送流程是如何的?
推送是Apple系统提供的功能。其实基本流程就是我们的客户端需要使用deviceToken去苹果服务器注册,并将这个deviceToken发送到我们的服务器来绑定我们的账号。服务器将推送的内容发送给苹果,苹果根据deviceToken将定制的内容发送给我们的客户端,我们就会收到推送。
也就是说,我们除了在客户端注册PUSH,接收苹果给我们的deviceToken,发送到我们的服务器绑定当前账号之外,除了等待接收PUSH进行处理之外,我们无法决定其他的事情。至于推送什么是由我们的服务器决定的。何时能收到取决于苹果服务器。
下图很好的解释了push的原理。图片来自网络。
PUSH原理
2. deviceToken是如何获取的?有什么用?
deviceToken是我们使用Apple的API注册PUSH时Apple的服务器发送给我们的,我们在代理方法中接收到它——(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken。那么这有什么作用呢?这是Apple 发送个性化推送来查找您的机器的凭据。有了它,苹果系统就知道这条消息要推送给你了。
我们在代理方法中收到推送后,一般需要将这个deviceToken发送到我们的服务器,让服务器将这个deviceToken绑定到你当前的App账号上,这样就可以进行个性化的推送和消息定制了。
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSLog(@"push - didRegisterForRemoteNotificationsWithDeviceToken");
NSString * deviceid=[NSString stringWithFormat:@"%@", deviceToken];
deviceid=[deviceid stringByReplacingOccurrencesOfString:@"" withString:@""];
deviceid=[deviceid stringByReplacingOccurrencesOfString:@"" withString:@""];
deviceid=[deviceid stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"push - deviceToken=%@", deviceid);
//这是我自己写的一个单例,用来存储App的一些基本信息。这里我使用NSUserDefaults 来存储当前接收到的deviceToken。
[JJAppPrefs setDeviceToken:deviceid];
//这是我写的一个单例,专门处理Push相关的事情。这是绑定token,并将收到的deviceToken发送到你的服务器。
//服务器执行绑定。你只需要知道绑定是成功还是失败,不需要做任何其他事情。
[[JJPushManager管理器]bindDeviceToken];
}
3. 客户端要如何开启推送?
这是一个开关。只需单击它即可启用推送。
打开推送
4. 关于证书要做什么?
我们需要推送证书。让有账号的人生成两份证书,一份是测试环境证书,一份是生产环境证书。
关于如何生成证书的具体说明,您可以阅读网上的资料,按照步骤操作即可。这里我就不详细说了。
注册PUSH
截至目前,iOS已经有11个系统。从10系统开始注册PUSH时,必须考虑版本差异。
如果你在iOS10之前使用PUSH,你就不用担心这个问题。不过随着iOS10的更新,出来了一个新的类UNUserNotificationCenter,所以需要根据不同的版本执行不同的注册逻辑。
iOS10及其以后版本//10及以后系统使用以下方法注册
UNUserNotificationCenter *center=[UNUserNotificationCenter currentNotificationCenter];
[中心设置Delegate:self];
[中心requestAuthorizationWithOptions:(UNAuthorizationOptionAlert |
UNAuthorizationOptionBadge | UNAuthorizationOptionBadge |
UNAuthorizationOptionSound)
completionHandler:^(BOOL 授予, NSError * _Nullable 错误) {
如果(授予){
NSLog(@"推送-注册成功");
}
别的{
NSLog(@"推送-注册失败");
}
}];
[[UIApplication共享应用程序]registerForRemoteNotifications];这里,[[UIApplication sharedApplication] registerForRemoteNotifications];一定不能少,否则收不到deviceToken。因为如果你不写这句话,就代表你没有注册。
同时,你需要设置代理@interface AppDelegate(),否则你处理PUSH的方法不会回调。
iOS9及其以前版本iOS9及之前版本使用UIUserNotificationSettings类来注册PUSH。
//9及以前的系统使用以下方法进行注册
否则如果([UIUserNotificationSettings self]){
id 设置=[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert |
UIUserNotificationTypeSound | UIUserNotificationTypeSound | UIUserNotificationTypeSound | UIUserNotificationTypeSound
UIUserNotificationTypeBadge)
类别:nil];
[[UIApplication共享应用程序]registerUserNotificationSettings:settings];
[[UIApplication共享应用程序]registerForRemoteNotifications];
}
别的{
[[UIApplication共享应用程序] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeSound
UIRemoteNotificationTypeAlert)];
}这里有一些小问题。 UIUserNotificationSettings 在10 系统上出现时就放弃了这个类。
NS_CLASS_DEPRECATED_IOS(8_0, 10_0, "使用UserNotifications 框架的UNNotificationSettings") __TVOS_PROHIBITED
@interface UIUserNotificationSettings : NSObject 这里大家也注意到了这个方法
- (void)registerForRemoteNotificationTypes:(UIRemoteNotificationType)types NS_DEPRECATED_IOS(3_0, 8_0, "使用-[UIApplication registerForRemoteNotifications] 和UserNotifications Framework 的-[UNUserNotificationCenter requestAuthorizationWithOptions:completionHandler:]") __TVOS_PROHIBITED;看吧,这个方法在iOS 8.0中已经被废弃了,改用上面建议的两种方法。
以上两种注册方式是否需要像iOS10及以上的方式一样设置代理呢?简单来说,你不需要这样做。他们的代理名为UIApplicationDelegate,系统已经为你设置好了。也就是说10之前的系统可以直接编写代理方法进行相应处理,不需要再走代理步骤。
//这个系统是为你编写的
@interface AppDelegate : UIResponder
获取deviceToken
在上面您注册了PUSH。注册成功后,Apple服务器会返回给您deviceToken。在下面的代理方法中获取了deviceToken的状态并进行了其他处理。
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
NSLog(@"push - didRegisterUserNotificationSettings");
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSLog(@"push - didRegisterForRemoteNotificationsWithDeviceToken");
NSString * deviceid=[NSString stringWithFormat:@"%@", deviceToken];
deviceid=[deviceid stringByReplacingOccurrencesOfString:@"" withString:@""];
deviceid=[deviceid stringByReplacingOccurrencesOfString:@"" withString:@""];
deviceid=[deviceid stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"push - deviceToken=%@", deviceid);
//这是我自己写的一个单例,用来存储App的一些基本信息。这里我使用NSUserDefaults 来存储当前接收到的deviceToken。
[JJAppPrefs setDeviceToken:deviceid];
//这是我写的一个单例,专门处理Push相关的事情。这是绑定token,并将收到的deviceToken发送到你的服务器。
//服务器执行绑定。你只需要知道绑定是成功还是失败,不需要做任何其他事情。
[[JJPushManager管理器]bindDeviceToken];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)错误
{
NSLog(@"push - didFailToRegisterForRemoteNotificationsWithError=%@", 错误);
}这里我们在代理方法中接收到deviceToken,首先将其存储在本地,然后发送到服务器以绑定当前帐户。
收到PUSH的处理
就像注册PUSH一样,PUSH的处理也取决于系统版本。
1. 代理方法的调用
iOS 10及其以后//iOS10新增
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler API_AVAILABLE(ios(10.0))
{
NSLog(@"push - didReceiveNotificationResponse=%@", 响应);
[[JJPushManager管理器] jj_userNotificationCenter:center didReceiveNotificationResponse:response];
完成处理程序();
}
//iOS10新功能
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler API_AVAILABLE(ios(10.0))
{
NSLog(@"push-willPresentNotification");
[[JJPushManager管理器]jj_userNotificationCenter:center willPresentNotification:notification];
完成处理程序(UNNotificationPresentationOptionBadge |
UNNotificationPresentationOptionSound|
UNNotificationPresentationOptionAlert);
}这里有几个问题需要注意:
JJPushManager是我自己编写的一个单例,用于处理接收到的PUSH以及绑定和解除绑定deviceToken。这里,将单例分开进行处理,这样可以降低AppDelegate中代码的复杂度,并且将单例分开进行更清晰的处理。
关于iOS10的两个方法,当收到banner时- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification 和CompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler API_AVAILABLE(ios(10.0)) 方法会被调用,当用户点击查看横幅时- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler API_AVAILABLE(ios(10.0)) 将被调用。
对于iOS 10之后的系统,应用程序无论是在前台、后台还是被杀死,都会收到推送横幅。
这样你就会收到广播通知,下一步就是点击处理。
iOS 9及其以后这是接收通知的唯一方式
//iOS9及以后的方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(@"push - didReceiveRemoteNotification=%@", userInfo);
[[JJPushManager管理器] jj_application:application didReceiveRemoteNotification:userInfo];
}这里有几个问题需要注意:
在iOS9系统中,App在前台时是没有banner的。这时候我们就需要进行特殊的处理。一种解决方案是模拟本地通知进行展示,另一种是弹出系统的AlertView,然后进行相关的业务逻辑处理,比如跳转到某个主播的直播间。
2. PUSH处理
PUSH 我统一在我写的单例JJPushManager中处理。
@接口JJPushManager()
@property (非原子,强) NSDictionary *currentPushDict;
@property(非原子,强)JJFeed *feed;
@结尾
@实现CPPushManager
#pragma mark - 类公共函数
+(实例类型)管理器
{
静态JJPushManager *pushManager;
静态dispatch_once_t谓词;
dispatch_once(谓词, ^{
PushManager=[[JJPushManager 分配] init];
[[NSNotificationCenter defaultCenter] addObserver:pushManager 选择器:@selector(handlePushWhenApplicationActive) name:UIApplicationDidBecomeActiveNotification object:nil];
});
返回推送管理器;
}
- (无效)dealloc
{
[[NSNotificationCenter defaultCenter]removeObserver:self];
}
#pragma mark - 对象私有函数
//根据信息数据返回Feed模型
- (CPFeed *)gainFeedInfo
{
self.feed=[[JJFeed alloc] initWithDict:self.currentPushDict];
返回自给;
}
- (void)initCurrentPush:(NSDictionary *)currentPushDict
{
如果(!currentPushDict){
返回;
}
self.currentPushDict=currentPushDict;
}
//直接跳转到直播间
- (void)转到游戏室
{
//未登录时,不处理推送信息
if ([JJUserManager loadUserPref]==NO) {
返回;
}
CPFeed *feedInfo=[自身增益FeedInfo];
如果(!feedInfo){
返回;
}
JJViewController *vc=(JJViewController *)JJCurrentNaviController.topViewController;
if ([vc isKindOfClass:[JJPlayingViewController 类]]) {
返回;
}
//直接跳转到直播间
JJPlayingViewController *playVC=[[JJPlayingViewController alloc] initWithFeed:feedInfo];
[CPCurrentNaviController PushViewController:playVCanimated:YES];
}
#pragma mark - 对象公共函数
//iOS10以下使用该方法接收通知
- (void)jj_application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[自我初始化CurrentPush:userInfo];
if ([UIApplication共享应用程序].applicationState==UIApplicationStateActive) {
JJViewController *vc=(JJViewController *)JJCurrentNaviController.topViewController;
if ([vc isKindOfClass:[JJPlayingViewController 类]]) {
返回;
}
[自我增益FeedInfo];
NSString *titleStr=[NSString stringWithFormat:@"快来观看,%@正在播出~", self.feed.anchorPrefs.userNickName];
IMP_WSELF();
[vc showAlertViewWithTitle:titleStr message:nil cancelAction:nil EnsureAction:^{
[wself 转到游戏室];
}];
}
}
//iOS10新功能
- (void)jj_userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)响应API_AVAILABLE(ios(10.0))
{
NSDictionary * userInfo=response.notification.request.content.userInfo;
[自我初始化CurrentPush:userInfo];
if ([UIApplication共享应用程序].applicationState==UIApplicationStateActive) {
[自我转到游戏室];
}
}
//iOS10新功能
- (void)jj_userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)通知API_AVAILABLE(ios(10.0))
{
NSDictionary * userInfo=notification.request.content.userInfo;
[自我初始化CurrentPush:userInfo];
}
#pragma mark - 操作通知
//输入活动消息通知
- (void)handlePushWhenApplicationActive
{
if (!self.currentPushDict) {
返回;
}
[自我转到游戏室];
self.currentPushDict=nil;
}注:以上只是简单的逻辑,更复杂的处理需要根据产品的需要进行额外的处理。
几个其他问题
1. 关于测试
测试时,开发和QA均应使用推送的开发证书进行测试。直接用官方证书测试是收不到的。
2. 关于到达率
使用开发证书进行推送测试。有时到达率不是100%。我用系统11试了一下,基本100%。我用系统9测试的时候,很大概率收不到,但偶尔也能收到。这个和苹果测试环境证书有关,在官方环境下就可以了。我们的客户无法控制这一点,所以不用担心,这不是一个错误。
3. 关于用户登录和退出
这需要额外的处理。用户登录时(无论是手机号还是第三方)都需要重新注册PUSH并绑定deviceToken。当用户注销时,需要将deviceToken发送到服务器来解绑并移除deviceToken。本地存储。
登录[(AppDelegate *)([UIApplication sharedApplication].delegate) registerPushNotifications];退出登录[[JJPushManager 管理器] unbindDeviceToken];
[JJUserManager 清除数据];
参考资料
1.IOS Push消息推送原理及应用
后记
本文主要讲系统PUSH的集成和相关问题。如果有兴趣的话,请点赞或者关注哦~~~~
【系统自动推送功能详解(一)—— 初识集成流程(一)】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
终于有关于系统集成的教程了,期待深入了解。
有6位网友表示赞同!
这篇文章能解决很多刚接触系统集成的新手疑问吧!
有9位网友表示赞同!
希望能详细介绍各个步骤的具体操作,这样学习起来更方便。
有10位网友表示赞同!
"基本流程"是指整个系统的流程吗?还是针对特定类型的集成?
有19位网友表示赞同!
期待后续的文章深入讨论一些进阶技巧和方案.
有6位网友表示赞同!
系统集成这么复杂的操作,这个教程是不是有点简单?
有6位网友表示赞同!
有没有相关的案例分析可以参考?能更直观地理解流程。
有10位网友表示赞同!
我看标题里 "(一)" ,还有后续文章吗?我真按捺不住想继续学习!
有12位网友表示赞同!
对系统集成一直好奇,现在终于有机会了解一下了!
有14位网友表示赞同!
这个教程是不是针对特定的软件体系结构?
有7位网友表示赞同!
希望可以涵盖常见的集成场景和技术架构的设计思路。
有5位网友表示赞同!
文章提到的集成流程具体包含什么?比如接口设计、数据转换等?
有20位网友表示赞同!
系统集成这块知识真的很实用,期待学到实操技能!
有7位网友表示赞同!
如果有开源项目的代码实战分享,那太棒了!
有8位网友表示赞同!
文章可以结合一些图示和流程图,更直观易懂。
有7位网友表示赞同!
我对不同类型的系统集成方法比较感兴趣。
有8位网友表示赞同!
希望能看到对常见的集成问题和解决方案的分析和讨论。
有9位网友表示赞同!
能不能针对不同的系统平台,讲解相应的集成方法?
有19位网友表示赞同!
学习完成后,我们可以搭建一个简单的系统模型进行实践吗?
有16位网友表示赞同!
这个教程适合什么样的开发人员参考学习呢?
有16位网友表示赞同!