Test

如何安装

CocoaPods

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

pod 'ConsentViewController', '7.7.6'

Carthage

我们也支持 Carthage。它需要更多的安装步骤,因此我们专门为此创建了一个完整的 wiki 页面。如果您发现我们遗漏了任何步骤,请告知我们。

Swift Package Manager

我们也支持 iOS 和 tvOS 的 Swift Package Manager。它是一个用于自动化 Swift 代码分发的工具,并且已集成到 swift 编译器中。

要将我们的 SDK 包作为依赖项添加到您的 Xcode 项目中,请在 Xcode 中选择“File”>“Swift Packages”>“Add Package Dependency”,然后输入我们的 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.7.6")
        ),
    ],
    targets: [
        .target(
            name: "MyPackage",
            dependencies: [
                "ConsentViewController"
            ]
        )
    ]
)

手动添加 XCFramework

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

  1. 下载 最新的代码版本
  2. 在 Xcode 中打开您的项目,选择您的目标,然后转到“General”选项卡。在“Frameworks, Libraries, and Embedded Content”部分中,从下载的项目 XCFramework 文件夹中拖放 ConsentViewController.xcframework
https://github.com/SourcePointUSA/ios-cmp-app.git

如何使用它

它非常简单,这里有 5 个简单的步骤供您参考

  1. 实现 SPDelegate 协议
  2. 使用您的帐户 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.loadUSNATPrivacyManager(withId: "14967")
    }

    lazy var consentManager: SPSDK = { SPConsentManager(
        accountId: 22,
        propertyId: 16893,
        propertyName: try! SPPropertyName("mobile.multicampaign.demo"),
        campaigns: SPCampaigns(
            gdpr: SPCampaign(), //only include if this campaign type is enabled in the Sourcepoint portal
            usnat: SPCampaign(), //only include if this campaign type is enabled in the Sourcepoint portal
            ccpa: SPCampaign(), //only include if this campaign type is enabled in the Sourcepoint portal
            ios14: SPCampaign() //only include if this campaign type is enabled in the Sourcepoint portal
        ),
        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 //only include if this campaign type is enabled in the Sourcepoint portal
            usnat: campaign //only include if this campaign type is enabled in the Sourcepoint portal
            ccpa: campaign //only include if this campaign type is enabled in the Sourcepoint portal
            ios14: campaign //only include if this campaign type is enabled in the Sourcepoint portal
            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

SPConsentManager 中配置帐户详细信息

SpConsentManager 构造函数包含您组织的帐户和属性详细信息。 SDK 将使用 SPConsentManager 中配置的详细信息来提取您在 Sourcepoint 门户中设置的相关广告系列。

lazy var consentManager: SPConsentManager = { SPConsentManager(
    accountId: 22,
    propertyId: 16893,
    propertyName: try! SPPropertyName("mobile.multicampaign.demo"),
    campaigns: SPCampaigns(
        gdpr: SPCampaign(),
        usnat: SPCampaign()
    ),
    delegate: self
)}()
字段 描述
accountId 在 Sourcepoint 门户中找到的组织帐户 ID
propertyId 在 Sourcepoint 门户中找到的属性 ID
propertyName 在 Sourcepoint 门户中找到的属性名称
campaigns 通过 Sourcepoint 门户在属性上启动的广告系列。 接受 gdpr | ccpa | usnat | ios14。 有关每种广告系列类型的信息,请参见下表。

有关可以通过 SDK 实施的不同广告系列,请参阅下表

广告系列 描述
gdpr 如果您的属性运行 GDPR TCF 或 GDPR 标准广告系列,则使用此选项
ccpa 如果您的属性运行美国隐私(旧版)广告系列,则使用此选项
usnat 如果您的属性运行美国多州隐私广告系列,则使用此选项。 请勿同时使用 ccpausnat,因为这会给您的组织带来合规性风险。

此广告系列类型只能通过移动设备上的 SPConsentManager 实施。 点击此处,了解有关在 tvOS 上实施美国多州隐私的更多信息。
ios14 如果您的属性运行 iOS 跟踪消息广告系列,则使用此选项

按需加载隐私管理器

您可以通过调用以下任一方法,随时以编程方式加载隐私管理器(带有切换开关的 UI):

SDK 将遵循与第一层同意消息完全相同的工作流程。 首先,当 PM 准备就绪时调用委托方法 onSPUIReady,当用户采取操作时调用 onAction,当 PM 准备好从视图堆栈中删除时调用 onSPUIFinished,最后,一旦 SDK 从服务器接收到同意数据,则调用 onConsentReady

了解 SPDelegate 协议(委托方法)

onSPUIReady(_ controller: UIViewController

SDK 会将 Web 消息包装到 UIViewController 中,并在有消息要显示时调用 onSPUIReady

optional onSPNativeMessageReady(_ message: SPNativeMessage)

仅当场景返回原生消息时,才会调用 onSPNativeMessageReady。 您需要使用最适合您的布局在屏幕上显示 message 对象。

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

每当用户采取操作(例如,点击按钮)时,SDK 都会调用 onAction 并将 action 作为参数传递。 此委托方法在主线程中运行

SPAction 内部是什么

在其他内部数据中,您会发现

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

onSPUIFinished(_ controller: UIViewController)

当采取操作时(请参见上文),SDK 会适当地处理它(例如,向我们的服务器发送同意请求),并调用 onSPUIFinished 以指示您的应用可以取消显示该消息。

optional onConsentReady(userData: SPUserData)

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

  1. 在调用 loadMessage 之后,但没有要显示的消息。
  2. 在 SDK 收到对其某个同意请求的响应之后。 这发生在用户在消息或隐私管理器中采取了同意操作(AcceptAllRejectAllSave&Exit)之后。

请务必查看 XCode 的 SPUserData 快速帮助,以获取有关 onConsentReady 期间可供您的应用使用的数据的更多信息。

optional onError(error: SPError)

如果发生错误,SDK 会将错误包装在 SPError 类中,并最终调用 onError(_ error: SPError) 回调。 点击此处,了解有关 SDK 可以生成的错误代码的更多信息。

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

SPUserData 结构

SPUserData 包含与用户同意操作相关的所有信息。 SPUserData 的结构如下

SPUserData(
    gdpr: SPConsent<SPGDPRConsent>?(
        applies: Bool,
        consents: SPGDPRConsents(
            acceptedCategories: [String],
            applies: Bool,
            consentStatus: ConsentStatus,
            googleConsentMode: SPGCMData?,
            objcGoogleConsentMode: SPGCMDataObjc?, // available only on ObjC
            dateCreated: SPDate,
            euconsent: String,
            tcfData: SPJson?,
            uuid: String?,
            vendorGrants: Dictionary<String, SPGDPRVendorGrant>,
        )
    ),
    usnat: SPConsent<SPUSNatConsent>?(
        applies: Bool,
        consents: SPUSNatConsent(
            GPPData: GPPSpec
            statuses: {
                rejectedAny: Bool?,
                consentedToAll: Bool?,
                consentedToAny: Bool?,
                sellStatus: Bool?,
                shareStatus: Bool,
                sensitiveDataStatus: Bool?,
                gpcStatus: Bool?,
                hasConsentData: Bool?
            }
            consentStrings: [
                {
                    sectionId: String,
                    sectionName: String,
                    consentString: String
                }
            ]
            vendors: [{ id: String, consented: Bool }]
            categories: [{ id: String, consented: Bool }]
            uuid: String?
        )
    ),
    ccpa: SPConsent<SPCCPAConsent>?(
        applies: Bool,
        consents: SPCCPAConsent(
            dateCreated: SPDate
            GPPData: SPJson,
            rejectedCategories: [String],
            rejectedVendors: [String],
            signedLspa: Bool,
            status: String,
            uspstring: String,
            uuid: String?,
        )
    )
)

点击此处,查看 GPPSpec 中的键。

Google Consent Mode

Google Consent Mode 2.0 确保您属性上的 Google 供应商遵守最终用户对 Google 定义的目的(称为同意检查)的同意选择。 它通过 Google Analytics for Firebase SDK 实现。

为同意检查设置默认同意状态

将以下键添加到您应用的 info.plist 中,以定义每个 Google 同意检查的初始同意状态 (.granted | .denied)

<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE</key> <true/> // set this to `true` or `false` as required
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE</key> <true/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA</key> <true/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS</key> <true/>

更新同意检查

当相关的目的被同意/拒绝时,使用 Google 的 setConsent 方法更新相关的同意检查。

通过 setConsent 方法更新的同意检查会有所不同,具体取决于您在 Sourcepoint 门户中如何在您的移动属性上实施 Google Consent Mode 2.0。 该方法应仅使用映射到您的供应商列表中的自定义目的的同意检查来调用。

有关更多信息,请查看 Sourcepoint 的以下实施文档

//Example only. Consent checks updated via setConsent will depend on implementation
func onSPFinished(userData: SPUserData) {
    let gcmData = userData.gdpr?.consents?.googleConsentMode
    Analytics.setConsent([
        .analyticsStorage: gcmData?.analyticsStorage == .granted ? .granted : .denied,
        .adStorage: gcmData?.adStorage == .granted ? .granted : .denied,
        .adUserData: gcmData?.adUserData == .granted ? .granted : .denied,
        .adPersonalization: gcmData?.adPersonalization == .granted ? .granted : .denied,
    ])
}

请注意,SPUserData 中的 googleConsentMode 对象仅会返回映射到您的供应商列表中的自定义目的的 Google 同意检查的值。 对于所有其他 Google 同意检查,响应将为 null

添加或删除自定义同意

可以使用以下方法以编程方式同意当前用户使用自定义供应商、类别和合法权益类别列表

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") 的同意,我们将从服务器获取同意配置文件,覆盖设备中存储的任何内容。

如果您的应用程序的注销过程需要,您的组织可以调用 clearAllData 方法来删除本地数据。 清除后,您的组织可以调用 loadMessage 以从未经身份验证的用户收集同意,或者使用新的 authId 为新的经过身份验证的用户调用 loadMessage

WKWebView 共享同意

在完成消息和同意流程之后(即在 onConsentReady 之后),SDK 会将同意数据存储在 UserDefaults 中。 然后,可以将该数据注入到 WKWebView 中,以便您的应用程序的 Web 部分不显示同意对话框,并且它将包含与原生部分相同的同意数据。

示例

// 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
}

注意:目标 URL 需要实现统一脚本。

一些说明

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

覆盖默认语言

默认情况下,SDK 将指示消息使用 WKWebView 定义的区域设置来呈现自身。如果您希望覆盖此行为并强制消息以特定语言显示,则需要在调用 .loadMessage() / .loadPrivacyManager() _之前_ 设置 SPConsentManager.messageLanguage 属性。

consentManager.messageLanguage = .German
consentManager.loadMessage()

在 Obj-C 中,这将是

consentManager.messageLanguage = SPMessageLanguageGerman;
[consentManager loadMessage];

需要注意的是,如果消息的任何组件没有该语言的翻译,则该组件将以消息构建器中配置的默认语言呈现。

当消息构建器中的 **使用浏览器默认设置** 开关启用时,Sourcepoint 将忽略 SDK 中配置的语言设置,并使用消息构建器中配置的默认语言。如果最终用户的浏览器语言不受消息构建器中翻译的支持,则将使用消息构建器中设置的默认语言。

加载 Stage 活动

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

设置定向参数

定向参数是一组传递给场景的键/值对。在场景中,您可以根据这些值有条件地显示消息或其他内容。您可以像这样为每个活动单独设置定向参数

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

在 Obj-C 中,这将是

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

将选择加入/选择退出偏好设置从 U.S. Privacy(旧版)转移到 U.S. Multi-State Privacy

当将属性从 U.S. Privacy(旧版)活动迁移到 U.S. Multi-State Privacy 活动时,SDK 将自动检测先前为 U.S. Privacy(旧版)设置的最终用户选择加入/选择退出偏好设置,并将其转移到 U.S. Multi-State Privacy。

如果最终用户拒绝了 U.S. Privacy 的供应商或类别,Sourcepoint 会将_定向广告的个人信息共享_和_个人信息出售_隐私选择或_个人信息的出售或共享/定向广告_隐私选择(取决于您的配置)设置为 **已选择退出**,当偏好设置被转移时。

如果您曾经对 CCPA 使用过经过身份验证的同意,您必须在配置要由 SDK 加载的活动时手动设置标志 transitionCCPAAuth。这样,即使该用户当前没有 CCPA 本地数据(例如,在全新安装中),SDK 也会在 CCPA 配置文件中查找经过身份验证的同意,并将其传递给 USNat。

var consentManager = SPConsentManager(
    accountId: accId,
    propertyId: propId,
    propertyName: try! SPPropertyName(propName),
    campaigns: SPCampaigns(usnat: SPCampaign(transitionCCPAAuth: true)), // <== here
    delegate: self
)

检查最终用户对 U.S. Multi-State Privacy 的同意状态

您的组织可以通过检查 SPUserDatausnatstatuses 对象来检查最终用户对隐私选择的同意状态。

在以下代码片段中,将 {status} 替换为下表中的状态

状态 描述
sellStatus 检查最终用户对_个人信息出售_隐私选择的同意状态。
shareStatus 检查最终用户对_个人信息的共享/定向广告_隐私选择的同意状态。
sensitiveDataStatus 检查最终用户对_敏感个人信息的处理_隐私选择的同意状态。

您的组织配置的每个敏感数据类别都在此单个隐私选择下进行整理。最终用户可以选择加入所有类别,也可以选择不加入任何类别。

代码片段将检查配置的状态并执行您为最终用户设置的代码。

//Replace {status} with the appropriate status
if SPUserData.usnat?.consents?.statuses.{status} {
    //execute code
}

如果您的组织已将_个人信息的共享/定向广告和个人信息的出售_合并为 Sourcepoint 门户中的单个隐私选择,您可以选择检查 sellStatusshareStatus 以了解最终用户的同意状态。

支持 U.S. Privacy(旧版)和 U.S. Multi-State Privacy

如果您要从 U.S. Privacy(旧版)过渡到 U.S. Multi-State Privacy,您可能希望继续支持旧版美国隐私字符串 (IABUSPrivacy_String)。

由于 U.S. Privacy(旧版)不支持敏感数据类别,因此任何需要敏感数据选择加入的组织都不应使用此方法。此外,仅需要_个人信息的共享/定向广告的组织_**不应**使用此方法。仅当您使用以下任一隐私选择时,才会设置 uspString

为此,在实例化 SDK 时,请务必将标志 .supportLegacyUSPString 设置为 true。例子

var consentManager = SPConsentManager(
    ...
    campaigns: SPCampaigns(usnat: SPCampaign(supportLegacyUSPString: true)), // <== here
    delegate: self
)

配置消息/同意超时

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

如果发生超时错误,将调用 onError 回调,并且同意流程将在那里停止。

pubData

当用户在同意 UI 中采取操作时,可以将任意有效负载附加到操作数据,并将其发送到我们的端点。有关如何执行此操作的更多信息,请查看我们的 Wiki:在用户采取操作时发送任意数据

以原生方式呈现消息

看看我们整理的这个简洁的 wiki

应用跟踪透明度

要显示用于访问 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)

当需要显示“基于 Web”的消息时,将调用 onSPUIReady 委托方法。controller 参数是包含要显示的消息的视图控制器。

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

一旦用户在第一层消息或隐私管理器中采取操作,就会调用 onAction 委托方法。

action: SPAction 参数,除其他数据(内部使用)外,还包含

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

onSPUIFinished()

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

除了 PMCancelShowPrivacyManager 操作外,SDK 将在处理操作后调用 onSPUIFinished。

onConsentReady()

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

onConsentReady 委托方法将同意操作发送到服务器并接收响应,SDK 会将数据存储在 UserDefaults 中。

onError()

在所有情况下,SDK 都会将错误包装在 SPError 类之一中,并最终调用 func onError(_ error: SPError) 回调。默认情况下,如果调用了 OnError 事件,SDK 会保留来自 UserDefaults 的所有用户同意数据。如果在初始化 SPConsentManager 后希望选择退出此行为,请将 consentManager.cleanUserDataOnError 标志设置为 true。如果设置为 true,则此用例将从 UserDefaults 中删除所有用户同意数据。这可能会导致再次显示同意消息,具体取决于您的场景。

Google 额外同意(GDPR TCF)

Google 额外同意是由 Google 和 IAB 框架创建的一个概念,用于将最终用户的同意传递给 Google Ad Technology Providers (ATP),尽管他们不遵守 IAB TCF 框架。点击此处获取更多信息。

我们的移动 SDK 支持 Google 额外同意,并将其存储在 UserDefaults 中的 IABTCF_AddtlConsent 键中。在用户的本地存储中查找该键并将该值传递给 Google 的 SDK。

tvOS 的全局隐私平台多州隐私 (MSPS) 支持

7.3.0 版本开始,如果您的 tvOS 配置包含 ccpa 活动,它将自动设置 GPP 数据。除非另有配置,否则以下 MSPA 属性将默认为

或者,您的组织可以通过将上述属性配置为 GPP 配置的一部分来自定义对 MSPS 的支持。点击此处获取有关每个属性、可能的值以及 MSPA 签署人和非签署人的示例的更多信息

示例

let campaigns = SPCampaigns(
    ccpa: SPCampaign(gppConfig: SPGPPConfig(
        MspaCoveredTransaction: .yes, // optional,
        MspaOptOutOptionMode: .yes, // optional
        MspaServiceProviderMode: .notApplicable // optional
    ))
)

注意:虽然可以将 SPGPPConfig 传递给任何 SPCampaign,但它仅影响 CCPA 活动。

删除用户数据

如果最终用户请求删除他们的数据,请使用以下方法

//Swift
SPConsentManager.clearAllData()
//Objective C
[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 活动的 Property Group 的 Privacy Manager Id 功能。

通过编程方式为用户全部拒绝

可以通过调用 rejectAll(campaignType) 函数,以编程方式代表当前用户发出“全部拒绝”操作。 rejectAll 函数的行为与用户在第一层或隐私管理器上按下“全部拒绝”按钮完全相同。 完成后,sdk 将在成功时调用 onConsentReady,或在失败时调用 onError

    consentManager.rejectAll(campaignType: .gdpr)

常见问题解答

1. SDK 有多大?

SDK 非常精简,没有资源文件,没有依赖项,只有纯代码。 由于我们使用 Swift,其大小会根据您项目的配置而有所不同,但不应超过 500 Kb

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

iOS 10 及以上。

3. 如果不支持 IDFA (iOS < 14) 怎么办?

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

我们会随着时间的推移更新此列表,如果您有任何问题,请随时提出问题或联系您的 SourcePoint 客户经理。

3. 是否支持深层链接?

Sourcepoint 不支持深层链接,因为我们的消息呈现应用(我们的应用内 SDK 用于在 webview 中呈现消息)中使用 HTML 清理器。 更改我们的 HTML 清理器的配置会损害我们的安全性,并为跨站点脚本 (XSS) 攻击引入漏洞。

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

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