RInAppMessaging 8.3.0

RInAppMessaging 8.3.0

RInAppMessagingRakuten MAG维护。



  • 楽天エコシステムモバイル

Build Status codecov Quality Gate Status

RInAppMessaging

内联消息(IAM)模块允许应用程序开发者轻松地在应用程序内配置和显示通知。

该模块支持iOS 12.0及以上。已与iOS 12.5及以上版本进行了测试。

要求

支持Xcode >= 14.1。

支持Swift >= 5.7.1。

注意:SDK可能可以在早期版本的Xcode上构建,但并未官方支持或测试。

安装方法

RInAppMessaging SDK作为Cocoapod和Swift Package分发。

CocoaPods

有关安装pod的更多信息:https://guides.cocoapods.org.cn/using/getting-started.html

  1. 请将以下内容包含在您的应用程序的Podfile中
pod 'RInAppMessaging'

注意: RInAppMessaging SDK需要在Podfile中包含use_frameworks!

  1. 在终端中运行以下命令
pod install

Swift包管理器

在Xcode中打开您的项目设置,并在“Swift包”选项卡中添加一个新的包

  • 存储库URL:https://github.com/rakutentech/ios-inappmessaging.git
  • 版本设置:6.1.0 "Up to Next Major"(6.1.0是支持SPM的第一个版本)

为您的目标选择RInAppMessaging产品。如果您想链接其他目标,请转到该目标的“构建 phases”,然后在“Link Binary With Libraries”中点击加号按钮并添加RInAppMessaging

配置

注意: 目前我们不托管任何公共API,但您可以创建自己的API并将SDK配置为使用这些API。

要使用模块,您必须使用提供的方法之一设置您的应用程序的订阅密钥和配置端点URL。

编译时配置

在您的应用的 Info.plist 中添加以下条目

InAppMessagingAppSubscriptionID your_subscription_key
InAppMessagingConfigurationURL 获取配置的端点

运行时配置

调用 RInAppMessaging.configure 方法时,提供 subscriptionIDconfigurationURL 参数的值。

RInAppMessaging.configure(subscriptionID: "your_subscription_key",
                          configurationURL: "Endpoint for fetching the configuration")

⚠️运行时配置值优先于编译时配置。

**远程启用和禁用 SDK**

作为良好的工程实践,我们建议您集成远程配置服务,以便您可以获取一个功能标记,例如 Enable_IAM_SDK,并使用它的值动态地启用/禁用 SDK 而不需要发布应用程序。市场上有很多远程配置服务,既有免费服务也有付费服务。

**使用 SDK**

SDK 为主机应用程序提供了 3 个公共方法

  1. configure()
  2. logEvent()
  3. registerPreference()
  4. closeMessage()

configure()

此方法用于初始化SDK,应放在您的AppDelegate的didFinishLaunchingWithOptions中。

import RInAppMessaging

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    RInAppMessaging.configure(subscriptionID: "runtime-config-subscription-id",
                              configurationURL: "runtime.config.url")
    return true
}

