diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index b04a798..a2afb50 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -26,6 +26,15 @@ android { compileSdk 34 namespace 'com.adobe.marketing.mobile.flutter.flutter_aepsdk_example' + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + lintOptions { disable 'InvalidPackage' } @@ -33,7 +42,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.adobe.marketing.mobile.flutter.flutter_aepsdk_example" - minSdkVersion 21 + minSdkVersion flutter.minSdkVersion targetSdkVersion 34 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/example/android/app/src/main/java/com/adobe/marketing/mobile/flutter/flutter_aepsdk_example/MainActivity.java b/example/android/app/src/main/java/com/adobe/marketing/mobile/flutter/flutter_aepsdk_example/MainActivity.java index 8020d3b..363362f 100644 --- a/example/android/app/src/main/java/com/adobe/marketing/mobile/flutter/flutter_aepsdk_example/MainActivity.java +++ b/example/android/app/src/main/java/com/adobe/marketing/mobile/flutter/flutter_aepsdk_example/MainActivity.java @@ -1,6 +1,6 @@ package com.adobe.marketing.mobile.flutter.flutter_aepsdk_example; -import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.android.FlutterFragmentActivity; -public class MainActivity extends FlutterActivity { +public class MainActivity extends FlutterFragmentActivity { } diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 2a3a460..3eed553 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Thu Apr 18 18:04:58 PDT 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/example/android/settings.gradle b/example/android/settings.gradle index d72a278..b9ac8d8 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -17,8 +17,8 @@ pluginManagement { } plugins { - id "com.android.application" version "8.2.2" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false + id "com.android.application" version "8.7.3" apply false + id "org.jetbrains.kotlin.android" version "2.1.0" apply false id "dev.flutter.flutter-plugin-loader" version "1.0.0" } diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 8c6e561..d57061d 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 12.0 + 13.0 diff --git a/example/ios/Podfile b/example/ios/Podfile index 2c068c4..10f3c9b 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '12.0' +platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 998c3d0..2c93aa8 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,33 +1,33 @@ PODS: - - AEPAssurance (5.0.1): + - AEPAssurance (5.0.2): - AEPCore (< 6.0.0, >= 5.0.0) - AEPServices (< 6.0.0, >= 5.0.0) - - AEPCore (5.4.0): + - AEPCore (5.7.0): - AEPRulesEngine (< 6.0.0, >= 5.0.0) - - AEPServices (< 6.0.0, >= 5.4.0) + - AEPServices (< 6.0.0, >= 5.7.0) - AEPEdge (5.0.3): - AEPCore (< 6.0.0, >= 5.3.1) - AEPEdgeIdentity (< 6.0.0, >= 5.0.0) - - AEPEdgeBridge (5.0.0): + - AEPEdgeBridge (5.1.0): - AEPCore (< 6.0.0, >= 5.0.0) - - AEPEdgeConsent (5.0.0): + - AEPEdgeConsent (5.0.1): - AEPCore (< 6.0.0, >= 5.0.0) - AEPEdge (< 6.0.0, >= 5.0.0) - AEPEdgeIdentity (5.0.0): - AEPCore (< 6.0.0, >= 5.0.0) - - AEPIdentity (5.4.0): - - AEPCore (< 6.0.0, >= 5.4.0) - - AEPLifecycle (5.4.0): - - AEPCore (< 6.0.0, >= 5.4.0) - - AEPMessaging (5.6.0): - - AEPCore (< 6.0.0, >= 5.3.0) + - AEPIdentity (5.7.0): + - AEPCore (< 6.0.0, >= 5.7.0) + - AEPLifecycle (5.7.0): + - AEPCore (< 6.0.0, >= 5.7.0) + - AEPMessaging (5.8.0): + - AEPCore (< 6.0.0, >= 5.6.0) - AEPEdge (< 6.0.0, >= 5.0.2) - AEPEdgeIdentity (< 6.0.0, >= 5.0.0) - - AEPServices (< 6.0.0, >= 5.3.0) + - AEPServices (< 6.0.0, >= 5.6.0) - AEPRulesEngine (5.0.0) - - AEPServices (5.4.0) - - AEPSignal (5.4.0): - - AEPCore (< 6.0.0, >= 5.4.0) + - AEPServices (5.7.0) + - AEPSignal (5.7.0): + - AEPCore (< 6.0.0, >= 5.7.0) - AEPUserProfile (5.0.0): - AEPCore (< 6.0.0, >= 5.0.0) - Flutter (1.0.0) @@ -108,20 +108,20 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_aepuserprofile/ios" SPEC CHECKSUMS: - AEPAssurance: df04baeace42befb0cc213fd6cdfe51651d11ba6 - AEPCore: 8cdc5390163f2b761e7f3eed1cae92b8a11c0237 + AEPAssurance: fedcd7ed72b431b5f310eb3a52921345c34c1051 + AEPCore: d1b0905c5a9531a883d9e8c31212ff61ca900be0 AEPEdge: 105afc7958acd7c016d57f7ac1d6f632bf05e6ee - AEPEdgeBridge: be78be4885ae420ef21bda91707d5eff9510ef70 - AEPEdgeConsent: d7db1d19eb4c1e2146360ed3c8df315f671b26d5 + AEPEdgeBridge: 2302555a67bf4677a903c42dedf9b3ab0dd941b9 + AEPEdgeConsent: 5f28a8ed6cd86812a73b1f5a4dbde9c81e486bf1 AEPEdgeIdentity: 3161ff33434586962946912d6b8e9e8fca1c4d23 - AEPIdentity: 44513e103592e8cc60508dde9f0b049c82897c07 - AEPLifecycle: 619ce7bf7b64a2caff7a172e9f12f0b6da636142 - AEPMessaging: 34d796c0a078c3e669b88150aae7dc468a308dcd + AEPIdentity: 1d491f04c11cbea9d94c6e2bc1b956b1264e3f42 + AEPLifecycle: da35d7393f0d635472719d292b9e4142123cb13c + AEPMessaging: 8018287b9504b8ab7ee8dc96d87e524c2f8e5a9f AEPRulesEngine: fe5800653a4bee07b1e41e61b4d5551f0dba557b - AEPServices: ce27e3f2de75a9b24b3d27c7b5f1bb519724f8cb - AEPSignal: 9b34890eea1b81714aa45b7d7f8deb82206b0ca2 + AEPServices: e1f14e286a8680cecbe0bcdf6ea47f46573635c4 + AEPSignal: 6e10c4d1dca8fb1ed8601cb4224ebd30fc241a59 AEPUserProfile: cf36305d683d993d528337a46b7a269029b63e5d - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 flutter_aepassurance: eec6156fe1f6324f05546b7df34f3f0d18187f71 flutter_aepcore: 5de99ca989c8f31c5a715ae5c2bf864b01518936 flutter_aepedge: 060db412454a60e1a970b3bdf649543c94a25fc0 @@ -131,6 +131,6 @@ SPEC CHECKSUMS: flutter_aepmessaging: a702f2691b29880d723aa0ff214a271fc6bdd381 flutter_aepuserprofile: c9c84653ece987b2ed5c9c8d49735c79aa362314 -PODFILE CHECKSUM: 4e8f8b2be68aeea4c0d5beb6ff1e79fface1d048 +PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b -COCOAPODS: 1.14.3 +COCOAPODS: 1.16.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 2617059..66abd9f 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -171,7 +171,6 @@ TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; - DevelopmentTeam = 66USX5VV9D; LastSwiftMigration = 1130; }; }; @@ -382,7 +381,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -398,14 +397,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 66USX5VV9D; + DEVELOPMENT_TEAM = FKGEE875K4; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -469,7 +468,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -518,7 +517,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -534,14 +533,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 66USX5VV9D; + DEVELOPMENT_TEAM = FKGEE875K4; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -566,14 +565,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 66USX5VV9D; + DEVELOPMENT_TEAM = FKGEE875K4; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/example/pubspec.lock b/example/pubspec.lock index 3614fc6..953803a 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -21,26 +21,26 @@ packages: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" cupertino_icons: dependency: "direct main" description: @@ -53,10 +53,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" flutter: dependency: "direct main" description: flutter @@ -110,7 +110,7 @@ packages: path: "../plugins/flutter_aepmessaging" relative: true source: path - version: "5.0.0" + version: "5.0.1" flutter_aepuserprofile: dependency: "direct main" description: @@ -127,34 +127,34 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" matcher: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -167,23 +167,23 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -196,18 +196,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: @@ -228,18 +228,18 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.6" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -249,5 +249,5 @@ packages: source: hosted version: "14.2.5" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.8.0-0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/plugins/flutter_aepcore/CHANGELOG.md b/plugins/flutter_aepcore/CHANGELOG.md index e44ec2c..c174567 100644 --- a/plugins/flutter_aepcore/CHANGELOG.md +++ b/plugins/flutter_aepcore/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.0.1 + +* Add `MobileCore.setApplication` call in Android FlutterPlugin's `onAttachedToEngine` to accurately register lifecycle callbacks for launcher activity. + ## 5.0.0 * Add `MobileCore.initializeWithAppId` and `MobileCore.initialize` APIs to simplify AEP SDK initialization by enabling automatic extension registration and lifecycle tracking. diff --git a/plugins/flutter_aepcore/android/src/main/java/com/adobe/marketing/mobile/flutter/flutter_aepcore/FlutterAEPCorePlugin.java b/plugins/flutter_aepcore/android/src/main/java/com/adobe/marketing/mobile/flutter/flutter_aepcore/FlutterAEPCorePlugin.java index 3e9a265..52c5db5 100644 --- a/plugins/flutter_aepcore/android/src/main/java/com/adobe/marketing/mobile/flutter/flutter_aepcore/FlutterAEPCorePlugin.java +++ b/plugins/flutter_aepcore/android/src/main/java/com/adobe/marketing/mobile/flutter/flutter_aepcore/FlutterAEPCorePlugin.java @@ -44,6 +44,21 @@ public void onAttachedToEngine(@NonNull final FlutterPluginBinding binding) { Context appContext = binding.getApplicationContext(); if (appContext instanceof Application) { application = (Application) appContext; + // Set the application early to register Activity lifecycle callbacks + // This ensures the SDK can track the current Activity for in-app messages + // Without this, the following will happen: + //1. Application.onCreate() + // ✗ No Activity lifecycle callbacks registered + // 2. MainActivity.onCreate() + // ✗ SDK doesn't know about it + // 3. MainActivity.onResume() + // ✗ SDK doesn't know this is current Activity + // 4. Flutter engine initializes + // 5. MobileCore.initialize() called from Flutter + // ↓ Might set Application context, but... + // ✗ MainActivity already went through lifecycle + // ✗ SDK missed the lifecycle events + MobileCore.setApplication(application); } MobileCore.setWrapperType(WrapperType.FLUTTER); flutterAEPIdentityPlugin.onAttachedToEngine(binding); diff --git a/plugins/flutter_aepcore/pubspec.yaml b/plugins/flutter_aepcore/pubspec.yaml index cfe9fab..ccd9b01 100644 --- a/plugins/flutter_aepcore/pubspec.yaml +++ b/plugins/flutter_aepcore/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_aepcore description: Official Adobe Experience Platform support for Flutter apps. The Mobile Core represents the core Adobe Experience Platform SDK that is required for every app implementation. -version: 5.0.0 +version: 5.0.1 homepage: https://developer.adobe.com/client-sdks repository: https://github.com/adobe/aepsdk-flutter/tree/main/plugins/flutter_aepcore diff --git a/plugins/flutter_aepmessaging/CHANGELOG.md b/plugins/flutter_aepmessaging/CHANGELOG.md index c24d7ce..7abe100 100644 --- a/plugins/flutter_aepmessaging/CHANGELOG.md +++ b/plugins/flutter_aepmessaging/CHANGELOG.md @@ -1,3 +1,6 @@ +## 5.0.1 +* Add a timeout to the call made from native bridge to custom messaging delegate to allow showing the in-app message if no delegate is provided by the app developer. + ## 5.0.0 * Update to use BOM [(Bill of Materials)](https://central.sonatype.com/artifact/com.adobe.marketing.mobile/sdk-bom) for Android SDK dependencies. diff --git a/plugins/flutter_aepmessaging/android/build.gradle b/plugins/flutter_aepmessaging/android/build.gradle index bc43e5d..2adc2ed 100644 --- a/plugins/flutter_aepmessaging/android/build.gradle +++ b/plugins/flutter_aepmessaging/android/build.gradle @@ -37,8 +37,8 @@ android { kotlinOptions { jvmTarget = '1.8' - languageVersion = "1.4" - apiVersion = "1.4" + languageVersion = "1.6" + apiVersion = "1.6" } sourceSets { @@ -49,6 +49,7 @@ android { minSdkVersion 21 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } + lintOptions { disable 'InvalidPackage' } diff --git a/plugins/flutter_aepmessaging/android/src/main/kotlin/com/adobe/marketing/mobile/flutter/flutter_aepmessaging/FlutterAEPMessagingDelegate.kt b/plugins/flutter_aepmessaging/android/src/main/kotlin/com/adobe/marketing/mobile/flutter/flutter_aepmessaging/FlutterAEPMessagingDelegate.kt index 05d50fc..dc2bb68 100644 --- a/plugins/flutter_aepmessaging/android/src/main/kotlin/com/adobe/marketing/mobile/flutter/flutter_aepmessaging/FlutterAEPMessagingDelegate.kt +++ b/plugins/flutter_aepmessaging/android/src/main/kotlin/com/adobe/marketing/mobile/flutter/flutter_aepmessaging/FlutterAEPMessagingDelegate.kt @@ -1,17 +1,18 @@ package com.adobe.marketing.mobile.flutter.flutter_aepmessaging +import android.os.Handler +import android.os.Looper import com.adobe.marketing.mobile.Message import com.adobe.marketing.mobile.messaging.MessagingUtils import com.adobe.marketing.mobile.services.ui.* -import io.flutter.embedding.android.FlutterActivity import io.flutter.plugin.common.MethodChannel import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit class FlutterAEPMessagingDelegate( private var cache: MutableMap, private var channel: MethodChannel -) : FlutterActivity(), PresentationDelegate { - var shouldShowMessage = true +): PresentationDelegate { override fun onDismiss(presentable: Presentable<*>) { if (presentable.getPresentation() !is InAppMessage) return @@ -22,7 +23,9 @@ class FlutterAEPMessagingDelegate( msg["id"] = message.id msg["autoTrack"] = message.autoTrack data["message"] = msg - channel.invokeMethod("onDismiss", data) + Handler(Looper.getMainLooper()).post { + channel.invokeMethod("onDismiss", data) + } } } @@ -35,7 +38,9 @@ class FlutterAEPMessagingDelegate( msg["id"] = message.id msg["autoTrack"] = message.autoTrack data["message"] = msg - channel.invokeMethod("onShow", data) + Handler(Looper.getMainLooper()).post { + channel.invokeMethod("onShow", data) + } } } @@ -48,51 +53,91 @@ class FlutterAEPMessagingDelegate( msg["id"] = message.id msg["autoTrack"] = message.autoTrack data["message"] = msg - channel.invokeMethod("onHide", data) + Handler(Looper.getMainLooper()).post { + channel.invokeMethod("onHide", data) + } } } override fun canShow(presentable: Presentable<*>): Boolean { if (presentable.getPresentation() !is InAppMessage) return false val message = MessagingUtils.getMessageForPresentable(presentable as Presentable) - val latch = CountDownLatch(2) if (message != null) { + var shouldSave = true // Default to true for fallback + var shouldShow = true // Default to true for fallback + val latch1 = CountDownLatch(1) + val latch2 = CountDownLatch(1) + val data = HashMap() val msg = HashMap() msg["id"] = message.id msg["autoTrack"] = message.autoTrack data["message"] = msg - runOnUiThread { + Handler(Looper.getMainLooper()).post { channel.invokeMethod("shouldSaveMessage", data, object : MethodChannel.Result { override fun success(result: Any?) { - if (result as Boolean) { - cache[message.id] = message - latch.countDown() + if (result is Boolean) { + shouldSave = result } + // If no Flutter handler is registered, result will be notImplemented + // In that case, we keep the default shouldSave = true + latch1.countDown() } - override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {} + override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) { + latch1.countDown() + } - override fun notImplemented() {} + override fun notImplemented() { + // Flutter handler not registered, use fallback + latch1.countDown() + } }) + } + // Wait with timeout - if Flutter handler isn't available, don't wait forever + if (!latch1.await(500, TimeUnit.MILLISECONDS)) { + // Timeout occurred - Flutter handler likely not registered, use fallback + shouldSave = true + } + + // Cache the message if shouldSave is true (either from Flutter or fallback) + if (shouldSave) { + cache[message.id] = message + } + + Handler(Looper.getMainLooper()).post { channel.invokeMethod("shouldShowMessage", data, object : MethodChannel.Result { override fun success(result: Any?) { - shouldShowMessage = result as Boolean - latch.countDown() + if (result is Boolean) { + shouldShow = result + } + // If no Flutter handler is registered, keep the default shouldShow = true + latch2.countDown() } - override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {} + override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) { + latch2.countDown() + } - override fun notImplemented() {} + override fun notImplemented() { + // Flutter handler not registered, use fallback + latch2.countDown() + } }) } - } - latch.await() - return shouldShowMessage + // Wait with timeout for shouldShowMessage + if (!latch2.await(500, TimeUnit.MILLISECONDS)) { + // Timeout occurred - Flutter handler likely not registered, use fallback + shouldShow = true + } + + return shouldShow + } + return true } override fun onContentLoaded(presentable: Presentable<*>, presentationContent: PresentationListener.PresentationContent?) { @@ -102,7 +147,9 @@ class FlutterAEPMessagingDelegate( val data = HashMap() data["id"] = message.id data["autoTrack"] = message.autoTrack - channel.invokeMethod("onContentLoaded", data) + Handler(Looper.getMainLooper()).post { + channel.invokeMethod("onContentLoaded", data) + } } } } \ No newline at end of file diff --git a/plugins/flutter_aepmessaging/ios/Classes/SwiftFlutterAEPMessagingPlugin.swift b/plugins/flutter_aepmessaging/ios/Classes/SwiftFlutterAEPMessagingPlugin.swift index 544fa5c..fd45fb0 100644 --- a/plugins/flutter_aepmessaging/ios/Classes/SwiftFlutterAEPMessagingPlugin.swift +++ b/plugins/flutter_aepmessaging/ios/Classes/SwiftFlutterAEPMessagingPlugin.swift @@ -185,14 +185,16 @@ public class SwiftFlutterAEPMessagingPlugin: NSObject, FlutterPlugin, MessagingD if let fullscreenMessage = message as? FullscreenMessage, let parentMessage = fullscreenMessage.parent { - channel.invokeMethod( - "onDismiss", - arguments: [ - "message": dataBridge.transformToFlutterMessage( - message: parentMessage - ) - ] - ) + DispatchQueue.main.async { + self.channel.invokeMethod( + "onDismiss", + arguments: [ + "message": self.dataBridge.transformToFlutterMessage( + message: parentMessage + ) + ] + ) + } } } @@ -200,14 +202,16 @@ public class SwiftFlutterAEPMessagingPlugin: NSObject, FlutterPlugin, MessagingD if let fullscreenMessage = message as? FullscreenMessage, let parentMessage = fullscreenMessage.parent { - channel.invokeMethod( - "onShow", - arguments: [ - "message": dataBridge.transformToFlutterMessage( - message: parentMessage - ) - ] - ) + DispatchQueue.main.async { + self.channel.invokeMethod( + "onShow", + arguments: [ + "message": self.dataBridge.transformToFlutterMessage( + message: parentMessage + ) + ] + ) + } } } @@ -215,43 +219,66 @@ public class SwiftFlutterAEPMessagingPlugin: NSObject, FlutterPlugin, MessagingD if let fullscreenMessage = message as? FullscreenMessage, let incomingMessage = fullscreenMessage.parent { - var shouldShow = true + var shouldSave = true // Default to true for fallback + var shouldShow = true // Default to true for fallback let semaphore = DispatchSemaphore(value: 0) - channel.invokeMethod( - "shouldSaveMessage", - arguments: [ - "message": dataBridge.transformToFlutterMessage( - message: incomingMessage - ) - ], - result: { (result: Any?) -> Void in - if let shouldSaveMessage = result as? Bool { - if shouldSaveMessage { - self.messageCache[incomingMessage.id] = incomingMessage + let timeout = DispatchTime.now() + .milliseconds(500) // 500ms timeout + + DispatchQueue.main.async { + self.channel.invokeMethod( + "shouldSaveMessage", + arguments: [ + "message": self.dataBridge.transformToFlutterMessage( + message: incomingMessage + ) + ], + result: { (result: Any?) -> Void in + if let shouldSaveMessage = result as? Bool { + shouldSave = shouldSaveMessage } + // If no Flutter handler is registered, result will be FlutterMethodNotImplemented + // In that case, we keep the default shouldSave = true + semaphore.signal() } - semaphore.signal() - } - ) + ) + } - semaphore.wait() + // Wait with timeout - if Flutter handler isn't available, don't wait forever + if semaphore.wait(timeout: timeout) == .timedOut { + // Timeout occurred - Flutter handler likely not registered, use fallback + shouldSave = true + } + + // Cache the message if shouldSave is true (either from Flutter or fallback) + if shouldSave { + self.messageCache[incomingMessage.id] = incomingMessage + } - channel.invokeMethod( - "shouldShowMessage", - arguments: [ - "message": dataBridge.transformToFlutterMessage( - message: incomingMessage - ) - ], - result: { (result: Any?) -> Void in - if let shouldShowMessage = result as? Bool { - shouldShow = shouldShowMessage + let semaphore2 = DispatchSemaphore(value: 0) + DispatchQueue.main.async { + self.channel.invokeMethod( + "shouldShowMessage", + arguments: [ + "message": self.dataBridge.transformToFlutterMessage( + message: incomingMessage + ) + ], + result: { (result: Any?) -> Void in + if let shouldShowMessage = result as? Bool { + shouldShow = shouldShowMessage + } + // If no Flutter handler is registered, keep the default shouldShow = true + semaphore2.signal() } - semaphore.signal() - } - ) + ) + } - semaphore.wait() + // Wait with timeout for shouldShowMessage + if semaphore2.wait(timeout: timeout) == .timedOut { + // Timeout occurred - Flutter handler likely not registered, use fallback + shouldShow = true + } + return shouldShow } return true @@ -261,15 +288,17 @@ public class SwiftFlutterAEPMessagingPlugin: NSObject, FlutterPlugin, MessagingD if let fullscreenMessage = message as? FullscreenMessage, let parentMessage = fullscreenMessage.parent { - channel.invokeMethod( - "urlLoaded", - arguments: [ - "url": url.absoluteString, - "message": dataBridge.transformToFlutterMessage( - message: parentMessage - ), - ] - ) + DispatchQueue.main.async { + self.channel.invokeMethod( + "urlLoaded", + arguments: [ + "url": url.absoluteString, + "message": self.dataBridge.transformToFlutterMessage( + message: parentMessage + ), + ] + ) + } } } } diff --git a/plugins/flutter_aepmessaging/pubspec.yaml b/plugins/flutter_aepmessaging/pubspec.yaml index 0688a0a..c16a5b3 100644 --- a/plugins/flutter_aepmessaging/pubspec.yaml +++ b/plugins/flutter_aepmessaging/pubspec.yaml @@ -1,7 +1,7 @@ name: flutter_aepmessaging description: Official Adobe Experience Platform support for Flutter apps. The Experience Platform Messaging extension enables handling of user push an in-app messages from a mobile app when using the Adobe Experience Platform SDK. -version: 5.0.0 +version: 5.0.1 homepage: https://aep-sdks.gitbook.io/docs/ repository: https://github.com/adobe/aepsdk_flutter/tree/main/plugins/flutter_aepmessaging