ConsentViewController 7.7.0

ConsentViewController 7.7.0

Carmelo IritiAndre HerculanoDmytro Fedko 维护。



  • SourcePoint

Test

如何安装

CocoaPods

在您的Podfile中,在应用程序目标中添加以下行:

pod 'ConsentViewController', '7.2.1'

Carthage

我们还支持Carthage。它需要更多步骤进行安装,因此我们为其专门编写了一个维基页面。如果遗漏了任何步骤,请告知我们。

Swift 包管理器

我们同样支持 Swift 包管理器。它是一个用于自动化分发 Swift 代码的工具,并集成到 swift 编译器中。它还在早期开发阶段,但 SourcePoint 支持在 iOS 平台上使用它。

要将我们的 SDK 包作为依赖项添加到您的 Xcode 项目中,在 Xcode 中选择“文件”>“Swift 包”>“添加包依赖”,然后输入我们的 SDK 仓库 URL。

或者您可以使用 Package.swift 文件并将其添加到依赖项中。

// swift-tools-version:5.5

import PackageDescription

let package = Package(
    name: "MyPackage",
    platforms: [.iOS(.v15), .macOS(.v12)],
    products: [
        .library(name: "MyPackage", targets: ["MyPackage"]),
    ],
    dependencies: [
        .package(
            name: "ConsentViewController",
            url: "https://github.com/SourcePointUSA/ios-cmp-app",
                .upToNextMinor(from: "7.2.0")
        ),
    ],
    targets: [
        .target(
            name: "MyPackage",
            dependencies: [
                "ConsentViewController"
            ]
        )
    ]
)

手动添加 XCFramework

如果您不希望使用任何依赖管理器,您可以将 ConsentViewController.xcframework 添加到您的项目或工作空间中作为库。

  1. 下载最新代码版本 最新代码版本
  2. 在 Xcode 中打开您的项目,选择您的目标,然后转到“通用”选项卡。在“框架、库和嵌入内容”部分,将下载数据的 ConsentViewController.xcframework 从 XCFramework 文件夹拖到相应的位置。
https://github.com/SourcePointUSA/ios-cmp-app.git

如何使用

非常简单,以下有 5 个简单的步骤供您参考

  1. 实现 SPDelegate 协议
  2. 使用您的 Account ID、属性名称、活动和 SPDelegate 实例实例化 SPConsentManager
  3. 调用 .loadMessage()
  4. 当消息准备好显示时(onSPUIReady),显示控制器。

Swift

import ConsentViewController

class ViewController: UIViewController {
    @IBAction func onClearConsentTap(_ sender: Any) {
        SPConsentManager.clearAllData()
    }

    @IBAction func onGDPRPrivacyManagerTap(_ sender: Any) {
        consentManager.loadGDPRPrivacyManager(withId: "13111", tab: .Features)
    }

    @IBAction func onCCPAPrivacyManagerTap(_ sender: Any) {
        consentManager.loadCCPAPrivacyManager(withId: "14967")
    }

    lazy var consentManager: SPSDK = { SPConsentManager(
        accountId: 22,
        propertyId: 16893,
        propertyName: try! SPPropertyName("mobile.multicampaign.demo"),
        campaigns: SPCampaigns(
            gdpr: SPCampaign(),
            ccpa: SPCampaign(),
            ios14: SPCampaign()
        ),
        delegate: self
    )}()

    override func viewDidLoad() {
        super.viewDidLoad()
        consentManager.loadMessage()
    }
}

extension ViewController: SPDelegate {
    func onSPUIReady(_ controller: SPMessageViewController) {
        controller.modalPresentationStyle = .overFullScreen
        present(controller, animated: true)
    }

    func onAction(_ action: SPAction, from controller: SPMessageViewController) {
        print(action)
    }

    func onSPUIFinished(_ controller: SPMessageViewController) {
        dismiss(animated: true)
    }

    func onConsentReady(userData: SPUserData) {
        print("onConsentReady:", userData)
        // checking if a gdpr vendor is consented
        userData.gdpr?.consents?.vendorGrants["myVendorId"]?.granted

        // checking if a ccpa vendor is rejected (on ccpa, vendors are accepted by default)
        userData.ccpa?.consents?.rejectedVendors.contains("myVendorId")
    }

