Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 8 additions & 14 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ if (localPropertiesFile.exists()) {
}
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
Expand All @@ -28,16 +23,16 @@ if (flutterVersionName == null) {
}

android {
namespace 'com.usercentrics.sdk.flutter_example'
compileSdk 35
namespace "com.usercentrics.sdk.flutter_example"
compileSdk 36

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}

kotlinOptions {
jvmTarget = '1.8'
jvmTarget = '17'
}

sourceSets {
Expand All @@ -46,8 +41,8 @@ android {

defaultConfig {
applicationId "com.usercentrics.sdk.flutter_example"
minSdkVersion 21 // webview_flutter requirement
targetSdkVersion 31
minSdk flutter.minSdkVersion
targetSdk 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true
Expand All @@ -66,6 +61,5 @@ flutter {
}

dependencies {
implementation "androidx.multidex:multidex:$multidex_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "androidx.multidex:multidex:2.0.1"
}
6 changes: 3 additions & 3 deletions example/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ pluginManagement {

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.3.2" apply false
id "com.android.library" version "8.3.2" apply false
id "org.jetbrains.kotlin.android" version "1.9.24" apply false
id "com.android.application" version "8.6.0" apply false
id "com.android.library" version "8.6.0" apply false
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
}

include ':app'
2 changes: 1 addition & 1 deletion example/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import UIKit
import Flutter

@UIApplicationMain
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
Expand Down
168 changes: 109 additions & 59 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,9 @@ void main() {
runApp(const MyApp());
}

class MyApp extends StatefulWidget {
class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();

_initializeUsercentrics();
}

void _initializeUsercentrics() {
/// Initialize Usercentrics with your configuration only once.
/// We should not call `initialize` directly inside [build].
Usercentrics.initialize(
settingsId: 'Yi9N3aXia',
loggerLevel: UsercentricsLoggerLevel.debug,
);
}

@override
Widget build(BuildContext context) {
return const MaterialApp(
Expand All @@ -43,6 +22,8 @@ class _MyAppState extends State<MyApp> {
}
}

enum _SdkStatus { idle, loading, ready, error }

class HomePage extends StatefulWidget {
const HomePage({super.key});

Expand All @@ -51,23 +32,39 @@ class HomePage extends StatefulWidget {
}

class HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
_showCMPIfNeeded();
}
_SdkStatus _sdkStatus = _SdkStatus.idle;
String? _statusMessage;

void _initializeUsercentrics() async {
setState(() {
_sdkStatus = _SdkStatus.loading;
_statusMessage = null;
});

void _showCMPIfNeeded() async {
try {
Usercentrics.initialize(
settingsId: 'Yi9N3aXia',
loggerLevel: UsercentricsLoggerLevel.debug,
);

final status = await Usercentrics.status;

setState(() {
_sdkStatus = _SdkStatus.ready;
_statusMessage =
'SDK ready. shouldCollectConsent: ${status.shouldCollectConsent}';
});

if (status.shouldCollectConsent) {
_showFirstLayer();
} else {
applyConsent(status.consents);
}
} catch (error) {
// Handle non-localized error
setState(() {
_sdkStatus = _SdkStatus.error;
_statusMessage = error.toString();
});
}
}

Expand Down Expand Up @@ -126,71 +123,124 @@ class HomePageState extends State<HomePage> {
default:
return const BannerSettings(/* Default Settings */);
}

// 'Activate with third-party tool' option
// final selectedVariant = WhateverTool.getABTestingVariant();
// switch (variant) {
// case "variantA":
// return const BannerSettings(variantName: "variantA");
// case "variantB":
// return const BannerSettings(variantName: "variantB");
// default:
// return const BannerSettings();
// }
}

@override
Widget build(BuildContext context) {
final bool isSdkReady = _sdkStatus == _SdkStatus.ready;

return Scaffold(
appBar: AppBar(
title: const Text('Usercentrics Flutter Sample'),
),
body: Padding(
padding: const EdgeInsets.all(50.0),
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
color: _statusColor,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'SDK status: ${_sdkStatus.name.toUpperCase()}',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 13,
),
),
if (_statusMessage != null) ...[
const SizedBox(height: 6),
Text(
_statusMessage!,
style: const TextStyle(fontSize: 12),
),
],
const SizedBox(height: 12),
ElevatedButton(
onPressed: _sdkStatus == _SdkStatus.loading
? null
: _initializeUsercentrics,
child: _sdkStatus == _SdkStatus.loading
? const SizedBox(
height: 16,
width: 16,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Text('Initialize SDK'),
),
],
),
),
),
// ── END TEMPORARY ──────────────────────────────────────────────
const SizedBox(height: 16),
ElevatedButton(
onPressed: () => _showFirstLayer(),
onPressed: isSdkReady ? () => _showFirstLayer() : null,
child: const Text("Show First Layer"),
),
ElevatedButton(
onPressed: () => _showSecondLayer(),
onPressed: isSdkReady ? () => _showSecondLayer() : null,
child: const Text("Show Second Layer"),
),
ElevatedButton(
onPressed: () => _showFirstLayer(
settings: bannerSettingsCustomizationExample1,
),
onPressed: isSdkReady
? () => _showFirstLayer(
settings: bannerSettingsCustomizationExample1,
)
: null,
child: const Text("Customization Example 1"),
),
ElevatedButton(
onPressed: () => _showFirstLayer(
settings: bannerSettingsCustomizationExample2,
),
onPressed: isSdkReady
? () => _showFirstLayer(
settings: bannerSettingsCustomizationExample2,
)
: null,
child: const Text("Customization Example 2"),
),
ElevatedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => const CustomUIPage()),
),
onPressed: isSdkReady
? () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const CustomUIPage()),
)
: null,
child: const Text("Custom UI"),
),
ElevatedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const WebViewIntegrationPage()),
),
onPressed: isSdkReady
? () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const WebViewIntegrationPage()),
)
: null,
child: const Text("Webview Integration"),
),
],
),
),
);
}

