如何在 iOS 中准确地追踪【远程推送已接收】事件?

| Swift , iOS

 

内容概览

  • 前言
  • 无效方案 UNUserNotificationCenterDelegate
  • 基于 Rich Notificaion,采用 App Extension (UNNotificationServiceExtension) 进行追踪
  • 在 App Extension 与宿主应用(Containing App) 间进行数据同步
  • 使用 lola 快速地发送测试推送消息
  • 总结

 

前言

 

在发送营销内容前,市场部的工作人员都会设计衡量营销效果的方案。移动互联网时代,推送消息是大多数企业常用的营销手段。

那么,如何衡量推送消息的转化率呢?

大致的计算方式:

  • 消息接收率 = 成功接收消息的设备数量 / 消息发送量
  • 消息查看率 = 查看消息的设备数量 / 成功接收消息的设备数量

可以看出,成功接收消息的设备数量 是必不可少的参数。所以,要衡量推送消息的转化率,必须要能够准确地追踪【推送消息已接收】事件。

看官心中是否已经浮现了一些方案呢?欢迎您留言和 Ficow 分享喔~

现在,请允许 Ficow 先来阐述一下自己的方案。如有不足,欢迎斧正,谢谢~

 

无效方案 UNUserNotificationCenterDelegate

 

UNUserNotificationCenterDelegate 不能完成我们的需求,这是该协议的文档:

@available(iOS 10.0, *)
public protocol UNUserNotificationCenterDelegate : NSObjectProtocol {

    // The method will be called on the delegate only if the application is in the <<<foreground>>>. blablabla...
    @available(iOS 10.0, *)
    optional func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)

    // The method will be called on the delegate when the user <<<responded to the notification>>> by opening the application, dismissing the notification or choosing a UNNotificationAction. blablabla...
    @available(iOS 10.0, *)
    optional func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
}

这两个代理方法被调用的场景分别如下:

  1. 应用在前台运行;
  2. 用户点击了推送;

所以,当应用 未启动时在后台运行时,我们无法追踪推送消息是否已接收。

好吧,只能找其他的方案了~

 

基于 Rich Notificaion,采用 App Extension (UNNotificationServiceExtension) 进行追踪

 

首先,我们先看一下 UNNotificationServiceExtension 的文档:

嗯,一个可以在远程推送被递送给用户前 修改内容 的对象。

既然可以修改,那么必然就已经知道推送已经收到。

不过,文档中也列出了相关的限制说明。UNNotificationServiceExtensiondidReceive(_:withContentHandler:) 会在满足以下条件后,系统才会执行它们:

  • 远程推送需要展示一个 弹框
  • 远程推送中的字典里的 aps 需要包含值为 1mutable-content 键;

这是一个具体的 JSON 示例:

{
   "aps" : {
      "category" : "SECRET",
      "mutable-content" : 1,
      "alert" : {
         "title" : "Secret Message!",
         "body"  : "(Encrypted)"
     },
   }
}

 

具备以上条件后,就可以在这个方法中调用您自定义的事件追踪方法:

open func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void)

请注意,在该方法的文档中有说明,需要在 30 秒内调用 contentHandler,否则系统就会调用 func serviceExtensionTimeWillExpire() 方法。如果在 serviceExtensionTimeWillExpire 方法中也没有调用 contentHandler,系统就会将推送消息显示给用户。

另外,Ficow 使用了 Segment 的 SDK 进行事件追踪,经常在发送几次远程推送之后才一次性地在 Segment 的控制台网页上看到这几次事件追踪的数据。如果您在发送一次远程推送后没有看到相关的数据,可以考虑多发几次喔~

 

在 App Extension 与宿主应用(Containing App) 间进行数据同步

 

如果您需要在 App Extension 与宿主应用(Containing App) 间进行数据同步,那么您一定要理解这二者之间的关系:

App Extension 与宿主应用之间是无法直接进行调用的,需要借助共享资源(Shared resources)来实现数据同步。

如上图所示,虽然宿主应用的 Bundle 中包括了 App Extension 的 Bundle,但是二者的进程是独立运行的,而且不能直接访问彼此的容器。

 

最常见的共享资源是 UserDefaults。操作方式大致如下:

  • 创建 UserDefaults 实例的时候指定一个 suite name,一般为 App Extension 的 App Group ID,如:UserDefaults(suiteName: "group.com.ficow.NotificationServiceExtension")
  • 在宿主应用内向指定了 suiteNameUserDefaults 实例写入数据,然后在 App Extension 内通过 suiteName 相同的 UserDefaults 读取数据。(UserDefaults 只支持:NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary,推荐使用 NSKeyedArchiverNSKeyedUnarchiver 来完成Data和自定义数据结构之间的序列化、反序列化)

 

更多相关的内容,请您参考:

 

使用 lola 快速地发送测试推送消息

 

如果需要用真机频繁地测试远程推送,建议您使用工具来发送推送。Ficow 认为,lola 就是这样一个比较好用的工具,推荐给您~

替换下面的命令行指令中相关的数据(app_bundle_id, device_token, apple_developer_team_id, filepath_to_p8_auth_key.p8 以及 json 内容),您就可以成功发送推送到设备上:

lola  \
-bundleId app_bundle_id  \
-device device_token  \
-teamId apple_developer_team_id \
-authKey filepath_to_p8_auth_key.p8  \
-notificationType alert \
-json "{ \"aps\": {\"alert\": \"A rich notification from lola 👋\", \"sound\": \"default\", \"mutable-content\": 1 }}"

您只需要在命令行重复执行该命令,设备就会收到推送消息,测试效率非常高!

顺便附上获取设备 device token 的代码(Swift 5):

let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()

如果要生成 p8 文件,您可以去 Apple Developer 登录您的开发者账号。
然后,在 Certificates, Identifiers & Profiles 中的 Keys 模块生成,如图所示:

 

总结

 

最后,总结一下大致的步骤:

  1. 将推送内容设置为 Rich Notification,需要显示推送消息弹框,而且aps 字典中需要将 mutable-content 的值设为 1
  2. 如果需要在 App Extension 与宿主应用(Containing App) 间进行数据同步,最简单的方式是使用 UserDefaults
  3. 使用 lola 快速地发送测试推送消息,减少不必要的繁琐流程;

推送测试的流程往往比较繁琐,希望本文可以帮您有效地提高效率。

如有任何疑问,欢迎您给 Ficow 留言~

 

参考内容:
Modifying Content in Newly Delivered Notifications
UNNotificationServiceExtension
How an App Extension Communicates
Sharing Data with Your Containing App
Sharing data between iOS apps and app extensions

 

觉得不错?点个赞呗~

本文链接:如何在 iOS 中准确地追踪【远程推送已接收】事件?

转载声明:本站文章如无特别说明,皆为原创。转载请注明:Ficow Shen's Blog

评论区(期待你的留言)