    func onSPFinished(userData: SPUserData) {
        print("sourcepoint sdk done")
    }

    func onError(error: SPError) {
        print("Something went wrong: ", error)
    }
}

Objective-C

#import "ViewController.h"
@import ConsentViewController;

@interface ViewController ()<SPDelegate> {
    SPConsentManager *consentManager;
}
@end

@implementation ViewController

    - (void)viewDidLoad {
        [super viewDidLoad];

        SPPropertyName *propertyName = [[SPPropertyName alloc] init:@"mobile.multicampaign.demo" error:NULL];

        SPCampaign *campaign = [[SPCampaign alloc] initWithTargetingParams: [NSDictionary dictionary]];

        SPCampaigns *campaigns = [[SPCampaigns alloc]
            initWithGdpr: campaign
            ccpa: campaign
            ios14: campaign
            environment: SPCampaignEnvPublic];

        consentManager = [[SPConsentManager alloc]
            initWithAccountId:22
            propertyId: 16893
            propertyName: propertyName
            campaigns: campaigns
            delegate: self];

        [consentManager loadMessageForAuthId: NULL];
    }

    - (void)onSPUIReady:(SPMessageViewController * _Nonnull)controller {
        [self presentViewController:controller animated:true completion:NULL];
    }

    - (void)onAction:(SPAction * _Nonnull)action from:(SPMessageViewController * _Nonnull)controller {
        NSLog(@"onAction: %@", action);
    }

    - (void)onSPUIFinished:(SPMessageViewController * _Nonnull)controller {
        [self dismissViewControllerAnimated:true completion:nil];
    }

    - (void)onConsentReadyWithConsents:(SPUserData *)userData {
        NSLog(@"onConsentReady");
        NSLog(@"GDPR Applies: %d", userData.objcGDPRApplies);
        NSLog(@"GDPR: %@", userData.objcGDPRConsents);
        NSLog(@"CCPA Applies: %d", userData.objcCCPAApplies);
        NSLog(@"CCPA: %@", userData.objcCCPAConsents);
    }

    - (void)onSPUIFinished:(SPMessageViewController * _Nonnull)controller {
        NSLog(@"sourcepoint sdk done");
    }
@end

按需加载隐私管理器

您可以通过调用以下任一方法,在任意时刻以编程方式加载隐私管理器(即带有开关的界面):

  • .loadGDPRPrivacyManager(withId: String, tab: SPPrivacyManagerTab = .Default)
  • .loadCCPAPrivacyManager(withId: String, tab: SPPrivacyManagerTab = .Default)

SDK 会遵循与第一层同意消息相同的生命周期。首先调用代理方法 onSPUIReady 来通知 PM 已准备就绪,然后在用户进行操作时调用 onAction,当 PM 准备从视图堆栈中移除时调用 onSPUIFinished,最后,在 SDK 从服务器接收到同意数据后调用 onConsentReady

了解 SPDelegate 协议(代理方法)

