本文旨在对 iOS 推送进行一个完整的剖析,如果你之前对推送一无所知,那么在你认真地阅读了全文后必将变成一个推送老手,你将会对其中的各种细节和原理有充分的理解。以下是 pikacode 使用 iOS 推送的一些经验,欢迎互相交流,指出错漏之处。

推送服务可以说是所有 App 的标配,不论是哪种类型的 App,推送都从很大程度上决定了 App 的 打开率、使用率、存活率 。因此,熟知并掌握推送原理及方法,对每一个开发者来说都是必备技能,对每一个依赖 App 的公司来说都至关重要。

从 iOS 10 新增的 UserNotifications Framework 可以发现,Apple 整合了原有散乱的 API,并且增加了许多强大的功能。以 Apple 官方的角度来看,也必然是相当重视推送服务对 App 的影响、以及对 Apple iOS 生态圈长远发展的影响。

准备篇

Tip 1:推送通知(Push Notification)必须购买 Apple 开发者账号,并使用特定的推送证书

使用免费帐号不能推送。
那如果我们使用的是第三方推送服务(以下简称第三方)呢?比如「极光推送」。也必须购买开发者帐号。因为所有的第三方都会将推送请求发至 APNs(Apple Push Notification service 苹果推送通知服务),所有推送均是由 APNs 下发。
如何注册及正确的配置证书。

原理篇

Tip 2:推送通知本身是 iOS 系统的行为,所以在 App 没有运行(没有在前台也没有在后台)的时候:
仍然能够推送及接收(通知中心通知、顶部横幅、刷新 App 右上角的小圆点即 badge [以下简称角标] 等都会由系统来控制和展示)。
收到推送时,是无法在 App 的代码中获取到通知内容的。因为沙盒机制,此时 App 的任何代码都不可能被执行。

Tip 3:手机向 APNs 注册推送服务
1.在代码中注册推送服务:

 #ifdef __IPHONE_8_0
 if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
   UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge| UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil];
   [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
 } else {
   UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
   [[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];
}
 #else
   UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
   [[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];
 #endif

2.在第一次触发这段代码的时候,会有一个系统弹窗,询问你是否允许该 App 要给你推送信息。当你选择允许时,系统会打包 App 手机唯一标识 证书 信息发送至 APNs 服务器注册推送服务,APNs 系统会对该手机安装的该 App 是否有推送权限进行验证,所以必须要加入了 Apple Deveice 的手机,使用对应 App 的推送证书才能够成功的注册。

3.如果注册成功,则可以在 AppDelegate.m 的如下方法中获取到 deviceToken,它是对 该手机 该App 组合的一个唯一标识,当使用远程推送时,只需将推送消息发给指定的 deviceToken 即可使推送信息传达给指定手机的指定 App 上。因此如果你使用第三方,就需要在这个方法里将 deviceToken 传给第三方。(在 iOS 9 为了更好的保护用户隐私,会出现多次重复删除/安装 App 导致 deviceToken 不断变化的情况。有时会出现一条推送手机会收到 2 次的问题,属于 iOS 9 系统问题)。

 -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { 
   [JPUSHService registerDeviceToken:deviceToken];//将 deviceToken 传给极光推送
 }

4.如果以上步骤均成功,此时你能够取到第三方提供的设备注册 id。能否取到该 id 值,可以作为判断设备是否能够成功推送的标准(见 Tip 6 - Registration ID)。因为当你取到该值时必然:

推送证书配置正确(你拥有了推送权限)。
设备成功在 APNs 注册并返回了 deviceToken(APNs 能识别你的设备了)。
返回 的 deviceToken 传给第三方,成功在第三方生成了唯一标识注册 id(第三方能将你的设备信息传给 APNs 了)。

5.综上,注册及接收推送必须使用真机,必须连网。

Tip 4:推送通知从 服务端 --> App 代码 的过程

1.使用你们公司或第三方的服务端向 APNs 发送推送请求(请参考苹果 APNs 相关资料,或者第三方推送提供了更简单的 REST API)。
2.APNs 接收并验证推送请求。
3.APNs 找到设备下发推送。
4.手机收到推送通知,系统根据 App 状态进行处理:
前台收到:
系统会将通知内容传到 didReceiveRemoteNotification
后台收到:
如果开启了 Remote Notification ,系统将推送传到 didReceiveRemoteNotification:fetchCompletionHandler:(见 Tip 5 - 后台推送),否则此时代码中收不到推送。
展示横幅、通知中心、声音、角标。
退出收到:
如果点击推送横幅/通知中心而启动 App,系统将通知传到 didFinishLaunchingWithOptions。
展示横幅、通知中心、声音、角标。

推送通知内容篇

Tip 5:推送通知分为 本地/远程 2 种类型:

本地通知,可指定推送时间,在该时间准时弹出推送通知。
远程推送通知,分为 普通推送/后台推送/静默推送 3 种类型。存在延迟问题(由于 Tip 1 第 2 点,APNs 的不稳定及高峰时段的巨量请求所致)。
    普通推送
      就是我们在手机上平时见到的推送通知。
     包含声音、横幅、角标、自定义字段。
     App :
          处于前台,不会展示横幅,可通过 didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after)获取通知内容(前台展示横幅的方法看这里)。
           处于后台,会展示横幅,无法获取通知内容。
           处于退出,会展示横幅,无法获取通知内容。
          点击图标启动,无法获取通知内容。
          点击通知横幅启动,在 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 个字段。
仅 iOS 7 以后支持。
必须在 Xcode 工程中 TARGETS - Capabilities - Background Modes - Remote notifications 开启该功能。

App:

处于前台,可通过didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after) 获取通知内容。
处于后台,可通过 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(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after) 获取通知内容。
      处于后台,可通过 didReceiveRemoteNotification:fetchCompletionHandler: 获取通知内容 //获取情况中与普通推送的唯一不同点,此时 iOS 系统允许开发者在 App 处于后台的情况下,执行一些代码,大概提供几分钟的时间,可以用来偷偷的刷新 UI、切换页面、下载更新包等等操作。
      处于退出,无法获取通知内容。