Color get _statusColor {
switch (_sdkStatus) {
case _SdkStatus.idle:
return Colors.grey.shade200;
case _SdkStatus.loading:
return Colors.blue.shade50;
case _SdkStatus.ready:
return Colors.green.shade100;
case _SdkStatus.error:
return Colors.red.shade100;
}
}
}

void applyConsent(List<UsercentricsServiceConsent>? consents) {
Expand Down
7 changes: 6 additions & 1 deletion lib/src/internal/platform/method_channel_usercentrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,12 @@ class MethodChannelUsercentrics extends UsercentricsPlatform {
isReadyCompleter = Completer();

if (ongoingInit != null) {
await ongoingInit.future;
try {
await ongoingInit.future;
} catch (error, stackTrace) {
debugPrint(
'Usercentrics: Initialization failed, retrying. Error: $error\n$stackTrace');
}
}

try {
Expand Down
9 changes: 7 additions & 2 deletions test/internal/bridge/fake_is_ready_bridge.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import 'package:usercentrics_sdk/src/internal/bridge/bridge.dart';
import 'package:usercentrics_sdk/src/model/ready_status.dart';

class FakeIsReadyBridge extends IsReadyBridge {
FakeIsReadyBridge({this.invokeAnswer, this.shouldFailInitialization = false});
FakeIsReadyBridge({
this.invokeAnswer,
this.shouldFailInitialization = false,
this.failFirstNTimes = 0,
});

final UsercentricsReadyStatus? invokeAnswer;
final bool shouldFailInitialization;
final int failFirstNTimes;

var invokeCount = 0;
MethodChannel? invokeChannelArgument;
Expand All @@ -18,7 +23,7 @@ class FakeIsReadyBridge extends IsReadyBridge {
invokeCount++;
invokeChannelArgument = channel;

if (shouldFailInitialization) {
if (shouldFailInitialization || invokeCount <= failFirstNTimes) {
throw PlatformException(
code: 'usercentrics_flutter_isReady_error',
message: 'Failed to initialize',
Expand Down
Loading
Loading