diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 38587093..cc3c0faa 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,6 +7,8 @@ assignees: '' --- +Keep the template and provide all requested information: + **Describe the bug** A clear and concise description of what the bug is. @@ -23,15 +25,15 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. -**Smartphone (Please complete the following information. remove session if not platform):** +**Mobile (Please complete the following information. remove session if not Mobile):** - Flutter: version: [e.g. 2.2.3] - - Package version: [e.g. 3.3.0] + - flutter_branch_sdk version: [e.g. 3.3.0] - OS: [e.g. iOS16.0, Android 12] - Device: [e.g. iPhone14, Google Pixel] -**Web (please complete the following information. remove session if not platform):** +**Web (please complete the following information. remove session if not is Web:** - Flutter: version: [e.g. 2.2.3] - - Package version: [e.g. 3.3.0] + - flutter_branch_sdk version: [e.g. 3.3.0] - OS: [e.g. Windows, Mac, Linux] - Browser [e.g. chrome, safari, edge] - Version [e.g. 22] diff --git a/.github/workflows/deploy-apk.yaml b/.github/workflows/deploy-apk.yaml index cf07e2e5..d516e7f8 100644 --- a/.github/workflows/deploy-apk.yaml +++ b/.github/workflows/deploy-apk.yaml @@ -34,7 +34,7 @@ jobs: run: chmod +x tool/build-apk.sh - name: Install dependencies & Build apk run: tool/build-apk.sh - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: release-apk path: ./example/build/app/outputs/apk/release/app-release.apk diff --git a/.gitignore b/.gitignore index 2ddde2a5..09309ec5 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,4 @@ !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +/ios/flutter_branch_sdk/.build diff --git a/CHANGELOG.md b/CHANGELOG.md index 46db99ef..a81c4826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,38 @@ +## 8.3.0 +### ⚠️ BREAKING CHANGE +* Minimum required Dart SDK version 3.3.0 (Flutter 3.19.0 - 15/02/2024) + +### 🎉 Features +* New Methods: + - `setConsumerProtectionAttributionLevel` - Sets the consumer protection attribution level. Read Branch documentation for details: + * [Introducing Consumer Protection Preference Levels](https://help.branch.io/using-branch/changelog/introducing-consumer-protection-preference-levels) + * [Consumer Protection Preferences](https://help.branch.io/developers-hub/docs/consumer-protection-preferences) + +#### Deprecated / Removed +* `FlutterBranchSdk.disableTracking()`. Use `FlutterBranchSdk.setConsumerProtectionAttributionLevel()`. +* Removed `initSession` method. + +### Native SDK Updates +### 🔧 Native SDK Updates +* Updated included iOS SDK to 3.7.0 - [iOS Version History](https://github.com/BranchMetrics/ios-branch-deep-linking-attribution/releases) +* Updated included Branch Android SDK to 5.15.0 - [Android Version History](https://github.com/BranchMetrics/android-branch-deep-linking-attribution/releases) + +## 8.2.0 +### ⚠️ BREAKING CHANGE +* Minimum required Dart SDK version 3.3.0 (Flutter 3.19.0 - 15/02/2024) + +### 🎉 Features +* Issue #361: Migrate to dart:js_interop to support Webassamebly. Thanks @hnvn + +## 8.1.1 +### 🐛 Bug Fixes +* Fix issue #368: "-118, Warning. Session initialization already happened" triggered in the listSession callback + +## 8.1.0 +### 🔧 Native SDK Updates +* Updated included iOS SDK to 3.6.0 - [iOS Version History](https://github.com/BranchMetrics/ios-branch-deep-linking-attribution/releases) +* Updated included Branch Android SDK to 5.12.2 - [Android Version History](https://github.com/BranchMetrics/android-branch-deep-linking-attribution/releases) + ## 8.0.4 ### ⚠️ BREAKING CHANGE This is a major release which contains breaking API changes. @@ -62,7 +97,6 @@ This is a major release which contains breaking API changes. ### 🔧 Native SDK Updates * Updated included iOS SDK to 3.4.3 - [iOS Version History](https://github.com/BranchMetrics/ios-branch-deep-linking-attribution/releases) - * Updated included Branch Android SDK to 5.12.0 - [Android Version History](https://github.com/BranchMetrics/android-branch-deep-linking-attribution/releases) diff --git a/README.md b/README.md index 319f2e27..74c26804 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ Branch.io helps mobile apps grow with deep links that power referral systems, sh Supports Android, iOS and Web. -* Android - Branch SDK Version >= 5.12.0 [Android Version History](https://github.com/BranchMetrics/android-branch-deep-linking-attribution/releases) -* iOS - Branch SDK Version >= 3.4.3 [iOS Version History](https://github.com/BranchMetrics/ios-branch-deep-linking-attribution/releases) +* Android - Branch SDK Version >= 5.15.0 [Android Version History](https://github.com/BranchMetrics/android-branch-deep-linking-attribution/releases) +* iOS - Branch SDK Version >= 3.7.0 [iOS Version History](https://github.com/BranchMetrics/ios-branch-deep-linking-attribution/releases) Implemented functions in plugin: @@ -159,7 +159,16 @@ await FlutterBranchSdk.init(enableLogging: false, disableTracking: false); The optional parameters are: - *enableLogging* : Sets `true` turn on debug logging. Default value: false -- *disableTracking*: Sets `true` to disable tracking in Branch SDK for GDPR compliant on start. Default value: false +- *disableTracking*: Sets `true` to disable tracking in Branch SDK for GDPR compliant on start. Default value: false +- *branchAttributionLevel* : The level of attribution data to collect. + - `BranchAttributionLevel.FULL`: Full Attribution (Default) + - `BranchAttributionLevel.REDUCE`: Reduced Attribution (Non-Ads + Privacy Frameworks) + - `BranchAttributionLevel.MINIMAL`: Minimal Attribution - Analytics Only + - `BranchAttributionLevel.NONE`: No Attribution - No Analytics (GDPR, CCPA) + + Read Branch documentation for details: [Introducing Consumer Protection Preference Levels](https://help.branch.io/using-branch/changelog/introducing-consumer-protection-preference-levels) and [Consumer Protection Preferences](https://help.branch.io/developers-hub/docs/consumer-protection-preferences) + +*Note: The `disableTracking` parameter is deprecated and should no longer be used. Please use `branchAttributionLevel` to control tracking behavior.* Initialization must be called from `main` or at any time, for example after getting consent for GPDR. @@ -531,7 +540,7 @@ FlutterBranchSdk.logout(); bool isUserIdentified = await FlutterBranchSdk.isUserIdentified(); ``` -### Enable or Disable User Tracking +### Enable or Disable User Tracking (Deprecated. Read Consumer Preference Levels) If you need to comply with a user's request to not be tracked for GDPR purposes, or otherwise determine that a user should not be tracked, utilize this field to prevent Branch from sending network requests. This setting can also be enabled across all users for a particular link, or across your Branch links. ```dart @@ -544,6 +553,35 @@ You can choose to call this throughout the lifecycle of the app. Once called, ne More information [here](https://help.branch.io/developers-hub/docs/honoring-opt-out-of-processing-requests) +### Consumer Preference Levels +Sets the consumer protection attribution level: + +* `BranchAttributionLevel.FULL`: Full Attribution (Default) + +```dart + FlutterBranchSdk.setConsumerProtectionAttributionLevel(BranchAttributionLevel.FULL); +``` +* `BranchAttributionLevel.REDUCE`: Reduced Attribution (Non-Ads + Privacy Frameworks) + +```dart + FlutterBranchSdk.setConsumerProtectionAttributionLevel(BranchAttributionLevel.REDUCED); +``` +* `BranchAttributionLevel.MINIMAL`: Minimal Attribution - Analytics + +```dart + FlutterBranchSdk.setConsumerProtectionAttributionLevel(BranchAttributionLevel.MINIMAL); +``` +* `BranchAttributionLevel.NONE`: No Attribution - No Analytics (GDPR, CCPA) + +```dart + FlutterBranchSdk.setConsumerProtectionAttributionLevel(BranchAttributionLevel.NONE); +``` +Read Branch documentation for details: + +- [Introducing Consumer Protection Preference Levels](https://help.branch.io/using-branch/changelog/introducing-consumer-protection-preference-levels) +- [Consumer Protection Preferences](https://help.branch.io/developers-hub/docs/consumer-protection-preferences) + + ### Set Request Meta data Add key value pairs to all requests @@ -634,6 +672,7 @@ adUserDataUsageConsent | Boolean | Whether end user has granted or denied consen When parameters are successfully set using `setDMAParamsForEEA`, they will be sent along with every future request to the following Branch endpoint. + # Configuring the project to use Branch Test Key ## Android @@ -694,11 +733,29 @@ Practices to avoid: 3. Don't wait to initialize the object until you conveniently need a link. 4. Don't create many objects at once and register views in a for loop. -# Deep links with Short Links -More information [here](https://help.branch.io/using-branch/docs/creating-a-deep-link#short-links) +# Create Deep Links +* Deep links with [Short Links](https://help.branch.io/using-branch/docs/creating-a-deep-link#short-links) +* Deep links with [Long links](https://help.branch.io/using-branch/docs/creating-a-deep-link#long-links) + +# Data Privacy +* [Introducing Consumer Protection Preference Levels] (https://help.branch.io/using-branch/changelog/introducing-consumer-protection-preference-levels) +* [Consumer Protection Preferences](https://help.branch.io/developers-hub/docs/consumer-protection-preferences) +* [Answering the App Store Connect Privacy Questions](https://help.branch.io/using-branch/docs/answering-the-app-store-connect-privacy-questions) +* [Answering the Google Play Store Privacy Questions](https://help.branch.io/using-branch/docs/answering-the-google-play-store-privacy-questions) + + + +# SDK FAQs +* [Android SDK FAQs](https://help.branch.io/faq/docs/android-sdk) +* [iOS SDK FAQs](https://help.branch.io/faq/docs/ios-sdk) + +# Testing +* [Android Testing](https://help.branch.io/developers-hub/docs/android-testing) +* [iOS Testing](https://help.branch.io/developers-hub/docs/ios-testing) -# Deep links with Long links -More information [here](https://help.branch.io/using-branch/docs/creating-a-deep-link#long-links) +# Troubleshooting +* [Android Troubleshooting](https://help.branch.io/developers-hub/docs/android-troubleshooting) +* [iOS Troubleshooting](https://help.branch.io/developers-hub/docs/ios-troubleshooting) # Branch Documentation Read the iOS or Android documentation for all Branch object parameters: diff --git a/analysis_options.yaml b/analysis_options.yaml index 8eed5e63..4eb147ce 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -4,4 +4,6 @@ include: package:flutter_lints/flutter.yaml # https://dart.dev/guides/language/analysis-options linter: rules: - constant_identifier_names: false \ No newline at end of file + constant_identifier_names: false + # public_member_api_docs: true + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule diff --git a/android/build.gradle b/android/build.gradle index ed301c1b..f3575a81 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -15,7 +15,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.3.1' + classpath 'com.android.tools.build:gradle:8.1.4' } } @@ -38,22 +38,23 @@ android { buildConfig = true } + compileSdk 35 + defaultConfig { minSdkVersion 21 - compileSdk 34 buildConfigField("String", "FBRANCH_VERSION", "\"${getPackageVersion()}\"") } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } dependencies { - implementation 'io.branch.sdk.android:library:5.12.+' - implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' - implementation 'androidx.lifecycle:lifecycle-runtime:2.7.0' + implementation 'io.branch.sdk.android:library:5.15.+' + implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0' + implementation 'androidx.lifecycle:lifecycle-runtime:2.8.7' implementation 'androidx.browser:browser:1.8.0' implementation "store.galaxy.samsung.installreferrer:samsung_galaxystore_install_referrer:4.0.0" } \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index 7d49f31d..989ef1a9 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,2 +1 @@ rootProject.name = 'flutter_branch_sdk' -android.defaults.buildfeatures.buildconfig=true diff --git a/android/src/main/java/br/com/rsmarques/flutter_branch_sdk/FlutterBranchSdkPlugin.java b/android/src/main/java/br/com/rsmarques/flutter_branch_sdk/FlutterBranchSdkPlugin.java index ea1a6bd1..795e55e1 100644 --- a/android/src/main/java/br/com/rsmarques/flutter_branch_sdk/FlutterBranchSdkPlugin.java +++ b/android/src/main/java/br/com/rsmarques/flutter_branch_sdk/FlutterBranchSdkPlugin.java @@ -10,6 +10,7 @@ import android.os.Looper; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.json.JSONException; import org.json.JSONObject; @@ -25,6 +26,7 @@ import io.branch.referral.Branch; import io.branch.referral.BranchError; import io.branch.referral.BranchLogger; +import io.branch.referral.Defines; import io.branch.referral.QRCode.BranchQRCode; import io.branch.referral.ServerRequestGetLATD; import io.branch.referral.util.BranchEvent; @@ -50,18 +52,63 @@ public class FlutterBranchSdkPlugin implements FlutterPlugin, MethodCallHandler, private static final String DEBUG_NAME = "FlutterBranchSDK"; private static final String MESSAGE_CHANNEL = "flutter_branch_sdk/message"; private static final String EVENT_CHANNEL = "flutter_branch_sdk/event"; - private Activity activity; - private Context context; - private ActivityPluginBinding activityPluginBinding; - private EventSink eventSink = null; - private Map sessionParams = null; - private BranchError initialError = null; private final FlutterBranchSdkHelper branchSdkHelper = new FlutterBranchSdkHelper(); private final JSONObject requestMetadata = new JSONObject(); private final JSONObject facebookParameters = new JSONObject(); private final JSONObject snapParameters = new JSONObject(); private final ArrayList preInstallParameters = new ArrayList(); private final ArrayList campaingParameters = new ArrayList(); + private Activity activity; + private Context context; + private ActivityPluginBinding activityPluginBinding; + private EventSink eventSink = null; + private Map sessionParams = null; + private BranchError initialError = null; + /** + * --------------------------------------------------------------------------------------------- + * Branch SDK Call Methods + * -------------------------------------------------------------------------------------------- + **/ + private final Branch.BranchReferralInitListener branchReferralInitListener = new + Branch.BranchReferralInitListener() { + @Override + public void onInitFinished(JSONObject params, BranchError error) { + LogUtils.debug(DEBUG_NAME, "triggered onInitFinished"); + if (error == null) { + LogUtils.debug(DEBUG_NAME, "BranchReferralInitListener - params: " + params.toString()); + try { + sessionParams = branchSdkHelper.paramsToMap(params); + } catch (JSONException e) { + LogUtils.debug(DEBUG_NAME, "BranchReferralInitListener - error to Map: " + e.getLocalizedMessage()); + return; + } + if (eventSink != null) { + eventSink.success(sessionParams); + sessionParams = null; + } + } else if (error.getErrorCode() == BranchError.ERR_BRANCH_ALREADY_INITIALIZED) { + LogUtils.debug(DEBUG_NAME, "BranchReferralInitListener : " + error.getMessage()); + try { + sessionParams = branchSdkHelper.paramsToMap(Branch.getInstance().getLatestReferringParams()); + } catch (JSONException e) { + LogUtils.debug(DEBUG_NAME, "BranchReferralInitListener - error to Map: " + e.getLocalizedMessage()); + return; + } + if (eventSink != null) { + eventSink.success(sessionParams); + sessionParams = null; + } + } else { + LogUtils.debug(DEBUG_NAME, "BranchReferralInitListener - error: " + error); + if (eventSink != null) { + eventSink.error(String.valueOf(error.getErrorCode()), error.getMessage(), null); + initialError = null; + } else { + initialError = error; + } + } + } + }; private boolean isInitialized = false; /** @@ -74,6 +121,7 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { LogUtils.debug(DEBUG_NAME, "triggered onAttachedToEngine"); setupChannels(binding.getBinaryMessenger(), binding.getApplicationContext()); } + @Override public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { LogUtils.debug(DEBUG_NAME, "triggered onDetachedFromEngine"); @@ -232,7 +280,7 @@ public boolean onNewIntent(@NonNull Intent intent) { return false; } this.activity.setIntent(intent); - if (intent.hasExtra("branch_force_new_session") && intent.getBooleanExtra("branch_force_new_session",false)) { + if (intent.hasExtra("branch_force_new_session") && intent.getBooleanExtra("branch_force_new_session", false)) { Branch.sessionBuilder(this.activity).withCallback(branchReferralInitListener).reInit(); LogUtils.debug(DEBUG_NAME, "triggered SessionBuilder reInit"); } @@ -336,47 +384,15 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result rawResult) { case "setDMAParamsForEEA": setDMAParamsForEEA(call); break; + case "setConsumerProtectionAttributionLevel": + setConsumerProtectionAttributionLevel(call); + break; default: result.notImplemented(); break; } } - /** - * --------------------------------------------------------------------------------------------- - * Branch SDK Call Methods - * -------------------------------------------------------------------------------------------- - **/ - private final Branch.BranchReferralInitListener branchReferralInitListener = new - Branch.BranchReferralInitListener() { - @Override - public void onInitFinished(JSONObject params, BranchError error) { - LogUtils.debug(DEBUG_NAME, "triggered onInitFinished"); - if (error == null) { - LogUtils.debug(DEBUG_NAME, "BranchReferralInitListener - params: " + params.toString()); - - try { - sessionParams = branchSdkHelper.paramsToMap(params); - } catch (JSONException e) { - LogUtils.debug(DEBUG_NAME, "BranchReferralInitListener - error to Map: " + e.getLocalizedMessage()); - return; - } - if (eventSink != null) { - eventSink.success(sessionParams); - sessionParams = null; - } - } else { - LogUtils.debug(DEBUG_NAME, "BranchReferralInitListener - error: " + error); - if (eventSink != null) { - eventSink.error(String.valueOf(error.getErrorCode()), error.getMessage(), null); - initialError = null; - } else { - initialError = error; - } - } - } - }; - private void setupBranch(MethodCall call, final Result result) { LogUtils.debug(DEBUG_NAME, "triggered setupBranch"); if (!(call.arguments instanceof Map)) { @@ -438,12 +454,18 @@ private void setupBranch(MethodCall call, final Result result) { Branch.getAutoInstance(context).setPreinstallCampaign(campaingParameters.get(i)); } } + if ((Boolean) argsMap.get("disableTracking")) { Branch.getInstance().disableTracking(true); } else { Branch.getInstance().disableTracking(false); } + final String branchAttributionLevelString = call.argument("branchAttributionLevel"); + if (branchAttributionLevelString != null && !branchAttributionLevelString.isEmpty()) { + Branch.getInstance().setConsumerProtectionAttributionLevel(Defines.BranchAttributionLevel.valueOf(branchAttributionLevelString)); + } + LogUtils.debug(DEBUG_NAME, "notifyNativeToInit()"); Branch.notifyNativeToInit(); isInitialized = true; @@ -451,7 +473,7 @@ private void setupBranch(MethodCall call, final Result result) { } private void validateSDKIntegration() { - IntegrationValidator.validate(activity); + IntegrationValidator.validate(this.activity); } private void getShortUrl(MethodCall call, final Result result) { @@ -508,6 +530,7 @@ public void onLinkShareResponse(String sharedLink, BranchError error) { } result.success(response); } + @Override public void onChannelSelected(String channelName) { LogUtils.debug(DEBUG_NAME, "Branch link share channel: " + channelName); @@ -662,14 +685,14 @@ private void setRequestMetadata(MethodCall call) { final String key = call.argument("key"); final String value = call.argument("value"); - if (requestMetadata.has(key) && value.isEmpty()) { - requestMetadata.remove(key); - } else { - try { - requestMetadata.put(key, value); - } catch (JSONException error) { - } - return; + if (requestMetadata.has(key) && value.isEmpty()) { + requestMetadata.remove(key); + } else { + try { + requestMetadata.put(key, value); + } catch (JSONException error) { + } + return; } new Handler(Looper.getMainLooper()).post(new Runnable() { @Override @@ -984,7 +1007,16 @@ private void setDMAParamsForEEA(MethodCall call) { final boolean adPersonalizationConsent = Boolean.TRUE.equals(call.argument("adPersonalizationConsent")); final boolean adUserDataUsageConsent = Boolean.TRUE.equals(call.argument("adUserDataUsageConsent")); - Branch.getInstance().setDMAParamsForEEA(eeaRegion,adPersonalizationConsent,adUserDataUsageConsent); + Branch.getInstance().setDMAParamsForEEA(eeaRegion, adPersonalizationConsent, adUserDataUsageConsent); + } + + private void setConsumerProtectionAttributionLevel(MethodCall call) { + LogUtils.debug(DEBUG_NAME, "triggered setConsumerProtectionAttributionLevel"); + if (!(call.arguments instanceof Map)) { + throw new IllegalArgumentException("Map argument expected"); + } + final String branchAttributionLevelString = call.argument("branchAttributionLevel"); + Branch.getInstance().setConsumerProtectionAttributionLevel(Defines.BranchAttributionLevel.valueOf(branchAttributionLevelString)); } } diff --git a/assets/example.png b/assets/example.png index 3f299892..eefeb9eb 100644 Binary files a/assets/example.png and b/assets/example.png differ diff --git a/example/.gitignore b/example/.gitignore index 1eab1a22..13f41015 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -5,9 +5,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related diff --git a/example/.metadata b/example/.metadata new file mode 100644 index 00000000..02e9c7bf --- /dev/null +++ b/example/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + - platform: web + create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml index b4ce1be2..c1f01ef1 100644 --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -23,7 +23,8 @@ linter: # producing the lint. rules: avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 4286cce4..278cd09b 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -33,10 +33,10 @@ android { ndkVersion flutter.ndkVersion compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } - + defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "br.com.rsmarques.flutter_branch_sdk_example" diff --git a/example/android/build.gradle b/example/android/build.gradle index ce6c61b4..94a816d9 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:8.0.0' + classpath 'com.android.tools.build:gradle:8.2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 95852224..09523c0e 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index b2afc16d..00af31dd 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,29 +1,22 @@ PODS: - - BranchSDK (3.4.3) - Flutter (1.0.0) - - flutter_branch_sdk (8.0.2): - - BranchSDK (~> 3.4.3) + + - flutter_branch_sdk (8.3.0): + - BranchSDK (~> 3.7.0) - Flutter DEPENDENCIES: - Flutter (from `Flutter`) - - flutter_branch_sdk (from `.symlinks/plugins/flutter_branch_sdk/ios`) - -SPEC REPOS: - trunk: - - BranchSDK EXTERNAL SOURCES: Flutter: :path: Flutter - flutter_branch_sdk: - :path: ".symlinks/plugins/flutter_branch_sdk/ios" SPEC CHECKSUMS: - BranchSDK: 078e92df232a7cc0a8d900287d1e57057a2e2997 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_branch_sdk: 77488aedfda2ec7a4dc65f2c71a98412a7443a2c + + flutter_branch_sdk: 5a91002c028d3157155e34ee934c0b216bebef1d PODFILE CHECKSUM: 4e8f8b2be68aeea4c0d5beb6ff1e79fface1d048 -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 11893122..6636b201 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,19 +3,20 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 530C6B849848A7137517F90B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5955988AC5EF176002150C7E /* Pods_Runner.framework */; }; 5B03A0662BEC5D550067F8F0 /* branch.json in Resources */ = {isa = PBXBuildFile; fileRef = 5B03A0652BEC5D550067F8F0 /* branch.json */; }; 5B86E4EB285AF073001770A9 /* Runner.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = 5B86E4EA285AF021001770A9 /* Runner.entitlements */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + E9523E76CBCDA24C4D5572B5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26184BD23321706DC5996BD9 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -32,17 +33,15 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 124E06BB8FCD54487179B61F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 26184BD23321706DC5996BD9 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 5955988AC5EF176002150C7E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5B03A0652BEC5D550067F8F0 /* branch.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = branch.json; path = ../../../assets/branch.json; sourceTree = ""; }; 5B86E4EA285AF021001770A9 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; 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 = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 896072A09BADE8B62197469F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -50,7 +49,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - A35C6EF0AAAF92EE49DA1FCA /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -58,17 +56,18 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 530C6B849848A7137517F90B /* Pods_Runner.framework in Frameworks */, + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, + E9523E76CBCDA24C4D5572B5 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 4B08117C6FAFAE2CA00517DF /* Frameworks */ = { + 1D602F69C758F611537BAA84 /* Frameworks */ = { isa = PBXGroup; children = ( - 5955988AC5EF176002150C7E /* Pods_Runner.framework */, + 26184BD23321706DC5996BD9 /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -76,9 +75,6 @@ 83204363E71EE2485FF0D939 /* Pods */ = { isa = PBXGroup; children = ( - 124E06BB8FCD54487179B61F /* Pods-Runner.debug.xcconfig */, - A35C6EF0AAAF92EE49DA1FCA /* Pods-Runner.release.xcconfig */, - 896072A09BADE8B62197469F /* Pods-Runner.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -101,7 +97,7 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 83204363E71EE2485FF0D939 /* Pods */, - 4B08117C6FAFAE2CA00517DF /* Frameworks */, + 1D602F69C758F611537BAA84 /* Frameworks */, ); sourceTree = ""; }; @@ -137,20 +133,22 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 51684BB5E9E4DDF572E3CBA1 /* [CP] Check Pods Manifest.lock */, + A77B349FFDA959DFBCE715C7 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - F2E1F5326562B92A6334FD21 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -161,6 +159,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { @@ -179,6 +178,9 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -221,28 +223,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 51684BB5E9E4DDF572E3CBA1 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - 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"; - showEnvVarsInLog = 0; - }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -258,21 +238,26 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - F2E1F5326562B92A6334FD21 /* [CP] Embed Pods Frameworks */ = { + A77B349FFDA959DFBCE715C7 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + 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-frameworks-${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-frameworks.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; }; /* End PBXShellScriptBuildPhase section */ @@ -332,6 +317,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -342,6 +328,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -406,6 +393,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -416,6 +404,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -461,6 +450,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -471,6 +461,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -563,6 +554,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index c4b79bd8..919434a6 100644 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -1,7 +1,7 @@ - - - - - + + + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..44f5985b --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,15 @@ +{ + "originHash" : "3721a649d3303e6d819fcb614b49ef1fc7f6da8948adb5762b841d04f2d81b5c", + "pins" : [ + { + "identity" : "ios-branch-sdk-spm", + "kind" : "remoteSourceControl", + "location" : "https://github.com/BranchMetrics/ios-branch-sdk-spm", + "state" : { + "revision" : "67b02bff0c21e257a3baeb65c73c4fb0ae62f29b", + "version" : "3.7.0" + } + } + ], + "version" : 3 +} diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 5e31d3d3..e598ba79 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + { print('Custom string: ${data['custom_string']}'); print('Custom number: ${data['custom_number']}'); print('Custom bool: ${data['custom_bool']}'); + print('Custom integer: ${data['custom_integer']}'); + print('Custom double: ${data['custom_double']}'); print('Custom date: ${data['custom_date_created']}'); print('Custom list number: ${data['custom_list_number']}'); print( @@ -113,12 +115,17 @@ class _HomePageState extends State { DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); metadata = BranchContentMetaData() - ..addCustomMetadata('custom_string', 'abcd') + ..addCustomMetadata('custom_string', 'abcdefg') ..addCustomMetadata('custom_number', 12345) + ..addCustomMetadata('custom_integer', 0) + ..addCustomMetadata('custom_double', 0.0) ..addCustomMetadata('custom_bool', true) ..addCustomMetadata('custom_list_number', [1, 2, 3, 4, 5]) ..addCustomMetadata('custom_list_string', ['a', 'b', 'c']) - ..addCustomMetadata('custom_date_created', dateString); + ..addCustomMetadata('custom_date_created', dateString) + ..addCustomMetadata('\$og_image_width', 237) + ..addCustomMetadata('\$og_image_height', 355) + ..addCustomMetadata('\$og_image_url', imageURL); //--optional Custom Metadata /* ..contentSchema = BranchContentSchema.COMMERCE_PRODUCT @@ -163,6 +170,9 @@ class _HomePageState extends State { expirationDateInMilliSec: DateTime.now() .add(const Duration(days: 365)) .millisecondsSinceEpoch); + + //id = 155; + lp = BranchLinkProperties( channel: 'share', feature: 'sharing', @@ -171,7 +181,7 @@ class _HomePageState extends State { // For example, instead of a random string of characters/integers, you can set the vanity alias as *.app.link/devonaustin. // Aliases are enforced to be unique** and immutable per domain, and per link - they cannot be reused unless deleted. //alias: 'https://branch.io' //define link url, - //alias: 'p/$id', //define link url, + //alias: 'p/$canonicalIdentifier', //define link url, stage: 'new share', campaign: 'campaign', tags: ['one', 'two', 'three']) @@ -237,14 +247,18 @@ class _HomePageState extends State { } } - void enableTracking() { - FlutterBranchSdk.disableTracking(false); - showSnackBar(message: 'Tracking enabled'); + void setConsumerProtectionFull() { + FlutterBranchSdk.setConsumerProtectionAttributionLevel( + BranchAttributionLevel.FULL); + showSnackBar(message: 'Consumer Preference Levels: Full Attribution'); } - void disableTracking() { - FlutterBranchSdk.disableTracking(true); - showSnackBar(message: 'Tracking disabled'); + void setConsumerProtectionNome() { + FlutterBranchSdk.setConsumerProtectionAttributionLevel( + BranchAttributionLevel.NONE); + showSnackBar( + message: + 'Consumer Preference Levels: No Attribution - No Analytics (GDPR, CCPA)'); } void identifyUser() async { @@ -531,7 +545,7 @@ class _HomePageState extends State { FlutterBranchSdk.shareWithLPLinkMetadata( buo: buo, linkProperties: lp, - title: "Share With LPLinkMetadata", + title: 'Share With LPLinkMetadata', icon: iconData); } @@ -586,14 +600,16 @@ class _HomePageState extends State { children: [ Expanded( child: CustomButton( - onPressed: enableTracking, - child: const Text('Enable tracking'), + onPressed: setConsumerProtectionFull, + child: const Text('Consumer Protection FULL', + textAlign: TextAlign.center), ), ), Expanded( child: CustomButton( - onPressed: disableTracking, - child: const Text('Disable tracking'), + onPressed: setConsumerProtectionNome, + child: const Text('Consumer Protection NOME', + textAlign: TextAlign.center), ), ), ], diff --git a/example/lib/main.dart b/example/lib/main.dart index 39e0d8b8..5b68078b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -21,7 +21,9 @@ void main() async { FlqutterBranchSdk.setRequestMetadata('key2', 'value2'); */ //await FlutterBranchSdk.requestTrackingAuthorization(); - await FlutterBranchSdk.init(enableLogging: true, disableTracking: false); - + await FlutterBranchSdk.init( + enableLogging: true, branchAttributionLevel: BranchAttributionLevel.FULL); + FlutterBranchSdk.setConsumerProtectionAttributionLevel( + BranchAttributionLevel.FULL); runApp(const MyApp()); } diff --git a/example/pubspec.lock b/example/pubspec.lock index b37ba1d0..e44af978 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -37,18 +37,18 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" cupertino_icons: dependency: "direct main" description: @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -84,15 +84,15 @@ packages: path: ".." relative: true source: path - version: "8.0.4" + version: "8.3.0" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "5.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -103,38 +103,46 @@ packages: description: flutter source: sdk version: "0.0.0" - intl: - dependency: "direct main" + http: + dependency: transitive description: - name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "0.19.0" - js: + version: "1.2.2" + http_parser: dependency: transitive description: - name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + name: http_parser + sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360" url: "https://pub.dev" source: hosted - version: "0.7.1" + version: "4.1.1" + intl: + dependency: "direct main" + description: + name: intl + sha256: "00f33b908655e606b86d2ade4710a231b802eec6f11e87e4ea3783fd72077a50" + url: "https://pub.dev" + source: hosted + version: "0.20.1" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -147,10 +155,10 @@ packages: dependency: transitive description: name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: "4a16b3f03741e1252fda5de3ce712666d010ba2122f8e912c94f9f7b90e1a4c3" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "5.1.0" matcher: dependency: transitive description: @@ -163,18 +171,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" path: dependency: transitive description: @@ -195,7 +203,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -216,10 +224,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" stream_channel: dependency: transitive description: @@ -232,10 +240,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" term_glyph: dependency: transitive description: @@ -248,26 +256,26 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.3" typed_data: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" uuid: dependency: "direct main" description: name: uuid - sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.5.1" vector_math: dependency: transitive description: @@ -280,10 +288,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.3.0" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + url: "https://pub.dev" + source: hosted + version: "1.1.0" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.6.0-0 <4.0.0" + flutter: ">=3.19.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index cf66e382..f542e912 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -6,7 +6,7 @@ description: Demonstrates how to use the flutter_branch_sdk plugin. publish_to: 'none' # Remove this line if you wish to publish to pub.dev environment: - sdk: ">=2.18.0 <4.0.0" + sdk: ">=3.3.0 <4.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -29,8 +29,8 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 - uuid: ^4.4.0 - intl: ^0.19.0 + uuid: ^4.5.1 + intl: ^0.20.1 dev_dependencies: flutter_test: @@ -41,7 +41,7 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^3.0.1 + flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/example/web/index.html b/example/web/index.html index 8fcb70f9..36bb8f22 100644 --- a/example/web/index.html +++ b/example/web/index.html @@ -32,34 +32,15 @@ Flutter Branch SDK Example - - - - - + diff --git a/ios/Assets/.gitkeep b/ios/Assets/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/ios/Classes/FlutterBranchSdkPlugin.h b/ios/Classes/FlutterBranchSdkPlugin.h deleted file mode 100644 index 4d7f89b8..00000000 --- a/ios/Classes/FlutterBranchSdkPlugin.h +++ /dev/null @@ -1,4 +0,0 @@ -#import - -@interface FlutterBranchSdkPlugin : NSObject -@end diff --git a/ios/Classes/FlutterBranchSdkPlugin.m b/ios/Classes/FlutterBranchSdkPlugin.m deleted file mode 100644 index 3e76edf5..00000000 --- a/ios/Classes/FlutterBranchSdkPlugin.m +++ /dev/null @@ -1,15 +0,0 @@ -#import "FlutterBranchSdkPlugin.h" -#if __has_include() -#import -#else -// Support project import fallback if the generated compatibility header -// is not copied when this plugin is created as a library. -// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 -#import "flutter_branch_sdk-Swift.h" -#endif - -@implementation FlutterBranchSdkPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - [SwiftFlutterBranchSdkPlugin registerWithRegistrar:registrar]; -} -@end diff --git a/ios/flutter_branch_sdk.podspec b/ios/flutter_branch_sdk.podspec index 5c766e0c..37a05cb5 100644 --- a/ios/flutter_branch_sdk.podspec +++ b/ios/flutter_branch_sdk.podspec @@ -18,9 +18,9 @@ Flutter Plugin for create deep link using Brach SDK (https://branch.io). This pl s.license = { :file => '../LICENSE' } s.author = { 'Rodrigo S. Marques' => 'rodrigosmarques@gmail.com' } s.source = { :path => '.' } - s.source_files = 'Classes/**/*' + s.source_files = 'flutter_branch_sdk/sources/flutter_branch_sdk/**/*.swift' s.dependency 'Flutter' - s.dependency 'BranchSDK', '~> 3.4.3' + s.dependency 'BranchSDK', '~> 3.7.0' s.platform = :ios, '12.0' # Flutter.framework does not contain a i386 slice. s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } diff --git a/ios/flutter_branch_sdk/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/ios/flutter_branch_sdk/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/ios/flutter_branch_sdk/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/flutter_branch_sdk/Package.resolved b/ios/flutter_branch_sdk/Package.resolved new file mode 100644 index 00000000..eb42b652 --- /dev/null +++ b/ios/flutter_branch_sdk/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "ios-branch-sdk-spm", + "kind" : "remoteSourceControl", + "location" : "https://github.com/BranchMetrics/ios-branch-sdk-spm", + "state" : { + "revision" : "67b02bff0c21e257a3baeb65c73c4fb0ae62f29b", + "version" : "3.7.0" + } + } + ], + "version" : 2 +} diff --git a/ios/flutter_branch_sdk/Package.swift b/ios/flutter_branch_sdk/Package.swift new file mode 100644 index 00000000..e0e78361 --- /dev/null +++ b/ios/flutter_branch_sdk/Package.swift @@ -0,0 +1,74 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription +/* +import Foundation + + +enum ConfigurationError: Error { + case fileNotFound(String) + case parsingError(String) + case invalidFormat(String) +} + +let branchDirectory = String(URL(string: #file)!.deletingLastPathComponent().absoluteString.dropLast()) + +func loadPubspecVersions() throws -> String { + let pubspecPath = NSString.path(withComponents: [branchDirectory,"..","..","pubspec.yaml"]) + do { + let yamlString = try String(contentsOfFile: pubspecPath, encoding: .utf8) + let lines = yamlString.split(separator: "\\\\r\\\\n") + + guard let packageVersionLine = lines.first(where: { $0.starts(with: "version:") }) else { + throw ConfigurationError.invalidFormat("No package version line found in pubspec.yaml: \(lines.count)") + } + var packageVersion = packageVersionLine.split(separator: ":")[1] + .trimmingCharacters(in: .whitespaces) + .replacingOccurrences(of: "+", with: "-") + packageVersion = packageVersion.replacingOccurrences(of: "^", with: "") + return packageVersion + } catch { + throw ConfigurationError.fileNotFound("Error loading or parsing pubspec.yaml \(pubspecPath) :\n Error: \(error)") + } +} + +let library_version: String + +do { + library_version = try loadPubspecVersions() +} catch { + fatalError("Failed to load configuration: \(error)") +} +*/ + +let package = Package( + name: "flutter_branch_sdk", + platforms: [ + .iOS("12.0") + ], + products: [ + .library(name: "flutter-branch-sdk", targets: ["flutter_branch_sdk"]) + ], + dependencies: [ + .package(url: "https://github.com/BranchMetrics/ios-branch-sdk-spm", "3.7.0"..."3.8.0") + ], + targets: [ + .target( + name: "flutter_branch_sdk", + dependencies: [ + .product(name: "BranchSDK", package: "ios-branch-sdk-spm"), + ], + //cSettings: [ + // .define("LIBRARY_VERSION", to: "\"\(library_version)\""), + //], + linkerSettings: [ + .linkedFramework("CoreServices"), + .linkedFramework("SystemConfiguration"), + .linkedFramework("WebKit", .when(platforms: [.iOS])), + .linkedFramework("CoreSpotlight", .when(platforms: [.iOS])), + .linkedFramework("AdServices", .when(platforms: [.iOS])) + ] + ) + ] +) diff --git a/ios/Classes/FlutterBranchIoSdkHelper.swift b/ios/flutter_branch_sdk/sources/flutter_branch_sdk/FlutterBranchIoSdkHelper.swift similarity index 100% rename from ios/Classes/FlutterBranchIoSdkHelper.swift rename to ios/flutter_branch_sdk/sources/flutter_branch_sdk/FlutterBranchIoSdkHelper.swift diff --git a/ios/Classes/SwiftFlutterBranchSdkPlugin.swift b/ios/flutter_branch_sdk/sources/flutter_branch_sdk/SwiftFlutterBranchSdkPlugin.swift similarity index 93% rename from ios/Classes/SwiftFlutterBranchSdkPlugin.swift rename to ios/flutter_branch_sdk/sources/flutter_branch_sdk/SwiftFlutterBranchSdkPlugin.swift index 83953c1d..ae820923 100644 --- a/ios/Classes/SwiftFlutterBranchSdkPlugin.swift +++ b/ios/flutter_branch_sdk/sources/flutter_branch_sdk/SwiftFlutterBranchSdkPlugin.swift @@ -10,16 +10,17 @@ let MESSAGE_CHANNEL = "flutter_branch_sdk/message"; let EVENT_CHANNEL = "flutter_branch_sdk/event"; let ERROR_CODE = "FLUTTER_BRANCH_SDK_ERROR"; let PLUGIN_NAME = "Flutter"; +let PLUGIN_VERSION = "8.3.0"; let COCOA_POD_NAME = "org.cocoapods.flutter-branch-sdk"; public class SwiftFlutterBranchSdkPlugin: NSObject, FlutterPlugin, FlutterStreamHandler { var eventSink: FlutterEventSink? var initialParams : [String: Any]? = nil var initialError : NSError? = nil - + var branch : Branch? var isInitialized = false - + var requestMetadata : [String: String] = [:] var facebookParameters : [String: String] = [:] var snapParameters : [String: String] = [:] @@ -39,20 +40,30 @@ public class SwiftFlutterBranchSdkPlugin: NSObject, FlutterPlugin, FlutterStream } func getPluginVersion() -> String { + var pluginVersion : String = "" +#if SWIFT_PACKAGE + pluginVersion = PLUGIN_VERSION; +#else if let version = Bundle(identifier: COCOA_POD_NAME)?.infoDictionary?["CFBundleShortVersionString"] as? String { pluginVersion = version; } +#endif + +#if DEBUG + print("Plugin: \(PLUGIN_NAME) - \(pluginVersion)") +#endif return pluginVersion } public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [AnyHashable : Any] = [:]) -> Bool { + Branch.getInstance().registerPluginName(PLUGIN_NAME, version: getPluginVersion()) - + if #available(iOS 15.0, *) { Branch.getInstance().checkPasteboardOnInstall() } - + Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in if error == nil { print("Branch InitSession params: \(String(describing: params as? [String: Any]))") @@ -226,6 +237,9 @@ public class SwiftFlutterBranchSdkPlugin: NSObject, FlutterPlugin, FlutterStream case "setDMAParamsForEEA": setDMAParamsForEEA(call: call) break; + case "setConsumerProtectionAttributionLevel" : + setConsumerProtectionAttributionLevel(call: call) + break; default: result(FlutterMethodNotImplemented) break @@ -252,7 +266,11 @@ public class SwiftFlutterBranchSdkPlugin: NSObject, FlutterPlugin, FlutterStream Branch.setTrackingDisabled(false) } - + let branchAttributionLevel = args["branchAttributionLevel"] as! String + if (!branchAttributionLevel.isEmpty) { + Branch.getInstance().setConsumerProtectionAttributionLevel(BranchAttributionLevel(rawValue: branchAttributionLevel)) + } + if args["enableLogging"] as! Bool == true { Branch.enableLogging(at: BranchLogLevel.debug) } @@ -294,6 +312,9 @@ public class SwiftFlutterBranchSdkPlugin: NSObject, FlutterPlugin, FlutterStream if let err = (error as NSError?) { response["errorCode"] = String(err.code) response["errorMessage"] = err.localizedDescription + } else { + response["errorCode"] = "" + response["errorMessage"] = "errorMessage not returned by Branch SDK. See log for details." } } DispatchQueue.main.async { @@ -499,10 +520,14 @@ public class SwiftFlutterBranchSdkPlugin: NSObject, FlutterPlugin, FlutterStream response["data"] = data } else { print("Failed to lastAttributedTouchData: \(String(describing: error))") - let err = (error! as NSError) response["success"] = NSNumber(value: false) - response["errorCode"] = String(err.code) - response["errorMessage"] = err.localizedDescription + if let err = (error as NSError?) { + response["errorCode"] = String(err.code) + response["errorMessage"] = err.localizedDescription + } else { + response["errorCode"] = "" + response["errorMessage"] = "errorMessage not returned by Branch SDK. See log for details." + } } DispatchQueue.main.async { result(response) @@ -563,12 +588,14 @@ public class SwiftFlutterBranchSdkPlugin: NSObject, FlutterPlugin, FlutterStream if let err = (error as NSError?) { response["errorCode"] = String(err.code) response["errorMessage"] = err.localizedDescription + } else { + response["errorCode"] = "" + response["errorMessage"] = "errorMessage not returned by Branch SDK. See log for details." } } DispatchQueue.main.async { result(response) } - }) } @@ -653,6 +680,14 @@ public class SwiftFlutterBranchSdkPlugin: NSObject, FlutterPlugin, FlutterStream } } + private func setConsumerProtectionAttributionLevel(call: FlutterMethodCall) { + let args = call.arguments as! [String: Any?] + let branchAttributionLevel = args["branchAttributionLevel"] as! String + DispatchQueue.main.async { + Branch.getInstance().setConsumerProtectionAttributionLevel(BranchAttributionLevel(rawValue: branchAttributionLevel)) + } + } + /* https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager diff --git a/lib/flutter_branch_sdk.dart b/lib/flutter_branch_sdk.dart index cf430dcc..a2ba79cb 100644 --- a/lib/flutter_branch_sdk.dart +++ b/lib/flutter_branch_sdk.dart @@ -1,18 +1,13 @@ -/// This is a Flutter plugin that implemented Branch SDK - https://branch.io/ -/// Branch.io helps mobile apps grow with deep links that power referral systems, -/// sharing links and invites with full attribution and analytics. -/// Supports Android, iOS and Web. - -library flutter_branch_sdk; - import 'dart:typed_data'; import 'src/flutter_branch_sdk_platform_interface.dart'; import 'src/objects/app_tracking_transparency.dart'; +import 'src/objects/branch_attribution_level.dart'; import 'src/objects/branch_universal_object.dart'; export 'src/flutter_branch_sdk_platform_interface.dart'; export 'src/objects/app_tracking_transparency.dart'; +export 'src/objects/branch_attribution_level.dart'; export 'src/objects/branch_universal_object.dart'; part 'src/flutter_branch_sdk.dart'; diff --git a/lib/src/flutter_branch_sdk.dart b/lib/src/flutter_branch_sdk.dart index f1c36139..a216e063 100644 --- a/lib/src/flutter_branch_sdk.dart +++ b/lib/src/flutter_branch_sdk.dart @@ -1,13 +1,30 @@ part of '../flutter_branch_sdk.dart'; class FlutterBranchSdk { - ///Initialize Branch SDK - /// [enableLogging] - Sets `true` turn on debug logging - /// [disableTracking] - Sets `true` to disable tracking in Branch SDK for GDPR compliant on start. After having consent, sets `false` + /// Initializes the Branch SDK. + /// + /// This function initializes the Branch SDK with the specified configuration options. + /// + /// **Parameters:** + /// + /// - [enableLogging]: Whether to enable detailed logging. Defaults to `false`. + /// - [branchAttributionLevel]: The level of attribution data to collect. + /// - `BranchAttributionLevel.FULL`: Full Attribution (Default) + /// - `BranchAttributionLevel.REDUCE`: Reduced Attribution (Non-Ads + Privacy Frameworks) + /// - `BranchAttributionLevel.MINIMAL`: Minimal Attribution - Analytics Only + /// - `BranchAttributionLevel.NONE`: No Attribution - No Analytics (GDPR, CCPA) + /// + /// **Note:** The `disableTracking` parameter is deprecated and should no longer be used. + /// Please use `branchAttributionLevel` to control tracking behavior. + /// static Future init( - {bool enableLogging = false, bool disableTracking = false}) async { - await FlutterBranchSdkPlatform.instance - .init(enableLogging: enableLogging, disableTracking: disableTracking); + {bool enableLogging = false, + @Deprecated('use branchAttributionLevel') bool disableTracking = false, + BranchAttributionLevel? branchAttributionLevel}) async { + await FlutterBranchSdkPlatform.instance.init( + enableLogging: enableLogging, + disableTracking: disableTracking, + branchAttributionLevel: branchAttributionLevel); } ///Identifies the current user to the Branch API by supplying a unique identifier as a userId value @@ -41,15 +58,9 @@ class FlutterBranchSdk { return FlutterBranchSdkPlatform.instance.disableTracking(value); } - ///Listen click em Branch Deeplinks - @Deprecated('Use `listSession') - static Stream> initSession() { - return FlutterBranchSdkPlatform.instance.initSession(); - } - ///Listen click em Branch Deeplinks static Stream> listSession() { - return FlutterBranchSdkPlatform.instance.initSession(); + return FlutterBranchSdkPlatform.instance.listSession(); } ///Use the SDK integration validator to check that you've added the Branch SDK and @@ -263,4 +274,11 @@ class FlutterBranchSdk { adPersonalizationConsent: adPersonalizationConsent, adUserDataUsageConsent: adUserDataUsageConsent); } + + /// Sets the consumer protection attribution level. + static void setConsumerProtectionAttributionLevel( + BranchAttributionLevel branchAttributionLevel) { + FlutterBranchSdkPlatform.instance + .setConsumerProtectionAttributionLevel(branchAttributionLevel); + } } diff --git a/lib/src/flutter_branch_sdk_method_channel.dart b/lib/src/flutter_branch_sdk_method_channel.dart index 156aac69..5a34c165 100644 --- a/lib/src/flutter_branch_sdk_method_channel.dart +++ b/lib/src/flutter_branch_sdk_method_channel.dart @@ -6,6 +6,7 @@ import 'package:flutter_branch_sdk/src/constants.dart'; import 'flutter_branch_sdk_platform_interface.dart'; import 'objects/app_tracking_transparency.dart'; +import 'objects/branch_attribution_level.dart'; import 'objects/branch_universal_object.dart'; /// An implementation of [FlutterBranchSdkPlatform] that uses method channels. @@ -17,17 +18,43 @@ class FlutterBranchSdkMethodChannel implements FlutterBranchSdkPlatform { static Stream>? _initSessionStream; static bool isInitialized = false; - ///Initialize Branch SDK - /// [enableLogging] - Sets `true` turn on debug logging - /// [disableTracking] - Sets `true` to disable tracking in Branch SDK for GDPR compliant on start. After having consent, sets `false` + /// Initializes the Branch SDK. + /// + /// This function initializes the Branch SDK with the specified configuration options. + /// + /// **Parameters:** + /// + /// - [enableLogging]: Whether to enable detailed logging. Defaults to `false`. + /// - [branchAttributionLevel]: The level of attribution data to collect. + /// - `BranchAttributionLevel.FULL`: Full Attribution (Default) + /// - `BranchAttributionLevel.REDUCE`: Reduced Attribution (Non-Ads + Privacy Frameworks) + /// - `BranchAttributionLevel.MINIMAL`: Minimal Attribution - Analytics Only + /// - `BranchAttributionLevel.NONE`: No Attribution - No Analytics (GDPR, CCPA) + /// + /// **Note:** The `disableTracking` parameter is deprecated and should no longer be used. + /// Please use `branchAttributionLevel` to control tracking behavior. + /// @override Future init( - {bool enableLogging = false, bool disableTracking = false}) async { + {bool enableLogging = false, + @Deprecated('use BranchAttributionLevel') bool disableTracking = false, + BranchAttributionLevel? branchAttributionLevel}) async { if (isInitialized) { return; } - await messageChannel.invokeMethod('init', - {'enableLogging': enableLogging, 'disableTracking': disableTracking}); + var branchAttributionLevelString = ''; + + if (branchAttributionLevel == null) { + branchAttributionLevelString = ''; + } else { + branchAttributionLevelString = + getBranchAttributionLevelString(branchAttributionLevel); + } + await messageChannel.invokeMethod('init', { + 'enableLogging': enableLogging, + 'disableTracking': disableTracking, + 'branchAttributionLevel': branchAttributionLevelString + }); isInitialized = true; } @@ -72,6 +99,7 @@ class FlutterBranchSdkMethodChannel implements FlutterBranchSdkPlatform { ///Method to change the Tracking state. If disabled SDK will not track any user data or state. ///SDK will not send any network calls except for deep linking when tracking is disabled + @Deprecated('Use [setConsumerProtectionAttributionLevel]') @override void disableTracking(bool value) async { assert(isInitialized, @@ -79,19 +107,6 @@ class FlutterBranchSdkMethodChannel implements FlutterBranchSdkPlatform { messageChannel.invokeMethod('setTrackingDisabled', {'disable': value}); } - ///Initialises a session with the Branch API - ///Listen click em Branch DeepLinks - @Deprecated('Use `listSession') - @override - Stream> initSession() { - assert(isInitialized, - 'Call `initSession` after `FlutterBranchSdk.init()` method'); - _initSessionStream ??= - eventChannel.receiveBroadcastStream().cast>(); - - return _initSessionStream!; - } - ///Listen click em Branch DeepLinks @override Stream> listSession() { @@ -457,4 +472,14 @@ class FlutterBranchSdkMethodChannel implements FlutterBranchSdkPlatform { 'adUserDataUsageConsent': adUserDataUsageConsent }); } + + /// Sets the consumer protection attribution level. + @override + void setConsumerProtectionAttributionLevel( + BranchAttributionLevel branchAttributionLevel) { + messageChannel.invokeMethod('setConsumerProtectionAttributionLevel', { + 'branchAttributionLevel': + getBranchAttributionLevelString(branchAttributionLevel) + }); + } } diff --git a/lib/src/flutter_branch_sdk_platform_interface.dart b/lib/src/flutter_branch_sdk_platform_interface.dart index b970a950..7512fa74 100644 --- a/lib/src/flutter_branch_sdk_platform_interface.dart +++ b/lib/src/flutter_branch_sdk_platform_interface.dart @@ -4,6 +4,7 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'flutter_branch_sdk_method_channel.dart'; import 'objects/app_tracking_transparency.dart'; +import 'objects/branch_attribution_level.dart'; import 'objects/branch_universal_object.dart'; abstract class FlutterBranchSdkPlatform extends PlatformInterface { @@ -27,11 +28,26 @@ abstract class FlutterBranchSdkPlatform extends PlatformInterface { _instance = instance; } - ///Initialize Branch SDK - /// [enableLogging] - Sets `true` turn on debug logging - /// [disableTracking] - Sets `true` to disable tracking in Branch SDK for GDPR compliant on start. After having consent, sets `false` + /// Initializes the Branch SDK. + /// + /// This function initializes the Branch SDK with the specified configuration options. + /// + /// **Parameters:** + /// + /// - [enableLogging]: Whether to enable detailed logging. Defaults to `false`. + /// - [branchAttributionLevel]: The level of attribution data to collect. + /// - `BranchAttributionLevel.FULL`: Full Attribution (Default) + /// - `BranchAttributionLevel.REDUCE`: Reduced Attribution (Non-Ads + Privacy Frameworks) + /// - `BranchAttributionLevel.MINIMAL`: Minimal Attribution - Analytics Only + /// - `BranchAttributionLevel.NONE`: No Attribution - No Analytics (GDPR, CCPA) + /// + /// **Note:** The `disableTracking` parameter is deprecated and should no longer be used. + /// Please use `branchAttributionLevel` to control tracking behavior. + /// Future init( - {bool enableLogging = false, bool disableTracking = false}) async { + {bool enableLogging = false, + @Deprecated('use branchAttributionLevel') bool disableTracking = false, + BranchAttributionLevel? branchAttributionLevel}) async { throw UnimplementedError('init has not been implemented'); } @@ -64,15 +80,11 @@ abstract class FlutterBranchSdkPlatform extends PlatformInterface { ///Method to change the Tracking state. If disabled SDK will not track any user data or state. ///SDK will not send any network calls except for deep linking when tracking is disabled + @Deprecated('Use [setConsumerProtectionAttributionLevel]') void disableTracking(bool value) async { throw UnimplementedError('disableTracking has not been implemented'); } - ///Listen click em Branch Deeplinks - Stream> initSession() { - throw UnimplementedError('initSession has not been implemented'); - } - ///Listen click em Branch Deeplinks Stream> listSession() { throw UnimplementedError('initSession has not been implemented'); @@ -271,4 +283,11 @@ abstract class FlutterBranchSdkPlatform extends PlatformInterface { required bool adUserDataUsageConsent}) { throw UnimplementedError('setDMAParamsForEEA has not been implemented'); } + + /// Sets the consumer protection attribution level. + void setConsumerProtectionAttributionLevel( + BranchAttributionLevel branchAttributionLevel) { + throw UnimplementedError( + 'setConsumerProtectionAttributionLevel has not been implemented'); + } } diff --git a/lib/src/flutter_branch_sdk_web.dart b/lib/src/flutter_branch_sdk_web.dart index 95abd6df..cbd98e5a 100644 --- a/lib/src/flutter_branch_sdk_web.dart +++ b/lib/src/flutter_branch_sdk_web.dart @@ -4,8 +4,8 @@ // ignore: avoid_web_libraries_in_flutter import 'dart:async'; import 'dart:convert'; -import 'dart:js' as js; -import 'dart:js_util'; +import 'dart:js_interop'; +import 'dart:js_interop_unsafe' as js; import 'dart:typed_data'; import 'package:flutter/widgets.dart'; @@ -13,13 +13,14 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'flutter_branch_sdk_platform_interface.dart'; import 'objects/app_tracking_transparency.dart'; +import 'objects/branch_attribution_level.dart'; import 'objects/branch_universal_object.dart'; import 'web/branch_js.dart'; /// A workaround to deep-converting an object from JS to a Dart Object. dynamic _jsObjectToDartObject(data) => json.decode(jsonStringify(data)); -dynamic _dartObjectToJsObject(data) => jsonParse(json.encode(data)); +JSAny _dartObjectToJsObject(data) => jsonParse(json.encode(data)); /// A web implementation of the FlutterBranchSdkPlatform of the FlutterBranchSdk plugin. class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { @@ -30,16 +31,29 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { FlutterBranchSdkPlatform.instance = FlutterBranchSdkWeb(); } - ///Initialize Branch SDK - /// [useTestKey] - Sets `true` to use the test `key_test_... - /// [enableLogging] - Sets `true` turn on debug logging - /// [disableTracking] - Sets `true` to disable tracking in Branch SDK for GDPR compliant on start. After having consent, sets `false` + /// Initializes the Branch SDK. + /// + /// This function initializes the Branch SDK with the specified configuration options. + /// + /// **Parameters:** + /// + /// - [enableLogging]: Whether to enable detailed logging. Defaults to `false`. + /// - [branchAttributionLevel]: The level of attribution data to collect. + /// - `BranchAttributionLevel.FULL`: Full Attribution (Default) + /// - `BranchAttributionLevel.REDUCE`: Reduced Attribution (Non-Ads + Privacy Frameworks) + /// - `BranchAttributionLevel.MINIMAL`: Minimal Attribution - Analytics Only + /// - `BranchAttributionLevel.NONE`: No Attribution - No Analytics (GDPR, CCPA) + /// + /// **Note:** The `disableTracking` parameter is deprecated and should no longer be used. + /// Please use `branchAttributionLevel` to control tracking behavior. + /// + @override Future init( - {bool useTestKey = false, - bool enableLogging = false, - bool disableTracking = false}) async { - debugPrint(''); + {bool enableLogging = false, + @Deprecated('use branchAttributionLevel') bool disableTracking = false, + BranchAttributionLevel? branchAttributionLevel}) async { + debugPrint('For web, start the SDK in index.html'); } static final StreamController> _initSessionStream = @@ -47,22 +61,6 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { static bool _userIdentified = false; static bool isInitialized = false; - ///Listen click em Branch DeepLinks - @Deprecated('Use `listSession') - @override - Stream> initSession() { - getLatestReferringParams().then((data) { - if (data.isNotEmpty) { - _initSessionStream.sink - .add(data.map((key, value) => MapEntry('$key', value))); - } else { - _initSessionStream.sink.add({}); - } - }); - - return _initSessionStream.stream; - } - ///Listen click em Branch Deeplinks @override Stream> listSession() { @@ -84,7 +82,7 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { final Completer> response = Completer(); try { - BranchJS.data(js.allowInterop((err, data) { + BranchJS.data((JSAny? err, JSAny? data) { if (err == null) { if (data != null) { var responseData = @@ -96,7 +94,7 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { } else { response.completeError(err); } - })); + }.toJS); } catch (e) { debugPrint('getLatestReferringParams() error: ${e.toString()}'); response.completeError(e); @@ -111,7 +109,7 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { Completer>(); try { - BranchJS.first(js.allowInterop((err, data) { + BranchJS.first((JSAny? err, JSAny? data) { if (err == null) { if (data != null) { var responseData = @@ -123,7 +121,7 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { } else { response.completeError(err); } - })); + }.toJS); } catch (e) { debugPrint('getFirstReferringParams() error: ${e.toString()}'); response.completeError(e); @@ -135,11 +133,13 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { @override void setIdentity(String userId) { try { - BranchJS.setIdentity(userId, js.allowInterop((error, data) { - if (error == null) { - _userIdentified = true; - } - })); + BranchJS.setIdentity( + userId, + (JSAny? error, JSAny? data) { + if (error == null) { + _userIdentified = true; + } + }.toJS); } catch (e) { debugPrint('setIdentity() error: ${e.toString()}'); } @@ -149,11 +149,11 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { @override void logout() { try { - BranchJS.logout(js.allowInterop((error) { + BranchJS.logout((JSAny? error) { if (error == null) { _userIdentified = false; } - })); + }.toJS); } catch (e) { debugPrint('logout() error: ${e.toString()}'); } @@ -181,19 +181,19 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { }); Map linkData = {...linkProperties.toMap(), 'data': data}; - Completer responseCompleter = Completer(); try { - BranchJS.link(_dartObjectToJsObject(linkData), - js.allowInterop((err, url) { - if (err == null) { - responseCompleter.complete(BranchResponse.success(result: url)); - } else { - responseCompleter.completeError( - BranchResponse.error(errorCode: '-1', errorMessage: err)); - } - })); + BranchJS.link( + _dartObjectToJsObject(linkData), + (String? err, String url) { + if (err == null) { + responseCompleter.complete(BranchResponse.success(result: url)); + } else { + responseCompleter.completeError( + BranchResponse.error(errorCode: '-1', errorMessage: err)); + } + }.toJS); } catch (e) { debugPrint('getShortUrl() error: ${e.toString()}'); responseCompleter.completeError(BranchResponse.error( @@ -214,11 +214,11 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { await getShortUrl(buo: buo, linkProperties: linkProperties); if (response.success) { try { - await promiseToFuture(navigatorShare(_dartObjectToJsObject({ + await navigatorShare(_dartObjectToJsObject({ "title": messageText, "text": buo.title, "url": response.result - }))); + })).toDart; } catch (e) { browserPrompt(messageText, response.result); } @@ -231,7 +231,7 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { void trackContent( {required List buo, required BranchEvent branchEvent}) { - List contentItems = []; + List contentItems = []; for (var element in buo) { contentItems.add(_dartObjectToJsObject(element.toMap())); } @@ -241,11 +241,11 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { BranchJS.logEvent( branchEvent.eventName, _dartObjectToJsObject(branchEvent.toMap()), - contentItems, + contentItems.toJS, branchEvent.alias); } else { BranchJS.logEvent(branchEvent.eventName, - _dartObjectToJsObject(branchEvent.toMap()), contentItems); + _dartObjectToJsObject(branchEvent.toMap()), contentItems.toJS); } } catch (e) { debugPrint('trackContent() error: ${e.toString()}'); @@ -268,7 +268,6 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { void registerView({required BranchUniversalObject buo}) { BranchEvent branchEvent = BranchEvent.standardEvent(BranchStandardEvent.VIEW_ITEM); - // This might not be exactly the same thing as BUO.registerView, but there's no clear implementation for web sdk trackContent(buo: [buo], branchEvent: branchEvent); } @@ -285,7 +284,8 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { Future listOnSearch( {required BranchUniversalObject buo, BranchLinkProperties? linkProperties}) async { - throw UnsupportedError('listOnSearch() Not supported by Branch JS SDK'); + debugPrint('listOnSearch() Not supported by Branch JS SDK'); + return true; } ///For Android: Remove the BUO from the local indexing if it is added to the local indexing already @@ -295,7 +295,8 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { Future removeFromSearch( {required BranchUniversalObject buo, BranchLinkProperties? linkProperties}) async { - throw UnsupportedError('removeFromSearch() Not supported by Branch JS SDK'); + debugPrint('removeFromSearch() Not supported by Branch JS SDK'); + return true; } ///Indicates whether or not this user has a custom identity specified for them. Note that this is independent of installs. @@ -311,24 +312,25 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { /// on Android returns notSupported @override Future requestTrackingAuthorization() async { - throw UnsupportedError( - 'requestTrackingAuthorization() Not available in Branch JS SDK'); + debugPrint('requestTrackingAuthorization() Not supported by Branch JS SDK'); + return AppTrackingStatus.notSupported; } /// return AppTrackingStatus /// on Android returns notSupported @override Future getTrackingAuthorizationStatus() async { - throw UnsupportedError( - 'getTrackingAuthorizationStatus() Not available in Branch JS SDK'); + debugPrint( + 'getTrackingAuthorizationStatus() Not supported by Branch JS SDK'); + return AppTrackingStatus.notSupported; } /// return advertising identifier (ie tracking data). /// on Android returns empty string @override Future getAdvertisingIdentifier() async { - throw UnsupportedError( - 'getAdvertisingIdentifier() Not available in Branch JS SDK'); + debugPrint('getAdvertisingIdentifier() Not supported by Branch JS SDK'); + return ''; } ///Use the SDK integration validator to check that you've added the Branch SDK and @@ -343,8 +345,7 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { ///a network * request. @override void setConnectTimeout(int connectTimeout) { - throw UnsupportedError( - 'setConnectTimeout() Not available in Branch JS SDK'); + debugPrint('setConnectTimeout() Not supported by Branch JS SDK'); } ///Sets the duration in milliseconds that the system should wait for a response @@ -353,7 +354,7 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { ///retries as set in setRetryCount(int). @override void setTimeout(int timeout) { - throw UnsupportedError('setTimeout() Not available in Branch JS SDK'); + debugPrint('setTimeout() Not supported by Branch JS SDK'); } ///Sets the max number of times to re-attempt a timed-out request to the Branch API, before @@ -363,14 +364,14 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { /// determine if the max retry count will be attempted. @override void setRetryCount(int retryCount) { - throw UnsupportedError('setRetryCount() Not available in Branch JS SDK'); + debugPrint('setRetryCount() Not supported by Branch JS SDK'); } ///Sets the amount of time in milliseconds to wait before re-attempting a ///timed-out request to the Branch API. Default 1000 ms. @override void setRetryInterval(int retryInterval) { - throw UnsupportedError('setRetryInterval() Not available in Branch JS SDK'); + debugPrint('setRetryInterval() Not supported by Branch JS SDK'); } ///Gets the available last attributed touch data with a custom set attribution window. @@ -380,20 +381,21 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { Completer responseCompleter = Completer(); try { - BranchJS.lastAttributedTouchData(attributionWindow, - js.allowInterop((err, data) { - if (err == null) { - if (data != null) { - responseCompleter.complete( - BranchResponse.success(result: _jsObjectToDartObject(data))); - } else { - responseCompleter.complete(BranchResponse.success(result: {})); - } - } else { - responseCompleter.complete(BranchResponse.error( - errorCode: '999', errorMessage: err.toString())); - } - })); + BranchJS.lastAttributedTouchData( + attributionWindow?.toJS, + (JSAny? err, JSAny? data) { + if (err == null) { + if (data != null) { + responseCompleter.complete(BranchResponse.success( + result: _jsObjectToDartObject(data))); + } else { + responseCompleter.complete(BranchResponse.success(result: {})); + } + } else { + responseCompleter.complete(BranchResponse.error( + errorCode: '999', errorMessage: err.toString())); + } + }.toJS); } catch (e) { debugPrint('getLastAttributedTouchData() error: ${e.toString()}'); responseCompleter.complete(BranchResponse.error( @@ -418,22 +420,23 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { Map linkData = {...linkProperties.toMap(), 'data': data}; try { - BranchJS.qrCode(_dartObjectToJsObject(linkData), + BranchJS.qrCode( + _dartObjectToJsObject(linkData), _dartObjectToJsObject(qrCodeSettings.toMap()), - js.allowInterop((err, qrCode) { - if (err == null) { - if (qrCode != null) { - responseCompleter.complete( - BranchResponse.success(result: qrCode.rawBuffer.asUint8List())); - } else { - responseCompleter.complete(BranchResponse.error( - errorCode: '-1', errorMessage: 'Qrcode generate error')); - } - } else { - responseCompleter.complete(BranchResponse.error( - errorCode: '-1', errorMessage: err.toString())); - } - })); + (JSAny? err, QrCodeData? qrCode) { + if (err == null) { + if (qrCode != null) { + responseCompleter.complete(BranchResponse.success( + result: qrCode.rawBuffer.toDart.asUint8List())); + } else { + responseCompleter.complete(BranchResponse.error( + errorCode: '-1', errorMessage: 'Qrcode generate error')); + } + } else { + responseCompleter.complete(BranchResponse.error( + errorCode: '-1', errorMessage: err.toString())); + } + }.toJS); } catch (e) { responseCompleter.complete(BranchResponse.error( errorCode: '-1', errorMessage: 'qrCode generate error')); @@ -480,7 +483,7 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { ///Have Branch end the current deep link session and start a new session with the provided URL. @override void handleDeepLink(String url) { - js.context.callMethod('open', [url, '_self']); + globalContext.callMethodVarArgs('open'.toJS, [url.toJS, '_self'.toJS]); } /// Add a Partner Parameter for Facebook. @@ -489,37 +492,32 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { @override void addFacebookPartnerParameter( {required String key, required String value}) { - throw UnsupportedError( - 'addFacebookPartnerParameter() Not available in Branch JS SDK'); + debugPrint('addFacebookPartnerParameter() Not supported by Branch JS SDK'); } /// Clears all Partner Parameters @override void clearPartnerParameters() { - throw UnsupportedError( - 'clearPartnerParameters() Not available in Branch JS SDK'); + debugPrint('clearPartnerParameters() Not supported by Branch JS SDK'); } /// Add the pre-install campaign analytics @override void setPreinstallCampaign(String value) { - throw UnsupportedError( - 'setPreinstallCampaign() Not available in Branch JS SDK'); + debugPrint('setPreinstallCampaign() Not supported by Branch JS SDK'); } /// Add the pre-install campaign analytics @override void setPreinstallPartner(String value) { - throw UnsupportedError( - 'setPreinstallPartner() Not available in Branch JS SDK'); + debugPrint('setPreinstallPartner() Not supported by Branch JS SDK'); } ///Add a Partner Parameter for Snap. ///Once set, this parameter is attached to installs, opens and events until cleared or the app restarts. @override void addSnapPartnerParameter({required String key, required String value}) { - throw UnsupportedError( - 'addSnapPartnerParameter() Not available in Branch JS SDK'); + debugPrint('addSnapPartnerParameter() Not supported by Branch JS SDK'); } void close() { @@ -538,4 +536,12 @@ class FlutterBranchSdkWeb extends FlutterBranchSdkPlatform { BranchJS.setDMAParamsForEEA( eeaRegion, adPersonalizationConsent, adUserDataUsageConsent); } + + /// Sets the consumer protection attribution level. + @override + void setConsumerProtectionAttributionLevel( + BranchAttributionLevel branchAttributionLevel) { + debugPrint( + 'setConsumerProtectionAttributionLevel() Not supported by Branch JS SDK'); + } } diff --git a/lib/src/objects/branch_attribution_level.dart b/lib/src/objects/branch_attribution_level.dart new file mode 100644 index 00000000..42d671e4 --- /dev/null +++ b/lib/src/objects/branch_attribution_level.dart @@ -0,0 +1,39 @@ +enum BranchAttributionLevel { + /// Full Attribution (Default) + /// - Advertising Ids + /// - Device Ids + /// - Local IP + /// - Persisted Non-Aggregate Ids + /// - Persisted Aggregate Ids + /// - Ads Postbacks / Webhooks + /// - Data Integrations Webhooks + /// - SAN Callouts + /// - Privacy Frameworks + /// - Deep Linking + FULL, + + /// Reduced Attribution (Non-Ads + Privacy Frameworks) + /// - Device Ids + /// - Local IP + /// - Data Integrations Webhooks + /// - Privacy Frameworks + /// - Deep Linking + REDUCED, + + /// Minimal Attribution - Analytics Only + /// - Device Ids + /// - Local IP + /// - Data Integrations Webhooks + /// - Deep Linking + MINIMAL, + + /// No Attribution - No Analytics (GDPR, CCPA) + /// - Only Deterministic Deep Linking + /// - Disables all other Branch requests + NONE +} + +String getBranchAttributionLevelString( + BranchAttributionLevel branchAttributionLevel) { + return branchAttributionLevel.toString().split('.').last; +} diff --git a/lib/src/objects/branch_universal_object.dart b/lib/src/objects/branch_universal_object.dart index 7bf75421..3494da3d 100644 --- a/lib/src/objects/branch_universal_object.dart +++ b/lib/src/objects/branch_universal_object.dart @@ -1,5 +1,3 @@ -library flutter_branch_sdk_objects; - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/lib/src/objects/content_meta_data.dart b/lib/src/objects/content_meta_data.dart index e327b551..54991655 100644 --- a/lib/src/objects/content_meta_data.dart +++ b/lib/src/objects/content_meta_data.dart @@ -341,8 +341,6 @@ class BranchContentMetaData { return "Toys & Games"; case BranchProductCategory.VEHICLES_AND_PARTS: return "Vehicles & Parts"; - default: - return "Home & Garden"; } } diff --git a/lib/src/web/branch_js.dart b/lib/src/web/branch_js.dart index e9543dea..73c18cd1 100644 --- a/lib/src/web/branch_js.dart +++ b/lib/src/web/branch_js.dart @@ -1,31 +1,27 @@ @JS() -library branchjs; - -import 'dart:typed_data'; - -import 'package:js/js.dart'; +import 'dart:js_interop'; @JS('JSON.stringify') -external String jsonStringify(Object obj); +external String jsonStringify(JSAny obj); @JS('JSON.parse') -external dynamic jsonParse(String str); +external JSAny jsonParse(String str); @JS('navigator.share') -external dynamic navigatorShare(Object data); +external JSPromise navigatorShare(JSAny data); @JS('prompt') -external dynamic browserPrompt(String message, [String data]); +external JSAny browserPrompt(String message, [String data]); @JS() @anonymous -class QrCodeData { - external ByteBuffer rawBuffer; - external Function base64(); +extension type QrCodeData._(JSObject _) implements JSObject { + external JSArrayBuffer rawBuffer; + external JSFunction base64(); } @JS('branch') -class BranchJS { +extension type BranchJS._(JSObject _) implements JSObject { /// addListener(event, listener) /// Parameters /// @@ -60,7 +56,7 @@ class BranchJS { /// didCloseJourney: Journey's close animation has completed and it is no longer visible to the user. /// didCallJourneyClose: Emitted when developer calls branch.closeJourney() to dismiss Journey. @JS('addListener') - external static void addListener([String event, Function listener]); + external static void addListener([String event, JSFunction listener]); // No documentation in full reference // @JS('banner') @@ -83,7 +79,7 @@ class BranchJS { /// /// branch.closeJourney(function(err) { console.log(err); }); @JS('closeJourney') - external static void closeJourney([Function callback]); + external static void closeJourney([JSFunction callback]); /// data(callback) /// Parameters @@ -98,7 +94,7 @@ class BranchJS { /// If the Branch session has already been initialized, the callback will return /// immediately, otherwise, it will return once Branch has been initialized. @JS('data') - external static void data([Function callback]); + external static void data([JSFunction callback]); /// deepview(data, options, callback) /// Parameters @@ -157,8 +153,8 @@ class BranchJS { /// "Error message" /// ); @JS('deepview') - external static void deepview(Object data, - [Object options, Function callback]); + external static void deepview(JSAny data, + [JSAny options, JSFunction callback]); /// deepviewCta() /// Perform the branch deepview CTA (call to action) on mobile after branch.deepview() call is @@ -213,7 +209,7 @@ class BranchJS { /// Warning: For a referral program, you should not use unique awards for custom events and redeem /// pre-identify call. This can allow users to cheat the system. @JS('deepviewCta') - external static void deepviewCta([Function errorCallback]); + external static void deepviewCta([JSFunction errorCallback]); /// first(callback) /// Parameters @@ -228,7 +224,7 @@ class BranchJS { /// If the Branch session has already been initialized, the callback will return /// immediately, otherwise, it will return once Branch has been initialized. @JS('first') - external static void first([Function callback]); + external static void first([JSFunction callback]); // No documentation on reference // @JS('getCode') @@ -295,7 +291,7 @@ class BranchJS { /// Note: Branch.init must be called prior to calling any other Branch functions. @JS('init') external static void init(String branchKey, - [Object? options, Function? callback]); + [JSAny? options, JSFunction? callback]); /// link(data, callback) /// Parameters @@ -377,7 +373,7 @@ class BranchJS { /// 'https://bnc.lt/l/3HZMytU-BW' // Branch deep linking URL /// ); @JS('link') - external static void link(Object data, Function callback); + external static void link(JSAny data, JSFunction callback); /// logout(callback) /// Parameters @@ -397,7 +393,7 @@ class BranchJS { /// "Error message" /// ); @JS('logout') - external static void logout([Function callback]); + external static void logout([JSFunction callback]); /// removeListener(listener) /// Parameters @@ -410,7 +406,7 @@ class BranchJS { /// passed a referrence to the same function that was passed to branch.addListener(), not /// just an identical clone of the function. @JS('removeListener') - external static void removeListener(Function listener); + external static void removeListener(JSFunction listener); /// sendSMS(phone, linkData, options, callback) /// Parameters @@ -486,8 +482,8 @@ class BranchJS { /// /// callback("Error message"); @JS('sendSMS') - external static void sendSMS(String phone, Object linkData, - [Object options, Function callback]); + external static void sendSMS(String phone, JSAny linkData, + [JSAny options, JSFunction callback]); /// setBranchViewData(data) /// Parameters @@ -515,7 +511,7 @@ class BranchJS { /// } /// }); @JS('setBranchViewData') - external static void setBranchViewData(Object data); + external static void setBranchViewData(JSAny data); /// setIdentity(identity, callback) /// Parameters @@ -550,7 +546,7 @@ class BranchJS { /// } /// ); @JS('setIdentity') - external static void setIdentity(String identity, [Function callback]); + external static void setIdentity(String identity, [JSFunction callback]); /// track(event, metadata, callback) /// Parameters @@ -577,7 +573,7 @@ class BranchJS { /// callback("Error message"); @JS('track') external static void track(String event, - [Object metadata, Function callback]); + [JSAny metadata, JSFunction callback]); /// trackCommerceEvent(event, commerce_data, metadata, callback) /// Parameters @@ -629,8 +625,8 @@ class BranchJS { /// } /// }); @JS('trackCommerceEvent') - external static void trackCommerceEvent(String name, Object commerceData, - [Object metadata, Function callback]); + external static void trackCommerceEvent(String name, JSAny commerceData, + [JSAny metadata, JSFunction callback]); /// logEvent(event, event_data_and_custom_data, content_items, customer_event_alias, callback) /// Parameters @@ -754,10 +750,10 @@ class BranchJS { @JS('logEvent') external static void logEvent(String event, - [Object eventDataAndCustomData, - Object contentItems, + [JSAny eventDataAndCustomData, + JSArray contentItems, String customerEventAlias, - Function callback]); + JSFunction callback]); /// disableTracking(disableTracking) /// Parameters @@ -779,7 +775,7 @@ class BranchJS { /// information associated to them. You can change this behavior at any time, by calling the aforementioned function. /// The do-not-track mode state is persistent: it is saved for the user across browser sessions for the web site. @JS('disableTracking') - external static void disableTracking([bool disableTracking]); + external static void disableTracking(bool disableTracking); /// lastAttributedTouchData (number, callback) /// @@ -809,8 +805,8 @@ class BranchJS { /// '{}' /// ); @JS('lastAttributedTouchData') - external static void lastAttributedTouchData(attributionWindow, - [Function callback]); + external static void lastAttributedTouchData(JSAny? attributionWindow, + [JSFunction callback]); /// qrcode(data, callback) /// Parameters @@ -894,8 +890,8 @@ class BranchJS { /// ); @JS('qrCode') - external static void qrCode(Object qrCodeLinkData, Object qrCodeSettings, - Function(String? err, QrCodeData? qrCode) callback); + external static void qrCode( + JSAny qrCodeLinkData, JSAny qrCodeSettings, JSFunction callback); /// Sets the value of parameters required by Google Conversion APIs for DMA Compliance in EEA region. /// [eeaRegion] `true` If European regulations, including the DMA, apply to this user and conversion. diff --git a/pubspec.lock b/pubspec.lock index f3e8675f..f274b31e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" fake_async: dependency: transitive description: @@ -58,10 +58,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -72,30 +72,22 @@ packages: description: flutter source: sdk version: "0.0.0" - js: - dependency: "direct main" - description: - name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf - url: "https://pub.dev" - source: hosted - version: "0.7.1" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -108,10 +100,10 @@ packages: dependency: transitive description: name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.0" matcher: dependency: transitive description: @@ -124,18 +116,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" path: dependency: transitive description: @@ -156,7 +148,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -169,10 +161,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" stream_channel: dependency: transitive description: @@ -185,10 +177,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" term_glyph: dependency: transitive description: @@ -201,10 +193,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.3" vector_math: dependency: transitive description: @@ -217,10 +209,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.3.0" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index 6a906155..9e353dbf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,10 @@ name: flutter_branch_sdk description: Flutter Plugin for create deep link using Brach SDK (https://branch.io). This plugin provides a cross-platform (iOS, Android, Web). -version: 8.0.4 -homepage: https://github.com/RodrigoSMarques/flutter_branch_sdk - +repository: https://github.com/RodrigoSMarques/flutter_branch_sdk +version: 8.3.0 environment: - sdk: ">=2.18.0 <4.0.0" - flutter: ">=3.3.0" + sdk: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" dependencies: flutter: @@ -13,12 +12,11 @@ dependencies: flutter_web_plugins: sdk: flutter plugin_platform_interface: ^2.1.8 - js: ^0.7.1 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^4.0.0 + flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec @@ -41,7 +39,7 @@ flutter: package: br.com.rsmarques.flutter_branch_sdk pluginClass: FlutterBranchSdkPlugin ios: - pluginClass: FlutterBranchSdkPlugin + pluginClass: SwiftFlutterBranchSdkPlugin web: pluginClass: FlutterBranchSdkWeb fileName: src/flutter_branch_sdk_web.dart diff --git a/tool/build-web.sh b/tool/build-web.sh index bd706302..f0d7d87d 100644 --- a/tool/build-web.sh +++ b/tool/build-web.sh @@ -7,4 +7,5 @@ flutter config --no-analytics flutter pub get #flutter build web --source-maps #flutter build web --profile --source-maps --dart-define=Dart2jsOptimization=O0 -flutter build web \ No newline at end of file +#flutter build web +flutter build web --wasm --source-maps \ No newline at end of file