iOS远程推送详解

Paste_Image.png

从上图我们可以看到:
1、应用程序注册消息推送。
2、iOS从APNS Server获取device token,应用程序接收device token。
3、应用程序将device token发送给PUSH服务端程序。
4、服务端程序向APNS服务发送消息。
5、APNS服务将消息发送给iPhone应用程序。

关于deviceToken:

deviceToken生成:

远程通知首先要向苹果APNs服务器注册并且生成一个唯一的deviceToken(每个设备的客户端都独一无二)。根据向APNs服务器发送的Token key(包含了设备的UUID和App的Bundle Identifier)。deviceToken将会以NSData对象发送到对应请求的App上。然后App把此deviceToken发送给我们自己的服务器,就是所谓的Provider。Provider收到deviceToken以后进行储存等相关处理,以后Provider根据这个deviceToken来进行消息推送。

deviceToken用处:

deviceToken是推送服务器(Provider)在向应用推送消息时,找到对应的设备以及该设备上对应的应用,从而把此推送消息推送给此应用。

deviceToken唯一性:

deviceToken根据设备唯一标识和客户端唯一标识生成。确保了deviceToken唯一。唯一性并不是说一台设备上的一个应用程序永远只有一个deviceToken,当用户升级系统的时候deviceToken是会变化的。

注册远程通知(获取deviceToken)

注册远程通知的方法

一般都是在App启动完成的时候去注册远程通知注册方法调用一般都在didFinishLaunchingWithOptions:方法中

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {

// 在iOS8之前注册远程通知的方法,如果项目要支持iOS8以前的版本,必须要写此方法
UIRemoteNotificationTypetypes=UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeAlert;   

[[UIApplicationsharedApplication] registerForRemoteNotificationTypes:types];

// iOS8之后注册远程通知的方法
UIUserNotificationTypetypes=UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert;
UIUserNotificationSettings*mySettings =[UIUserNotificationSettingssettingsForTypes:types categories:nil];    
[[UIApplicationsharedApplication] registerUserNotificationSettings:mySettings];
}

处理注册远程通知的回调方法

// 注册成功回调方法,其中deviceToken即为APNs返回的token

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {  

 [self sendProviderDeviceToken:deviceToken];// 将此deviceToken发送给Provider

}

// 注册失败回调方法,处理失败情况

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {}

处理接收到远程通知消息分两种情况:前台和后台
application: didFinishLaunchingWithOptions:此方法在程序在第一次启动时调用,根据方法内代码判断是否有推送消息。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 // userInfo为收到远程通知的内容 
NSDictionary*userInfo=launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
 if (userInfo) { 
// 有推送的消息,处理推送的消息
 } 
return YES;
}

各种状态下APP收到消息以及处理:

首先不管在前台还是在后台,如果设置后台模式为Remote Notifications
具体设置方式(或者在info.plist中配置了UIBackgroundModes):如图
TARGETS-Capabilities-Background Modes-Remote Notifications



此时不论App处于Foreground状态还是处于Background状态,收到远程推送消息的时候都会立即调用此方法。

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ }

这里引入一个概念:
**推送唤醒(remote notifications)
**iOS7以前,当你收到推送消息时,你需要先打开应用,等待应用从网络上获取推送的信息之后,才能将信息呈现出来。而iOS7改变了这一过程。当系统收到推送消息时,不是首先提醒用户,而是唤醒对应的应用,让应用在后台获取对应的信息。当信息处理完成后,再提醒用户。一个很小的改变,但是可以很大的提升用户体验。同样,iOS系统也会限制这种推送消息的频率,防止系统被频繁唤醒影响续航。

此时需要更改推送的payload,如果想要使用推送来唤醒应用运行代码的话,需要在payload中加入content-available,并设置为1。

aps {
     content-available: 1  
     alert: {...}
 }

1.程序在前台(Foreground)时收到推送:
如果设置remote notifications,那么先执行相对应的方法,在后台收到推送也是如此。
在前台收到通知时,会调用下面这个方法,可以在这个方法里面实现收到通知时刷新或跳转界面的功能;程序在前台收到推送时通知栏不会弹出推送信息

-(void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo{}

2.程序在后台时收到推送:
如果设置remote notifications,那么先执行相对应的方法,在前台收到推送也是如此。
如果用户点击通知栏信息进入程序会调用情况1中的方法,所以在情况1的方法里面需要根据程序在前台还是后台来执行不同操application.applicationState

3.当程序关闭时收到推送:程序关闭时收到推送时,用户点击通知栏信息进入应用的时会调用

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
 // 在此方法中一定要调用completionHandler这个回调,告诉系统是否处理成功
 UIBackgroundFetchResultNewData, // 成功接收到数据 UIBackgroundFetchResultNoData, // 没有接收到数据 UIBackgroundFetchResultFailed // 接受失败
 if (userInfo) { 
completionHandler(UIBackgroundFetchResultNewData);
 } else {
 completionHandler(UIBackgroundFetchResultNoData); 
}
}

可操作通知类型收到推送消息时回调方法

// 此两个回调方法对应可操作通知类型,具体使用方法参考以上方法很容易理解,不在详细叙述
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler {


}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler {


}

未读消息数量角标设置
设置角标

[UIApplication sharedApplication].applicationIconBadgeNumber=badgeNum;

这个方法可以设置应用程序的角标的数值。但是当程序关闭时,收到推送后我们就不能改变角标数值了。所以建议让服务端推送过来的信息里加上'badge' = 88这个键值对来确定角标的显示数值。这样程序在后台还是关闭,只要显示服务端传给我们的角标值就好了。
不过当我们阅读完一条消息的时需要告诉服务器,并且将[UIApplication sharedApplication].applicationIconBadgeNumber减一。

当客户端杀死情况走本地推送(当客户端开启走—(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions)。

 if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
        
        // 当被杀死状态收到本地通知时执行的跳转代码
        UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
        NSDictionary *infoDict = [mnResource parseJSONStringToNSDictionary:notification.userInfo[@"info"]];

            [self.delegate diaplayAlertWhenReceivePushInfo:infoDict];
     
  }

到现在为止做iOS 推送也差不多算入行了吧(都是用的个推)
昨天调试个推送也让我蛋疼,调试了一晚上,其他系统的没什么问题,就有个手机是iOS 10.0.2的系统,不知道为什么走不通apns。

遇到这些问题不要慌,先定为到问题。下面列举自己踩过的个推方面的坑:

1.打包的证书与个推后台的证书环境不一致,导致推送失败。
2.服务端忘记设置了个推安卓和ios的key,没有区分,所以会向客户端下发两条推送,那是我解析的时候是蒙蔽的,json解析出来怎么会有两种key完全不同的字典。这时候alert很大几率显示null且不能跳转,因为你解析不出来。
3.上面那种讲到的情况,自己分析应该是

这里在说明一点在使用个推的时候上传个推平台的.p12要和打包的证书环境一致哦(生产环境和调试环境)
参考:http://www.jianshu.com/p/4b947569a548

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容