diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 877f868b..a4d3db8d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -129,7 +129,7 @@ jobs:
- name: Setup code
uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1
with:
- xcode-version: '15.4'
+ xcode-version: '16.2'
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Setup Flutter
@@ -139,6 +139,28 @@ jobs:
channel: 'stable'
- name: Get dependencies
run: flutter pub get
+ - name: Create stub GoogleService-Info.plist for CI
+ run: |
+ cat > example/ios/Runner/GoogleService-Info.plist << 'EOF'
+
+
+
+
+ API_KEYAIzaCI00000000000000000000000000000000
+ GCM_SENDER_ID000000000000
+ PLIST_VERSION1
+ BUNDLE_IDcom.placeholder.ci
+ PROJECT_IDplaceholder-ci
+ STORAGE_BUCKETplaceholder-ci.appspot.com
+ IS_ADS_ENABLED
+ IS_ANALYTICS_ENABLED
+ IS_APPINVITE_ENABLED
+ IS_GCM_ENABLED
+ IS_SIGNIN_ENABLED
+ GOOGLE_APP_ID1:000000000000:ios:0000000000000000000000
+
+
+ EOF
- name: Setup Pods
working-directory: ./example/ios
run: pod install
@@ -199,7 +221,7 @@ jobs:
- name: Setup code
uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1
with:
- xcode-version: '15.4'
+ xcode-version: '16.2'
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Setup Flutter
@@ -209,6 +231,28 @@ jobs:
channel: 'stable'
- name: Get dependencies
run: flutter pub get
+ - name: Create stub GoogleService-Info.plist for CI
+ run: |
+ cat > example/ios/Runner/GoogleService-Info.plist << 'EOF'
+
+
+
+
+ API_KEYAIzaCI00000000000000000000000000000000
+ GCM_SENDER_ID000000000000
+ PLIST_VERSION1
+ BUNDLE_IDcom.placeholder.ci
+ PROJECT_IDplaceholder-ci
+ STORAGE_BUCKETplaceholder-ci.appspot.com
+ IS_ADS_ENABLED
+ IS_ANALYTICS_ENABLED
+ IS_APPINVITE_ENABLED
+ IS_GCM_ENABLED
+ IS_SIGNIN_ENABLED
+ GOOGLE_APP_ID1:000000000000:ios:0000000000000000000000
+
+
+ EOF
- name: Build
working-directory: ./example
run: flutter build ios --debug --no-codesign --simulator
diff --git a/example/.gitignore b/example/.gitignore
index 1130e20d..add25a5e 100644
--- a/example/.gitignore
+++ b/example/.gitignore
@@ -72,3 +72,7 @@ app.*.symbols
# Obfuscation related
app.*.map.json
+
+# Firebase config files — kept locally, not committed
+android/app/google-services.json
+ios/Runner/GoogleService-Info.plist
diff --git a/example/README.md b/example/README.md
index b4d407a3..da240e76 100644
--- a/example/README.md
+++ b/example/README.md
@@ -1,18 +1,64 @@
-# Usercentrics SDK for Flutter - Quickstart
+# Usercentrics SDK for Flutter — Example App
-The goal of this project is to show how to use Usercentrics SDK inside of a Flutter application.
+This app demonstrates how to integrate and test the Usercentrics SDK in a Flutter application, including consent mediation with Firebase Analytics.
-## Instructions
+---
-This project is a starting point for a Flutter application.
+## Prerequisites
-- Step 1: Clone the repository
+- [Flutter SDK](https://docs.flutter.dev/get-started/install) installed
+- For iOS: Xcode + CocoaPods (`gem install cocoapods`)
+- For Android: Android Studio or a connected device/emulator
-- Step 2: Get the dependencies by executing `flutter pub get`
+---
-- Step 3: Run the application by executing `flutter run`
+## Running the App (without Consent Mediation)
-## Result
+No Firebase setup is required for the standard flow.
+
+**Step 1 — Clone the repository**
+```bash
+git clone https://github.com/Usercentrics/flutter-sdk.git
+cd flutter-sdk
+```
+
+**Step 2 — Install dependencies**
+```bash
+flutter pub get
+```
+
+**Step 3 — iOS only: install pods**
+
+> **Note:** The iOS Podfile includes a local path override for `UsercentricsUI` pointing to
+> `../../../mobile-sdk/platforms/ios/UsercentricsUI`. This is used for testing local
+> mobile-sdk changes without a full release. If you do not have the `mobile-sdk` repository
+> checked out at that relative path, remove or comment out that line in `example/ios/Podfile`
+> before running `pod install`:
+> ```ruby
+> # pod 'UsercentricsUI', :path => '../../../mobile-sdk/platforms/ios/UsercentricsUI'
+> ```
+
+```bash
+cd example/ios && pod install && cd ../..
+```
+
+**Step 4 — Run the app**
+```bash
+cd example && flutter run
+```
+
+> **Note:** Consent mediation is **enabled by default** in this example app
+> (`_kMediationTestEnabled = true`). To run without mediation, pass the flag explicitly:
+> ```bash
+> flutter run --dart-define=MEDIATION_TEST=false
+> ```
+> Without Firebase config files in place, the app will still run but Firebase will not
+> initialise — you will see an error in the logs. Add the config files as described below
+> to test mediation end-to-end.
+
+---
+
+## App Features
After running the app you should see a screen like this:
@@ -20,17 +66,108 @@ After running the app you should see a screen like this:
### UsercentricsUI
+The default Usercentrics-provided consent banner.
+
-### CustomUI
+### Custom UI
+
+Build your own consent UI using the raw consent data from the SDK.
-### Consent Mediation
+### Customization Examples
+
+Two built-in examples (`Customization Example 1` and `Customization Example 2`) show how to customise the banner appearance — fonts, colours, button layouts, and layer settings — using `BannerSettings`.
+
+### Webview Integration
+
+Demonstrates how to inject the user's Usercentrics session data into a `WebView` so the Browser CMP can pick up the native consent without asking the user again.
+
+### GPP Testing
+
+A dedicated screen for testing the Global Privacy Platform (GPP) API:
+- Fetch and display the encoded GPP string
+- Fetch full GPP data (applicable sections and field values)
+- Set consent values for specific GPP sections (e.g. `usnat`, `usfl`)
+- Monitor real-time `onGppSectionChange` stream events
+
+---
+
+## Running the App with Consent Mediation
+
+Consent mediation automatically forwards the user's consent decisions to integrated third-party SDKs (e.g. Firebase Analytics). Testing this requires Firebase to be configured in the app.
+
+### Step 1 — Create a Firebase project
+
+1. Go to the [Firebase Console](https://console.firebase.google.com)
+2. Click **Add project** and follow the setup wizard
+3. Once the project is created, register two apps (Android + iOS) in the next steps
+
+### Step 2 — Register the Android app and download `google-services.json`
+
+1. In your Firebase project, click **Add app** → select **Android**
+2. Enter the package name: `com.usercentrics.sdk.mediation.test`
+3. Click **Register app**
+4. Download the `google-services.json` file
+5. Place it at:
+ ```
+ example/android/app/google-services.json
+ ```
+
+### Step 3 — Register the iOS app and download `GoogleService-Info.plist`
+
+1. In your Firebase project, click **Add app** → select **iOS**
+2. Enter the bundle ID: `com.usercentrics.sdk.mediation.test`
+3. Click **Register app**
+4. Download the `GoogleService-Info.plist` file
+5. Place it at:
+ ```
+ example/ios/Runner/GoogleService-Info.plist
+ ```
+
+> **Note:** Both config files are excluded from version control (`.gitignore`) as they
+> contain API keys. You must add them locally before running the app with mediation.
+
+### Step 4 — Run the app
+
+Since mediation is enabled by default, simply run:
+
+```bash
+cd example && flutter run
+```
+
+To explicitly disable mediation:
+
+```bash
+cd example && flutter run --dart-define=MEDIATION_TEST=false
+```
+
+### Step 5 — Test consent mediation
+
+1. Tap **Initialize SDK** — the Usercentrics CMP will appear
+2. Accept or deny consent
+3. Check the debug logs — you should see mediation output like:
+ ```
+ [USERCENTRICS][DEBUG] [Mediation] Firebase - Consent applied successfully.
+ ```
+
+> **Important:** Consent is persisted locally on the device. To re-test mediation from a
+> clean state, clear the app data (Android) or uninstall and reinstall the app (iOS)
+> before running again.
+
+---
+
+## Settings ID
+
+The example app uses the settings ID `Yi9N3aXia` by default, configured in
+`example/lib/main.dart`. To test with your own Usercentrics configuration, replace it
+with your settings ID from the [Usercentrics Admin Interface](https://admin.usercentrics.eu).
-You can enable and run the Consent Mediation example in this example by following the [documentation](https://usercentrics.com/docs/apps/features/consent-mediation/#enable-mediation).
+---
-## Learn more
+## Learn More
-- Check out the full [documentation](https://docs.usercentrics.com/cmp_in_app_sdk).
-- Check our [website](https://usercentrics.com).
+- [Usercentrics Documentation](https://docs.usercentrics.com/cmp_in_app_sdk)
+- [Consent Mediation Guide](https://usercentrics.com/docs/apps/features/consent-mediation/#enable-mediation)
+- [Usercentrics Website](https://usercentrics.com)
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
index ff67f652..ab28d6b8 100644
--- a/example/android/app/build.gradle
+++ b/example/android/app/build.gradle
@@ -2,6 +2,10 @@ plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
+ // Uncomment to enable Firebase Analytics (required for consent mediation testing).
+ // Place google-services.json in example/android/app/ before building.
+ // See example/README.md for setup instructions.
+ // id "com.google.gms.google-services"
}
def localProperties = new Properties()
@@ -40,7 +44,7 @@ android {
}
defaultConfig {
- applicationId "com.usercentrics.sdk.flutter_example"
+ applicationId "com.usercentrics.sdk.mediation.test"
minSdk flutter.minSdkVersion
targetSdk 34
versionCode flutterVersionCode.toInteger()
@@ -62,4 +66,7 @@ flutter {
dependencies {
implementation "androidx.multidex:multidex:2.0.1"
+
+ implementation platform('com.google.firebase:firebase-bom:33.13.0')
+ implementation 'com.google.firebase:firebase-analytics'
}
diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml
index 8687b253..de5c0aa6 100644
--- a/example/android/app/src/main/AndroidManifest.xml
+++ b/example/android/app/src/main/AndroidManifest.xml
@@ -4,6 +4,12 @@
android:label="Usercentrics Flutter Sample"
android:icon="@mipmap/ic_launcher"
android:name="androidx.multidex.MultiDexApplication" >
+
+
+
+
+
+
'../../../mobile-sdk/platforms/ios/UsercentricsUI'
+
+ # Firebase Analytics — required for consent mediation testing.
+ pod 'FirebaseAnalytics'
+
target 'RunnerTests' do
inherit! :complete
end
diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock
index 5997b60e..6efbbdf0 100644
--- a/example/ios/Podfile.lock
+++ b/example/ios/Podfile.lock
@@ -1,5 +1,93 @@
PODS:
+ - FirebaseAnalytics (11.15.0):
+ - FirebaseAnalytics/Default (= 11.15.0)
+ - FirebaseCore (~> 11.15.0)
+ - FirebaseInstallations (~> 11.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - FirebaseAnalytics/Default (11.15.0):
+ - FirebaseCore (~> 11.15.0)
+ - FirebaseInstallations (~> 11.0)
+ - GoogleAppMeasurement/Default (= 11.15.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - FirebaseCore (11.15.0):
+ - FirebaseCoreInternal (~> 11.15.0)
+ - GoogleUtilities/Environment (~> 8.1)
+ - GoogleUtilities/Logger (~> 8.1)
+ - FirebaseCoreInternal (11.15.0):
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - FirebaseInstallations (11.15.0):
+ - FirebaseCore (~> 11.15.0)
+ - GoogleUtilities/Environment (~> 8.1)
+ - GoogleUtilities/UserDefaults (~> 8.1)
+ - PromisesObjC (~> 2.4)
- Flutter (1.0.0)
+ - GoogleAdsOnDeviceConversion (2.1.0):
+ - GoogleUtilities/Logger (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - nanopb (~> 3.30910.0)
+ - GoogleAppMeasurement/Core (11.15.0):
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - GoogleAppMeasurement/Default (11.15.0):
+ - GoogleAdsOnDeviceConversion (= 2.1.0)
+ - GoogleAppMeasurement/Core (= 11.15.0)
+ - GoogleAppMeasurement/IdentitySupport (= 11.15.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - GoogleAppMeasurement/IdentitySupport (11.15.0):
+ - GoogleAppMeasurement/Core (= 11.15.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - GoogleUtilities/AppDelegateSwizzler (8.1.0):
+ - GoogleUtilities/Environment
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Network
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Environment (8.1.0):
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Logger (8.1.0):
+ - GoogleUtilities/Environment
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/MethodSwizzler (8.1.0):
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Network (8.1.0):
+ - GoogleUtilities/Logger
+ - "GoogleUtilities/NSData+zlib"
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Reachability
+ - "GoogleUtilities/NSData+zlib (8.1.0)":
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Privacy (8.1.0)
+ - GoogleUtilities/Reachability (8.1.0):
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/UserDefaults (8.1.0):
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Privacy
+ - nanopb (3.30910.0):
+ - nanopb/decode (= 3.30910.0)
+ - nanopb/encode (= 3.30910.0)
+ - nanopb/decode (3.30910.0)
+ - nanopb/encode (3.30910.0)
+ - PromisesObjC (2.4.0)
- Usercentrics (2.26.2)
- usercentrics_sdk (2.26.2):
- Flutter
@@ -11,12 +99,22 @@ PODS:
- FlutterMacOS
DEPENDENCIES:
+ - FirebaseAnalytics
- Flutter (from `Flutter`)
- usercentrics_sdk (from `.symlinks/plugins/usercentrics_sdk/ios`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
SPEC REPOS:
trunk:
+ - FirebaseAnalytics
+ - FirebaseCore
+ - FirebaseCoreInternal
+ - FirebaseInstallations
+ - GoogleAdsOnDeviceConversion
+ - GoogleAppMeasurement
+ - GoogleUtilities
+ - nanopb
+ - PromisesObjC
- Usercentrics
- UsercentricsUI
@@ -29,12 +127,21 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
SPEC CHECKSUMS:
+ FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae
+ FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e
+ FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4
+ FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
- Usercentrics: add954fa1e0a1cfde768e350f895252b72bc6c1f
- usercentrics_sdk: 73e1f87f065dbea395012fa2a09d81fc70ed68f1
- UsercentricsUI: c1491664512f56c68425da2d270d94ba48a470f9
+ GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64
+ GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539
+ GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
+ nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
+ PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
+ Usercentrics: 26f9f31e4e83cc0de49c3913577c6a819ba172f8
+ usercentrics_sdk: 6be3d30f8371353fbee168b7daf8b4a92d168d84
+ UsercentricsUI: 3ed95d8cae63a71e67c28402e8fe7367e2b14179
webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2
-PODFILE CHECKSUM: 723de1cf6e2f18b51eb3426c945e31134a750097
+PODFILE CHECKSUM: e97bfdbafeca8809c8aa9477153c465633bd1c02
COCOAPODS: 1.16.2
diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj
index e2a4cdc7..56947d60 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
+ DA0000021CF9000F007C117D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = DA0000011CF9000F007C117D /* GoogleService-Info.plist */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
17F28FC4AC3BF66FC4301149 /* Pods_Runner_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 760C9E4CB26E7DAC6C729A22 /* Pods_Runner_RunnerTests.framework */; };
3453DCAF2B3D971200EFE874 /* GetAdditionalConsentModeBridgeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3453DCAE2B3D971200EFE874 /* GetAdditionalConsentModeBridgeTest.swift */; };
@@ -70,6 +71,7 @@
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ DA0000011CF9000F007C117D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
760C9E4CB26E7DAC6C729A22 /* Pods_Runner_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
773DA90C23F572C5E5B4A715 /* Pods-Runner-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-Runner-RunnerTests/Pods-Runner-RunnerTests.debug.xcconfig"; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
@@ -190,6 +192,7 @@
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+ DA0000011CF9000F007C117D /* GoogleService-Info.plist */,
);
path = Runner;
sourceTree = "";
@@ -252,7 +255,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
1F342D11C70C4597B5713902 /* [CP] Embed Pods Frameworks */,
- ACEB877A4FF050D5B02BD9F9 /* [CP] Copy Pods Resources */,
+ 6AA24D08C3DF3E0B10B1AE84 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -272,7 +275,7 @@
A2DF520F2716C91700204F07 /* Frameworks */,
A2DF52102716C91700204F07 /* Resources */,
A6E8EE0276D65A197F751858 /* [CP] Embed Pods Frameworks */,
- 874B1E5DDFFFAF8DA8696787 /* [CP] Copy Pods Resources */,
+ E16650957EA3675D6DBDF252 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -332,6 +335,7 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ DA0000021CF9000F007C117D /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -400,21 +404,21 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 874B1E5DDFFFAF8DA8696787 /* [CP] Copy Pods Resources */ = {
+ 6AA24D08C3DF3E0B10B1AE84 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-Runner-RunnerTests/Pods-Runner-RunnerTests-resources-${CONFIGURATION}-input-files.xcfilelist",
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-Runner-RunnerTests/Pods-Runner-RunnerTests-resources-${CONFIGURATION}-output-files.xcfilelist",
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner-RunnerTests/Pods-Runner-RunnerTests-resources.sh\"\n";
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
@@ -449,43 +453,43 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner-RunnerTests/Pods-Runner-RunnerTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- ACEB877A4FF050D5B02BD9F9 /* [CP] Copy Pods Resources */ = {
+ B2878DD7ABAFFBDED4E812A9 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
- name = "[CP] Copy Pods Resources";
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- B2878DD7ABAFFBDED4E812A9 /* [CP] Check Pods Manifest.lock */ = {
+ E16650957EA3675D6DBDF252 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner-RunnerTests/Pods-Runner-RunnerTests-resources-${CONFIGURATION}-input-files.xcfilelist",
);
- inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
- );
- name = "[CP] Check Pods Manifest.lock";
+ name = "[CP] Copy Pods Resources";
outputFileListPaths = (
- );
- outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ "${PODS_ROOT}/Target Support Files/Pods-Runner-RunnerTests/Pods-Runner-RunnerTests-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner-RunnerTests/Pods-Runner-RunnerTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -624,7 +628,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.usercentrics.sdk.usercentricsExample;
+ PRODUCT_BUNDLE_IDENTIFIER = com.usercentrics.sdk.mediation.test;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -757,7 +761,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.usercentrics.sdk.usercentricsExample;
+ PRODUCT_BUNDLE_IDENTIFIER = com.usercentrics.sdk.mediation.test;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -784,7 +788,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.usercentrics.sdk.usercentricsExample;
+ PRODUCT_BUNDLE_IDENTIFIER = com.usercentrics.sdk.mediation.test;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift
index 62666446..43280071 100644
--- a/example/ios/Runner/AppDelegate.swift
+++ b/example/ios/Runner/AppDelegate.swift
@@ -1,3 +1,5 @@
+// Firebase mediation: uncomment to enable. See example/README.md for setup instructions.
+// import FirebaseCore
import Flutter
import UIKit
@@ -7,6 +9,9 @@ import UIKit
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
+ // Firebase mediation: uncomment to enable. Place GoogleService-Info.plist in Runner/ first.
+ // See example/README.md for setup instructions.
+ // FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist
index 189e88d2..0f18f01b 100644
--- a/example/ios/Runner/Info.plist
+++ b/example/ios/Runner/Info.plist
@@ -2,6 +2,8 @@
+ FIREBASE_ANALYTICS_COLLECTION_ENABLED
+
CADisableMinimumFrameDurationOnPhone
CFBundleDevelopmentRegion
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 59112c02..c2944f10 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -7,6 +7,16 @@ import 'build_your_own_ui.dart';
import 'customization_example_1.dart';
import 'customization_example_2.dart';
+// Build-time flag — shows the consent mediation toggle when true.
+// Usage: flutter run --dart-define=MEDIATION_TEST=true
+// Omit (or false) for normal builds — safe to publish.
+const bool _kMediationTestEnabled =
+ bool.fromEnvironment('MEDIATION_TEST', defaultValue: true);
+
+// Settings ID for the sample app. When testing consent mediation this must be a
+// settings ID that has the target 3rd-party SDKs configured in the Usercentrics dashboard.
+const String _kSettingsId = 'Yi9N3aXia';
+
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
@@ -35,7 +45,6 @@ class HomePage extends StatefulWidget {
class HomePageState extends State {
_SdkStatus _sdkStatus = _SdkStatus.idle;
String? _statusMessage;
-
void _initializeUsercentrics() async {
setState(() {
_sdkStatus = _SdkStatus.loading;
@@ -44,8 +53,9 @@ class HomePageState extends State {
try {
Usercentrics.initialize(
- settingsId: 'Yi9N3aXia',
+ settingsId: _kSettingsId,
loggerLevel: UsercentricsLoggerLevel.debug,
+ consentMediation: _kMediationTestEnabled,
);
final status = await Usercentrics.status;
@@ -177,7 +187,6 @@ class HomePageState extends State {
),
),
),
- // ── END TEMPORARY ──────────────────────────────────────────────
const SizedBox(height: 16),
ElevatedButton(
onPressed: isSdkReady ? () => _showFirstLayer() : null,
diff --git a/example/pubspec.lock b/example/pubspec.lock
index db4e201f..25c147b9 100644
--- a/example/pubspec.lock
+++ b/example/pubspec.lock
@@ -111,10 +111,10 @@ packages:
dependency: transitive
description:
name: matcher
- sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
+ sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
url: "https://pub.dev"
source: hosted
- version: "0.12.18"
+ version: "0.12.19"
material_color_utilities:
dependency: transitive
description:
@@ -196,10 +196,10 @@ packages:
dependency: transitive
description:
name: test_api
- sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
+ sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
url: "https://pub.dev"
source: hosted
- version: "0.7.9"
+ version: "0.7.10"
usercentrics_sdk:
dependency: "direct main"
description:
diff --git a/pubspec.lock b/pubspec.lock
index fa4433ab..cee705ff 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -215,10 +215,10 @@ packages:
dependency: transitive
description:
name: matcher
- sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
+ sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
url: "https://pub.dev"
source: hosted
- version: "0.12.18"
+ version: "0.12.19"
material_color_utilities:
dependency: transitive
description:
@@ -380,26 +380,26 @@ packages:
dependency: "direct dev"
description:
name: test
- sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a"
+ sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7"
url: "https://pub.dev"
source: hosted
- version: "1.29.0"
+ version: "1.30.0"
test_api:
dependency: transitive
description:
name: test_api
- sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
+ sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
url: "https://pub.dev"
source: hosted
- version: "0.7.9"
+ version: "0.7.10"
test_core:
dependency: transitive
description:
name: test_core
- sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943"
+ sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51"
url: "https://pub.dev"
source: hosted
- version: "0.6.15"
+ version: "0.6.16"
typed_data:
dependency: transitive
description:
diff --git a/scripts/ios_unit_tests.sh b/scripts/ios_unit_tests.sh
index 5ef7da96..2fad2edb 100755
--- a/scripts/ios_unit_tests.sh
+++ b/scripts/ios_unit_tests.sh
@@ -4,6 +4,6 @@ rm -rf TestResults.xcresult
xcodebuild test -workspace 'Runner.xcworkspace' \
-scheme 'Runner' \
- -destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
+ -destination 'platform=iOS Simulator,name=iPhone 16' \
-enableCodeCoverage YES \
-resultBundlePath TestResults