注意:

  • subscriptionIDconfigurationURL参数为可选,如果您在Info.plist中设置了它们的值(请参阅构建时间配置
  • 您可以将对configure()的调用包裹在if <enable IAM-SDK boolean value> == true条件中,以控制启用/禁用SDK。
  • 如果没有调用configure(),那么使用其他公共API SDK函数的后续调用都将没有效果。

logEvent()

此方法提供供宿主应用记录并保存事件。这些事件将用于匹配营销触发器。

方法签名是

func logEvent(_ event: Event)

IAM提供了三种预定义事件类型和一个自定义事件类型

  1. AppStartEvent - 此事件应在宿主应用认为应用已启动时记录。例如AppDelegate的didFinishLaunchingWithOptions。它是持久的,这意味着一旦记录,它将始终满足营销中相应的触发器。此事件的后续所有记录都将被忽略。仅需要AppStartEvent的营销活动在每个应用启动时只会显示一次。
  2. LoginSuccessfulEvent - 此事件应在用户成功登录时记录。
  3. PurchaseSuccessfulEvent - 此事件应在成功购买发生时记录,并具有一些预定义属性——购买金额、项目数量、货币代码和商品列表。
  4. CustomEvent - 此事件由宿主应用开发者创建,可以接受任何事件名称和自定义属性列表。
// App start event.
RInAppMessaging.logEvent(AppStartEvent())
 
// Purchase successful event.
let purchaseEvent = PurchaseSuccessfulEvent()
purchaseEvent.setPurchaseAmount(50)
purchaseEvent.setItemList(["box", "hammer"])
purchaseEvent.setCurrencyCode("USD")

RInAppMessaging.logEvent(purchaseEvent)
 
// Login event.
RInAppMessaging.logEvent(LoginSuccessfulEvent())
 
// Custom event.
let stringAttribute = CustomAttribute(withKeyName: "userResponse", withStringValue: "hi")
let intAttribute = CustomAttribute(withKeyName: "numberOfClicks", withIntValue: 100)
let boolAttribute = CustomAttribute(withKeyName: "didNavigateToPage", withBoolValue: false)
let doubleAttribute = CustomAttribute(withKeyName: "percentageOfCompletion", withDoubleValue: 55.0)
let timeAttribute = CustomAttribute(withKeyName: "timeOfCompletion", withTimeInMilliValue: 32423424)
 
let attributesList = [stringAttribute, intAttribute, boolAttribute, doubleAttribute, timeAttribute]
 
RInAppMessaging.logEvent(CustomEvent(withName: "any_event_name_here", withCustomAttributes: attributesList))

registerPreference()

偏好设置允许IAM识别用于定位和分割的用户。偏好对象应实现UserInfoProvider协议并提供以下标识符之一(不一定都需要提供)

  1. UserID - 与用户会员资格关联的唯一标识符。通常它是登录过程中使用的名称(例如电子邮件地址)。
  2. IDTrackingIdentifier - 内部ID SDK提供的作为“跟踪标识符”值的值。
  3. AccessToken - 由内部RAuthentication SDK提供的作为“accessToken”值的令牌。

⚠️该方法设计为每個应用会话调用一次 - 即只能创建一个UserInfoProvider实例。IAM SDK将按需读取对象的属性。例如,登录/注销后无需再次调用此方法。

为确保正确定位用户,请确保用户信息在偏好对象中最新。注销流程完成后,偏好对象应在所有UserInfoProvider方法中返回nil""
首选项不会被持久化,因此每次启动时都需要调用此功能。

使用UserID的通用示例

import RInAppMessaging

class UserPreference: UserInfoProvider {
    func getUserID() -> String? { 
        "member-id" 
    }

    func getIDTrackingIdentifier() -> String? { nil }
    func getAccessToken() -> String? { nil }
}

let preference = UserPreference()
RInAppMessaging.registerPreference(preference)

closeMessage()

在某些情况下,可能会有手动关闭活动信息的需求,而无需用户交互。例如,当另一个用户登录且当前显示的活动不针对新用户时(或者当活动信息在登录过程开始后显示时)。在这种情况下,为了避免用户困惑,主应用可以通过调用closeMessage() API方法强制关闭活动。可选参数clearQueuedCampaigns,当设置为true(默认为false)时,还将删除所有排队的要显示的活动。

RInAppMessaging.closeMessage(clearQueuedCampaigns: true)

注意:调用此API不会增加活动的显示次数(即不计入显示)。

自定义事件

如上例中所示,IAM亦支持自定义事件。自定义事件是具有唯一名称和与它们相关联的属性列表的事件。

为了正确使用自定义事件,创建活动的个人必须与主机应用程序的开发者同步,以确保事件名称和属性名称/值完全匹配,注意这些是区分大小写的。

在仪表板方面,您还可以添加一个操作员。以下支持的操作员包括:

  1. EQUALS - 值应该相等。在timeInMillis方面,将有一个1000毫秒的公差。例如,1001和500毫秒将被认为是相等的。
  2. IS_NOT_EQUAL - 值应该不同。在timeInMillis方面,将有一个1000毫秒的公差。例如,1001和500毫秒将被认为是相等的。
  3. GREATER_THAN - 事件属性值大于活动的触发值。仅适用于算术类型。
  4. LESS_THAN - 事件属性值小于活动的触发值。仅适用于算术类型。
  5. IS_BLANK - 属性值是空的。仅适用于String类型。
  6. IS_NOT_BLANK - 属性值不为空。仅适用于String类型。
  7. MATCHES_REGEX - 属性值与正则表达式匹配。仅适用于String类型。
  8. DOES_NOT_MATCH_REGEX - 属性值不对正则表达式匹配。仅适用于String类型字符串。

注意: 在将日期作为timeInMillis值进行比较时,存在1000毫秒的公差。这意味着使用任何相关操作符类型进行比较时,将有一个1秒的宽容度。例如,使用EQUALS操作符比较300ms和600ms将返回true,而比较300和1400将返回false

从SDK方面,主机应用程序的开发者可以按照上面示例中的方法记录自定义事件。当发生匹配过程时,请注意,主机应用程序记录的事件的属性将与活动的触发属性值进行比较,例如,如果触发属性值是一个整数5,操作员类型为GREATER_THAN,并且记录的事件属性值是一个整数10,那么10将成功地与5匹配一个GREATER_THAN操作符(即10 > 5)。

可选功能

活动上下文验证

可选变量 onVerifyContext 在显示消息之前被调用,适用于定义了一个或多个上下文的营销活动。上下文可以作为一个 IAM 门户“营销活动名称”中“[]”内的文本添加,例如,营销活动名称为“[ctx1] 标题”,那么上下文就是“ctx1”。在 onVerifyContext 闭包中返回 false,以防止营销活动显示(它不会计入展示量)。
注意:没有定义上下文的营销活动不会调用 onVerifyContext
注意:此功能也支持工具提示。 ('[工具提示]' 在标题中不被视为上下文)

RInAppMessaging.onVerifyContext = { (contexts: [String], campaignTitle: String) in
    guard campaignTitle == "[context1] campaign-title-1", contexts.contains("context1") else {
        return true
    }
    if /* check your condition e.g. are you on the correct screen to display this message? */ {
        return true
    } else {
        return false
    }
}

错误回调

开发者可以设置一个可选变量 errorCallback 来接收内部 SDK 错误。这允许你在某个地方记录错误,例如第三方分析服务,以便稍后进行故障排除。

import RInAppMessaging

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    RInAppMessaging.errorCallback = { [weak self] error in
        self?.logger.log(error.description)
    }
}

