iOS10 推送完整剖析和注意事项
本文旨在对iOS推送进行一个完整的剖析,如果你之前对推送一无所知,那么在你认真地阅读了全文后必将变成一个推送老手,你将会对其中的各种细节和原理有充分的理解。以下是pikacode使用iOS推送的一些经验,欢迎互相交流,指出错漏之处。
推送服务可以说是所有App的标配,不论是哪种类型的App,推送都从很大程度上决定了App的打开率、使用率、存活率。因此,熟知并掌握推送原理及方法,对每一个开发者来说都是必备技能,对每一个依赖App的公司来说都至关重要。
从iOS10新增的UserNotificationsFramework可以发现,Apple整合了原有散乱的API,并且增加了许多强大的功能。以Apple官方的角度来看,也必然是相当重视推送服务对App的影响、以及对AppleiOS生态圈长远发展的影响。
准备篇
Tip1:推送通知(PushNotification)必须购买Apple开发者账号,并使用特定的推送证书
使用免费帐号不能推送。
那如果我们使用的是第三方推送服务(以下简称第三方)呢?比如「极光推送」。也必须购买开发者帐号。因为所有的第三方都会将推送请求发至APNs(ApplePushNotificationservice苹果推送通知服务),所有推送均是由APNs下发。
如何注册及正确的配置证书。
原理篇
Tip2:推送通知本身是iOS系统的行为,所以在App没有运行(没有在前台也没有在后台)的时候:
仍然能够推送及接收(通知中心通知、顶部横幅、刷新App右上角的小圆点即badge[以下简称角标]等都会由系统来控制和展示)。
收到推送时,是无法在App的代码中获取到通知内容的。因为沙盒机制,此时App的任何代码都不可能被执行。
Tip3:手机向APNs注册推送服务
1.在代码中注册推送服务:
#ifdef__IPHONE_8_0 if([[UIApplicationsharedApplication]respondsToSelector:@selector(registerUserNotificationSettings:)]){ UIUserNotificationSettings*settings=[UIUserNotificationSettingssettingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlertcategories:nil]; [[UIApplicationsharedApplication]registerUserNotificationSettings:settings]; }else{ UIRemoteNotificationTypemyTypes=UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound; [[UIApplicationsharedApplication]registerForRemoteNotificationTypes:myTypes]; } #else UIRemoteNotificationTypemyTypes=UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound; [[UIApplicationsharedApplication]registerForRemoteNotificationTypes:myTypes]; #endif
2.在第一次触发这段代码的时候,会有一个系统弹窗,询问你是否允许该App要给你推送信息。当你选择允许时,系统会打包App+手机唯一标识+证书信息发送至APNs服务器注册推送服务,APNs系统会对该手机安装的该App是否有推送权限进行验证,所以必须要加入了AppleDeveice的手机,使用对应App的推送证书才能够成功的注册。
3.如果注册成功,则可以在AppDelegate.m的如下方法中获取到deviceToken,它是对该手机+该App组合的一个唯一标识,当使用远程推送时,只需将推送消息发给指定的deviceToken即可使推送信息传达给指定手机的指定App上。因此如果你使用第三方,就需要在这个方法里将deviceToken传给第三方。(在iOS9为了更好的保护用户隐私,会出现多次重复删除/安装App导致deviceToken不断变化的情况。有时会出现一条推送手机会收到2次的问题,属于iOS9系统问题)。
-(void)application:(UIApplication*)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken{ [JPUSHServiceregisterDeviceToken:deviceToken];//将deviceToken传给极光推送 }
4.如果以上步骤均成功,此时你能够取到第三方提供的设备注册id。能否取到该id值,可以作为判断设备是否能够成功推送的标准(见Tip6-RegistrationID)。因为当你取到该值时必然:
推送证书配置正确(你拥有了推送权限)。
设备成功在APNs注册并返回了deviceToken(APNs能识别你的设备了)。
返回的deviceToken传给第三方,成功在第三方生成了唯一标识注册id(第三方能将你的设备信息传给APNs了)。
5.综上,注册及接收推送必须使用真机,必须连网。
Tip4:推送通知从服务端-->App代码的过程
1.使用你们公司或第三方的服务端向APNs发送推送请求(请参考苹果APNs相关资料,或者第三方推送提供了更简单的RESTAPI)。
2.APNs接收并验证推送请求。
3.APNs找到设备下发推送。
4.手机收到推送通知,系统根据App状态进行处理:
前台收到:
系统会将通知内容传到didReceiveRemoteNotification
后台收到:
如果开启了RemoteNotification,系统将推送传到didReceiveRemoteNotification:fetchCompletionHandler:(见Tip5-后台推送),否则此时代码中收不到推送。
展示横幅、通知中心、声音、角标。
退出收到:
如果点击推送横幅/通知中心而启动App,系统将通知传到didFinishLaunchingWithOptions。
展示横幅、通知中心、声音、角标。
推送通知内容篇
Tip5:推送通知分为本地/远程2种类型:
本地通知,可指定推送时间,在该时间准时弹出推送通知。
远程推送通知,分为普通推送/后台推送/静默推送3种类型。存在延迟问题(由于Tip1第2点,APNs的不稳定及高峰时段的巨量请求所致)。
普通推送
就是我们在手机上平时见到的推送通知。
包含声音、横幅、角标、自定义字段。
App:
处于前台,不会展示横幅,可通过didReceiveRemoteNotification(iOS7before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS7after)获取通知内容(前台展示横幅的方法看这里)。
处于后台,会展示横幅,无法获取通知内容。
处于退出,会展示横幅,无法获取通知内容。
点击图标启动,无法获取通知内容。
点击通知横幅启动,在didFinishLaunchingWithOptions获取通知内容。
通知内容类似如下:
{ "_j_msgid"=200806057;//第三方附带的id,用于统计点击 aps={ alert="显示内容"; badge=1;//App角标,可推送n、+n、-n来实现角标的固定、增加、减少 sound=default;//推送声音,默认系统三全音,如需使用自己的声音,需要将声音文件拖拽&拷贝至Xcode工程目录任意位置,并在推送时指定其文件名 }; key1=value1;//自定义字段,可设置多组,用于处理内部逻辑 key2=value2; }
后台推送
各种显示效果跟普通推送完全一样。
必须携带"content-available"=1;
必须携带alert、badge、sound中至少1个字段。
仅iOS7以后支持。
必须在Xcode工程中TARGETS-Capabilities-BackgroundModes-Remotenotifications开启该功能。
App:
处于前台,可通过didReceiveRemoteNotification(iOS7before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS7after)获取通知内容。
处于后台,可通过didReceiveRemoteNotification:fetchCompletionHandler:获取通知内容//获取情况中与普通推送的唯一不同点,此时iOS系统允许开发者在App处于后台的情况下,执行一些代码,大概提供几分钟的时间,可以用来偷偷的刷新UI、切换页面、下载更新包等等操作。
处于退出,无法获取通知内容。
点击图标启动,无法获取通知内容。
点击推送横幅启动,在didFinishLaunchingWithOptions获取通知内容。
通知内容类似如下:
{ "_j_msgid"=2090737306; aps={ alert="显示内容"; badge=1; "content-available"=1;//必带字段 sound=default; }; key1=value1; }
静默推送
没有任何展示效果。
必须携带"content-available"=1;,因此静默必然是后台的。
必须不携带alert、badge、sound。
可携带自定义字段。
App:
处于前台,可通过didReceiveRemoteNotification(iOS7before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS7after)获取通知内容。
处于后台,可通过didReceiveRemoteNotification:fetchCompletionHandler:获取通知内容//获取情况中与普通推送的唯一不同点,此时iOS系统允许开发者在App处于后台的情况下,执行一些代码,大概提供几分钟的时间,可以用来偷偷的刷新UI、切换页面、下载更新包等等操作。
处于退出,无法获取通知内容。
通知内容类似如下:
{ "_j_msgid"=3938587719; aps={ alert=""; "content-available"=1;//必带字段 }; key1=value1; }
推送目标篇
别名、标签、RegistrationID均是第三方提供的用于更方便地指定推送目标的功能。
Tip6:推送根据目标的不同可分为:
广播
无差别发送给所有用户。
别名alias推送
第三方提供的功能
一个手机的一款App只能设置一个alias(可修改)。
建议对每一个用户都取不同的别名,以此来确定唯一的用户(也可多个用户取1个别名)。
推送时可指定多个alias来下发同一内容。
仅指定alias的用户能够收到推送。
标签tag推送
第三方提供的功能。
可设置多个、可增加、清空。
用于指定多样的属性,如『1000』+『daily』+『discount』可用于表示月消费超过1k、喜欢购买日用品、偏好折扣商品的用户。
如果要删除,需要在上次设置时,将设置的tags保存至NSUserDefaults,本次剔除不需要的tag后,再重新设置。
推送时可指定多个tag来下发同一内容。
手机如果设置了推送指定的多个tag中任一个tag,都能够收到推送消息。如指定『1000』+『globe』+『original』(千元级消费者、全球购、原价),那么设置了『100』+『globe』+『discount』(百元级消费者、全球购、折扣价)的用户可以收到该推送消息。
RegistrationID推送
第三方提供的功能。
在Tip3的第3步时将deviceToken提供给第三方之后,其服务器会自动生成的指向该手机的唯一id。
可在推送时指定多个id来下发消息。
可用于对核心用户、旗舰用户的精准推送。
应用内消息篇
Tip7:应用内消息(以下简称消息)和推送通知的区别,消息:
不需要Apple推送证书。
由第三方的服务器下发,而不是APNs。
相比通知,更快速,几乎没有延迟,可用于IM消息的即时送达。
能够长时间保留离线消息,可获取所有历史消息内容。
通过长连接技术下发消息,因此:
手机必须启动并与第三方服务器建立连接。
如果手机启动立刻切至后台,很可能连接没有建立。
手机必须处于前台才能收到消息。
手机从后台切回前台,会自动重新建立连接,并收到离线消息。
没有任何展示(横幅、通知中心、角标、声音),因此可以:
自定义字段实现UI效果。
完全在静默情况下处理App内部逻辑。
使用一些AppStore审核不会通过的功能,在审核时关闭功能,上架后通过接收消息,开启相关功能。
组合大招篇
Tip8:tags的组合技巧
见Tip5-标签tag推送。
可以在服务端来统计分析用户行为,然后将指定的tags发送至手机,手机接收后再为用户打上对应的tags。
Tip9:通知+消息的组合技巧
首先来看通知和消息特性的对比:
通知 消息
送达时间 可能存在几秒延迟 几乎无延迟
获取时机 处于前台或后台能获取内容 仅处于前台能获取内容
离线内容 保留『一段时间』,过期会抛弃,无法查询历史内容 始终保留,可查询全部历史内容
系统展示 会展示(静默推送或App处于前台不展示) 不展示
由于各自的特性都存在差异,因此二者结合使用是使得App推送性能最大化的必然选择:
情景一:
QQ/微信聊天。会同时下发一组通知+消息,如果用户没有启动QQ,虽有延迟但必然能够先收到通知,在收到通知的提醒之后,用户打开App,此时收到了离线消息,即时更新UI,与好友即时地发送/接收消息。(在收到通知后,断网,然后启动App,你会发现此时手机里并不会显示刚刚通知的内容,因为它是依靠拉取消息来刷新页面的,而不是不够稳定的通知)。
情景二:(期待您的补充...)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。