通知内容类似如下:

{
  "_j_msgid" = 3938587719;
  aps =   {
  alert = "";
  "content-available" = 1; // 必带字段
  };
  key1 = value1;
}

推送目标篇

别名、标签、Registration ID 均是第三方提供的用于更方便地指定推送目标的功能。
Tip 6:推送根据目标的不同可分为:

广播
无差别发送给所有用户。

别名 alias 推送

第三方提供的功能
一个手机的一款 App 只能设置一个 alias(可修改)。
建议对每一个用户都取不同的别名,以此来确定唯一的用户(也可多个用户取 1 个别名)。
推送时可指定多个 alias 来下发同一内容。
仅指定 alias 的用户能够收到推送。

标签 tag 推送

第三方提供的功能。
可设置多个、可增加、清空。
用于指定多样的属性,如 『1000』 『daily』 『discount』 可用于表示月消费超过 1k、喜欢购买日用品、偏好折扣商品的用户。
如果要删除,需要在上次设置时,将设置的 tags 保存至 NSUserDefaults,本次剔除不需要的 tag 后,再重新设置。
推送时可指定多个 tag 来下发同一内容。
手机如果设置了推送指定的多个 tag 中任一个tag,都能够收到推送消息。如指定 『1000』 『globe』 『original』 (千元级消费者、全球购、原价),那么设置了 『100』 『globe』 『discount』(百元级消费者、全球购、折扣价)的用户可以收到该推送消息。

Registration ID 推送

第三方提供的功能。
在 Tip 3 的第 3 步时将 deviceToken 提供给第三方之后,其服务器会自动生成的指向该手机的唯一 id。
可在推送时指定多个 id 来下发消息。
可用于对核心用户、旗舰用户的精准推送。

应用内消息篇

Tip 7:应用内消息(以下简称消息 )和推送通知的区别,消息:
不需要 Apple 推送证书。
由第三方的服务器下发,而不是 APNs。
相比通知,更快速,几乎没有延迟,可用于 IM 消息的即时送达。
能够长时间保留离线消息,可获取所有历史消息内容。
通过长连接技术下发消息,因此:
       手机必须启动并与第三方服务器建立连接。
       如果手机启动立刻切至后台,很可能连接没有建立。
       手机必须处于前台才能收到消息。
       手机从后台切回前台,会自动重新建立连接,并收到离线消息。
没有任何展示(横幅、通知中心、角标、声音),因此可以:
        自定义字段实现 UI 效果。
        完全在静默情况下处理 App 内部逻辑。
        使用一些 App Store 审核不会通过的功能,在审核时关闭功能,上架后通过接收消息,开启相关功能。

组合大招篇

Tip 8:tags 的组合技巧
见 Tip 5 - 标签 tag 推送。
可以在服务端来统计分析用户行为,然后将指定的 tags 发送至手机,手机接收后再为用户打上对应的 tags。