onSPUIReady(_ controller: UIViewController

当有要显示的消息时,SDK 会将网页消息包装在一个 UIViewController 中,并调用 onSPUIReady

optional onSPNativeMessageReady(_ message: SPNativeMessage)

onSPNativeMessageReady 该方法仅在返回原生消息的情况下才会被调用。具体如何使用 message 对象并在屏幕上布局,取决于您自己的选择。

onAction(_ action: SPAction, from controller: UIViewController)

每当用户进行操作(例如,点击按钮)时,SDK 会通过 onAction 方法来调用,并将 action 作为参数传递。**这个委托方法在主线程上运行**。

SPAction 中包含什么

除了其他内部数据,您还可以找到以下内容:

  • type: SPActionType:一个枚举,用于表示操作的类型。使用 XCode 的快速帮助了解 SPActionType 的更多信息。
  • campaignType: SPCampaignType:一个枚举,用于表示执行操作时的活动类型(gdpr, ios14, ccpa, unknown
  • customActionId: String:如果操作的类型是 Custom,则此属性将包含在消息构建(发布者门户)中指定时分配给它的 ID。
  • :也称为一些 SP 服务中的 pubData,这是您应用程序设置的关键值对的任意字典,将发送到我们的服务器,并在以后使用 pubData API 获取。

除了 PMCancelShowPrivacyManager 操作外,SDK 在处理操作后还会调用 onSPUIFinished

onSPUIFinished(_ controller: UIViewController)

当执行某个操作时(见上文),SDK 将适当地处理它(例如向我们的服务器发送同意请求)并调用 onSPUIFinished 以指示您的应用程序可以关闭此消息。

可选 onConsentReady(userData: SPUserData)

onConsentReady 将在两种不同情况下被调用

  1. 调用 loadMessage 但没有待显示的消息后。
  2. SDK 收到其同意请求之一的响应后。这发生在用户在消息或隐私管理器中执行同意操作(AcceptAllRejectAllSave&Exit)之后。

确保查看 XCode 的 SPUserData 快速帮助,以获取有关在 onConsentReady 期间应用程序可用的数据的更多信息。

可选 onError(error: SPError)

如果发生错误,SDK 将将错误包装在 SPError 类之一中,并最终调用 onError(_ error: SPError) 回调。

默认情况下,SDK 会在 OnError 事件调用时保留所有用户同意数据从 UserDefaults。如果您希望在初始化 SPConsentManager 之后选择退出此行为,请将 consentManager.cleanUserDataOnError 标志设置为 true。这可能取决于您的场景而使某个同意消息再次显示。

添加或删除自定义同意

可以使用该方法以编程方式允许当前用户接受一系列自定义供应商、类别和合法兴趣类别。

func customConsentToGDPR(
    vendors: [String],
    categories: [String],
    legIntCategories: [String],
    handler: @escaping (SPGDPRConsent) -> Void
)

将重新生成供应商授权,这次将考虑您作为参数传递的供应商、类别和合法兴趣类别列表。该方法异步执行,因此您必须传递一个完成处理程序,以便在成功的情况下接收 SPGDPRConsent 实例,或者在失败的情况下调用代理方法 onError

使用与自定义同意相同的策略,可以使用以下方法通过编程方式删除当前用户的供应商、类别和合法兴趣类别列表中的同意。

func deleteCustomConsentGDPR(
   vendors: [String], 
   categories: [String], 
   legIntCategories: [String], 
   handler: @escaping (SPGDPRConsent) -> Void
)

该方法异步执行,因此您必须传递一个完成处理程序,以便在成功的情况下接收 SPGDPRConsent 实例,或者在失败的情况下调用代理方法 onError。

请注意,这些方法仅适用于 自定义 供应商和目的。对于 IAB 供应商和目的,仍需要通过同意消息或隐私管理器获取同意。

已验证同意

此功能使用我们所谓的 已验证同意。简而言之,您提供当前用户的标识符(用户名、用户 ID、uuid 或任何唯一字符串),然后我们将负责将同意配置文件与该标识符关联。

为了使用已验证的同意,您只需将 .loadMessage() 替换为 .loadMessage(forAuthId: String)。示例

consentManager.loadMessage(forAuthId: "JohnDoe")

在 Obj-C 中

[consentManager loadMessage forAuthId: @"JohnDoe"]

这样,如果我们已经为该令牌(《"JohDoe"》)拥有了同意,我们将从服务器获取同意配置文件,覆盖设备中存储的内容。

通过 WKWebView 共享同意

在经过信息和同意流程后(即 onConsentReady 后),SDK 将将同意数据存储在 UserDefaults 中。这些数据可以注入到 WKWebView 中,这样您的应用网页部分不会显示同意对话框,并且它将包含与原生部分相同的同意数据。

示例

// somewhere earlier in your app's lifecycle
var userConsents: SPUserData?

func onSPFinished(userData: SPUserData) {
    userConsents = userData
}

let webview = WKWebView()
if let userConsents = userConsents {
    webview.load(URLRequest(URL(string: "https://my-url.com/?_sp_pass_consent=true")!))
    webview.preloadConsent(from: userConsents)
} else {
    webview.load(URLRequest(URL(string: "https://my-url.com/")!)) // load url without _sp_pass_consent=true
}

几点说明

  1. 正在加载的网页内容(网页属性)需要与应用相同的供应商列表。
  2. 供应商列表的同意范围需要设置为由 共享站点 而不是 单一站点
  3. 您的网页内容需要在 webview 中加载(或正在加载),并且我们的 web SDK 必须包含在其中。此外,您需要将查询参数 _sp_pass_consent=true 添加到您的 URL 中,这将向 Sourcepoint 的 web SDK 发出信号,表示它需要等待从原生代码注入同意数据,而不是立即从我们的服务器查询它。

覆盖默认语言

默认情况下,SDK 会指导消息使用由 WKWebView 定义的地理位置进行渲染。如果您希望覆盖此行为并强制消息以某种语言显示,您需要在使用 .loadMessage() / .loadPrivacyManager() 之前设置 SPConsentManager.messageLanguage 属性。

consentManager.messageLanguage = .German
consentManager.loadMessage()

在 Obj-C 中

consentManager.messageLanguage = SPMessageLanguageGerman;
[consentManager loadMessage];

请注意,如果消息的任何组件没有该语言的翻译,则组件将以英语作为后备语言进行渲染。

加载阶段活动

SPConsentManager 构造函数接受一个可选参数,称为 campaignsEnv: SPCampaignEnv。如果在其中省略,则默认值为 .Public。目前,我们不支持加载不同环境的活动。换句话说,您只能加载所有阶段或公共活动。

设置定向参数

目标参数是一组键/值对,提供给场景。在场景中,根据这些值有条件地显示消息或另一条消息。您可以为每个活动单独设置目标参数,如下所示

let myCampaign = SPCampaign(targetingParams: ["foo": "bar"])

在 Obj-C 中

SPCampaign *myCampaign = [[SPCampaign alloc]
    initWithTargetingParams: [[NSDictionary alloc] initWithObjectsAndKeys:@"value1", @"key1"]
];

配置消息/同意超时

在调用 .loadMessage.loadPrivacyManager 之前,将 .messageTimeoutInSeconds 属性设置为对您的应用程序最有意义的间隔时间。默认情况下,我们将其设置为30秒。

如果发生超时错误,将会调用 onError 回调,并在此处停止同意流程。

pubData

当用户在同意用户界面中采取行动时,可以将任意有效负载附加到操作数据并发送到我们的端点。有关如何操作的更多信息,请参阅我们的维基百科: 当用户采取行动时发送任意数据

原生消息渲染

请参阅我们整理的这篇有趣的 维基百科

应用跟踪透明度

要显示访问IDFA的应用跟踪透明度授权请求,请更新您的Info.plist文件,添加带有描述您用途的自定义消息的NSUserTrackingUsageDescription键。下面是一个示例描述文本:

<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>

App Tracking

事件回调

当发生某些事件时,iOS的代理方法会被触发,例如,当有一条消息即将显示,或者最终用户打开隐私管理器时。本节将描述这些函数的用途和操作。

Sourcepoint的CMP在iOS中的实现有五个事件回调

onSPUIReady (_ controller: UIViewController)

当需要显示“基于网页”的消息时,会调用onSPUIReady代理方法。控制器参数是包含要显示的消息的视图控制器。

onAction (_ action: SPAction, from controller: UIViewController)

当用户在第一层消息或隐私管理器中采取行动时,将会调用onAction代理方法。

action参数SPAction包含以下数据(用于内部使用):

属性 描述
type: SPActionType 指示动作的类型,这是一个枚举值。例如,对ATT消息的响应是RequestATTAccess,或者显示隐私管理器是ShowPrivacyManager
campaignType: SPCampaignType 指示执行动作的活动的类型。这是一个枚举值,例如:gdpr, ios14, ccpa, unknown
customActionId: String 如果动作类型是Custom,则此属性将包含您在消息构建器(发行商门户)构建消息时分配给它的ID。
consentLanguage 消息中使用的语言。
publisherData: [String: String] 这是一个包含要发送到我们服务器的数据的任意字符串到字符串字典。[String: String]。出版商希望在回调期间设置此字段,如果他们需要将数据发送到我们的服务器以便稍后通过API检索。

onSPUIFinished()

当SDK确定可以删除视图层次结构或关闭UI时,将调用onSPUIFinished代理方法。这通常发生在终端用户采取同意操作(例如接受全部、拒绝全部、保存并退出)之后。

PMCancelShowPrivacyManager动作外,SDK在处理动作后会调用onSPUIFinished。

onConsentReady()

onConsentReady 将在两种不同情况下被调用

  • 在调用loadMessage而没有要显示的消息之后
  • SDK收到对它的同意请求之一的一个响应后。这发生在用户已经在消息或隐私管理器中采取了同意操作(如AcceptAllRejectAllSave&Exit)之后。

onConsentReady代理方法将同意操作发送到服务器并获得响应,SDK将数据存储在UserDefaults中。

onError()

SDK将在所有情况下将错误包装在SPError类之一中,并最终调用func onError(_ error: SPError)回调。默认情况下,SDK在OnError事件被调用的情况下保留所有用户同意数据在UserDefaults中。如果您希望在初始化SPConsentManager后退出此行为,请在初始化后设置consentManager.cleanUserDataOnError标志为true。如果设置为true,则此用例将擦除UserDefaults中的所有用户同意数据。这可能会根据您的场景重新显示同意消息。

Google Additional Consent (GDPR TCF)

Google附加同意是Google和IAB框架共同创建的一个概念,旨在在不遵循IAB TCF框架的情况下将最终用户的同意传递给Google广告技术提供商(ATP)。有关更多信息,请点击此处

Google附加同意受我们移动SDK支持,并存储在UserDefaultsIABTCF_AddtlConsent键中。请在用户的本地存储中查找此键,并将值传递给Google的SDK。

删除用户数据

如果最终用户请求删除其数据,请使用以下方法。

SPConsentManager.clearAllData()

为属性组设置隐私管理器ID

属性组允许您的组织将属性分组,以便简化大规模活动和服务更新的配置。为了使用属性组的隐私管理器ID,您应该按以下方式编辑SDK配置对象

lazy var consentManager: SPConsentManager = { SPConsentManager(
   accountId: 22,
   propertyName: try! SPPropertyName("mobile.multicampaign.demo"),
   campaigns: SPCampaigns(
       gdpr: SPCampaign(groupPmId: "123") // <- "123" is the id of the privacy manager for the property group
   ),
   delegate: self
)}()

添加了属性组的隐私管理器ID之后,您应在loadGDPRPrivacyManager中将标志useGroupPmIfAvailable设置为true

consentManager.loadGDPRPrivacyManager(withId: "111", useGroupPmIfAvailable: true)

注意:目前不支持CCPA活动的属性组隐私管理器ID功能。

常见问题

1. SDK有多大?

SDK相对较瘦,没有资源,没有依赖,只有纯代码。由于我们使用Swift,其大小会根据您项目的配置而变化,但不应超过500 Kb

2. 支持最低的iOS版本是什么?

iOS 10及更高版本。

3. 如果不支持IDFA(iOS < 14)呢?

我们将IDFA状态封装在我们的自定义枚举SPIDFAstatus中。如果SDK运行在不支持IDFA的iOS版本上,状态将被设置为不可用。否则,它会假设以下3个值之一

  • 未知:用户从未被提示接受/拒绝跟踪(原生的iOS ATT提示)。
  • 接受:用户接受了ATT提示,允许您的应用程序访问IDFA。
  • 拒绝:用户拒绝了ATT提示,拒绝您的应用程序访问IDFA。

我们将随着时间的推移更新此列表,如果您有任何问题,请随时打开一个问题或联系您的SourcePoint账户经理。

3. 深链接是否受到支持?

由于我们的消息渲染应用程序(由我们的应用内 SDK 用于在 WebView 中渲染消息)中使用了 HTML 清除器,因此 Sourcepoint 不支持深链接。更改到我们的 HTML 清除器配置会损害我们的安全性,并引入跨站脚本(XSS)攻击的漏洞。

您可以通过在第一层消息中创建一个带有 自定义操作 选项的按钮,并利用以下代码在您的实现中复现深链接

func onAction(_ action: SPAction, from controller: UIViewController) {
    if action.type == .Custom,
       action.customActionId == "id-specified-in-portal" {
        // navigate user to intended page
    }
}