无障碍性/自动化测试支持

营销活动消息视图包含具有 accessibilityIdentifier 值的元素。在某些应用程序中,这些元素可能对测试自动化工具(如 Appium)不可见。要修复此问题,请将 accessibilityCompatibleDisplay 标志设置为 true。SDK 将使用不同的逻辑来显示营销活动消息。
注意:此功能会更改将营销活动视图添加到视图层次结构的方式,在某些应用程序中,可能会导致营销活动显示不正确。

import RInAppMessaging

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    RInAppMessaging.accessibilityCompatibleDisplay = true
    return true
}

推送入门指南

推送入门指南是一种特殊的行为类型,可以在营销活动消息按钮之一中设置。当用户点击推送入门指南按钮时,SDK 会尝试授权并随后注册远程通知。开发者可以通过设置 pushPrimerAuthorizationOptions 变量来设置在授权过程中使用的 UNUserAuthorizationOptions

RInAppMessaging.pushPrimerAuthorizationOptions = [.badge, .provisional]

如果没有修改该变量,将使用默认值。

⚠️如果用户在系统设置中禁用了远程通知,则推送入门指南功能将无法工作。

使用“错误回调”功能可以访问授权请求相关的错误。与注册请求相关的错误将在应用代理对象的application(_:didFailToRegisterForRemoteNotificationsWithError:)方法中返回。当调用application(_:didRegisterForRemoteNotificationsWithDeviceToken:)方法时,整个过程可以视为成功。

如何设置您的应用程序以使用APNS进行注册

提示信息活动

提示功能目前处于Beta测试阶段;其功能和行为可能会在未来发生变化。请参阅内部指南以获取更多信息。

要启用提示,必须在调用configure()时将enableTooltipFeature标志设置为true。

RInAppMessaging.configure(enableTooltipFeature: true)
UIKit

要将提示信息附加到UIView实例,将其accessibilityIdentifier值设置为提示信息的UIElement标识符。

let actionButton = UIButton()
actionButton.accessibilityIdentifier = "tooltip.1"
SwiftUI

要将提示信息附加到SwiftUI视图,请使用canHaveTooltip()修饰符。
重要:必须在此后调用RInAppMessaging.configure()才能调用此修饰符。否则,提示信息不会显示。

import RInAppMessaging
(...)
var body: some View {
    Button("Action")
        .canHaveTooltip(identifier: "tooltip.1")
}

注意:此功能需要最低iOS版本为15.0

显示标签栏按钮上的工具提示

(仅适用于UIKit集成)
要在UITabBar项/按钮上显示工具提示,需要设置与你的标签视图控制器关联的UITabBarItem对象的accessibilityIdentifier。然后需要在UITabBar对象上调用updateItemIdentifiers()方法。

以下是从UIViewController的viewDidLoad()方法中的代码示例

tabBarItem.accessibilityIdentifier = "UIElement.4"
tabBarController?.tabBar.updateItemIdentifiers()

此设置也可以在生命周期的其他方法和类中进行。

手动关闭显示的工具提示

类似于使用closeMessage() API方法关闭活动消息,工具提示也可以手动关闭。
closeTooltip(with uiElementIdentifier: String) API方法在不进行用户交互的情况下关闭当前显示的工具提示,该工具提示附加到提供的UI元素。参数uiElementIdentifier的标识符告诉SDK应关闭哪个工具提示。其值应与工具提示JSON有效负载中UIElement参数下放置的值匹配。

