Compliant with GDPR, CCPA, COPPA, LGPD, PECR, PDPA, PIPEDA, and more.
UniConsent CMP 是一个用于在 iOS 中处理 GDPR IAB TCF 2.3 同意管理的软件包。您可以在"UniConsentDemo"目录中找到集成了 UniConsent CMP 的演示应用。
将 UniConsent.xcframework 添加到您的项目中。在目标的 General > Frameworks, Libraries, and Embedded Content 中,将 UniConsent.xcframework 设置为 Embed & Sign。
在集成 SDK 之前,请在 UniConsent 控制面板 中自定义同意横幅的外观,使其与您的品牌一致并优化同意率。
前往 Projects → 选择您的项目 → Settings → Step 5: UI & Style Settings 进行配置:
如需更精确的控制,请在 Step 5 的 CSS Content 字段中添加自定义 CSS。建议通过此方式使横幅在您的应用中看起来更加原生,以获得最佳同意率:
/* 示例:设置接受按钮以匹配您的品牌 */
.unic-btn-accept {
background-color: #4CAF50;
border-radius: 8px;
font-weight: 600;
}
/* 示例:调整横幅字体 */
.unic-banner {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
/* 示例:降低拒绝按钮的突出程度 */
.unic-btn-reject {
background-color: transparent;
border: 1px solid #ccc;
color: #666;
}
提示: 精心设计品牌风格的同意界面通常能获得更高的同意率。用户更愿意与符合他们期望的外观和风格的横幅积极互动。
要在应用中使用 UniConsent CMP,请按照以下步骤操作:
使用从您的客户经理处获取的 App ID 初始化 CMP:
import UniConsent
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Init CMP with appId
UniConsentCMP.shared.initialize(apiId: "YOUR_APP_ID_CHANGE_THIS")
return true
}
显示 CMP 界面:
// Display CMP as full-screen modal (default)
UniConsentCMP.shared.setUIStage(.GDPRFirstScreen)
UniConsentCMP.shared.launchCMP(rootVC: self)
// Display CMP as a modal bottom sheet
UniConsentCMP.shared.launchCMP(rootVC: self, displayMode: .modalSheet)
// Display CMP as a modal bottom sheet at 60% of the available height
UniConsentCMP.shared.launchCMP(rootVC: self, displayMode: .modalSheet, heightRatio: 0.6)
// Display CMP as a center dialog
UniConsentCMP.shared.launchCMP(rootVC: self, displayMode: .dialog)
// Display CMP as a center dialog at 80% width and 60% height
UniConsentCMP.shared.launchCMP(rootVC: self, displayMode: .dialog, widthRatio: 0.8, heightRatio: 0.6)
可用的显示模式(CMPDisplayMode):
.fullScreen — 全屏模态展示(默认).modalSheet — 底部弹出面板,带拖动手柄(iOS 15+).dialog — 居中对话框,带暗色背景自 SDK 26.8.0 版本起可用。
两个比例参数均为可选,所有显示模式不传它们也能正常工作。仅在需要覆盖默认尺寸时才传入比例(相对屏幕的比例,会被限制在 0.1...1.0 范围内):
| 参数 | 适用于 | 省略时的默认值 |
|---|---|---|
heightRatio | .modalSheet、.dialog | 面板:可用高度的 90%。对话框:屏幕的 70% |
widthRatio | 仅 .dialog | 屏幕宽度的 90%,最大 500pt |
不适用于所选显示模式的比例会被忽略(.fullScreen 会忽略两者)。在 iOS 16+ 上,面板会精确使用 heightRatio;iOS 15 会回退到系统的 medium detent(比例 ≤ 0.5)或 large detent(比例 > 0.5)。
使用 CMPEventHandler 监听 SDK 生命周期事件。这是了解 SDK 初始化完成时间、界面显示时间和关闭时间的推荐方式。
可用事件(CMPEventType):
.sdkInit — SDK 初始化开始.ready — SDK 初始化完成(GEO、配置和供应商已加载).uiDisplay — 同意界面已显示.uiClose — 同意界面已关闭在调用 initialize() 之前订阅事件以接收所有事件:
import UniConsent
@main
class AppDelegate: UIResponder, UIApplicationDelegate, CMPEventHandler {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UniConsentCMP.shared.subscribe(self)
UniConsentCMP.shared.initialize(apiId: "YOUR_APP_ID")
return true
}
func handle(event: CMPEvent) {
switch event.type {
case .ready:
// SDK is ready — check consent and launch CMP if needed
if UniConsentCMP.shared.shouldRequestConsent() {
// launch CMP from your root view controller
}
case .uiClose:
// User finished interacting with consent UI
print("TC String:", UniConsentCMP.shared.getTCString())
default:
break
}
}
}
您也可以从视图控制器中订阅:
class ViewController: UIViewController, CMPEventHandler {
override func viewDidLoad() {
super.viewDidLoad()
UniConsentCMP.shared.subscribe(self)
}
func handle(event: CMPEvent) {
switch event.type {
case .uiDisplay:
print("CMP UI is now visible")
case .uiClose:
print("Consent given, vendor 1 allowed:", UniConsentCMP.shared.isAllowVendorById(vendorId: 1))
default:
break
}
}
}
取消订阅:
UniConsentCMP.shared.unsubscribe(self)
您也可以使用 CMPUIDelegate 监听同意关闭事件:
class ViewController: UIViewController, CMPUIDelegate {
func showCMP() {
UniConsentCMP.shared.view.delegate = self
UniConsentCMP.shared.setUIStage(.GDPRFirstScreen)
UniConsentCMP.shared.launchCMP(rootVC: self, displayMode: .modalSheet)
}
func onDismiss() {
// Called when the user closes the consent UI
print("TC String:", UniConsentCMP.shared.getTCString())
}
}
当供应商列表更新时自动检查同意是否过期:
// Automatic check if consent is expired when vendorList updates
if UniConsentCMP.shared.shouldRequestConsent() {
UniConsentCMP.shared.launchCMP(rootVC: self)
}
如需获取 tcString:
// Get tcString if required
UniConsentCMP.shared.getTCString()
读取同意状态:
// Check consent for a specific IAB purpose
UniConsentCMP.shared.isAllowPurposeById(purposeId: 1)
// Check consent for a specific IAB vendor
UniConsentCMP.shared.isAllowVendorById(vendorId: 1)
// Get all allowed purpose/vendor IDs
UniConsentCMP.shared.getAllowedPurposeIds()
UniConsentCMP.shared.getAllowedVendorIds()
// Check if GDPR applies
UniConsentCMP.shared.gdprApplies
// Check if any consent has been given
UniConsentCMP.shared.isConsentGiven()
如需重置同意状态:
// Reset consent status if required
UniConsentCMP.shared.clearConsentData()
自 SDK 26.7.0 版本起可用。如果您构建自己的首层同意界面而不显示 CMP webview,可以直接保存同意状态:
// Grant consent for all purposes, special features and vendors
let saved = UniConsentCMP.shared.agreeAll()
// Reject all purposes, special features and vendors
let saved = UniConsentCMP.shared.rejectAll()
这两个 API 保存的同意值与 CMP UI 流程相同(IAB TCF 键、附加同意和 consent mode 信号),并向订阅者触发相同的 .uiClose 事件。
注意: 这些 API 会同步通过网络获取供应商列表和项目配置,如果无法保存同意状态(例如离线),则返回
false。请在initialize()之后调用,并避免在主线程调用。重要: 您的自定义首层界面仍须满足 IAB TCF 要求(披露目的和供应商,并以同等显著程度提供同意和拒绝选项)。用户应仍能打开完整的 CMP 界面(
launchCMP())进行精细化选择。
如果您的应用打开了一个加载带有 UniConsent CMP 标签的网页的 WKWebView,您可以传递原生同意状态,这样 CMP 标签会识别现有的同意,不会再次显示横幅。
在加载网页之前调用 syncConsent(to:):
import WebKit
import UniConsent
let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
// Inject native consent before page load
UniConsentCMP.shared.syncConsent(to: webView)
// Then load your web page
webView.load(URLRequest(url: URL(string: "https://example.com")!))
// Initialize with event handler
@interface AppDelegate () <CMPEventHandler>
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UniConsentCMP shared] subscribe:self];
[[UniConsentCMP shared] initializeWithApiId:@"YOUR_APP_ID"];
return YES;
}
- (void)handleWithEvent:(CMPEvent *)event {
switch (event.type) {
case CMPEventTypeReady:
NSLog(@"CMP ready");
break;
case CMPEventTypeUiClose:
NSLog(@"TC String: %@", [[UniConsentCMP shared] getTCString]);
break;
default:
break;
}
}
@end
// Display CMP (full screen by default)
[UniConsentCMP.shared launchCMPWithRootVC:self];
// Display CMP with a specific display mode
// Use CMPDisplayModeFullScreen, CMPDisplayModeModalSheet, or CMPDisplayModeDialog
[UniConsentCMP.shared launchCMPWithRootVC:self displayMode:CMPDisplayModeModalSheet];
设置默认同意状态键值:
<key>FIREBASE_ANALYTICS_COLLECTION_ENABLED</key> <false/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE</key> <false/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE</key> <false/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA</key> <false/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS</key> <false/>
根据同意标志控制分析功能:
// SDK Version <= 25.6.1
public func onDismiss() {
if(UniConsentCMP.shared.isAllowPurposeById(purposeId: 1)) {
Analytics.setConsent([
.analyticsStorage: .granted,
.adStorage: .granted,
.adUserData: .granted,
.adPersonalization: .granted,
])
Analytics.setAnalyticsCollectionEnabled(true);
} else {
Analytics.setConsent([
.analyticsStorage: .denied,
.adStorage: .denied,
.adUserData: .denied,
.adPersonalization: .denied,
])
Analytics.setAnalyticsCollectionEnabled(false);
}
// other logics such as send analytics events
}
更多信息请参阅 Set up consent mode for apps