Tip 9:通知 消息的组合技巧
首先来看通知和消息特性的对比:
                                通知                                                                       消息
送达时间 可能存在几秒延迟                                                       几乎无延迟
获取时机 处于前台或后台能获取内容                             仅处于前台能获取内容
离线内容 保留『一段时间』,过期会抛弃,无法查询历史内容 始终保留,可查询全部历史内容
系统展示 会展示(静默推送或App处于前台不展示)                不展示

由于各自的特性都存在差异,因此二者结合使用是使得 App 推送性能最大化的必然选择:
情景一:
QQ/微信 聊天。会同时下发一组通知 消息 ,如果用户没有启动 QQ,虽有延迟但必然能够先收到通知,在收到通知的提醒之后,用户打开 App,此时收到了离线消息,即时更新 UI,与好友即时地发送/接收消息。(在收到通知后,断网,然后启动 App,你会发现此时手机里并不会显示刚刚通知的内容,因为它是依靠拉取消息来刷新页面的,而不是不够稳定的通知)。
情景二: (期待您的补充...)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

iOS10 推送完整剖析和注意事项的更多相关文章

  1. HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题

    HTML5在微信内置浏览器下,在右上角菜单的调整字体导致页面显示错乱的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  2. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. ios – containerURLForSecurityApplicationGroupIdentifier:在iPhone和Watch模拟器上给出不同的结果

    我使用默认的XCode模板创建了一个WatchKit应用程序.我向iOSTarget,WatchkitAppTarget和WatchkitAppExtensionTarget添加了应用程序组权利.(这是应用程序组名称:group.com.lombax.fiveminutes)然后,我尝试使用iOSApp和WatchKitExtension访问共享文件夹URL:延期:iOS应用:但是,测试NSURL

  4. ios – Testflight无法安装应用程序

    我有几个测试人员注册了testflight并连接了他们的设备……他们有不同的ios型号……但是所有这些都有同样的问题.当他们从“safari”或“testflight”应用程序本身单击应用程序的安装按钮时……达到约90%并出现错误消息…

  5. ibm-mobilefirst – 在iOS 7.1上获取“无法安装应用程序,因为证书无效”错误

    当我的客户端将他们的设备更新到iOS7.1,然后尝试从AppCenter更新我们的应用程序时,我收到了上述错误.经过一番搜索,我找到了一个类似问题的帖子here.但是后来因为我在客户端使用AppCenter更新应用程序的环境中,我无法使用USB插件并为他们安装应用程序.在发布支持之前,是否有通过AppCenter进行下载的解决方法?

  6. ios – 视图的简单拖放?

    我正在学习iOS,但我找不到如何向UIView添加拖放行为.我试过了:它说“UIView没有可见的接口声明选择器addTarget”此外,我尝试添加平移手势识别器,但不确定这是否是我需要的它被称为,但不知道如何获得事件的坐标.在iOS中注册移动事件回调/拖放操作的标准简单方法是什么?

  7. ios – 什么控制iTunes中iPhone应用程序支持的语言列表?

    什么控制iPhone应用程序的iTunes页面中支持的语言?

  8. ios – 获得APNs响应BadDeviceToken或Unregistered的可能原因是什么?

    我知道设备令牌在某些时候是有效的.用户如何使其设备令牌变坏?从关于“未注册”的文档:Thedevicetokenisinactiveforthespecifiedtopic.这是否意味着应用程序已被删除?.您应该看到四种分发方法:如果您选择AppStore或Enterprise,您将在后面的对话框中看到Xcode将APNS权利更改为生产:如果选择AdHoc或Development,则aps-environment下的文本将是开发,然后应与后端的配置匹配.

  9. ios – 当我关闭应用程序时,我从调试器获得消息:由于信号15而终止

    我怎么能解决这个问题,我不知道这个链接MypreviousproblemaboutCoredata对我的问题有影响吗?当我cmd应用程序的Q时,将出现此消息.Messagefromdebugger:Terminatedduetosignal15如果谁知道我以前的问题的解决方案,请告诉我.解决方法>来自调试器的消息:每当用户通过CMD-Q(退出)或STOP手动终止应用程序(无论是在iOS模拟器中还是

  10. ios – NSUbiquityIdentityDidChangeNotification和SIGKILL

    当应用程序被发送到后台时,我们会删除观察者吗?我遇到的问题是,当UbiquityToken发生变化时,应用程序终止,因为用户已经更改了iCloud设置.你们如何设法订阅这个通知,如果你不这样做,你会做什么来跟踪当前登录的iCloud用户?

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部