RInAppMessaging.closeTooltip(with: "uielement.button.action1")

注意:调用此方法不会计算为印象(即消息不会计算为显示)。

构建/运行示例应用程序和单元测试

  • 克隆或分支存储库
  • 在存储库文件夹下执行cd
  • 根据内部集成指南设置环境变量RIAM_CONFIG_URLRIAM_APP_SUBSCRIPTION_KEY
  • 重要提示InAppMessaging-Secrets.xcconfig 绝对不能提交到git - 它在存储库的.gitignore文件中被git忽略
  • 执行bundle install然后运行bundle exec pod install
  • 在Xcode中打开RInAppMessaging.xcworkspace然后进行构建/运行
  • 要运行测试,请按快捷键command-U

SDK 逻辑

用户缓存

每个用户都有一个独立的缓存容器,该容器存储在UserDefaults中。每个userId和idTrackingIdentifier的组合被视为一个不同的用户,包括一个特殊的匿名用户,代表未登录用户(userId和idTrackingIdentifier为null或空)。缓存存储了ping响应中的数据,包括展示次数计数字段和退订状态。调用registerPerference()重新加载缓存并刷新可用的活动列表(带有ping请求)。

客户端退订处理

如果用户(使用registerPerference()注册标识符)退订了活动,该信息将保存到设备的本地用户缓存中,且在该设备上不会再次向该用户展示该活动。退订状态不会在设备之间共享。匿名用户也同样适用。

客户端最大展示次数处理

对于每个用户,活动曝光(展示)数量是本地计算。这意味着具有最大显示值3的活动将向每个用户(已通过registerPerference()注册)最多展示3次。活动的最大曝光次数可以在仪表板/后端中进行修改。然后SDK在下一个ping调用后,将新值与旧的最大曝光次数进行比较,并将差异添加到当前的曝光计数器中。最大曝光数据不会在不同设备间共享。这对于匿名用户同样适用。

(可选) 如何在你的活动中启用自定义字体

如果您的应用预注册了自定义字体,SDK将可选地使用您的活动的自定义字体。指定用于文本正文/标题的一个,用于按钮的一个,格式为ttfotf。如果没有设置,将回退到系统字体。

首先将两个字体文件添加到您的Xcode目标中。

通过以下方法获取您的字体的“PostScript名称”:

$ fc-scan --format "%{postscriptname}\n" customfont-medium.otf

AdventPro-Medium

在您的Info.plist配置中,在InAppMessagingCustomFontNameTitleInAppMessagingCustomFontNameTextInAppMessagingCustomFontNameButton下设置字体的PostScript名称,以及文件名下的UIAppFonts

<key>InAppMessagingCustomFontNameTitle</key>
<string>AdventPro-Bold</string>
<key>InAppMessagingCustomFontNameText</key>
<string>AdventPro-Regular</string>
<key>InAppMessagingCustomFontNameButton</key>
<string>AdventPro-Medium</string>

<key>UIAppFonts</key>
<array>
    <string>customfont-bold.otf</string>
    <string>customfont-regular.otf</string>
    <string>customfont-medium.otf</string>
</array>

故障排除 & 常见问题解答

  • 配置服务返回了RequestError.missingMetadata错误
    • 确保正确集成IAM SDK(不要作为静态库)
  • 如果您收到HTTP错误401
    • 如果您在UserInfoProvider中提供访问令牌,请确保它来自PROD端点。(仅适用于乐天开发者)
  • 如果您发现用户定位不起作用
    • 确保在UserInfoProvider对象中提供了userIdidTrackingIdentifier
    • 如果您设置了accessToken,您必须同时提供相关的userId。(仅适用于乐天开发者)
    • 确保您没有同时提供accessTokenidTrackingIdentifier。(仅适用于乐天开发者)
    • IAM SDK无法验证提供的accessToken是否无效或与userId不匹配。
  • 在全屏活动展示时,状态栏字符和图标不可见
    • 如果您的应用在iOS版本低于13.0上运行,您需要更改活动的背景颜色或在上层视图控制器中设置正确的preferredStatusbarStyle。(对于iOS版本高于13.0,此问题由SDK内部处理)
  • 启动活动展示的次数比预期多。
    • 确保在调用configure()后和任何logEvent()方法之前调用registerPreference()
    • 在调用registerPreference()之前,偏好对象必须包含最新信息
    • 每个userId/idTrackingIdentifier组合(包括空的)都有一个自己的活动印象计数器。
    • 在活动展示时停止应用程序或调用closeMessage() API不算作印象。

对于其他问题和更详细的信息,Rakuten 开发者应参考内部开发者文档门户上的故障排除指南。