Compliant with GDPR, CCPA, COPPA, LGPD, PECR, PDPA, PIPEDA, and more.
UniConsent CMP 是用于在 Flutter 应用中处理 GDPR IAB TCF 2.4 同意管理的软件包。您可以在 "uniconsent_demo" 目录中找到集成了 UniConsent CMP 的演示应用。
要在 Flutter 项目中包含 UniConsent 软件包,请将其作为依赖项添加到 pubspec.yaml 文件中:
dependencies:
uniconsent:
path: ../uniconsent
然后运行以下命令同步依赖项:
flutter pub get
在集成 SDK 之前,请在 UniConsent 控制台 中自定义同意横幅的外观,以匹配您的品牌并优化同意率。
前往 Projects → 选择您的项目 → Settings → Step 5: UI & Style Settings 进行配置:
如需更精确的控制,请在 Step 5 的 CSS Content 字段中添加自定义 CSS。建议使用此功能让横幅呈现原生应用的观感,以获得最佳同意率:
/* Example: Style the accept button to match your brand */
.unic-btn-accept {
background-color: #4CAF50;
border-radius: 8px;
font-weight: 600;
}
/* Example: Adjust banner font */
.unic-banner {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
/* Example: Make the reject button less prominent */
.unic-btn-reject {
background-color: transparent;
border: 1px solid #ccc;
color: #666;
}
提示: 具有原生应用观感的精心设计的同意界面通常能获得更高的同意率。用户更可能对符合预期外观和风格的横幅做出积极响应。
要在应用中使用 UniConsent CMP,请按照以下步骤操作:
使用客户经理提供的 App ID 初始化 CMP:
// Init CMP with appId
UniConsent.instance.setAppId("YOUR_APP_ID_CHANGE_THIS");
// Set language (Optional)
UniConsent.instance.setLanguage("EN");
显示 CMP 界面:
// Display CMP as full-screen page (default)
UniConsent.instance.launchCMP(context);
// Display CMP as a modal bottom sheet
UniConsent.instance.launchCMP(context, displayMode: CMPDisplayMode.modalSheet);
// Display CMP as a modal bottom sheet at 70% of the available height
UniConsent.instance.launchCMP(
context,
displayMode: CMPDisplayMode.modalSheet,
heightRatio: 0.7,
);
// Display CMP as a center dialog
UniConsent.instance.launchCMP(context, displayMode: CMPDisplayMode.dialog);
// Display CMP as a center dialog at 85% width and 70% height
UniConsent.instance.launchCMP(
context,
displayMode: CMPDisplayMode.dialog,
widthRatio: 0.85,
heightRatio: 0.7,
);
自 SDK 26.8.0 版本起可用。
两个比例参数均为可选,所有显示模式不传它们也能正常工作。仅在需要覆盖默认尺寸时才传入比例(相对可用空间的比例,需大于 0 且不超过 1);无效值会抛出 ArgumentError:
| 参数 | 适用于 | 省略时的默认值 |
|---|---|---|
heightRatio | modalSheet、dialog | 面板:高度的 90%。对话框:70% |
widthRatio | 仅 dialog | 宽度的 90%,最大 500 逻辑像素 |
不适用于所选显示模式的比例会被忽略(page 会忽略两者)。
使用 subscribe() 监听 SDK 生命周期事件。这是了解界面何时显示和关闭的推荐方式。
可用事件(CMPEventType):
CMPEventType.uiDisplay — 同意界面已显示CMPEventType.uiClose — 同意界面已关闭UniConsent.instance.subscribe((event) {
switch (event.type) {
case CMPEventType.uiDisplay:
print('CMP UI displayed');
break;
case CMPEventType.uiClose:
print('CMP UI closed');
break;
default:
break;
}
});
使用可选回调监听同意变更:
// Display CMP UI with consent change callback
UniConsent.instance.launchCMP(context, onConsentChanged: (info) {
// Called when the user saves consent choices
print('Consent updated: ${info?.tcString}');
});
如需完全控制,使用 buildCMPWidget() 将 CMP 嵌入您自己的布局中:
// Embed in your own widget tree
UniConsent.instance.buildCMPWidget(
onConsentChanged: (info) { /* ... */ },
onClose: () { /* dismiss your custom UI */ },
);
在应用启动时自动检查是否需要同意:
// Check if consent should be requested (e.g. first visit, or vendor list updated)
final shouldRequest = await UniConsent.instance.shouldRequestConsent();
if (shouldRequest) {
UniConsent.instance.launchCMP(context);
}
获取 tcString(如需要):
// Get tcString
final info = await UniConsent.instance.getConsentInfo();
print(info?.tcString);
读取同意状态:
// Read consent status
final info = await UniConsent.instance.getConsentInfo();
if (info is ConsentInfo &&
info.purposeConsents.contains(DataUsagePurpose.useLimitedDataToSelectAds)) {
// do something
}
重置同意状态(如需要):
// Clear all consent data
await UniConsent.instance.clearAll();
自 SDK 26.7.0 版本起可用。如果您构建自己的首层同意界面而不显示 CMP webview,可以直接保存同意状态:
// Grant consent for all purposes, special features and vendors
final saved = await UniConsent.instance.agreeAll();
// Reject all purposes, special features and vendors
final saved = await UniConsent.instance.rejectAll();
这两个 API 保存与 CMP UI 流程相同的同意值(IAB TCF 键、附加同意和同意模式信号),并向订阅者发送相同的关闭事件。
对于美国和加拿大用户,这两个 API 还会按照与 CMP 界面相同的规则,保存适用于该用户的 CCPA、US State Privacy 和 IAB TCF 加拿大选择,并写入 IAB GPP 和 US Privacy 键。请在 UniConsent 控制台的项目设置中开启 API-Only 模式,这些地区便不会显示 CMP 横幅。
在适用 Cookie 类别横幅的地区,它们还会保存 Cookie 类别选择(全部类别,或仅“绝对必要”),以及项目的自定义目的和自定义供应商。
要确定显示哪个首层界面,请调用 getPolicy()(自 SDK 26.10.0 版本起)。它按照与 CMP 相同的规则返回适用于该用户的政策:gdpr(IAB TCF)、tcfca(IAB TCF 加拿大)、uss(US State Privacy)、ccpa、categories(见下文 Cookie 类别)或 none。
final cmp = UniConsent.instance;
if (await cmp.shouldRequestConsent()) {
// 用户需要做出选择:显示该政策对应的首层界面
final policy = await cmp.getPolicy(); // gdpr、tcfca 或 categories
}
注意: 这些 API 通过网络获取供应商列表和项目配置,如果无法保存同意状态(例如离线时)则返回
false。重要: 您的自定义首层界面仍须满足 IAB TCF 要求(披露目的和供应商,并以同等显著程度提供接受和拒绝选项)。用户仍应能够打开完整的 CMP 界面(
launchCMP())进行精细选择。
如果您的应用打开了加载带有 UniConsent CMP 标签的网页的 WebView,您可以传递原生同意状态,这样 CMP 标签会识别已有的同意记录,不会再次显示横幅。
import 'package:webview_flutter/webview_flutter.dart';
import 'package:uniconsent/uniconsent.dart';
final controller = WebViewController();
controller
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(NavigationDelegate(
onPageStarted: (url) async {
// Inject consent at page start, before CMP tag runs
await UniConsent.instance.syncConsent(controller);
},
))
..loadRequest(Uri.parse('https://example.com'));
导入 package:uniconsent/uniconsent.dart 后可使用以下类型:
UniConsent — SDK 主单例UniConsentInfo — 基础同意数据(sdkId、tcString、gdprApplies、vendorListVersion 等)ConsentInfo — 继承自 UniConsentInfo,包含目的级别的同意列表DataUsagePurpose — IAB TCF 2.4 目的 ID 枚举KVDBKeys — IAB TCF 存储键常量(例如 KVDBKeys.tcString、KVDBKeys.purposeConsents)CMPDisplayMode — 显示样式枚举(page、modalSheet、dialog)CMPEventType — 生命周期事件枚举(SDK 会触发 uiDisplay 和 uiClose)CMPEvent — 带有 type 属性的事件对象CMPEventCallback — subscribe() 回调的类型定义LogLevel — debug / prodConsentCallback — onConsentChanged 回调的类型定义UniConsentCMPContent — 用于自定义布局的核心 CMP 组件可以在指定界面打开 CMP,例如从应用中的“隐私设置”链接打开。请求的界面总会打开。对于美国用户,设置界面会打开适用于他们的 CCPA 或 US State Privacy 设置。加拿大用户看到的是 IAB TCF 界面的 IAB TCF Canada 版本。
| 界面 | 显示内容 |
|---|---|
CMPStage.gdprFirstScreen | 首层界面(横幅) |
CMPStage.gdprSecondScreen | 设置(目的) |
CMPStage.gdprVendorsScreen | 供应商 |
CMPStage.ccpaFirstScreen | CCPA 首层界面 |
CMPStage.ccpaSecondScreen | CCPA 设置 |
CMPStage.usStateFirstScreen | US State Privacy 首层界面 |
CMPStage.usStateSecondScreen | US State Privacy 设置 |
CMPStage.categoriesFirstScreen | Cookie 类别首层界面(横幅) |
CMPStage.categoriesSecondScreen | Cookie 类别设置 |
final cmp = UniConsent.instance;
// 打开设置界面
cmp.launchCMP(context, stage: CMPStage.gdprSecondScreen);
// 仅在需要同意时打开 CMP(欧盟和 IAB TCF 加拿大),返回是否已打开
final opened = await cmp.launchCMPIfNeeded(context);
// 调试日志,正式版本请使用 LogLevel.prod
cmp.setLogLevel(LogLevel.debug);
// 仅用于测试:按其他地区的用户显示 CMP,"EU"、"CA"(加拿大)、"CAQC"(魁北克)、"US" 加上州代码(如 "USCA" 或 "USTX")、"BR"、"CN"、"ZA"、"VN" 或其他任何国家代码,或 "N"(以上地区以外)。也适用于 getPolicy() 和 shouldRequestConsent();正式版本中请删除
cmp.setTestRegion("CA");
// 用户的国家代码(未知时为 "AA"),以及美国和加拿大用户的州或省代码
final geo = await cmp.getGEO();
final state = await cmp.getGEOState();
CMP 会按照 IAB 规范,将 IAB GPP 键和 US Privacy 键存储到应用的原生存储(Android 为 SharedPreferences,iOS 为 UserDefaults)中。应用内的广告 SDK 会从那里读取,无需修改代码。在 UniConsent 控制台的项目设置中启用 GPP、US State Privacy 或 IAB TCF 加拿大后会写入 GPP 键;只要启用 CCPA,就会写入 US Privacy 键。
| 键 | 值 |
|---|---|
IABGPP_HDR_Version | GPP 版本(1) |
IABGPP_HDR_Sections | GPP 字符串中的部分 ID,以 _ 分隔 |
IABGPP_HDR_GppString | 完整的 GPP 字符串 |
IABGPP_GppSID | 适用于该用户的部分 ID,以 _ 分隔;均不适用时为 -1 |
IABGPP_2_String | IAB TCF EU 字符串(适用 GDPR 时) |
IABGPP_5_String | IAB TCF 加拿大字符串(适用加拿大 TCF 时) |
IABGPP_6_String | US Privacy 字符串(适用 CCPA 时) |
IABGPP_7_String | US National(usnat)字符串(适用 US State Privacy 或 CCPA 时) |
IABGPP_8_String 至 IABGPP_27_String | 用户所在州的部分(8 加利福尼亚至 27 罗得岛),适用 US State Privacy 时写入,或在 CCPA 下写入加利福尼亚,遵循 GPP Sections 设置 |
IABUSPrivacy_String | 只要启用 CCPA 就会写入:在 CCPA 地区为用户的选择,否则为 1--- |
每次加载 CMP 以及每次做出同意选择后,这些键都会更新。关闭 GPP 后,IABGPP_ 键会被删除。
应用支持与网站相同的美国和加拿大选项:CCPA、US State Privacy(包括州列表、GPP Sections 和 MSPA 设置)以及 IAB TCF 加拿大。对于适用 IAB TCF 加拿大的加拿大用户,在其做出选择之前,shouldRequestConsent() 会返回 true。美国隐私采用退出(opt-out)模式,因此不会主动询问美国用户:当您的应用打开 CMP 时(例如通过隐私设置链接),他们会看到美国横幅或设置。在此之前,启用 CCPA 或 US State Privacy 时,SDK 会为美国用户写入默认的 US Privacy 和 GPP 键,不显示任何内容:未退出;若设备关闭了广告跟踪,则为已退出。新的 Mobile App 项目默认关闭 US State Privacy,请在控制台中开启。
当用户在设备上关闭广告跟踪时,CMP 会将其视为美国用户对出售、共享和定向广告的退出,与网站上的 Global Privacy Control 相同。在 iOS 上指 App Tracking Transparency 中不允许跟踪;在 Android 上指已删除广告 ID 或限制广告跟踪(应用包含 Google Play 服务时通过其读取)。用户之后在横幅中保存的选择优先。
SDK 也会返回已存储的字符串:
final gppString = await UniConsent.instance.getGPPString();
final gppSid = await UniConsent.instance.getGPPSID();
final usPrivacy = await UniConsent.instance.getUSPrivacyString();
自 SDK 26.10.0 版本起可用。当某个地区使用 Cookie 类别而不是 IAB TCF 或美国政策时,CMP 会显示包含四个类别的横幅:绝对必要、性能、功能性、定向或广告。适用于:
选择加入(opt-in)类别初始只开启“绝对必要”,在用户做出选择之前,以及您更改配置版本之后,shouldRequestConsent() 会返回 true。选择退出(opt-out)类别初始开启所有类别(在美国,若设备关闭了广告跟踪,则关闭“定向或广告”),应用不会主动询问:用户可通过您的隐私设置链接更改。选择退出适用于其他国家的 opt-out 规则,以及应用中位于美国的 Consent Categories 项目。
使用 CMPStage.categoriesFirstScreen(横幅)和 CMPStage.categoriesSecondScreen(设置)打开类别界面。setTestRegion() 也支持 BR、CN、ZA、VN 及其他国家代码,用于测试这些地区。
自 SDK 26.10.0 版本起可用。您在 UniConsent 控制台项目设置中添加的自定义目的和自定义供应商会显示在 CMP 界面中:自定义目的显示在 IAB TCF 首层界面和设置以及 Cookie 类别设置中,自定义供应商显示在 IAB TCF 供应商列表中。在 CCPA 和 US State Privacy 设置中,只列出敏感的自定义目的。在 Cookie 类别设置中,自定义供应商跟随“定向或广告”类别。在不适用 IAB TCF 的地区(Cookie 类别和美国),自定义供应商以只读方式列在菜单的供应商列表中,并在 Cookie 类别设置的“定向或广告”下列出。
要据此启动或停止您自己的 SDK,请询问 SDK 应用现在是否可以使用某个自定义目的或自定义供应商。结果遵循用户适用的政策,规则与 CMP 用于标签的规则相同:
final cmp = UniConsent.instance;
if (await cmp.isCustomPurposeConsented(1)) {
// 启动自定义目的 1 涵盖的 SDK
}
final vendorAllowed = await cmp.isCustomVendorConsented(2);
final all = await cmp.getCustomConsents(); // {'purposes': {'1': true}, 'vendors': {'2': false}}
在 CMP 关闭或同意变化后请再次调用。项目中不存在的 ID,以及 SDK 就绪前的所有 ID,都返回 false。
CMP 可以列出您应用中的第三方 SDK(广告网络、分析、归因等),包括其公司、用途和隐私政策。用户在供应商列表中查看它们,在所有地区均为只读:没有开关,您的应用仍根据用户对目的或 Cookie 类别的选择来开启或关闭各个 SDK。
要设置列表,请在应用项目的 Step 4: Advanced Features 中开启 Enable Third-party SDKs,在 Third-party SDKs 标签页中选择您的 SDK 或添加自己的 SDK,然后保存并发布。您的应用中无需任何代码。
getGPPString()、getGPPSID() 和 getUSPrivacyString()launchCMP(context, stage:) 打开指定界面;新增 launchCMPIfNeeded()、getGEO() 和 getGEOState()CMPStage.ccpaFirstScreen 和 CMPStage.usStateFirstScreen 打开 CCPA 和 US State Privacy 首层界面;新增 setTestRegion(),可按其他地区(例如加拿大)的用户测试 CMPCMPStage.categoriesFirstScreen 和 CMPStage.categoriesSecondScreengetPolicy();agreeAll() 和 rejectAll() 还会保存 Cookie 类别、自定义目的和自定义供应商setTestRegion() 也支持 BR、CN、ZA、VN 及其他国家代码,并适用于 getPolicy() 和 shouldRequestConsent()isCustomPurposeConsented()、isCustomVendorConsented() 和 getCustomConsents():应用按照用户适用的政策现在可以使用的自定义目的和自定义供应商