├── .github ├── ISSUE_TEMPLATE │ ├── PULL_REQUEST_TEMPLATE.md │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── ci.yaml │ ├── deploy-apk.yaml │ ├── deploy-web.yaml │ ├── pr-bugfix-dev.yaml │ ├── pr-master-bugfix.yaml │ ├── publish-plugin.yml │ ├── send-dispatch.yaml │ └── sync-upstream.yaml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── branch.json │ └── java │ └── br │ └── com │ └── rsmarques │ └── flutter_branch_sdk │ ├── FlutterBranchSdkHelper.java │ ├── FlutterBranchSdkInit.java │ ├── FlutterBranchSdkPlugin.java │ ├── LogUtils.java │ ├── MainThreadEventSink.java │ └── MethodResultWrapper.java ├── assets ├── app_tracking_dialog.png ├── branch.json ├── branch.png ├── branch_json_add.png ├── branch_json_project.png ├── branch_logo_qrcode.jpeg └── example.png ├── example ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── br │ │ │ │ │ └── com │ │ │ │ │ └── rsmarques │ │ │ │ │ └── flutter_branch_sdk_example │ │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ └── images │ │ └── branch_logo.jpeg ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── swiftpm │ │ │ │ └── Package.resolved │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── swiftpm │ │ │ └── Package.resolved │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── Runner-Bridging-Header.h │ │ └── Runner.entitlements ├── lib │ ├── app.dart │ ├── custom_button.dart │ ├── home_page.dart │ └── main.dart ├── pubspec.lock ├── pubspec.yaml └── web │ ├── favicon.png │ ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png │ ├── index.html │ └── manifest.json ├── ios ├── .gitignore ├── flutter_branch_sdk.podspec └── flutter_branch_sdk │ ├── .swiftpm │ └── xcode │ │ └── package.xcworkspace │ │ └── contents.xcworkspacedata │ ├── Package.resolved │ ├── Package.swift │ └── sources │ └── flutter_branch_sdk │ ├── FlutterBranchIoSdkHelper.swift │ └── FlutterBranchSdkPlugin.swift ├── lib ├── flutter_branch_sdk.dart └── src │ ├── constants.dart │ ├── flutter_branch_sdk.dart │ ├── flutter_branch_sdk_method_channel.dart │ ├── flutter_branch_sdk_platform_interface.dart │ ├── flutter_branch_sdk_web.dart │ ├── objects │ ├── app_tracking_transparency.dart │ ├── branch_attribution_level.dart │ ├── branch_event.dart │ ├── branch_qrcode.dart │ ├── branch_response.dart │ ├── branch_universal_object.dart │ ├── content_meta_data.dart │ ├── content_schema.dart │ └── link_properties.dart │ └── web │ └── branch_js.dart ├── pubspec.lock ├── pubspec.yaml └── tool ├── build-apk.sh ├── build-web.sh └── flutter-dependencies.sh /.github/ISSUE_TEMPLATE/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Fixes # 2 | 3 | ## Proposed Changes 4 | 5 | - 6 | - 7 | - 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | Keep the template and provide all requested information: 11 | 12 | **Describe the bug** 13 | A clear and concise description of what the bug is. 14 | 15 | **To Reproduce** 16 | Steps to reproduce the behavior: 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Mobile (Please complete the following information. remove session if not Mobile):** 29 | - Flutter: version: [e.g. 2.2.3] 30 | - flutter_branch_sdk version: [e.g. 3.3.0] 31 | - OS: [e.g. iOS16.0, Android 12] 32 | - Device: [e.g. iPhone14, Google Pixel] 33 | 34 | **Web (please complete the following information. remove session if not is Web:** 35 | - Flutter: version: [e.g. 2.2.3] 36 | - flutter_branch_sdk version: [e.g. 3.3.0] 37 | - OS: [e.g. Windows, Mac, Linux] 38 | - Browser [e.g. chrome, safari, edge] 39 | - Version [e.g. 22] 40 | 41 | - **Additional context** 42 | 43 | Add any other context about the problem here. 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: 'Please replace with a clear and descriptive title' 5 | labels: 'type: feature' 6 | assignees: '' 7 | --- 8 | 9 | 14 | 15 | **Which problem is this feature request solving?** 16 | 17 | 20 | 21 | **Describe the solution you'd like** 22 | 23 | 26 | 27 | **Describe alternatives you've considered** 28 | 29 | 32 | 33 | **Can you submit a pull request?** 34 | 35 | Yes/No. 36 | 37 | 41 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: Plugin code analysis 2 | 3 | on: 4 | push: 5 | branches: 6 | - "master" 7 | - "dev" 8 | - "bugfix" 9 | paths-ignore: 10 | - "**/README.md" 11 | - "docs/**" 12 | pull_request: 13 | branches: 14 | - "master" 15 | - "dev" 16 | - "bugfix" 17 | 18 | jobs: 19 | check-lint-flutter: 20 | name: Lint (flutter) 21 | timeout-minutes: 5 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Checkout code 25 | uses: actions/checkout@v4 26 | - name: Setup flutter 27 | uses: subosito/flutter-action@v2 28 | with: 29 | channel: stable 30 | #flutter-version-file: pubspec.yaml 31 | - name: Lint 32 | #run: dart format --output=none --set-exit-if-changed lib/ 33 | run: dart format --output=none lib/ 34 | check-code-analysis-flutter: 35 | name: Code analysis (flutter) 36 | timeout-minutes: 5 37 | runs-on: ubuntu-latest 38 | steps: 39 | - name: Checkout code 40 | uses: actions/checkout@v4 41 | - name: Setup flutter 42 | uses: subosito/flutter-action@v2 43 | with: 44 | cache: true 45 | - name: Install dependencies 46 | run: flutter pub get 47 | - name: Analyze code 48 | run: flutter analyze --no-fatal-infos 49 | -------------------------------------------------------------------------------- /.github/workflows/deploy-apk.yaml: -------------------------------------------------------------------------------- 1 | name: Create sample app APK 2 | 3 | on: 4 | # pull_request: 5 | # branches: 6 | # - "master" 7 | # paths-ignore: 8 | # - "**/README.md" 9 | # - "**/CHANGELOG.md" 10 | # - "docs/**" 11 | push: 12 | tags: 13 | - 'v*' 14 | workflow_dispatch: 15 | 16 | jobs: 17 | build: 18 | name: Build APK 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | - name: Setup Java 24 | uses: actions/setup-java@v4 25 | with: 26 | java-version: "17.x" 27 | distribution: "zulu" 28 | - name: Setup Flutter 29 | uses: subosito/flutter-action@v2 30 | with: 31 | channel: "stable" 32 | cache: true 33 | - name: Make executeable build-apk.sh 34 | run: chmod +x tool/build-apk.sh 35 | - name: Install dependencies & Build apk 36 | run: tool/build-apk.sh 37 | - uses: actions/upload-artifact@v4 38 | with: 39 | name: release-apk 40 | path: ./example/build/app/outputs/apk/release/app-release.apk 41 | if-no-files-found: error 42 | -------------------------------------------------------------------------------- /.github/workflows/deploy-web.yaml: -------------------------------------------------------------------------------- 1 | name: Deploying the sample app to the web 2 | 3 | on: 4 | # pull_request: 5 | # branches: 6 | # - "master" 7 | # paths-ignore: 8 | # - "**/README.md" 9 | # - "**/CHANGELOG.md" 10 | # - "docs/**" 11 | push: 12 | tags: 13 | - 'v*' 14 | workflow_dispatch: 15 | 16 | jobs: 17 | build: 18 | name: Build Web 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | - name: Setup Flutter 24 | uses: subosito/flutter-action@v2 25 | with: 26 | channel: "stable" 27 | cache: true 28 | - name: Make executeable build-web.sh 29 | run: chmod +x tool/build-web.sh 30 | - name: Install dependencies & Build web 31 | run: tool/build-web.sh 32 | - name: Deploy to Netlify 33 | if: ${{ github.repository == 'RodrigoSMarques/flutter_branch_sdk' }} 34 | uses: nwtgck/actions-netlify@v3 35 | with: 36 | publish-dir: './example/build/web' 37 | production-branch: master 38 | production-deploy: true 39 | github-token: ${{ secrets.GITHUB_TOKEN }} 40 | deploy-message: "Deploy from GitHub Actions" 41 | enable-pull-request-comment: false 42 | enable-commit-comment: true 43 | overwrites-pull-request-comment: true 44 | env: 45 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} 46 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} 47 | timeout-minutes: 1 48 | -------------------------------------------------------------------------------- /.github/workflows/pr-bugfix-dev.yaml: -------------------------------------------------------------------------------- 1 | name: PR Branch BUGFIX to DEV 2 | 3 | on: 4 | push: 5 | branches: 6 | - "bugfix" 7 | 8 | jobs: 9 | pull-request: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: pull-request-master-to-bugfix 14 | if: ${{ github.repository == 'RodrigoSMarques/flutter_branch_sdk' }} 15 | uses: repo-sync/pull-request@v2 16 | with: 17 | source_branch: "bugfix" 18 | destination_branch: "dev" 19 | pr_title: "PR Branch BUGFIX into DEV" 20 | pr_body: "👑 *An automated PR*" 21 | pr_label: "auto-pr" 22 | pr_draft: false 23 | pr_allow_empty: false 24 | github_token: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/pr-master-bugfix.yaml: -------------------------------------------------------------------------------- 1 | name: PR Branch MASTER to BUGFIX 2 | 3 | on: 4 | push: 5 | branches: 6 | - "master" 7 | 8 | jobs: 9 | pull-request: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: pull-request-master-to-bugfix 14 | if: ${{ github.repository == 'RodrigoSMarques/flutter_branch_sdk' }} 15 | uses: repo-sync/pull-request@v2 16 | with: 17 | source_branch: "master" 18 | destination_branch: "bugfix" 19 | pr_title: "PR Branch MASTER into BUGFIX" 20 | pr_body: "👑 *An automated PR*" 21 | pr_label: "auto-pr" 22 | pr_draft: false 23 | pr_allow_empty: false 24 | github_token: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/publish-plugin.yml: -------------------------------------------------------------------------------- 1 | name: Publish plugin - pub.dev 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish: 11 | permissions: 12 | id-token: write # Required for authentication using OIDC 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v4 17 | - uses: dart-lang/setup-dart@v1 18 | - name: Setup Flutter 19 | uses: subosito/flutter-action@v2 20 | with: 21 | channel: "stable" 22 | cache: true 23 | - name: Install dependencies 24 | run: dart pub get 25 | - name: Generate documentation 26 | run: dart doc 27 | - name: Publish flutter package 28 | #run: dart pub publish --dry-run 29 | run: dart pub publish --force 30 | -------------------------------------------------------------------------------- /.github/workflows/send-dispatch.yaml: -------------------------------------------------------------------------------- 1 | name: Send Dispatch to Branch fork 2 | 3 | on: 4 | push: 5 | # branches: 6 | # - "master" 7 | # - "dev" 8 | tags: 9 | - 'v*' 10 | workflow_dispatch: 11 | 12 | jobs: 13 | send-dispatch: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Repository Dispatch 17 | if: ${{ github.repository == 'RodrigoSMarques/flutter_branch_sdk' }} 18 | uses: peter-evans/repository-dispatch@v3 19 | with: 20 | token: ${{ secrets.TOKEN_BRANCH_UPSTREAM}} 21 | repository: BranchMetrics/flutter_branch_sdk 22 | event-type: new-release 23 | -------------------------------------------------------------------------------- /.github/workflows/sync-upstream.yaml: -------------------------------------------------------------------------------- 1 | name: 'Upstream Sync' 2 | 3 | on: 4 | repository_dispatch: 5 | types: [new-release] 6 | workflow_dispatch: # click the button on Github repo! 7 | 8 | jobs: 9 | update_repository_branch: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Repository master 13 | uses: TobKed/github-forks-sync-action@master 14 | with: 15 | github_token: ${{ secrets.GITHUB_TOKEN }} 16 | upstream_repository: RodrigoSMarques/flutter_branch_sdk 17 | target_repository: BranchMetrics/flutter_branch_sdk 18 | upstream_branch: master 19 | target_branch: master 20 | force: true 21 | tags: true 22 | - name: Repository dev 23 | uses: TobKed/github-forks-sync-action@master 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | upstream_repository: RodrigoSMarques/flutter_branch_sdk 27 | target_repository: BranchMetrics/flutter_branch_sdk 28 | upstream_branch: dev 29 | target_branch: dev 30 | force: true 31 | tags: true 32 | - name: Repository bugfix 33 | uses: TobKed/github-forks-sync-action@master 34 | with: 35 | github_token: ${{ secrets.GITHUB_TOKEN }} 36 | upstream_repository: RodrigoSMarques/flutter_branch_sdk 37 | target_repository: BranchMetrics/flutter_branch_sdk 38 | upstream_branch: bugfix 39 | target_branch: bugfix 40 | force: true 41 | tags: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | 32 | # Android related 33 | **/android/**/gradle-wrapper.jar 34 | **/android/.gradle 35 | **/android/captures/ 36 | **/android/gradlew 37 | **/android/gradlew.bat 38 | **/android/local.properties 39 | **/android/**/GeneratedPluginRegistrant.java 40 | 41 | # iOS/XCode related 42 | **/ios/**/*.mode1v3 43 | **/ios/**/*.mode2v3 44 | **/ios/**/*.moved-aside 45 | **/ios/**/*.pbxuser 46 | **/ios/**/*.perspectivev3 47 | **/ios/**/*sync/ 48 | **/ios/**/.sconsign.dblite 49 | **/ios/**/.tags* 50 | **/ios/**/.vagrant/ 51 | **/ios/**/DerivedData/ 52 | **/ios/**/Icon? 53 | **/ios/**/Pods/ 54 | **/ios/**/.symlinks/ 55 | **/ios/**/profile 56 | **/ios/**/xcuserdata 57 | **/ios/.generated/ 58 | **/ios/Flutter/App.framework 59 | **/ios/Flutter/Flutter.framework 60 | **/ios/Flutter/Generated.xcconfig 61 | **/ios/Flutter/app.flx 62 | **/ios/Flutter/app.zip 63 | **/ios/Flutter/flutter_assets/ 64 | **/ios/Flutter/flutter_export_environment.sh 65 | **/ios/ServiceDefinitions.json 66 | **/ios/Runner/GeneratedPluginRegistrant.* 67 | 68 | # Exceptions to above rules. 69 | !**/ios/**/default.mode1v3 70 | !**/ios/**/default.mode2v3 71 | !**/ios/**/default.pbxuser 72 | !**/ios/**/default.perspectivev3 73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 74 | /ios/flutter_branch_sdk/.build 75 | /example/android/app/.cxx 76 | /ios/flutter_branch_sdk/.index-build 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Rodrigo de Souza Marques 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | 6 | formatter: 7 | page_width: 123 8 | 9 | linter: 10 | rules: 11 | constant_identifier_names: false 12 | # public_member_api_docs: true 13 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 14 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .cxx 10 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group = 'br.com.rsmarques.flutter_branch_sdk' 2 | version = '1.0' 3 | 4 | def getPackageVersion() { 5 | def props = new Properties() 6 | file('../pubspec.yaml').withInputStream { props.load(it) } 7 | // println props.getProperty("version") 8 | props.getProperty("version") 9 | } 10 | 11 | buildscript { 12 | repositories { 13 | google() 14 | mavenCentral() 15 | } 16 | 17 | dependencies { 18 | classpath("com.android.tools.build:gradle:8.2.2") 19 | } 20 | } 21 | 22 | rootProject.allprojects { 23 | repositories { 24 | google() 25 | mavenCentral() 26 | } 27 | } 28 | 29 | apply plugin: 'com.android.library' 30 | 31 | android { 32 | // Conditional for compatibility with AGP <4.2. 33 | if (project.android.hasProperty("namespace")) { 34 | namespace 'br.com.rsmarques.flutter_branch_sdk' 35 | } 36 | 37 | compileSdk 35 38 | 39 | compileOptions { 40 | sourceCompatibility JavaVersion.VERSION_11 41 | targetCompatibility JavaVersion.VERSION_11 42 | } 43 | 44 | buildFeatures { 45 | buildConfig = true 46 | } 47 | defaultConfig { 48 | minSdkVersion 21 49 | buildConfigField("String", "FBRANCH_VERSION", "\"${getPackageVersion()}\"") 50 | } 51 | 52 | dependencies { 53 | implementation 'io.branch.sdk.android:library:5.18.+' 54 | implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0' 55 | implementation 'androidx.lifecycle:lifecycle-runtime:2.8.7' 56 | implementation 'androidx.browser:browser:1.8.0' 57 | implementation "store.galaxy.samsung.installreferrer:samsung_galaxystore_install_referrer:4.0.0" 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'flutter_branch_sdk' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/src/main/assets/branch.json: -------------------------------------------------------------------------------- 1 | { 2 | "deferInitForPluginRuntime": true 3 | } -------------------------------------------------------------------------------- /android/src/main/java/br/com/rsmarques/flutter_branch_sdk/FlutterBranchSdkHelper.java: -------------------------------------------------------------------------------- 1 | package br.com.rsmarques.flutter_branch_sdk; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONException; 5 | import org.json.JSONObject; 6 | 7 | import java.time.Instant; 8 | import java.util.ArrayList; 9 | import java.util.Calendar; 10 | import java.util.Date; 11 | import java.util.HashMap; 12 | import java.util.Iterator; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | import io.branch.indexing.BranchUniversalObject; 17 | import io.branch.referral.QRCode.BranchQRCode; 18 | import io.branch.referral.util.AdType; 19 | import io.branch.referral.util.BRANCH_STANDARD_EVENT; 20 | import io.branch.referral.util.BranchContentSchema; 21 | import io.branch.referral.util.BranchEvent; 22 | import io.branch.referral.util.ContentMetadata; 23 | import io.branch.referral.util.CurrencyType; 24 | import io.branch.referral.util.LinkProperties; 25 | import io.branch.referral.util.ProductCategory; 26 | 27 | public class FlutterBranchSdkHelper { 28 | /**--------------------------------------------------------------------------------------------- 29 | Object Conversion Functions 30 | --------------------------------------------------------------------------------------------**/ 31 | BranchUniversalObject convertToBUO(HashMap argsMap) { 32 | 33 | BranchUniversalObject buo = new BranchUniversalObject(); 34 | String canonicalIdentifier = (String) argsMap.get("canonicalIdentifier"); 35 | buo.setCanonicalIdentifier(canonicalIdentifier); 36 | 37 | if (argsMap.containsKey("canonicalUrl")) 38 | buo.setCanonicalUrl((String) argsMap.get("canonicalUrl")); 39 | if (argsMap.containsKey("title")) 40 | buo.setTitle((String) argsMap.get("title")); 41 | if (argsMap.containsKey("contentDescription")) 42 | buo.setContentDescription((String) argsMap.get("contentDescription")); 43 | if (argsMap.containsKey("imageUrl")) 44 | buo.setContentImageUrl((String) argsMap.get("imageUrl")); 45 | if (argsMap.containsKey("keywords")) 46 | buo.addKeyWords((ArrayList) argsMap.get("keywords")); 47 | if (argsMap.containsKey("expirationDate")) 48 | buo.setContentExpiration(new Date((long) argsMap.get("expirationDate"))); 49 | 50 | if (argsMap.containsKey("locallyIndex")) { 51 | boolean value = (boolean) argsMap.get("locallyIndex"); 52 | if (value) { 53 | buo.setLocalIndexMode(BranchUniversalObject.CONTENT_INDEX_MODE.PUBLIC); 54 | } else 55 | buo.setLocalIndexMode(BranchUniversalObject.CONTENT_INDEX_MODE.PRIVATE); 56 | } 57 | if (argsMap.containsKey("publiclyIndex")) { 58 | boolean value = (boolean) argsMap.get("publiclyIndex"); 59 | if (value) { 60 | buo.setContentIndexingMode(BranchUniversalObject.CONTENT_INDEX_MODE.PUBLIC); 61 | } else 62 | buo.setContentIndexingMode(BranchUniversalObject.CONTENT_INDEX_MODE.PRIVATE); 63 | } 64 | if (argsMap.containsKey("contentMetadata")) { 65 | HashMap contentMap = (HashMap) argsMap.get("contentMetadata"); 66 | ContentMetadata contentMetadata = new ContentMetadata(); 67 | if (contentMap.containsKey("quantity")) 68 | contentMetadata.setQuantity((double) contentMap.get("quantity")); 69 | if (contentMap.containsKey("price") && contentMap.containsKey("currency")) { 70 | contentMetadata.setPrice((double) contentMap.get("price"), CurrencyType.getValue((String) contentMap.get("currency"))); 71 | } 72 | if (contentMap.containsKey("rating_average") || contentMap.containsKey("rating_count") || 73 | contentMap.containsKey("rating_max") || contentMap.containsKey("rating")) { 74 | Double rating = null; 75 | if (contentMap.containsKey("rating")) { 76 | rating = (double) contentMap.get("rating"); 77 | } 78 | Double rating_average = null; 79 | if (contentMap.containsKey("rating_average")) { 80 | rating_average = (double) contentMap.get("rating_average"); 81 | } 82 | Integer rating_count = null; 83 | if (contentMap.containsKey("rating_count")) { 84 | rating_count = (Integer) contentMap.get("rating_count"); 85 | } 86 | Double rating_max = null; 87 | if (contentMap.containsKey("rating_max")) { 88 | rating_max = (double) contentMap.get("rating_max"); 89 | } 90 | contentMetadata.setRating(rating, rating_average, rating_max, rating_count); 91 | } 92 | if (contentMap.containsKey("latitude") && contentMap.containsKey("longitude")) { 93 | contentMetadata.setLocation((double) contentMap.get("latitude"), (double) contentMap.get("longitude")); 94 | } 95 | if (contentMap.containsKey("address_street") || contentMap.containsKey("address_city") || 96 | contentMap.containsKey("address_region") || contentMap.containsKey("address_country") || contentMap.containsKey("address_postal_code")) { 97 | String street = (String) contentMap.get("address_street"); 98 | String city = (String) contentMap.get("address_city"); 99 | String region = (String) contentMap.get("address_region"); 100 | String country = (String) contentMap.get("address_country"); 101 | String postal_code = (String) contentMap.get("address_postal_code"); 102 | contentMetadata.setAddress(street, city, region, country, postal_code); 103 | } 104 | if (contentMap.containsKey("content_schema")) { 105 | contentMetadata.setContentSchema(BranchContentSchema.getValue((String) contentMap.get("content_schema"))); 106 | } 107 | if (contentMap.containsKey("sku")) { 108 | contentMetadata.setSku((String) contentMap.get("sku")); 109 | } 110 | if (contentMap.containsKey("product_name")) { 111 | contentMetadata.setProductName((String) contentMap.get("product_name")); 112 | } 113 | if (contentMap.containsKey("product_brand")) { 114 | contentMetadata.setProductBrand((String) contentMap.get("product_brand")); 115 | } 116 | if (contentMap.containsKey("product_category")) { 117 | contentMetadata.setProductCategory(ProductCategory.getValue((String) contentMap.get("product_category"))); 118 | } 119 | if (contentMap.containsKey("product_variant")) { 120 | contentMetadata.setProductVariant((String) contentMap.get("product_variant")); 121 | } 122 | if (contentMap.containsKey("condition")) { 123 | contentMetadata.setProductCondition(ContentMetadata.CONDITION.getValue((String) contentMap.get("product_category"))); 124 | } 125 | if (contentMap.containsKey("image_captions")) { 126 | ArrayList _imageCaptions = (ArrayList) contentMap.get("image_captions"); 127 | for (int i = 0; i < _imageCaptions.size(); i++) { 128 | contentMetadata.addImageCaptions(_imageCaptions.get(i)); 129 | } 130 | } 131 | if (contentMap.containsKey("customMetadata")) { 132 | for (Map.Entry customMetaData : ((HashMap) contentMap.get("customMetadata")).entrySet()) { 133 | contentMetadata.addCustomMetadata(customMetaData.getKey(), customMetaData.getValue().toString()); 134 | } 135 | } 136 | buo.setContentMetadata(contentMetadata); 137 | } 138 | return buo; 139 | } 140 | 141 | LinkProperties convertToLinkProperties(HashMap argsMap) { 142 | 143 | LinkProperties linkProperties = new LinkProperties(); 144 | 145 | if (argsMap.containsKey("channel")) 146 | linkProperties.setChannel((String) argsMap.get("channel")); 147 | if (argsMap.containsKey("feature")) 148 | linkProperties.setFeature((String) argsMap.get("feature")); 149 | if (argsMap.containsKey("campaign")) 150 | linkProperties.setCampaign((String) argsMap.get("campaign")); 151 | if (argsMap.containsKey("stage")) 152 | linkProperties.setStage((String) argsMap.get("stage")); 153 | if (argsMap.containsKey("alias")) 154 | linkProperties.setAlias((String) argsMap.get("alias")); 155 | if (argsMap.containsKey("matchDuration")) 156 | linkProperties.setDuration((int) argsMap.get("matchDuration")); 157 | if (argsMap.containsKey("tags")) { 158 | ArrayList _tags = (ArrayList) argsMap.get("tags"); 159 | for (int i = 0; i < _tags.size(); i++) { 160 | linkProperties.addTag(_tags.get(i)); 161 | } 162 | } 163 | if (argsMap.containsKey("controlParams")) { 164 | for (Map.Entry content : ((HashMap) argsMap.get("controlParams")).entrySet()) { 165 | linkProperties.addControlParameter(content.getKey(), content.getValue()); 166 | } 167 | } 168 | return linkProperties; 169 | } 170 | 171 | BranchEvent convertToEvent(HashMap eventMap) { 172 | BranchEvent event; 173 | 174 | if ((boolean) eventMap.get("isStandardEvent")) { 175 | event = new BranchEvent(BRANCH_STANDARD_EVENT.valueOf((String) eventMap.get("eventName"))); 176 | } else { 177 | event = new BranchEvent((String) eventMap.get("eventName")); 178 | } 179 | if (eventMap.containsKey("transactionID")) 180 | event.setTransactionID((String) eventMap.get("transactionID")); 181 | if (eventMap.containsKey("currency")) 182 | event.setCurrency(CurrencyType.getValue((String) eventMap.get("currency"))); 183 | if (eventMap.containsKey("revenue")) 184 | event.setRevenue((Double) eventMap.get("revenue")); 185 | if (eventMap.containsKey("shipping")) 186 | event.setShipping((Double) eventMap.get("shipping")); 187 | if (eventMap.containsKey("tax")) 188 | event.setTax((Double) eventMap.get("tax")); 189 | if (eventMap.containsKey("coupon")) 190 | event.setCoupon((String) eventMap.get("coupon")); 191 | if (eventMap.containsKey("affiliation")) 192 | event.setAffiliation((String) eventMap.get("affiliation")); 193 | if (eventMap.containsKey("eventDescription")) 194 | event.setDescription((String) eventMap.get("eventDescription")); 195 | if (eventMap.containsKey("searchQuery")) 196 | event.setSearchQuery((String) eventMap.get("searchQuery")); 197 | if (eventMap.containsKey("adType")) 198 | event.setAdType(convertToAdType((String) eventMap.get("adType"))); 199 | if (eventMap.containsKey("customData")) { 200 | for (Map.Entry customData : ((HashMap) eventMap.get("customData")).entrySet()) { 201 | event.addCustomDataProperty(customData.getKey(), customData.getValue()); 202 | } 203 | } 204 | if (eventMap.containsKey("alias")) { 205 | event.setCustomerEventAlias((String) eventMap.get("alias")); 206 | } 207 | return event; 208 | } 209 | 210 | BranchQRCode convertToQRCode(HashMap qrCodeMap) { 211 | BranchQRCode branchQRCode = new BranchQRCode(); 212 | if (qrCodeMap.containsKey("width")) { 213 | branchQRCode.setWidth((int) qrCodeMap.get("width")); 214 | } 215 | if (qrCodeMap.containsKey("margin")) { 216 | branchQRCode.setMargin((int) qrCodeMap.get("margin")); 217 | } 218 | if (qrCodeMap.containsKey("codeColor")) { 219 | branchQRCode.setCodeColor((String) qrCodeMap.get("codeColor")); 220 | } 221 | if (qrCodeMap.containsKey("backgroundColor")) { 222 | branchQRCode.setBackgroundColor((String) qrCodeMap.get("backgroundColor")); 223 | } 224 | if (qrCodeMap.containsKey("imageFormat")) { 225 | final String imageFormat = (String) qrCodeMap.get("imageFormat"); 226 | if (imageFormat.equals("JPEG")) { 227 | branchQRCode.setImageFormat(BranchQRCode.BranchImageFormat.JPEG); 228 | } else { 229 | branchQRCode.setImageFormat(BranchQRCode.BranchImageFormat.PNG); 230 | } 231 | } 232 | if (qrCodeMap.containsKey("centerLogoUrl")) { 233 | branchQRCode.setCenterLogo((String) qrCodeMap.get("centerLogoUrl")); 234 | } 235 | return branchQRCode; 236 | } 237 | 238 | AdType convertToAdType(String adType) { 239 | switch (adType) { 240 | case "BANNER": 241 | return AdType.BANNER; 242 | case "INTERSTITIAL": 243 | return AdType.INTERSTITIAL; 244 | case "REWARDED_VIDEO": 245 | return AdType.REWARDED_VIDEO; 246 | case "NATIVE": 247 | return AdType.NATIVE; 248 | default: 249 | throw new IllegalStateException("Unexpected value: " + adType); 250 | } 251 | } 252 | 253 | //---------------------------------------------------------------------------------------------- 254 | 255 | Map paramsToMap(JSONObject jsonObject) throws JSONException { 256 | Map map = new HashMap<>(); 257 | Iterator keys = jsonObject.keys(); 258 | while (keys.hasNext()) { 259 | String key = keys.next(); 260 | Object value = jsonObject.get(key); 261 | if (value instanceof JSONArray) { 262 | value = jsonArrayToList((JSONArray) value); 263 | } else if (value instanceof JSONObject) { 264 | value = paramsToMap((JSONObject) value); 265 | } 266 | map.put(key, value); 267 | } 268 | return map; 269 | } 270 | 271 | List jsonArrayToList(JSONArray array) throws JSONException { 272 | List list = new ArrayList<>(); 273 | for (int i = 0; i < array.length(); i++) { 274 | Object value = array.get(i); 275 | if (value instanceof JSONArray) { 276 | value = jsonArrayToList((JSONArray) value); 277 | } else if (value instanceof JSONObject) { 278 | value = paramsToMap((JSONObject) value); 279 | } 280 | list.add(value); 281 | } 282 | return list; 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /android/src/main/java/br/com/rsmarques/flutter_branch_sdk/FlutterBranchSdkInit.java: -------------------------------------------------------------------------------- 1 | package br.com.rsmarques.flutter_branch_sdk; 2 | 3 | import android.content.Context; 4 | 5 | import io.branch.referral.Branch; 6 | 7 | public class FlutterBranchSdkInit { 8 | private static final String DEBUG_NAME = "FlutterBranchSDK"; 9 | private static final String PLUGIN_NAME = "Flutter"; 10 | //private static final String PLUGIN_VERSION = "8.0.0"; 11 | 12 | public static void init(Context context) { 13 | LogUtils.debug(DEBUG_NAME, "SDK Init"); 14 | Branch.expectDelayedSessionInitialization(true); 15 | Branch.registerPlugin(PLUGIN_NAME, br.com.rsmarques.flutter_branch_sdk.BuildConfig.FBRANCH_VERSION); 16 | Branch.getAutoInstance(context); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /android/src/main/java/br/com/rsmarques/flutter_branch_sdk/LogUtils.java: -------------------------------------------------------------------------------- 1 | package br.com.rsmarques.flutter_branch_sdk; 2 | 3 | import android.util.Log; 4 | 5 | import io.flutter.BuildConfig; 6 | 7 | public class LogUtils { 8 | public static void debug(final String tag, String message) { 9 | if (BuildConfig.DEBUG) { 10 | Log.d(tag, message); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/src/main/java/br/com/rsmarques/flutter_branch_sdk/MainThreadEventSink.java: -------------------------------------------------------------------------------- 1 | package br.com.rsmarques.flutter_branch_sdk; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | 6 | import io.flutter.plugin.common.EventChannel; 7 | 8 | public class MainThreadEventSink implements EventChannel.EventSink { 9 | private final EventChannel.EventSink eventSink; 10 | private final Handler handler; 11 | 12 | MainThreadEventSink(EventChannel.EventSink eventSink) { 13 | this.eventSink = eventSink; 14 | handler = new Handler(Looper.getMainLooper()); 15 | } 16 | 17 | @Override 18 | public void success(final Object o) { 19 | handler.post(new Runnable() { 20 | @Override 21 | public void run() { 22 | try { 23 | if (eventSink != null) { 24 | eventSink.success(o); 25 | } 26 | } catch (Exception e) { 27 | e.printStackTrace(); 28 | } 29 | } 30 | }); 31 | } 32 | 33 | @Override 34 | public void error(final String s, final String s1, final Object o) { 35 | handler.post(new Runnable() { 36 | @Override 37 | public void run() { 38 | try { 39 | if (eventSink != null) { 40 | eventSink.error(s, s1, o); 41 | } 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | }); 47 | } 48 | 49 | @Override 50 | public void endOfStream() { 51 | handler.post(new Runnable() { 52 | @Override 53 | public void run() { 54 | try { 55 | if (eventSink != null) { 56 | eventSink.endOfStream(); 57 | } 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /android/src/main/java/br/com/rsmarques/flutter_branch_sdk/MethodResultWrapper.java: -------------------------------------------------------------------------------- 1 | package br.com.rsmarques.flutter_branch_sdk; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | 6 | import io.flutter.plugin.common.MethodChannel; 7 | 8 | // MethodChannel.Result wrapper that responds on the platform thread. 9 | public class MethodResultWrapper implements MethodChannel.Result { 10 | private final MethodChannel.Result methodResult; 11 | private final Handler handler; 12 | private boolean called; 13 | 14 | MethodResultWrapper(MethodChannel.Result result) { 15 | methodResult = result; 16 | handler = new Handler(Looper.getMainLooper()); 17 | } 18 | 19 | private synchronized boolean checkNotCalled() { 20 | if (called) { 21 | return false; 22 | } 23 | called = true; 24 | return true; 25 | } 26 | 27 | @Override 28 | public void success(final Object result) { 29 | if (!checkNotCalled()) { 30 | return; 31 | } 32 | handler.post( 33 | new Runnable() { 34 | @Override 35 | public void run() { 36 | try { 37 | methodResult.success(result); 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | } 42 | }); 43 | } 44 | 45 | @Override 46 | public void error( 47 | final String errorCode, final String errorMessage, final Object errorDetails) { 48 | if (!checkNotCalled()) { 49 | return; 50 | } 51 | handler.post( 52 | new Runnable() { 53 | @Override 54 | public void run() { 55 | try { 56 | methodResult.error(errorCode, errorMessage, errorDetails); 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | } 60 | } 61 | }); 62 | } 63 | 64 | @Override 65 | public void notImplemented() { 66 | if (!checkNotCalled()) { 67 | return; 68 | } 69 | handler.post( 70 | new Runnable() { 71 | @Override 72 | public void run() { 73 | try { 74 | methodResult.notImplemented(); 75 | } catch (Exception e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | }); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /assets/app_tracking_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/assets/app_tracking_dialog.png -------------------------------------------------------------------------------- /assets/branch.json: -------------------------------------------------------------------------------- 1 | { 2 | "useTestInstance": true 3 | } 4 | -------------------------------------------------------------------------------- /assets/branch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/assets/branch.png -------------------------------------------------------------------------------- /assets/branch_json_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/assets/branch_json_add.png -------------------------------------------------------------------------------- /assets/branch_json_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/assets/branch_json_project.png -------------------------------------------------------------------------------- /assets/branch_logo_qrcode.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/assets/branch_logo_qrcode.jpeg -------------------------------------------------------------------------------- /assets/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/assets/example.png -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | /build/ 36 | 37 | # Web related 38 | 39 | # Symbolication related 40 | app.*.symbols 41 | 42 | # Obfuscation related 43 | app.*.map.json 44 | 45 | # Android Studio will place build artifacts here 46 | /android/app/debug 47 | /android/app/profile 48 | /android/app/release 49 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 17 | base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 18 | - platform: web 19 | create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 20 | base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819 21 | 22 | # User provided section 23 | 24 | # List of Local paths (relative to this file) that should be 25 | # ignored by the migrate tool. 26 | # 27 | # Files that are not part of the templates will be ignored by default. 28 | unmanaged_files: 29 | - 'lib/main.dart' 30 | - 'ios/Runner.xcodeproj/project.pbxproj' 31 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # flutter_branch_sdk_example 2 | 3 | Demonstrates how to use the flutter_branch_sdk plugin. 4 | 5 | ## Getting Started 6 | 7 | See the `example` directory for a complete sample app using Branch SDK. 8 | 9 | ![Example app](https://user-images.githubusercontent.com/17687286/70445281-0b87c180-1a7a-11ea-8611-7217d46c75a7.png) -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | formatter: 13 | page_width: 123 14 | 15 | linter: 16 | # The lint rules applied to this project can be customized in the 17 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 18 | # included above or to enable additional rules. A list of all available lints 19 | # and their documentation is published at 20 | # https://dart-lang.github.io/linter/lints/index.html. 21 | # 22 | # Instead of disabling a lint rule for the entire project in the 23 | # section below, it can also be suppressed for a single line of code 24 | # or a specific dart file by using the `// ignore: name_of_lint` and 25 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 26 | # producing the lint. 27 | rules: 28 | avoid_print: false # Uncomment to disable the `avoid_print` rule 29 | prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 30 | 31 | 32 | # Additional information about this file can be found at 33 | # https://dart.dev/guides/language/analysis-options 34 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id "dev.flutter.flutter-gradle-plugin" 6 | } 7 | 8 | android { 9 | namespace 'br.com.rsmarques.flutter_branch_sdk_example' 10 | compileSdk = flutter.compileSdkVersion 11 | ndkVersion = flutter.ndkVersion 12 | 13 | compileOptions { 14 | sourceCompatibility JavaVersion.VERSION_11 15 | targetCompatibility JavaVersion.VERSION_11 16 | } 17 | 18 | kotlinOptions { 19 | jvmTarget = JavaVersion.VERSION_11 20 | } 21 | 22 | defaultConfig { 23 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 24 | applicationId "br.com.rsmarques.flutter_branch_sdk_example" 25 | // You can update the following values to match your application needs. 26 | // For more information, see: https://flutter.dev/to/review-gradle-config. 27 | minSdk = flutter.minSdkVersion 28 | targetSdk = flutter.targetSdkVersion 29 | versionCode = flutter.versionCode 30 | versionName = flutter.versionName 31 | multiDexEnabled true 32 | } 33 | 34 | buildTypes { 35 | release { 36 | // TODO: Add your own signing config for the release build. 37 | // Signing with the debug keys for now, so `flutter run --release` works. 38 | signingConfig signingConfigs.debug 39 | shrinkResources true 40 | minifyEnabled true 41 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 42 | } 43 | } 44 | } 45 | 46 | flutter { 47 | source '../..' 48 | } 49 | -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class com.google.android.gms.** { *; } -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 51 | 52 | 55 | 56 | 59 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/br/com/rsmarques/flutter_branch_sdk_example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package br.com.rsmarques.flutter_branch_sdk_example; 2 | 3 | import io.flutter.embedding.android.FlutterActivity; 4 | 5 | public class MainActivity extends FlutterActivity { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = '../build' 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(':app') 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | android.defaults.buildfeatures.buildconfig=true 5 | android.nonTransitiveRClass=false 6 | android.nonFinalResIds=false 7 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "8.2.2" apply false 22 | id "org.jetbrains.kotlin.android" version "1.8.22" apply false 23 | } 24 | 25 | include ":app" 26 | -------------------------------------------------------------------------------- /example/assets/images/branch_logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/assets/images/branch_logo.jpeg -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '12.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | 4 | DEPENDENCIES: 5 | - Flutter (from `Flutter`) 6 | 7 | EXTERNAL SOURCES: 8 | Flutter: 9 | :path: Flutter 10 | 11 | SPEC CHECKSUMS: 12 | Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 13 | 14 | PODFILE CHECKSUM: 4e8f8b2be68aeea4c0d5beb6ff1e79fface1d048 15 | 16 | COCOAPODS: 1.16.2 17 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "5d76efac60f24ab19e3242c4ab5e2221c42909bca3cd8f4f737ce4a88473446e", 3 | "pins" : [ 4 | { 5 | "identity" : "ios-branch-sdk-spm", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/BranchMetrics/ios-branch-sdk-spm", 8 | "state" : { 9 | "revision" : "26d4a43d7b8bda3ecb2a88eabc0d7c09d4baa8b7", 10 | "version" : "3.12.1" 11 | } 12 | } 13 | ], 14 | "version" : 3 15 | } 16 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 11 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 56 | 57 | 58 | 59 | 60 | 61 | 73 | 75 | 81 | 82 | 83 | 84 | 90 | 92 | 98 | 99 | 100 | 101 | 103 | 104 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "5d76efac60f24ab19e3242c4ab5e2221c42909bca3cd8f4f737ce4a88473446e", 3 | "pins" : [ 4 | { 5 | "identity" : "ios-branch-sdk-spm", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/BranchMetrics/ios-branch-sdk-spm", 8 | "state" : { 9 | "revision" : "26d4a43d7b8bda3ecb2a88eabc0d7c09d4baa8b7", 10 | "version" : "3.12.1" 11 | } 12 | } 13 | ], 14 | "version" : 3 15 | } 16 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | Flutter Branch Sdk 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | flutter_branch_sdk_example 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleURLTypes 26 | 27 | 28 | CFBundleTypeRole 29 | Editor 30 | CFBundleURLSchemes 31 | 32 | flutterbranchsdk 33 | 34 | CFBundleURLName 35 | br.com.rsmarques.flutter-branch-sdk-example 36 | 37 | 38 | CFBundleVersion 39 | $(FLUTTER_BUILD_NUMBER) 40 | LSRequiresIPhoneOS 41 | 42 | NSUserTrackingUsageDescription 43 | App would like to access IDFA for tracking purpose 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UISupportedInterfaceOrientations~ipad 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationPortraitUpsideDown 58 | UIInterfaceOrientationLandscapeLeft 59 | UIInterfaceOrientationLandscapeRight 60 | 61 | UIViewControllerBasedStatusBarAppearance 62 | 63 | branch_key 64 | 65 | live 66 | key_live_bkJRqpb15wLqUAgsDVNUIobjyviWi6Wx 67 | test 68 | key_test_ipQTteg11ENANDeCzSXgqdgfuycWoXYH 69 | 70 | branch_universal_link_domains 71 | 72 | flutterbranchsdk.app.link 73 | flutterbranchsdk-alternate.app.link 74 | flutterbranchsdk-alternate.test-app.link 75 | flutterbranchsdk.test-app.link 76 | 77 | branch_disable_nativelink 78 | 79 | FlutterDeepLinkingEnabled 80 | 81 | UIApplicationSupportsIndirectInputEvents 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.associated-domains 6 | 7 | applinks:flutterbranchsdk.app.link 8 | applinks:flutterbranchsdk-alternate.app.link 9 | applinks:flutterbranchsdk.test-app.link 10 | applinks:flutterbranchsdk-alternate.test-app.link 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/lib/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'home_page.dart'; 4 | 5 | class MyApp extends StatelessWidget { 6 | const MyApp({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | title: 'Flutter Branch SDK Example', 12 | debugShowCheckedModeBanner: false, 13 | home: const HomePage(), 14 | theme: ThemeData( 15 | colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), 16 | useMaterial3: false, 17 | ), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /example/lib/custom_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomButton extends StatelessWidget { 4 | const CustomButton({super.key, required this.onPressed, required this.child}); 5 | 6 | final GestureTapCallback onPressed; 7 | final Widget child; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | height: 50, 13 | padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 2), 14 | child: ElevatedButton( 15 | onPressed: onPressed, 16 | child: child, 17 | )); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart' show PlatformDispatcher; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_branch_sdk/flutter_branch_sdk.dart'; 4 | 5 | import 'app.dart'; 6 | 7 | void main() async { 8 | WidgetsFlutterBinding.ensureInitialized(); 9 | FlutterError.onError = (details) { 10 | FlutterError.presentError(details); 11 | }; 12 | 13 | PlatformDispatcher.instance.onError = (error, stack) { 14 | debugPrintStack(stackTrace: stack); 15 | return true; 16 | }; 17 | 18 | //FlutterBranchSdk.setPreinstallCampaign('My Campaign Name'); 19 | //FlutterBranchSdk.setPreinstallPartner('Branch \$3p Parameter Value'); 20 | //FlutterBranchSdk.clearPartnerParameters(); 21 | /* 22 | FlutterBranchSdk.addFacebookPartnerParameter( 23 | key: 'em', 24 | value: 25 | '11234e56af071e9c79927651156bd7a10bca8ac34672aba121056e2698ee7088'); 26 | FlutterBranchSdk.addSnapPartnerParameter( 27 | key: 'hashed_email_address', 28 | value: 29 | '11234e56af071e9c79927651156bd7a10bca8ac34672aba121056e2698ee7088'); 30 | FlutterBranchSdk.setRequestMetadata('key1', 'value1'); 31 | FlqutterBranchSdk.setRequestMetadata('key2', 'value2'); 32 | */ 33 | 34 | await FlutterBranchSdk.init(enableLogging: true, branchAttributionLevel: BranchAttributionLevel.FULL); 35 | FlutterBranchSdk.setConsumerProtectionAttributionLevel(BranchAttributionLevel.FULL); 36 | 37 | /* 38 | AppTrackingStatus status = await FlutterBranchSdk.requestTrackingAuthorization(); 39 | if (status == AppTrackingStatus.notSupported) { 40 | debugPrint('not supported'); 41 | } 42 | FlutterBranchSdk.disableTracking(true); 43 | */ 44 | runApp(const MyApp()); 45 | } 46 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.13.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.2" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.4.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.2" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.19.1" 44 | crypto: 45 | dependency: transitive 46 | description: 47 | name: crypto 48 | sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "3.0.6" 52 | cupertino_icons: 53 | dependency: "direct main" 54 | description: 55 | name: cupertino_icons 56 | sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.0.8" 60 | fake_async: 61 | dependency: transitive 62 | description: 63 | name: fake_async 64 | sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.3.3" 68 | fixnum: 69 | dependency: transitive 70 | description: 71 | name: fixnum 72 | sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "1.1.1" 76 | flutter: 77 | dependency: "direct main" 78 | description: flutter 79 | source: sdk 80 | version: "0.0.0" 81 | flutter_branch_sdk: 82 | dependency: "direct main" 83 | description: 84 | path: ".." 85 | relative: true 86 | source: path 87 | version: "8.5.0" 88 | flutter_lints: 89 | dependency: "direct dev" 90 | description: 91 | name: flutter_lints 92 | sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" 93 | url: "https://pub.dev" 94 | source: hosted 95 | version: "5.0.0" 96 | flutter_test: 97 | dependency: "direct dev" 98 | description: flutter 99 | source: sdk 100 | version: "0.0.0" 101 | flutter_web_plugins: 102 | dependency: transitive 103 | description: flutter 104 | source: sdk 105 | version: "0.0.0" 106 | intl: 107 | dependency: "direct main" 108 | description: 109 | name: intl 110 | sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" 111 | url: "https://pub.dev" 112 | source: hosted 113 | version: "0.20.2" 114 | leak_tracker: 115 | dependency: transitive 116 | description: 117 | name: leak_tracker 118 | sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" 119 | url: "https://pub.dev" 120 | source: hosted 121 | version: "10.0.9" 122 | leak_tracker_flutter_testing: 123 | dependency: transitive 124 | description: 125 | name: leak_tracker_flutter_testing 126 | sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 127 | url: "https://pub.dev" 128 | source: hosted 129 | version: "3.0.9" 130 | leak_tracker_testing: 131 | dependency: transitive 132 | description: 133 | name: leak_tracker_testing 134 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 135 | url: "https://pub.dev" 136 | source: hosted 137 | version: "3.0.1" 138 | lints: 139 | dependency: transitive 140 | description: 141 | name: lints 142 | sha256: "4a16b3f03741e1252fda5de3ce712666d010ba2122f8e912c94f9f7b90e1a4c3" 143 | url: "https://pub.dev" 144 | source: hosted 145 | version: "5.1.0" 146 | matcher: 147 | dependency: transitive 148 | description: 149 | name: matcher 150 | sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 151 | url: "https://pub.dev" 152 | source: hosted 153 | version: "0.12.17" 154 | material_color_utilities: 155 | dependency: transitive 156 | description: 157 | name: material_color_utilities 158 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 159 | url: "https://pub.dev" 160 | source: hosted 161 | version: "0.11.1" 162 | meta: 163 | dependency: transitive 164 | description: 165 | name: meta 166 | sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c 167 | url: "https://pub.dev" 168 | source: hosted 169 | version: "1.16.0" 170 | path: 171 | dependency: transitive 172 | description: 173 | name: path 174 | sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" 175 | url: "https://pub.dev" 176 | source: hosted 177 | version: "1.9.1" 178 | plugin_platform_interface: 179 | dependency: transitive 180 | description: 181 | name: plugin_platform_interface 182 | sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" 183 | url: "https://pub.dev" 184 | source: hosted 185 | version: "2.1.8" 186 | sky_engine: 187 | dependency: transitive 188 | description: flutter 189 | source: sdk 190 | version: "0.0.0" 191 | source_span: 192 | dependency: transitive 193 | description: 194 | name: source_span 195 | sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" 196 | url: "https://pub.dev" 197 | source: hosted 198 | version: "1.10.1" 199 | sprintf: 200 | dependency: transitive 201 | description: 202 | name: sprintf 203 | sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" 204 | url: "https://pub.dev" 205 | source: hosted 206 | version: "7.0.0" 207 | stack_trace: 208 | dependency: transitive 209 | description: 210 | name: stack_trace 211 | sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" 212 | url: "https://pub.dev" 213 | source: hosted 214 | version: "1.12.1" 215 | stream_channel: 216 | dependency: transitive 217 | description: 218 | name: stream_channel 219 | sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" 220 | url: "https://pub.dev" 221 | source: hosted 222 | version: "2.1.4" 223 | string_scanner: 224 | dependency: transitive 225 | description: 226 | name: string_scanner 227 | sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" 228 | url: "https://pub.dev" 229 | source: hosted 230 | version: "1.4.1" 231 | term_glyph: 232 | dependency: transitive 233 | description: 234 | name: term_glyph 235 | sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" 236 | url: "https://pub.dev" 237 | source: hosted 238 | version: "1.2.2" 239 | test_api: 240 | dependency: transitive 241 | description: 242 | name: test_api 243 | sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd 244 | url: "https://pub.dev" 245 | source: hosted 246 | version: "0.7.4" 247 | typed_data: 248 | dependency: transitive 249 | description: 250 | name: typed_data 251 | sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 252 | url: "https://pub.dev" 253 | source: hosted 254 | version: "1.4.0" 255 | uuid: 256 | dependency: "direct main" 257 | description: 258 | name: uuid 259 | sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff 260 | url: "https://pub.dev" 261 | source: hosted 262 | version: "4.5.1" 263 | vector_math: 264 | dependency: transitive 265 | description: 266 | name: vector_math 267 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 268 | url: "https://pub.dev" 269 | source: hosted 270 | version: "2.1.4" 271 | vm_service: 272 | dependency: transitive 273 | description: 274 | name: vm_service 275 | sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 276 | url: "https://pub.dev" 277 | source: hosted 278 | version: "15.0.0" 279 | sdks: 280 | dart: ">=3.7.0-0 <4.0.0" 281 | flutter: ">=3.27.0" 282 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_branch_sdk_example 2 | description: Demonstrates how to use the flutter_branch_sdk plugin. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | environment: 9 | sdk: ">=3.3.0 <4.0.0" 10 | flutter: 3.27.0 11 | 12 | # Dependencies specify other packages that your package needs in order to work. 13 | # To automatically upgrade your package dependencies to the latest versions 14 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 15 | # dependencies can be manually updated by changing the version numbers below to 16 | # the latest version available on pub.dev. To see which dependencies have newer 17 | # versions available, run `flutter pub outdated`. 18 | dependencies: 19 | flutter: 20 | sdk: flutter 21 | 22 | flutter_branch_sdk: 23 | # When depending on this package from a real application you should use: 24 | # flutter_branch_sdk: ^x.y.z 25 | # See https://dart.dev/tools/pub/dependencies#version-constraints 26 | # The example app is bundled with the plugin so we use a path dependency on 27 | # the parent directory to use the current plugin's version. 28 | path: ../ 29 | 30 | # The following adds the Cupertino Icons font to your application. 31 | # Use with the CupertinoIcons class for iOS style icons. 32 | cupertino_icons: ^1.0.8 33 | uuid: ^4.5.1 34 | intl: ^0.20.2 35 | 36 | dev_dependencies: 37 | flutter_test: 38 | sdk: flutter 39 | 40 | # The "flutter_lints" package below contains a set of recommended lints to 41 | # encourage good coding practices. The lint set provided by the package is 42 | # activated in the `analysis_options.yaml` file located at the root of your 43 | # package. See that file for information about deactivating specific lint 44 | # rules and activating additional ones. 45 | flutter_lints: ^5.0.0 46 | 47 | # For information on the generic Dart part of this file, see the 48 | # following page: https://dart.dev/tools/pub/pubspec 49 | 50 | # The following section is specific to Flutter packages. 51 | flutter: 52 | 53 | # The following line ensures that the Material Icons font is 54 | # included with your application, so that you can use the icons in 55 | # the material Icons class. 56 | uses-material-design: true 57 | 58 | # To add assets to your application, add an assets section, like this: 59 | # assets: 60 | # - images/a_dot_burr.jpeg 61 | # - images/a_dot_ham.jpeg 62 | assets: 63 | - assets/images/branch_logo.jpeg 64 | 65 | # An image asset can refer to one or more resolution-specific "variants", see 66 | # https://flutter.dev/assets-and-images/#resolution-aware 67 | 68 | # For details regarding adding assets from package dependencies, see 69 | # https://flutter.dev/assets-and-images/#from-packages 70 | 71 | # To add custom fonts to your application, add a fonts section here, 72 | # in this "flutter" section. Each entry in this list should have a 73 | # "family" key with the font family name, and a "fonts" key with a 74 | # list giving the asset and other descriptors for the font. For 75 | # example: 76 | # fonts: 77 | # - family: Schyler 78 | # fonts: 79 | # - asset: fonts/Schyler-Regular.ttf 80 | # - asset: fonts/Schyler-Italic.ttf 81 | # style: italic 82 | # - family: Trajan Pro 83 | # fonts: 84 | # - asset: fonts/TrajanPro.ttf 85 | # - asset: fonts/TrajanPro_Bold.ttf 86 | # weight: 700 87 | # 88 | # For details regarding fonts from package dependencies, 89 | # see https://flutter.dev/custom-fonts/#from-packages 90 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/a49642822f80613a7f526dba45a84ecedb341ee4/example/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Flutter Branch SDK Example 33 | 34 | 35 | 36 | 37 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Demonstrates how to use the flutter_branch_sdk plugin.", 3 | "name": "Flutter Branch SDK Example", 4 | "short_name": "Flutter_Branch_SDK", 5 | "start_url": ".", 6 | "display": "standalone", 7 | "background_color": "#0175C2", 8 | "theme_color": "#0175C2", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/ephemeral/ 38 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/flutter_branch_sdk.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint flutter_branch_sdk.podspec` to validate before publishing. 4 | # 5 | require 'yaml' 6 | 7 | pubspec = YAML.load_file(File.join('..', 'pubspec.yaml')) 8 | library_version = pubspec['version'].gsub('+', '-') 9 | 10 | Pod::Spec.new do |s| 11 | s.name = 'flutter_branch_sdk' 12 | s.version = library_version 13 | s.summary = 'Flutter Plugin for create deep link using Brach SDK (https://branch.io). This plugin provides a cross-platform (iOS, Android, Web).' 14 | s.description = <<-DESC 15 | Flutter Plugin for create deep link using Brach SDK (https://branch.io). This plugin provides a cross-platform (iOS, Android, Web). 16 | DESC 17 | s.homepage = 'https://github.com/RodrigoSMarques/flutter_branch_sdk' 18 | s.license = { :file => '../LICENSE' } 19 | s.author = { 'Rodrigo S. Marques' => 'rodrigosmarques@gmail.com' } 20 | s.source = { :path => '.' } 21 | s.source_files = 'flutter_branch_sdk/sources/flutter_branch_sdk/**/*.swift' 22 | s.dependency 'Flutter' 23 | s.dependency 'BranchSDK', '~> 3.12.0' 24 | s.platform = :ios, '12.0' 25 | # Flutter.framework does not contain a i386 slice. 26 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 27 | s.swift_version = '5.0' 28 | end 29 | -------------------------------------------------------------------------------- /ios/flutter_branch_sdk/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/flutter_branch_sdk/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "ios-branch-sdk-spm", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/BranchMetrics/ios-branch-sdk-spm", 7 | "state" : { 8 | "revision" : "c68af055c0e2c643fff5b63705e815b780e4b014", 9 | "version" : "3.12.0" 10 | } 11 | } 12 | ], 13 | "version" : 2 14 | } 15 | -------------------------------------------------------------------------------- /ios/flutter_branch_sdk/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.9 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "flutter_branch_sdk", 8 | platforms: [ 9 | .iOS("12.0") 10 | ], 11 | products: [ 12 | .library(name: "flutter-branch-sdk", targets: ["flutter_branch_sdk"]) 13 | ], 14 | dependencies: [ 15 | .package(url: "https://github.com/BranchMetrics/ios-branch-sdk-spm", "3.12.0"..."3.13.0") 16 | ], 17 | targets: [ 18 | .target( 19 | name: "flutter_branch_sdk", 20 | dependencies: [ 21 | .product(name: "BranchSDK", package: "ios-branch-sdk-spm"), 22 | ], 23 | linkerSettings: [ 24 | .linkedFramework("CoreServices"), 25 | .linkedFramework("SystemConfiguration"), 26 | .linkedFramework("WebKit", .when(platforms: [.iOS])), 27 | .linkedFramework("CoreSpotlight", .when(platforms: [.iOS])), 28 | .linkedFramework("AdServices", .when(platforms: [.iOS])) 29 | ] 30 | ) 31 | ] 32 | ) 33 | -------------------------------------------------------------------------------- /ios/flutter_branch_sdk/sources/flutter_branch_sdk/FlutterBranchIoSdkHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterBranchIoSdkFunctions.swift 3 | // 4 | // 5 | // Created by Rodrigo Marques on 04/11/19. 6 | // 7 | 8 | import Foundation 9 | import BranchSDK 10 | 11 | //--------------------------------------------------------------------------------------------- 12 | // Object Conversion Functions 13 | // -------------------------------------------------------------------------------------------- 14 | func convertToBUO(dict: [String: Any?]) -> BranchUniversalObject? { 15 | guard let canonicalIdentifier = dict["canonicalIdentifier"] as? String? else { 16 | return nil 17 | } 18 | let buo = BranchUniversalObject.init() 19 | buo.canonicalIdentifier = canonicalIdentifier 20 | 21 | if let canonicalUrl = dict["canonicalUrl"] as? String { 22 | buo.canonicalUrl = canonicalUrl 23 | } 24 | if let title = dict["title"] as? String { 25 | buo.title = title 26 | } 27 | if let contentDescription = dict["contentDescription"] as? String { 28 | buo.contentDescription = contentDescription 29 | } 30 | if let imageUrl = dict["imageUrl"] as? String { 31 | buo.imageUrl = imageUrl 32 | } 33 | if let keywords = dict["keywords"] as? [String] { 34 | buo.keywords = keywords 35 | } 36 | if let expirationDate = dict["expirationDate"] as? Int64 { 37 | buo.expirationDate = Date(milliseconds: expirationDate) 38 | } 39 | if let locallyIndex = dict["locallyIndex"] as? Bool { 40 | buo.locallyIndex = locallyIndex 41 | } 42 | if let publiclyIndex = dict["publiclyIndex"] as? Bool { 43 | buo.publiclyIndex = publiclyIndex 44 | } 45 | if let contentMetadata = dict["contentMetadata"] as? [String: Any] { 46 | if let content_schema = contentMetadata["content_schema"] as? String { 47 | buo.contentMetadata.contentSchema = BranchContentSchema.init(rawValue: content_schema) 48 | } 49 | if let quantity = contentMetadata["quantity"] as? Double { 50 | buo.contentMetadata.quantity = quantity 51 | } 52 | if let price = contentMetadata["price"] as? Double { 53 | buo.contentMetadata.price = NSDecimalNumber(floatLiteral: price) 54 | } 55 | if let currency = contentMetadata["currency"] as? String { 56 | buo.contentMetadata.currency = BNCCurrency.init(rawValue: currency) 57 | } 58 | if let sku = contentMetadata["sku"] as? String { 59 | buo.contentMetadata.sku = sku 60 | } 61 | if let product_name = contentMetadata["product_name"] as? String { 62 | buo.contentMetadata.productName = product_name 63 | } 64 | if let product_brand = contentMetadata["product_brand"] as? String { 65 | buo.contentMetadata.productBrand = product_brand 66 | } 67 | if let product_category = contentMetadata["product_category"] as? String { 68 | buo.contentMetadata.productCategory = BNCProductCategory.init(rawValue: product_category) 69 | } 70 | if let product_variant = contentMetadata["product_variant"] as? String { 71 | buo.contentMetadata.productVariant = product_variant 72 | } 73 | if let condition = contentMetadata["condition"] as? String { 74 | buo.contentMetadata.condition = BranchCondition.init(rawValue: condition) 75 | } 76 | if let rating_average = contentMetadata["rating_average"] as? Double { 77 | buo.contentMetadata.ratingAverage = rating_average 78 | } 79 | if let rating_count = contentMetadata["rating_count"] as? Int { 80 | buo.contentMetadata.ratingCount = rating_count 81 | } 82 | if let rating_max = contentMetadata["rating_max"] as? Double { 83 | buo.contentMetadata.ratingMax = rating_max 84 | } 85 | if let rating = contentMetadata["rating"] as? Double { 86 | buo.contentMetadata.rating = rating 87 | } 88 | if let address_street = contentMetadata["address_street"] as? String { 89 | buo.contentMetadata.addressStreet = address_street 90 | } 91 | if let address_city = contentMetadata["address_city"] as? String { 92 | buo.contentMetadata.addressCity = address_city 93 | } 94 | if let address_region = contentMetadata["address_region"] as? String { 95 | buo.contentMetadata.addressRegion = address_region 96 | } 97 | if let address_country = contentMetadata["address_country"] as? String { 98 | buo.contentMetadata.addressCountry = address_country 99 | } 100 | if let address_postal_code = contentMetadata["address_postal_code"] as? String { 101 | buo.contentMetadata.addressPostalCode = address_postal_code 102 | } 103 | if let latitude = contentMetadata["latitude"] as? Double { 104 | buo.contentMetadata.latitude = latitude 105 | } 106 | if let longitude = contentMetadata["longitude"] as? Double { 107 | buo.contentMetadata.longitude = longitude 108 | } 109 | if let image_captions = contentMetadata["image_captions"] as? NSMutableArray { 110 | buo.contentMetadata.imageCaptions = image_captions 111 | } 112 | if let customMetadata = contentMetadata["customMetadata"] as? [String: Any] { 113 | for metaData in customMetadata { 114 | buo.contentMetadata.customMetadata[metaData.key] = metaData.value 115 | } 116 | } 117 | } 118 | return buo 119 | } 120 | 121 | func convertToLp(dict: [String: Any?]) -> BranchLinkProperties? { 122 | let lp: BranchLinkProperties = BranchLinkProperties() 123 | if let lpChannel = dict["channel"] as? String { 124 | lp.channel = lpChannel 125 | } 126 | if let lpFeature = dict["feature"] as? String { 127 | lp.feature = lpFeature 128 | } 129 | if let lpCampaign = dict["campaign"] as? String { 130 | lp.campaign = lpCampaign 131 | } 132 | if let lpStage = dict["stage"] as? String { 133 | lp.stage = lpStage 134 | } 135 | if let lpAlias = dict["alias"] as? String { 136 | lp.alias = lpAlias 137 | } 138 | if let lpmatchDuration = dict["matchDuration"] as? UInt { 139 | lp.matchDuration = lpmatchDuration 140 | } 141 | if let lptags = dict["tags"] as? [String] { 142 | lp.tags = lptags 143 | } 144 | if let lpControlParams = dict["controlParams"] as? [String: Any] { 145 | for param in lpControlParams { 146 | lp.addControlParam(param.key, withValue: param.value as? String) 147 | } 148 | } 149 | return lp 150 | } 151 | 152 | func convertToEvent(dict: [String: Any?]) -> BranchEvent? { 153 | var event : BranchEvent 154 | 155 | let eventName = dict["eventName"] as! String 156 | let isStandardEvent = dict["isStandardEvent"] as! Bool 157 | if (isStandardEvent) { 158 | event = BranchEvent.init(name: eventName) 159 | } else { 160 | event = BranchEvent.customEvent(withName: eventName) 161 | } 162 | if let transactionID = dict["transactionID"] as? String { 163 | event.transactionID = transactionID 164 | } 165 | if let currency = dict["currency"] as? String { 166 | event.currency = BNCCurrency.init(rawValue: currency) 167 | } 168 | if let revenue = dict["revenue"] as? Double { 169 | event.revenue = NSDecimalNumber(floatLiteral: revenue) 170 | } 171 | if let shipping = dict["shipping"] as? Double { 172 | event.shipping = NSDecimalNumber(floatLiteral: shipping) 173 | } 174 | if let tax = dict["tax"] as? Double { 175 | event.tax = NSDecimalNumber(floatLiteral: tax) 176 | } 177 | if let coupon = dict["coupon"] as? String { 178 | event.coupon = coupon 179 | } 180 | if let affiliation = dict["affiliation"] as? String { 181 | event.affiliation = affiliation 182 | } 183 | if let eventDescription = dict["eventDescription"] as? String { 184 | event.eventDescription = eventDescription 185 | } 186 | if let searchQuery = dict["searchQuery"] as? String { 187 | event.searchQuery = searchQuery 188 | } 189 | if let adType = dict["adType"] as? String { 190 | event.adType = convertToAdType(adType: adType) 191 | } 192 | if let dictCustomData = dict["customData"] as? [String: Any] { 193 | for customData in dictCustomData { 194 | event.customData[customData.key] = (customData.value as! String) 195 | } 196 | } 197 | if let alias = dict["alias"] as? String { 198 | event.alias = alias 199 | } 200 | return event 201 | } 202 | 203 | func convertToAdType(adType: String) -> BranchEventAdType { 204 | switch adType { 205 | case "BANNER": 206 | return BranchEventAdType.banner 207 | case "INTERSTITIAL": 208 | return BranchEventAdType.interstitial 209 | case "REWARDED_VIDEO": 210 | return BranchEventAdType.rewardedVideo 211 | case "NATIVE": 212 | return BranchEventAdType.native 213 | default: 214 | return BranchEventAdType.none 215 | } 216 | } 217 | 218 | func convertToQRCode(dict: [String: Any?]) -> BranchQRCode { 219 | let qrCode : BranchQRCode = BranchQRCode() 220 | 221 | if let width = dict["width"] as? Int { 222 | qrCode.width = NSNumber(value: width) 223 | } 224 | if let margin = dict["margin"] as? Int { 225 | qrCode.margin = NSNumber(value: margin) 226 | } 227 | if let codeColor = dict["codeColor"] as? String { 228 | qrCode.codeColor = UIColor.init(hexString: codeColor) 229 | } 230 | if let backgroundColor = dict["backgroundColor"] as? String { 231 | qrCode.backgroundColor = UIColor.init(hexString: backgroundColor) 232 | } 233 | if let imageFormat = dict["imageFormat"] as? String { 234 | if (imageFormat == "JPEG") { 235 | qrCode.imageFormat = BranchQRCodeImageFormat.JPEG 236 | } else { 237 | qrCode.imageFormat = BranchQRCodeImageFormat.PNG 238 | } 239 | } 240 | if let centerLogoUrl = dict["centerLogoUrl"] as? String { 241 | qrCode.centerLogo = centerLogoUrl 242 | } 243 | return qrCode 244 | } 245 | 246 | //--------------------------------------------------------------------------------------------- 247 | // Extension 248 | // -------------------------------------------------------------------------------------------- 249 | 250 | extension Date { 251 | var millisecondsSince1970:Int64 { 252 | return Int64((self.timeIntervalSince1970 * 1000.0).rounded()) 253 | } 254 | 255 | init(milliseconds:Int64) { 256 | self = Date(timeIntervalSince1970: TimeInterval(milliseconds) / 1000) 257 | } 258 | } 259 | 260 | extension Bundle { 261 | static func infoPlistValue(forKey key: String) -> Any? { 262 | guard let value = Bundle.main.object(forInfoDictionaryKey: key) else { 263 | return nil 264 | } 265 | return value 266 | } 267 | public var icon: UIImage? { 268 | if let icons = infoDictionary?["CFBundleIcons"] as? [String: Any], 269 | let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any], 270 | let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String], 271 | let lastIcon = iconFiles.last { 272 | return UIImage(named: lastIcon) 273 | } 274 | return nil 275 | } 276 | } 277 | 278 | extension UIColor { 279 | convenience init(hexString: String, alpha: CGFloat = 1.0) { 280 | let hexString: String = hexString.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) 281 | let scanner = Scanner(string: hexString) 282 | if (hexString.hasPrefix("#")) { 283 | scanner.scanLocation = 1 284 | } 285 | var color: UInt32 = 0 286 | scanner.scanHexInt32(&color) 287 | let mask = 0x000000FF 288 | let r = Int(color >> 16) & mask 289 | let g = Int(color >> 8) & mask 290 | let b = Int(color) & mask 291 | let red = CGFloat(r) / 255.0 292 | let green = CGFloat(g) / 255.0 293 | let blue = CGFloat(b) / 255.0 294 | self.init(red:red, green:green, blue:blue, alpha:alpha) 295 | } 296 | func toHexString() -> String { 297 | var r:CGFloat = 0 298 | var g:CGFloat = 0 299 | var b:CGFloat = 0 300 | var a:CGFloat = 0 301 | getRed(&r, green: &g, blue: &b, alpha: &a) 302 | let rgb:Int = (Int)(r*255)<<16 | (Int)(g*255)<<8 | (Int)(b*255)<<0 303 | return String(format:"#%06x", rgb) 304 | } 305 | } 306 | 307 | extension UIImage { 308 | public static func loadFrom(url: URL, completion: @escaping (_ image: UIImage?) -> ()) { 309 | DispatchQueue.global().async { 310 | if let data = try? Data(contentsOf: url) { 311 | DispatchQueue.main.async { 312 | completion(UIImage(data: data)) 313 | } 314 | } else { 315 | DispatchQueue.main.async { 316 | completion(nil) 317 | } 318 | } 319 | } 320 | } 321 | 322 | } 323 | -------------------------------------------------------------------------------- /lib/flutter_branch_sdk.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'src/flutter_branch_sdk_platform_interface.dart'; 4 | import 'src/objects/app_tracking_transparency.dart'; 5 | import 'src/objects/branch_attribution_level.dart'; 6 | import 'src/objects/branch_universal_object.dart'; 7 | 8 | export 'src/flutter_branch_sdk_platform_interface.dart'; 9 | export 'src/objects/app_tracking_transparency.dart'; 10 | export 'src/objects/branch_attribution_level.dart'; 11 | export 'src/objects/branch_universal_object.dart'; 12 | 13 | part 'src/flutter_branch_sdk.dart'; 14 | -------------------------------------------------------------------------------- /lib/src/constants.dart: -------------------------------------------------------------------------------- 1 | class AppConstants { 2 | AppConstants._internal(); 3 | static const MESSAGE_CHANNEL = 'flutter_branch_sdk/message'; 4 | static const EVENT_CHANNEL = 'flutter_branch_sdk/event'; 5 | } 6 | -------------------------------------------------------------------------------- /lib/src/flutter_branch_sdk.dart: -------------------------------------------------------------------------------- 1 | part of '../flutter_branch_sdk.dart'; 2 | 3 | class FlutterBranchSdk { 4 | /// Initializes the Branch SDK. 5 | /// 6 | /// This function initializes the Branch SDK with the specified configuration options. 7 | /// 8 | /// **Parameters:** 9 | /// 10 | /// - [enableLogging]: Whether to enable detailed logging. Defaults to `false`. 11 | /// - [branchAttributionLevel]: The level of attribution data to collect. 12 | /// - `BranchAttributionLevel.FULL`: Full Attribution (Default) 13 | /// - `BranchAttributionLevel.REDUCE`: Reduced Attribution (Non-Ads + Privacy Frameworks) 14 | /// - `BranchAttributionLevel.MINIMAL`: Minimal Attribution - Analytics Only 15 | /// - `BranchAttributionLevel.NONE`: No Attribution - No Analytics (GDPR, CCPA) 16 | /// 17 | /// **Note:** The `disableTracking` parameter is deprecated and should no longer be used. 18 | /// Please use `branchAttributionLevel` to control tracking behavior. 19 | /// 20 | static Future init( 21 | {bool enableLogging = false, 22 | @Deprecated('use branchAttributionLevel') bool disableTracking = false, 23 | BranchAttributionLevel? branchAttributionLevel}) async { 24 | await FlutterBranchSdkPlatform.instance.init( 25 | enableLogging: enableLogging, disableTracking: disableTracking, branchAttributionLevel: branchAttributionLevel); 26 | } 27 | 28 | ///Identifies the current user to the Branch API by supplying a unique identifier as a userId value 29 | static void setIdentity(String userId) { 30 | FlutterBranchSdkPlatform.instance.setIdentity(userId); 31 | } 32 | 33 | ///Add key value pairs to all requests 34 | static void setRequestMetadata(String key, String value) { 35 | FlutterBranchSdkPlatform.instance.setRequestMetadata(key, value); 36 | } 37 | 38 | ///This method should be called if you know that a different person is about to use the app 39 | static void logout() { 40 | FlutterBranchSdkPlatform.instance.logout(); 41 | } 42 | 43 | ///Returns the last parameters associated with the link that referred the user 44 | static Future> getLatestReferringParams() async { 45 | return await FlutterBranchSdkPlatform.instance.getLatestReferringParams(); 46 | } 47 | 48 | ///Returns the first parameters associated with the link that referred the user 49 | static Future> getFirstReferringParams() async { 50 | return await FlutterBranchSdkPlatform.instance.getFirstReferringParams(); 51 | } 52 | 53 | ///Method to change the Tracking state. If disabled SDK will not track any user data or state. 54 | ///SDK will not send any network calls except for deep linking when tracking is disabled 55 | static void disableTracking(bool value) async { 56 | return FlutterBranchSdkPlatform.instance.disableTracking(value); 57 | } 58 | 59 | ///Listen click em Branch Deeplinks 60 | static Stream> listSession() { 61 | return FlutterBranchSdkPlatform.instance.listSession(); 62 | } 63 | 64 | ///Use the SDK integration validator to check that you've added the Branch SDK and 65 | ///handle deep links correctly when you first integrate Branch into your app. 66 | static void validateSDKIntegration() { 67 | FlutterBranchSdkPlatform.instance.validateSDKIntegration(); 68 | } 69 | 70 | ///Creates a short url for the BUO 71 | static Future getShortUrl( 72 | {required BranchUniversalObject buo, required BranchLinkProperties linkProperties}) async { 73 | return FlutterBranchSdkPlatform.instance.getShortUrl(buo: buo, linkProperties: linkProperties); 74 | } 75 | 76 | ///Showing a Share Sheet 77 | static Future showShareSheet( 78 | {required BranchUniversalObject buo, 79 | required BranchLinkProperties linkProperties, 80 | required String messageText, 81 | String androidMessageTitle = '', 82 | String androidSharingTitle = ''}) async { 83 | return FlutterBranchSdkPlatform.instance.showShareSheet( 84 | buo: buo, 85 | linkProperties: linkProperties, 86 | messageText: messageText, 87 | androidMessageTitle: androidMessageTitle, 88 | androidSharingTitle: androidSharingTitle); 89 | } 90 | 91 | ///Logs this BranchEvent to Branch for tracking and analytics 92 | static void trackContent({required List buo, required BranchEvent branchEvent}) { 93 | return FlutterBranchSdkPlatform.instance.trackContent(buo: buo, branchEvent: branchEvent); 94 | } 95 | 96 | ///Logs this BranchEvent to Branch for tracking and analytics 97 | static void trackContentWithoutBuo({required BranchEvent branchEvent}) { 98 | return FlutterBranchSdkPlatform.instance.trackContentWithoutBuo(branchEvent: branchEvent); 99 | } 100 | 101 | ///Mark the content referred by this object as viewed. This increment the view count of the contents referred by this object. 102 | static void registerView({required BranchUniversalObject buo}) { 103 | return FlutterBranchSdkPlatform.instance.registerView(buo: buo); 104 | } 105 | 106 | ///For Android: Publish this BUO with Google app indexing so that the contents will be available with google search 107 | ///For iOS: List items on Spotlight 108 | static Future listOnSearch({required BranchUniversalObject buo, BranchLinkProperties? linkProperties}) async { 109 | return FlutterBranchSdkPlatform.instance.listOnSearch(buo: buo, linkProperties: linkProperties); 110 | } 111 | 112 | ///For Android: Remove the BUO from the local indexing if it is added to the local indexing already 113 | /// This will remove the content from Google(Firebase) and other supported Indexing services 114 | ///For iOS: Remove Branch Universal Object from Spotlight if privately indexed 115 | static Future removeFromSearch({required BranchUniversalObject buo, BranchLinkProperties? linkProperties}) async { 116 | return FlutterBranchSdkPlatform.instance.removeFromSearch(buo: buo, linkProperties: linkProperties); 117 | } 118 | 119 | ///Indicates whether or not this user has a custom identity specified for them. Note that this is independent of installs. 120 | ///If you call setIdentity, this device will have that identity associated with this user until logout is called. 121 | ///This includes persisting through uninstalls, as we track device id. 122 | static Future isUserIdentified() async { 123 | return FlutterBranchSdkPlatform.instance.isUserIdentified(); 124 | } 125 | 126 | /// request AppTracking Autorization and return AppTrackingStatus 127 | /// on Android returns notSupported 128 | static Future requestTrackingAuthorization() async { 129 | return FlutterBranchSdkPlatform.instance.requestTrackingAuthorization(); 130 | } 131 | 132 | /// return AppTrackingStatus 133 | /// on Android returns notSupported 134 | static Future getTrackingAuthorizationStatus() async { 135 | return FlutterBranchSdkPlatform.instance.getTrackingAuthorizationStatus(); 136 | } 137 | 138 | /// return advertising identifier (ie tracking data). 139 | /// on Android returns empty string 140 | static Future getAdvertisingIdentifier() async { 141 | return FlutterBranchSdkPlatform.instance.getAdvertisingIdentifier(); 142 | } 143 | 144 | ///Sets the duration in milliseconds that the system should wait for initializing 145 | ///a network * request. 146 | static void setConnectTimeout(int connectTimeout) { 147 | return FlutterBranchSdkPlatform.instance.setConnectTimeout(connectTimeout); 148 | } 149 | 150 | ///Sets the duration in milliseconds that the system should wait for a response 151 | ///before timing out any Branch API. 152 | ///Default 5500 ms. Note that this is the total time allocated for all request 153 | ///retries as set in setRetryCount(int). 154 | static void setTimeout(int timeout) { 155 | return FlutterBranchSdkPlatform.instance.setTimeout(timeout); 156 | } 157 | 158 | ///Sets the max number of times to re-attempt a timed-out request to the Branch API, before 159 | /// considering the request to have failed entirely. Default to 3. 160 | /// Note that the the network timeout, as set in setNetworkTimeout(int), 161 | /// together with the retry interval value from setRetryInterval(int) will 162 | /// determine if the max retry count will be attempted. 163 | static void setRetryCount(int retryCount) { 164 | return FlutterBranchSdkPlatform.instance.setRetryCount(retryCount); 165 | } 166 | 167 | ///Sets the amount of time in milliseconds to wait before re-attempting a 168 | ///timed-out request to the Branch API. Default 1000 ms. 169 | static void setRetryInterval(int retryInterval) { 170 | return FlutterBranchSdkPlatform.instance.setRetryInterval(retryInterval); 171 | } 172 | 173 | ///Gets the available last attributed touch data with a custom set attribution window. 174 | static Future getLastAttributedTouchData({int? attributionWindow}) async { 175 | return FlutterBranchSdkPlatform.instance.getLastAttributedTouchData(attributionWindow: attributionWindow); 176 | } 177 | 178 | ///Creates a Branch QR Code image. Returns the QR code as Uint8List. 179 | static Future getQRCodeAsData( 180 | {required BranchUniversalObject buo, 181 | required BranchLinkProperties linkProperties, 182 | required BranchQrCode qrCode}) async { 183 | return FlutterBranchSdkPlatform.instance 184 | .getQRCodeAsData(buo: buo, linkProperties: linkProperties, qrCodeSettings: qrCode); 185 | } 186 | 187 | ///Creates a Branch QR Code image. Returns the QR code as a Image. 188 | static Future getQRCodeAsImage( 189 | {required BranchUniversalObject buo, 190 | required BranchLinkProperties linkProperties, 191 | required BranchQrCode qrCode}) async { 192 | return FlutterBranchSdkPlatform.instance 193 | .getQRCodeAsImage(buo: buo, linkProperties: linkProperties, qrCodeSettings: qrCode); 194 | } 195 | 196 | ///Share with LPLinkMetadata on iOS 197 | static void shareWithLPLinkMetadata( 198 | {required BranchUniversalObject buo, 199 | required BranchLinkProperties linkProperties, 200 | required Uint8List icon, 201 | required String title}) { 202 | Map params = {}; 203 | params['buo'] = buo.toMap(); 204 | params['lp'] = linkProperties.toMap(); 205 | params['title'] = title; 206 | 207 | FlutterBranchSdkPlatform.instance 208 | .shareWithLPLinkMetadata(buo: buo, linkProperties: linkProperties, icon: icon, title: title); 209 | } 210 | 211 | ///Have Branch end the current deep link session and start a new session with the provided URL. 212 | static void handleDeepLink(String url) { 213 | FlutterBranchSdkPlatform.instance.handleDeepLink(url); 214 | } 215 | 216 | /// Add a Partner Parameter for Facebook. 217 | /// Once set, this parameter is attached to installs, opens and events until cleared or the app restarts. 218 | /// See Facebook's documentation for details on valid parameters 219 | static void addFacebookPartnerParameter({required String key, required String value}) { 220 | FlutterBranchSdkPlatform.instance.addFacebookPartnerParameter(key: key, value: value); 221 | } 222 | 223 | /// Clears all Partner Parameters 224 | static void clearPartnerParameters() { 225 | FlutterBranchSdkPlatform.instance.clearPartnerParameters(); 226 | } 227 | 228 | /// Add the pre-install campaign analytics 229 | static void setPreinstallCampaign(String value) { 230 | FlutterBranchSdkPlatform.instance.setPreinstallCampaign(value); 231 | } 232 | 233 | /// Add the pre-install campaign analytics 234 | static void setPreinstallPartner(String value) { 235 | FlutterBranchSdkPlatform.instance.setPreinstallPartner(value); 236 | } 237 | 238 | ///Add a Partner Parameter for Snap. 239 | ///Once set, this parameter is attached to installs, opens and events until cleared or the app restarts. 240 | static void addSnapPartnerParameter({required String key, required String value}) { 241 | FlutterBranchSdkPlatform.instance.addSnapPartnerParameter(key: key, value: value); 242 | } 243 | 244 | /// Sets the value of parameters required by Google Conversion APIs for DMA Compliance in EEA region. 245 | /// [eeaRegion] `true` If European regulations, including the DMA, apply to this user and conversion. 246 | /// [adPersonalizationConsent] `true` If End user has granted/denied ads personalization consent. 247 | /// [adUserDataUsageConsent] `true If User has granted/denied consent for 3P transmission of user level data for ads. 248 | static void setDMAParamsForEEA( 249 | {required bool eeaRegion, required bool adPersonalizationConsent, required bool adUserDataUsageConsent}) { 250 | FlutterBranchSdkPlatform.instance.setDMAParamsForEEA( 251 | eeaRegion: eeaRegion, 252 | adPersonalizationConsent: adPersonalizationConsent, 253 | adUserDataUsageConsent: adUserDataUsageConsent); 254 | } 255 | 256 | /// Sets the consumer protection attribution level. 257 | static void setConsumerProtectionAttributionLevel(BranchAttributionLevel branchAttributionLevel) { 258 | FlutterBranchSdkPlatform.instance.setConsumerProtectionAttributionLevel(branchAttributionLevel); 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /lib/src/flutter_branch_sdk_method_channel.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/services.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | import 'package:flutter_branch_sdk/src/constants.dart'; 6 | 7 | import 'flutter_branch_sdk_platform_interface.dart'; 8 | import 'objects/app_tracking_transparency.dart'; 9 | import 'objects/branch_attribution_level.dart'; 10 | import 'objects/branch_universal_object.dart'; 11 | 12 | /// An implementation of [FlutterBranchSdkPlatform] that uses method channels. 13 | class FlutterBranchSdkMethodChannel implements FlutterBranchSdkPlatform { 14 | /// The method channel used to interact with the native platform. 15 | final messageChannel = const MethodChannel(AppConstants.MESSAGE_CHANNEL); 16 | final eventChannel = const EventChannel(AppConstants.EVENT_CHANNEL); 17 | 18 | static Stream>? _initSessionStream; 19 | static bool isInitialized = false; 20 | 21 | /// Initializes the Branch SDK. 22 | /// 23 | /// This function initializes the Branch SDK with the specified configuration options. 24 | /// 25 | /// **Parameters:** 26 | /// 27 | /// - [enableLogging]: Whether to enable detailed logging. Defaults to `false`. 28 | /// - [branchAttributionLevel]: The level of attribution data to collect. 29 | /// - `BranchAttributionLevel.FULL`: Full Attribution (Default) 30 | /// - `BranchAttributionLevel.REDUCE`: Reduced Attribution (Non-Ads + Privacy Frameworks) 31 | /// - `BranchAttributionLevel.MINIMAL`: Minimal Attribution - Analytics Only 32 | /// - `BranchAttributionLevel.NONE`: No Attribution - No Analytics (GDPR, CCPA) 33 | /// 34 | /// **Note:** The `disableTracking` parameter is deprecated and should no longer be used. 35 | /// Please use `branchAttributionLevel` to control tracking behavior. 36 | /// 37 | @override 38 | Future init( 39 | {bool enableLogging = false, 40 | @Deprecated('use BranchAttributionLevel') bool disableTracking = false, 41 | BranchAttributionLevel? branchAttributionLevel}) async { 42 | if (isInitialized) { 43 | return; 44 | } 45 | var branchAttributionLevelString = ''; 46 | 47 | if (branchAttributionLevel == null) { 48 | branchAttributionLevelString = ''; 49 | } else { 50 | branchAttributionLevelString = getBranchAttributionLevelString(branchAttributionLevel); 51 | } 52 | await messageChannel.invokeMethod('init', { 53 | 'enableLogging': enableLogging, 54 | 'disableTracking': disableTracking, 55 | 'branchAttributionLevel': branchAttributionLevelString 56 | }); 57 | isInitialized = true; 58 | } 59 | 60 | ///Identifies the current user to the Branch API by supplying a unique identifier as a userId value 61 | @override 62 | void setIdentity(String userId) { 63 | assert(isInitialized, 'Call `setIdentity` after `FlutterBranchSdk.init()` method'); 64 | messageChannel.invokeMethod('setIdentity', {'userId': userId}); 65 | } 66 | 67 | ///Add key value pairs to all requests 68 | @override 69 | void setRequestMetadata(String key, String value) { 70 | messageChannel.invokeMethod('setRequestMetadata', {'key': key, 'value': value}); 71 | } 72 | 73 | ///This method should be called if you know that a different person is about to use the app 74 | @override 75 | void logout() { 76 | assert(isInitialized, 'Call `logout` after `FlutterBranchSdk.init()` method'); 77 | messageChannel.invokeMethod('logout'); 78 | } 79 | 80 | ///Returns the last parameters associated with the link that referred the user 81 | @override 82 | Future> getLatestReferringParams() async { 83 | assert(isInitialized, 'Call `getLatestReferringParams` after `FlutterBranchSdk.init()` method'); 84 | return await messageChannel.invokeMethod('getLatestReferringParams'); 85 | } 86 | 87 | ///Returns the first parameters associated with the link that referred the user 88 | @override 89 | Future> getFirstReferringParams() async { 90 | assert(isInitialized, 'Call `getFirstReferringParams` after `FlutterBranchSdk.init()` method'); 91 | return await messageChannel.invokeMethod('getFirstReferringParams'); 92 | } 93 | 94 | ///Method to change the Tracking state. If disabled SDK will not track any user data or state. 95 | ///SDK will not send any network calls except for deep linking when tracking is disabled 96 | @Deprecated('Use [setConsumerProtectionAttributionLevel]') 97 | @override 98 | void disableTracking(bool value) async { 99 | assert(isInitialized, 'Call `disableTracking` after `FlutterBranchSdk.init()` method'); 100 | messageChannel.invokeMethod('setTrackingDisabled', {'disable': value}); 101 | } 102 | 103 | ///Listen click em Branch DeepLinks 104 | @override 105 | Stream> listSession() { 106 | assert(isInitialized, 'Call `listSession` after `FlutterBranchSdk.init()` method'); 107 | _initSessionStream ??= eventChannel.receiveBroadcastStream().cast>(); 108 | 109 | return _initSessionStream!; 110 | } 111 | 112 | ///Use the SDK integration validator to check that you've added the Branch SDK and 113 | ///handle deep links correctly when you first integrate Branch into your app. 114 | @override 115 | void validateSDKIntegration() { 116 | assert(isInitialized, 'Call `validateSDKIntegration` after `FlutterBranchSdk.init()` method'); 117 | messageChannel.invokeMethod('validateSDKIntegration'); 118 | } 119 | 120 | ///Creates a short url for the BUO 121 | @override 122 | Future getShortUrl( 123 | {required BranchUniversalObject buo, required BranchLinkProperties linkProperties}) async { 124 | assert(isInitialized, 'Call `getShortUrl` after `FlutterBranchSdk.init()` method'); 125 | Map response = 126 | await messageChannel.invokeMethod('getShortUrl', {'buo': buo.toMap(), 'lp': linkProperties.toMap()}); 127 | 128 | if (response['success']) { 129 | return BranchResponse.success(result: response['url']); 130 | } else { 131 | return BranchResponse.error(errorCode: response['errorCode'], errorMessage: response['errorMessage']); 132 | } 133 | } 134 | 135 | ///Showing a Share Sheet 136 | @override 137 | Future showShareSheet( 138 | {required BranchUniversalObject buo, 139 | required BranchLinkProperties linkProperties, 140 | required String messageText, 141 | String androidMessageTitle = '', 142 | String androidSharingTitle = ''}) async { 143 | assert(isInitialized, 'Call `showShareSheet` after `FlutterBranchSdk.init()` method'); 144 | Map response = await messageChannel.invokeMethod('showShareSheet', { 145 | 'buo': buo.toMap(), 146 | 'lp': linkProperties.toMap(), 147 | 'messageText': messageText, 148 | 'messageTitle': androidMessageTitle, 149 | 'sharingTitle': androidSharingTitle 150 | }); 151 | 152 | if (response['success']) { 153 | return BranchResponse.success(result: response['url']); 154 | } else { 155 | return BranchResponse.error(errorCode: response['errorCode'], errorMessage: response['errorMessage']); 156 | } 157 | } 158 | 159 | ///Logs this BranchEvent to Branch for tracking and analytics 160 | @override 161 | void trackContent({required List buo, required BranchEvent branchEvent}) { 162 | assert(isInitialized, 'Call `trackContent` after `FlutterBranchSdk.init()` method'); 163 | Map params = {}; 164 | params['buo'] = buo.map((b) => b.toMap()).toList(); 165 | if (branchEvent.toMap().isNotEmpty) { 166 | params['event'] = branchEvent.toMap(); 167 | } 168 | messageChannel.invokeMethod('trackContent', params); 169 | } 170 | 171 | ///Logs this BranchEvent to Branch for tracking and analytics 172 | @override 173 | void trackContentWithoutBuo({required BranchEvent branchEvent}) { 174 | assert(isInitialized, 'Call `trackContentWithoutBuo` after `FlutterBranchSdk.init()` method'); 175 | if (branchEvent.toMap().isEmpty) { 176 | throw ArgumentError('branchEvent is required'); 177 | } 178 | messageChannel.invokeMethod('trackContentWithoutBuo', {'event': branchEvent.toMap()}); 179 | } 180 | 181 | ///Mark the content referred by this object as viewed. This increment the view count of the contents referred by this object. 182 | @override 183 | void registerView({required BranchUniversalObject buo}) { 184 | assert(isInitialized, 'Call `registerView` after `FlutterBranchSdk.init()` method'); 185 | messageChannel.invokeMethod('registerView', {'buo': buo.toMap()}); 186 | } 187 | 188 | ///For Android: Publish this BUO with Google app indexing so that the contents will be available with google search 189 | ///For iOS: List items on Spotlight 190 | @override 191 | Future listOnSearch({required BranchUniversalObject buo, BranchLinkProperties? linkProperties}) async { 192 | assert(isInitialized, 'Call `listOnSearch` after `FlutterBranchSdk.init()` method'); 193 | Map params = {}; 194 | params['buo'] = buo.toMap(); 195 | if (linkProperties != null && linkProperties.toMap().isNotEmpty) { 196 | params['lp'] = linkProperties.toMap(); 197 | } 198 | return await messageChannel.invokeMethod('listOnSearch', params); 199 | } 200 | 201 | ///For Android: Remove the BUO from the local indexing if it is added to the local indexing already 202 | /// This will remove the content from Google(Firebase) and other supported Indexing services 203 | ///For iOS: Remove Branch Universal Object from Spotlight if privately indexed 204 | @override 205 | Future removeFromSearch({required BranchUniversalObject buo, BranchLinkProperties? linkProperties}) async { 206 | assert(isInitialized, 'Call `removeFromSearch` after `FlutterBranchSdk.init()` method'); 207 | Map params = {}; 208 | params['buo'] = buo.toMap(); 209 | if (linkProperties != null && linkProperties.toMap().isNotEmpty) { 210 | params['lp'] = linkProperties.toMap(); 211 | } 212 | return await messageChannel.invokeMethod('removeFromSearch', params); 213 | } 214 | 215 | ///Indicates whether or not this user has a custom identity specified for them. Note that this is independent of installs. 216 | ///If you call setIdentity, this device will have that identity associated with this user until logout is called. 217 | ///This includes persisting through uninstalls, as we track device id. 218 | @override 219 | Future isUserIdentified() async { 220 | assert(isInitialized, 'Call `isUserIdentified` after `FlutterBranchSdk.init()` method'); 221 | return await messageChannel.invokeMethod('isUserIdentified'); 222 | } 223 | 224 | /// request AppTracking Autorization and return AppTrackingStatus 225 | /// on Android returns notSupported 226 | @override 227 | Future requestTrackingAuthorization() async { 228 | assert(isInitialized, 'Call `requestTrackingAuthorization` after `FlutterBranchSdk.init()` method'); 229 | if (!Platform.isIOS) { 230 | return AppTrackingStatus.notSupported; 231 | } 232 | final int status = (await messageChannel.invokeMethod('requestTrackingAuthorization'))!; 233 | return AppTrackingStatus.values[status]; 234 | } 235 | 236 | /// return AppTrackingStatus 237 | /// on Android returns notSupported 238 | @override 239 | Future getTrackingAuthorizationStatus() async { 240 | assert(isInitialized, 'Call `getTrackingAuthorizationStatus` after `FlutterBranchSdk.init()` method'); 241 | if (!Platform.isIOS) { 242 | return AppTrackingStatus.notSupported; 243 | } 244 | final int status = (await messageChannel.invokeMethod('getTrackingAuthorizationStatus'))!; 245 | return AppTrackingStatus.values[status]; 246 | } 247 | 248 | /// return advertising identifier (ie tracking data). 249 | /// on Android returns empty string 250 | @override 251 | Future getAdvertisingIdentifier() async { 252 | assert(isInitialized, 'Call `getAdvertisingIdentifier` after `FlutterBranchSdk.init()` method'); 253 | if (!Platform.isIOS) { 254 | return ""; 255 | } 256 | final String uuid = (await messageChannel.invokeMethod('getAdvertisingIdentifier'))!; 257 | return uuid; 258 | } 259 | 260 | @override 261 | void setConnectTimeout(int connectTimeout) { 262 | assert(isInitialized, 'Call `setConnectTimeout` after `FlutterBranchSdk.init()` method'); 263 | messageChannel.invokeMethod('setConnectTimeout', {'connectTimeout': connectTimeout}); 264 | } 265 | 266 | @override 267 | void setRetryCount(int retryCount) { 268 | assert(isInitialized, 'Call `setRetryCount` after `FlutterBranchSdk.init()` method'); 269 | messageChannel.invokeMethod('setRetryCount', {'retryCount': retryCount}); 270 | } 271 | 272 | @override 273 | void setRetryInterval(int retryInterval) { 274 | assert(isInitialized, 'Call `setRetryInterval` after `FlutterBranchSdk.init()` method'); 275 | messageChannel.invokeMethod('setRetryInterval', {'retryInterval': retryInterval}); 276 | } 277 | 278 | @override 279 | void setTimeout(int timeout) { 280 | assert(isInitialized, 'Call `setTimeout` after `FlutterBranchSdk.init()` method'); 281 | messageChannel.invokeMethod('setTimeout', {'timeout': timeout}); 282 | } 283 | 284 | @override 285 | Future getLastAttributedTouchData({int? attributionWindow}) async { 286 | assert(isInitialized, 'Call `getLastAttributedTouchData` after `FlutterBranchSdk.init()` method'); 287 | Map params = {}; 288 | if (attributionWindow != null) { 289 | params['attributionWindow'] = attributionWindow; 290 | } 291 | Map response = await messageChannel.invokeMethod('getLastAttributedTouchData', params); 292 | if (response['success']) { 293 | return BranchResponse.success(result: response['data']['latd']); 294 | } else { 295 | return BranchResponse.error(errorCode: response['errorCode'], errorMessage: response['errorMessage']); 296 | } 297 | } 298 | 299 | ///Creates a Branch QR Code image. Returns the QR code as Uint8List. 300 | @override 301 | Future getQRCodeAsData( 302 | {required BranchUniversalObject buo, 303 | required BranchLinkProperties linkProperties, 304 | required BranchQrCode qrCodeSettings}) async { 305 | assert(isInitialized, 'Call `getQRCodeAsData` after `FlutterBranchSdk.init()` method'); 306 | Map response = await messageChannel.invokeMethod( 307 | 'getQRCode', {'buo': buo.toMap(), 'lp': linkProperties.toMap(), 'qrCodeSettings': qrCodeSettings.toMap()}); 308 | 309 | if (response['success']) { 310 | return BranchResponse.success(result: response['result']); 311 | } else { 312 | return BranchResponse.error(errorCode: response['errorCode'], errorMessage: response['errorMessage']); 313 | } 314 | } 315 | 316 | ///Creates a Branch QR Code image. Returns the QR code as a Image. 317 | @override 318 | Future getQRCodeAsImage( 319 | {required BranchUniversalObject buo, 320 | required BranchLinkProperties linkProperties, 321 | required BranchQrCode qrCodeSettings}) async { 322 | assert(isInitialized, 'Call `getQRCodeAsImage` after `FlutterBranchSdk.init()` method'); 323 | Map response = await messageChannel.invokeMethod( 324 | 'getQRCode', {'buo': buo.toMap(), 'lp': linkProperties.toMap(), 'qrCodeSettings': qrCodeSettings.toMap()}); 325 | 326 | if (response['success']) { 327 | return BranchResponse.success(result: Image.memory(response['result'])); 328 | } else { 329 | return BranchResponse.error(errorCode: response['errorCode'], errorMessage: response['errorMessage']); 330 | } 331 | } 332 | 333 | ///Share with LPLinkMetadata on iOS 334 | @override 335 | void shareWithLPLinkMetadata( 336 | {required BranchUniversalObject buo, 337 | required BranchLinkProperties linkProperties, 338 | required Uint8List icon, 339 | required String title}) async { 340 | assert(isInitialized, 'Call `shareWithLPLinkMetadata` after `FlutterBranchSdk.init()` method'); 341 | Map params = {}; 342 | params['buo'] = buo.toMap(); 343 | params['lp'] = linkProperties.toMap(); 344 | params['messageText'] = title; 345 | params['iconData'] = icon; 346 | 347 | messageChannel.invokeMethod('shareWithLPLinkMetadata', params); 348 | } 349 | 350 | ///Have Branch end the current deep link session and start a new session with the provided URL. 351 | @override 352 | void handleDeepLink(String url) { 353 | assert(isInitialized, 'Call `handleDeepLink` after `FlutterBranchSdk.init()` method'); 354 | if (url.isEmpty) { 355 | throw ArgumentError('url is required'); 356 | } 357 | messageChannel.invokeMethod('handleDeepLink', {'url': url}); 358 | } 359 | 360 | /// Add a Partner Parameter for Facebook. 361 | /// Once set, this parameter is attached to installs, opens and events until cleared or the app restarts. 362 | /// See Facebook's documentation for details on valid parameters 363 | @override 364 | void addFacebookPartnerParameter({required String key, required String value}) { 365 | messageChannel.invokeMethod('addFacebookPartnerParameter', {'key': key, 'value': value}); 366 | } 367 | 368 | /// Clears all Partner Parameters 369 | @override 370 | void clearPartnerParameters() { 371 | messageChannel.invokeMethod('clearPartnerParameters'); 372 | } 373 | 374 | /// Add the pre-install campaign analytics 375 | @override 376 | void setPreinstallCampaign(String value) { 377 | messageChannel.invokeMethod('setPreinstallCampaign', {'value': value}); 378 | } 379 | 380 | /// Add the pre-install campaign analytics 381 | @override 382 | void setPreinstallPartner(String value) { 383 | messageChannel.invokeMethod('setPreinstallPartner', {'value': value}); 384 | } 385 | 386 | ///Add a Partner Parameter for Snap. 387 | ///Once set, this parameter is attached to installs, opens and events until cleared or the app restarts. 388 | @override 389 | void addSnapPartnerParameter({required String key, required String value}) { 390 | messageChannel.invokeMethod('addSnapPartnerParameter', {'key': key, 'value': value}); 391 | } 392 | 393 | /// Sets the value of parameters required by Google Conversion APIs for DMA Compliance in EEA region. 394 | /// [eeaRegion] `true` If European regulations, including the DMA, apply to this user and conversion. 395 | /// [adPersonalizationConsent] `true` If End user has granted/denied ads personalization consent. 396 | /// [adUserDataUsageConsent] `true If User has granted/denied consent for 3P transmission of user level data for ads. 397 | @override 398 | void setDMAParamsForEEA( 399 | {required bool eeaRegion, required bool adPersonalizationConsent, required bool adUserDataUsageConsent}) { 400 | messageChannel.invokeMethod('setDMAParamsForEEA', { 401 | 'eeaRegion': eeaRegion, 402 | 'adPersonalizationConsent': adPersonalizationConsent, 403 | 'adUserDataUsageConsent': adUserDataUsageConsent 404 | }); 405 | } 406 | 407 | /// Sets the consumer protection attribution level. 408 | @override 409 | void setConsumerProtectionAttributionLevel(BranchAttributionLevel branchAttributionLevel) { 410 | messageChannel.invokeMethod('setConsumerProtectionAttributionLevel', 411 | {'branchAttributionLevel': getBranchAttributionLevelString(branchAttributionLevel)}); 412 | } 413 | } 414 | -------------------------------------------------------------------------------- /lib/src/flutter_branch_sdk_platform_interface.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 4 | 5 | import 'flutter_branch_sdk_method_channel.dart'; 6 | import 'objects/app_tracking_transparency.dart'; 7 | import 'objects/branch_attribution_level.dart'; 8 | import 'objects/branch_universal_object.dart'; 9 | 10 | abstract class FlutterBranchSdkPlatform extends PlatformInterface { 11 | /// Constructs a FlutterBranchSdkPlatform. 12 | FlutterBranchSdkPlatform() : super(token: _token); 13 | 14 | static final Object _token = Object(); 15 | 16 | static FlutterBranchSdkPlatform _instance = FlutterBranchSdkMethodChannel(); 17 | 18 | /// The default instance of [FlutterBranchSdkPlatform] to use. 19 | /// 20 | /// Defaults to [FlutterBranchSdkMethodChannel]. 21 | static FlutterBranchSdkPlatform get instance => _instance; 22 | 23 | /// Platform-specific implementations should set this with their own 24 | /// platform-specific class that extends [FlutterBranchSdkPlatform] when 25 | /// they register themselves. 26 | static set instance(FlutterBranchSdkPlatform instance) { 27 | PlatformInterface.verifyToken(instance, _token); 28 | _instance = instance; 29 | } 30 | 31 | /// Initializes the Branch SDK. 32 | /// 33 | /// This function initializes the Branch SDK with the specified configuration options. 34 | /// 35 | /// **Parameters:** 36 | /// 37 | /// - [enableLogging]: Whether to enable detailed logging. Defaults to `false`. 38 | /// - [branchAttributionLevel]: The level of attribution data to collect. 39 | /// - `BranchAttributionLevel.FULL`: Full Attribution (Default) 40 | /// - `BranchAttributionLevel.REDUCE`: Reduced Attribution (Non-Ads + Privacy Frameworks) 41 | /// - `BranchAttributionLevel.MINIMAL`: Minimal Attribution - Analytics Only 42 | /// - `BranchAttributionLevel.NONE`: No Attribution - No Analytics (GDPR, CCPA) 43 | /// 44 | /// **Note:** The `disableTracking` parameter is deprecated and should no longer be used. 45 | /// Please use `branchAttributionLevel` to control tracking behavior. 46 | /// 47 | Future init( 48 | {bool enableLogging = false, 49 | @Deprecated('use branchAttributionLevel') bool disableTracking = false, 50 | BranchAttributionLevel? branchAttributionLevel}) async { 51 | throw UnimplementedError('init has not been implemented'); 52 | } 53 | 54 | ///Identifies the current user to the Branch API by supplying a unique identifier as a userId value 55 | void setIdentity(String userId) { 56 | throw UnimplementedError('setIdentity has not been implemented'); 57 | } 58 | 59 | ///Add key value pairs to all requests 60 | void setRequestMetadata(String key, String value) { 61 | throw UnimplementedError('setRequestMetadata has not been implemented'); 62 | } 63 | 64 | ///This method should be called if you know that a different person is about to use the app 65 | void logout() { 66 | throw UnimplementedError('logout has not been implemented'); 67 | } 68 | 69 | ///Returns the last parameters associated with the link that referred the user 70 | Future> getLatestReferringParams() async { 71 | throw UnimplementedError('getLatestReferringParams has not been implemented'); 72 | } 73 | 74 | ///Returns the first parameters associated with the link that referred the user 75 | Future> getFirstReferringParams() async { 76 | throw UnimplementedError('getFirstReferringParams has not been implemented'); 77 | } 78 | 79 | ///Method to change the Tracking state. If disabled SDK will not track any user data or state. 80 | ///SDK will not send any network calls except for deep linking when tracking is disabled 81 | @Deprecated('Use [setConsumerProtectionAttributionLevel]') 82 | void disableTracking(bool value) async { 83 | throw UnimplementedError('disableTracking has not been implemented'); 84 | } 85 | 86 | ///Listen click em Branch Deeplinks 87 | Stream> listSession() { 88 | throw UnimplementedError('initSession has not been implemented'); 89 | } 90 | 91 | ///Use the SDK integration validator to check that you've added the Branch SDK and 92 | ///handle deep links correctly when you first integrate Branch into your app. 93 | void validateSDKIntegration() { 94 | throw UnimplementedError('validateSDKIntegration has not been implemented'); 95 | } 96 | 97 | ///Creates a short url for the BUO 98 | Future getShortUrl( 99 | {required BranchUniversalObject buo, required BranchLinkProperties linkProperties}) async { 100 | throw UnimplementedError('getShortUrl has not been implemented'); 101 | } 102 | 103 | ///Showing a Share Sheet 104 | Future showShareSheet( 105 | {required BranchUniversalObject buo, 106 | required BranchLinkProperties linkProperties, 107 | required String messageText, 108 | String androidMessageTitle = '', 109 | String androidSharingTitle = ''}) async { 110 | throw UnimplementedError('showShareSheet has not been implemented'); 111 | } 112 | 113 | ///Logs this BranchEvent to Branch for tracking and analytics 114 | void trackContent({required List buo, required BranchEvent branchEvent}) { 115 | throw UnimplementedError('trackContent has not been implemented'); 116 | } 117 | 118 | ///Logs this BranchEvent to Branch for tracking and analytics 119 | void trackContentWithoutBuo({required BranchEvent branchEvent}) { 120 | throw UnimplementedError('trackContentWithoutBuo has not been implemented'); 121 | } 122 | 123 | ///Mark the content referred by this object as viewed. This increment the view count of the contents referred by this object. 124 | void registerView({required BranchUniversalObject buo}) { 125 | throw UnimplementedError('registerView has not been implemented'); 126 | } 127 | 128 | ///For Android: Publish this BUO with Google app indexing so that the contents will be available with google search 129 | ///For iOS: List items on Spotlight 130 | Future listOnSearch({required BranchUniversalObject buo, BranchLinkProperties? linkProperties}) async { 131 | throw UnimplementedError('listOnSearch has not been implemented'); 132 | } 133 | 134 | ///For Android: Remove the BUO from the local indexing if it is added to the local indexing already 135 | /// This will remove the content from Google(Firebase) and other supported Indexing services 136 | ///For iOS: Remove Branch Universal Object from Spotlight if privately indexed 137 | Future removeFromSearch({required BranchUniversalObject buo, BranchLinkProperties? linkProperties}) async { 138 | throw UnimplementedError('removeFromSearch has not been implemented'); 139 | } 140 | 141 | ///Indicates whether or not this user has a custom identity specified for them. Note that this is independent of installs. 142 | ///If you call setIdentity, this device will have that identity associated with this user until logout is called. 143 | ///This includes persisting through uninstalls, as we track device id. 144 | Future isUserIdentified() async { 145 | throw UnimplementedError('isUserIdentified has not been implemented'); 146 | } 147 | 148 | /// request AppTracking Autorization and return AppTrackingStatus 149 | /// on Android returns notSupported 150 | Future requestTrackingAuthorization() async { 151 | throw UnimplementedError('requestTrackingAuthorization has not been implemented'); 152 | } 153 | 154 | /// return AppTrackingStatus 155 | /// on Android returns notSupported 156 | Future getTrackingAuthorizationStatus() async { 157 | throw UnimplementedError('getTrackingAuthorizationStatus has not been implemented'); 158 | } 159 | 160 | /// return advertising identifier (ie tracking data). 161 | /// on Android returns empty string 162 | Future getAdvertisingIdentifier() async { 163 | throw UnimplementedError('getAdvertisingIdentifier has not been implemented'); 164 | } 165 | 166 | ///Sets the duration in milliseconds that the system should wait for initializing 167 | ///a network * request. 168 | void setConnectTimeout(int connectTimeout) { 169 | throw UnimplementedError('setConnectTimeout has not been implemented'); 170 | } 171 | 172 | ///Sets the duration in milliseconds that the system should wait for a response 173 | ///before timing out any Branch API. 174 | ///Default 5500 ms. Note that this is the total time allocated for all request 175 | ///retries as set in setRetryCount(int). 176 | void setTimeout(int timeout) { 177 | throw UnimplementedError('setTimeout has not been implemented'); 178 | } 179 | 180 | ///Sets the max number of times to re-attempt a timed-out request to the Branch API, before 181 | /// considering the request to have failed entirely. Default to 3. 182 | /// Note that the the network timeout, as set in setNetworkTimeout(int), 183 | /// together with the retry interval value from setRetryInterval(int) will 184 | /// determine if the max retry count will be attempted. 185 | void setRetryCount(int retryCount) { 186 | throw UnimplementedError('setRetryCount has not been implemented'); 187 | } 188 | 189 | ///Sets the amount of time in milliseconds to wait before re-attempting a 190 | ///timed-out request to the Branch API. Default 1000 ms. 191 | void setRetryInterval(int retryInterval) { 192 | throw UnimplementedError('setRetryInterval has not been implemented'); 193 | } 194 | 195 | ///Gets the available last attributed touch data with a custom set attribution window. 196 | Future getLastAttributedTouchData({int? attributionWindow}) async { 197 | throw UnimplementedError('getLastAttributedTouchData has not been implemented'); 198 | } 199 | 200 | ///Creates a Branch QR Code image. Returns the QR code as Uint8List. 201 | Future getQRCodeAsData( 202 | {required BranchUniversalObject buo, 203 | required BranchLinkProperties linkProperties, 204 | required BranchQrCode qrCodeSettings}) async { 205 | throw UnimplementedError('getQRCodeAsData has not been implemented'); 206 | } 207 | 208 | ///Creates a Branch QR Code image. Returns the QR code as a Image. 209 | Future getQRCodeAsImage( 210 | {required BranchUniversalObject buo, 211 | required BranchLinkProperties linkProperties, 212 | required BranchQrCode qrCodeSettings}) async { 213 | throw UnimplementedError('getQRCodeAsImage has not been implemented'); 214 | } 215 | 216 | ///Showing a Share Sheet with LPLinkMetadata in iOS 217 | void shareWithLPLinkMetadata( 218 | {required BranchUniversalObject buo, 219 | required BranchLinkProperties linkProperties, 220 | required Uint8List icon, 221 | required String title}) { 222 | throw UnimplementedError('shareWithLPLinkMetadata has not been implemented'); 223 | } 224 | 225 | ///Have Branch end the current deep link session and start a new session with the provided URL. 226 | void handleDeepLink(String url) async { 227 | throw UnimplementedError('handleDeepLink has not been implemented'); 228 | } 229 | 230 | /// Add the pre-install campaign analytics 231 | void setPreinstallCampaign(String value) { 232 | throw UnimplementedError('setPreinstallCampaign has not been implemented'); 233 | } 234 | 235 | /// Add the pre-install campaign analytics 236 | void setPreinstallPartner(String value) { 237 | throw UnimplementedError('setPreinstallPartner has not been implemented'); 238 | } 239 | 240 | /// Add a Partner Parameter for Facebook. 241 | /// Once set, this parameter is attached to installs, opens and events until cleared or the app restarts. 242 | /// See Facebook's documentation for details on valid parameters 243 | void addFacebookPartnerParameter({required String key, required String value}) { 244 | throw UnimplementedError('addFacebookPartnerParameter has not been implemented'); 245 | } 246 | 247 | ///Clears all Partner Parameters 248 | void clearPartnerParameters() { 249 | throw UnimplementedError('clearPartnerParameters has not been implemented'); 250 | } 251 | 252 | ///Add a Partner Parameter for Snap. 253 | ///Once set, this parameter is attached to installs, opens and events until cleared or the app restarts. 254 | void addSnapPartnerParameter({required String key, required String value}) { 255 | throw UnimplementedError('addSnapPartnerParameter has not been implemented'); 256 | } 257 | 258 | /// Sets the value of parameters required by Google Conversion APIs for DMA Compliance in EEA region. 259 | /// [eeaRegion] `true` If European regulations, including the DMA, apply to this user and conversion. 260 | /// [adPersonalizationConsent] `true` If End user has granted/denied ads personalization consent. 261 | /// [adUserDataUsageConsent] `true If User has granted/denied consent for 3P transmission of user level data for ads. 262 | void setDMAParamsForEEA( 263 | {required bool eeaRegion, required bool adPersonalizationConsent, required bool adUserDataUsageConsent}) { 264 | throw UnimplementedError('setDMAParamsForEEA has not been implemented'); 265 | } 266 | 267 | /// Sets the consumer protection attribution level. 268 | void setConsumerProtectionAttributionLevel(BranchAttributionLevel branchAttributionLevel) { 269 | throw UnimplementedError('setConsumerProtectionAttributionLevel has not been implemented'); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /lib/src/objects/app_tracking_transparency.dart: -------------------------------------------------------------------------------- 1 | enum AppTrackingStatus { 2 | /// The user has not yet received an authorization request dialog 3 | notDetermined, 4 | 5 | /// The device is restricted, tracking is disabled and the system can't show a request dialog 6 | restricted, 7 | 8 | /// The user denies authorization for tracking 9 | denied, 10 | 11 | /// The user authorizes access to tracking 12 | authorized, 13 | 14 | /// The platform is not iOS or the iOS version is below 14.0 15 | notSupported, 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/objects/branch_attribution_level.dart: -------------------------------------------------------------------------------- 1 | enum BranchAttributionLevel { 2 | /// Full Attribution (Default) 3 | /// - Advertising Ids 4 | /// - Device Ids 5 | /// - Local IP 6 | /// - Persisted Non-Aggregate Ids 7 | /// - Persisted Aggregate Ids 8 | /// - Ads Postbacks / Webhooks 9 | /// - Data Integrations Webhooks 10 | /// - SAN Callouts 11 | /// - Privacy Frameworks 12 | /// - Deep Linking 13 | FULL, 14 | 15 | /// Reduced Attribution (Non-Ads + Privacy Frameworks) 16 | /// - Device Ids 17 | /// - Local IP 18 | /// - Data Integrations Webhooks 19 | /// - Privacy Frameworks 20 | /// - Deep Linking 21 | REDUCED, 22 | 23 | /// Minimal Attribution - Analytics Only 24 | /// - Device Ids 25 | /// - Local IP 26 | /// - Data Integrations Webhooks 27 | /// - Deep Linking 28 | MINIMAL, 29 | 30 | /// No Attribution - No Analytics (GDPR, CCPA) 31 | /// - Only Deterministic Deep Linking 32 | /// - Disables all other Branch requests 33 | NONE 34 | } 35 | 36 | String getBranchAttributionLevelString(BranchAttributionLevel branchAttributionLevel) { 37 | return branchAttributionLevel.toString().split('.').last; 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/objects/branch_event.dart: -------------------------------------------------------------------------------- 1 | part of 'branch_universal_object.dart'; 2 | /* 3 | * Enum for creating Branch events for tracking and analytical purpose. 4 | * Enum class represent a standard or custom BranchEvents. Standard Branch events are defined with BRANCH_STANDARD_EVENT}. 5 | * Please use #logEvent() method to log the events for tracking. 6 | */ 7 | 8 | enum BranchStandardEvent { 9 | // Commerce events 10 | ADD_TO_CART, 11 | ADD_TO_WISHLIST, 12 | VIEW_CART, 13 | INITIATE_PURCHASE, 14 | ADD_PAYMENT_INFO, 15 | PURCHASE, 16 | SPEND_CREDITS, 17 | CLICK_AD, 18 | RESERVE, 19 | VIEW_AD, 20 | // Content Events 21 | SEARCH, 22 | VIEW_ITEM, 23 | VIEW_ITEMS, 24 | RATE, 25 | SHARE, 26 | INITIATE_STREAM, 27 | COMPLETE_STREAM, 28 | // User Lifecycle Events 29 | COMPLETE_REGISTRATION, 30 | COMPLETE_TUTORIAL, 31 | ACHIEVE_LEVEL, 32 | UNLOCK_ACHIEVEMENT, 33 | INVITE, 34 | LOGIN, 35 | START_TRIAL, 36 | SUBSCRIBE 37 | } 38 | 39 | String getBranchStandardEventString(BranchStandardEvent branchStandardEvent) { 40 | return branchStandardEvent.toString().split('.').last; 41 | } 42 | 43 | enum BranchEventAdType { BANNER, INTERSTITIAL, REWARDED_VIDEO, NATIVE } 44 | 45 | String getBranchEventAdTypeString(BranchEventAdType branchEventAdType) { 46 | return branchEventAdType.toString().split('.').last; 47 | } 48 | 49 | class BranchEvent { 50 | String _eventName = ''; 51 | bool _isStandardEvent = true; 52 | String transactionID = ''; 53 | BranchCurrencyType? currency; 54 | double revenue = -1; 55 | double shipping = -1; 56 | double tax = -1; 57 | String coupon = ''; 58 | String affiliation = ''; 59 | String eventDescription = ''; 60 | String searchQuery = ''; 61 | BranchEventAdType? adType; 62 | final Map _customData = {}; 63 | String alias = ''; 64 | 65 | BranchEvent.standardEvent(BranchStandardEvent branchStandardEvent) { 66 | _eventName = getBranchStandardEventString(branchStandardEvent); 67 | _isStandardEvent = true; 68 | } 69 | 70 | BranchEvent.customEvent(this._eventName) { 71 | _isStandardEvent = false; 72 | } 73 | 74 | String get eventName => _eventName; 75 | bool get isStandardEvent => _isStandardEvent; 76 | 77 | void addCustomData(String key, dynamic value) { 78 | _customData[key] = value; 79 | } 80 | 81 | void removeCustomData(String key) { 82 | _customData.remove(key); 83 | } 84 | 85 | Map toMap() { 86 | Map data = {}; 87 | 88 | if (!kIsWeb) { 89 | data["eventName"] = _eventName; 90 | data["isStandardEvent"] = _isStandardEvent; 91 | if (transactionID.isNotEmpty) { 92 | data["transactionID"] = transactionID; 93 | } 94 | if (currency != null) { 95 | data["currency"] = getCurrencyTypeString(currency!); 96 | } 97 | if (revenue != -1) data["revenue"] = revenue; 98 | if (shipping != -1) data["shipping"] = shipping; 99 | if (tax != -1) data["tax"] = tax; 100 | if (coupon.isNotEmpty) data["coupon"] = coupon; 101 | if (affiliation.isNotEmpty) data["affiliation"] = affiliation; 102 | if (eventDescription.isNotEmpty) { 103 | data["eventDescription"] = eventDescription; 104 | } 105 | if (searchQuery.isNotEmpty) { 106 | data["searchQuery"] = searchQuery; 107 | } 108 | if (adType != null) { 109 | data["adType"] = getBranchEventAdTypeString(adType!); 110 | } 111 | if (_customData.isNotEmpty) data["customData"] = _customData; 112 | if (alias.isNotEmpty) data["alias"] = alias; 113 | } else { 114 | if (_isStandardEvent) { 115 | if (transactionID.isNotEmpty) { 116 | data["transactionID"] = transactionID; 117 | } 118 | if (currency != null) { 119 | data["currency"] = getCurrencyTypeString(currency!); 120 | } 121 | if (revenue != -1) data["revenue"] = revenue; 122 | if (shipping != -1) data["shipping"] = shipping; 123 | if (tax != -1) data["tax"] = tax; 124 | if (coupon.isNotEmpty) data["coupon"] = coupon; 125 | if (affiliation.isNotEmpty) data["affiliation"] = affiliation; 126 | if (eventDescription.isNotEmpty) { 127 | data["eventDescription"] = eventDescription; 128 | } 129 | if (searchQuery.isNotEmpty) { 130 | data["searchQuery"] = searchQuery; 131 | } 132 | if (adType != null) { 133 | data["adType"] = getBranchEventAdTypeString(adType!); 134 | } 135 | } 136 | _customData.forEach((key, value) { 137 | data[key] = value; 138 | }); 139 | } 140 | return data; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /lib/src/objects/branch_qrcode.dart: -------------------------------------------------------------------------------- 1 | part of 'branch_universal_object.dart'; 2 | 3 | enum BranchImageFormat { 4 | JPEG, 5 | /* QR code is returned as a JPEG */ 6 | PNG 7 | /*QR code is returned as a PNG */ 8 | } 9 | 10 | class BranchQrCode { 11 | /* Primary color of the generated QR code itself. */ 12 | Color? primaryColor; 13 | /* Secondary color used as the QR Code background. */ 14 | Color? backgroundColor; 15 | /* The number of pixels for the QR code's border. Min 1px. Max 20px. */ 16 | int? margin; 17 | /* Output size of QR Code image. Min 300px. Max 2000px. */ 18 | int? width; 19 | /* A URL of an image that will be added to the center of the QR code. Must be a PNG or JPEG. */ 20 | String centerLogoUrl; 21 | /* Image Format of the returned QR code. Can be a JPEG or PNG. */ 22 | BranchImageFormat imageFormat; 23 | 24 | BranchQrCode( 25 | {this.primaryColor, 26 | this.backgroundColor, 27 | this.margin, 28 | this.width, 29 | this.imageFormat = BranchImageFormat.PNG, 30 | this.centerLogoUrl = ''}) { 31 | if (centerLogoUrl.isNotEmpty) { 32 | assert(Uri.parse(centerLogoUrl).isAbsolute == true, 'Invalid URL'); 33 | } 34 | } 35 | 36 | Map toMap() { 37 | Map ret = {}; 38 | 39 | if (!kIsWeb) { 40 | if (primaryColor != null) { 41 | ret["codeColor"] = _colorToHex(primaryColor!); 42 | } 43 | if (backgroundColor != null) { 44 | ret["backgroundColor"] = _colorToHex(backgroundColor!); 45 | } 46 | if (margin != null) { 47 | ret["margin"] = margin; 48 | } 49 | if (width != null) { 50 | ret["width"] = width; 51 | } 52 | ret["imageFormat"] = imageFormat.name.toUpperCase(); 53 | if (centerLogoUrl.isNotEmpty) { 54 | ret["centerLogoUrl"] = centerLogoUrl; 55 | } 56 | } else { 57 | if (primaryColor != null) { 58 | ret["code_color"] = _colorToHex(primaryColor!); 59 | } 60 | if (backgroundColor != null) { 61 | ret["background_color"] = _colorToHex(backgroundColor!); 62 | } 63 | if (margin != null) { 64 | ret["margin"] = margin; 65 | } 66 | if (width != null) { 67 | ret["width"] = width; 68 | } 69 | ret["image_format"] = imageFormat.name.toLowerCase(); 70 | if (centerLogoUrl.isNotEmpty) { 71 | ret["center_logo_url"] = centerLogoUrl; 72 | } 73 | } 74 | return ret; 75 | } 76 | 77 | String _colorToHex(Color color) { 78 | return '#${color.value.toRadixString(16).substring(2, 8)}'; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/src/objects/branch_response.dart: -------------------------------------------------------------------------------- 1 | part of 'branch_universal_object.dart'; 2 | 3 | class BranchResponse { 4 | bool success = true; 5 | T? result; 6 | String errorCode = ''; 7 | String errorMessage = ''; 8 | 9 | BranchResponse.success({required this.result}) { 10 | success = true; 11 | } 12 | BranchResponse.error({required this.errorCode, required this.errorMessage}) { 13 | success = false; 14 | } 15 | 16 | @override 17 | String toString() { 18 | return ('success: $success, errorCode: $errorCode, errorMessage: $errorMessage}'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/objects/branch_universal_object.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | part 'branch_event.dart'; 5 | part 'branch_qrcode.dart'; 6 | part 'branch_response.dart'; 7 | part 'content_meta_data.dart'; 8 | part 'content_schema.dart'; 9 | part 'link_properties.dart'; 10 | 11 | /* 12 | * Class represents a single piece of content within your app, as well as any associated metadata. 13 | * It provides convenient methods for sharing, deep linking, and tracking how often that content is viewed. This information is then used to provide you with powerful content analytics 14 | * and deep linking. 15 | */ 16 | class BranchUniversalObject { 17 | /* Canonical identifier for the content referred. */ 18 | final String canonicalIdentifier; 19 | 20 | /* Canonical url for the content referred. This would be the corresponding website URL */ 21 | String canonicalUrl = ''; 22 | 23 | /* Title for the content referred by BranchUniversalObject */ 24 | String title = ''; 25 | 26 | /* Description for the content referred */ 27 | String contentDescription = ''; 28 | 29 | /* An image url associated with the content referred */ 30 | String imageUrl = ''; 31 | 32 | /* Meta data provided for the content. {@link ContentMetadata} object holds the metadata for this content */ 33 | BranchContentMetaData? contentMetadata; 34 | 35 | /* Content index mode */ 36 | bool publiclyIndex = true; 37 | 38 | /* Any keyword associated with the content. Used for indexing */ 39 | List keywords; 40 | 41 | /* Expiry date for the content and any associated links. Represented as epoch milli second */ 42 | int expirationDateInMilliSec = 0; 43 | 44 | /* Index mode for local content indexing */ 45 | bool locallyIndex = true; 46 | final int _creationDateTimeStamp = DateTime.now().millisecondsSinceEpoch; 47 | 48 | ///Create a BranchUniversalObject with the given content. 49 | BranchUniversalObject( 50 | {required this.canonicalIdentifier, 51 | this.canonicalUrl = '', 52 | this.title = '', 53 | this.contentDescription = '', 54 | this.imageUrl = '', 55 | this.contentMetadata, 56 | this.keywords = const [], 57 | this.publiclyIndex = true, 58 | this.locallyIndex = true, 59 | this.expirationDateInMilliSec = 0}); 60 | 61 | ///Adds any keywords associated with the content referred 62 | void addKeyWords(List keywords) { 63 | keywords.addAll(keywords); 64 | } 65 | 66 | ///Add a keyword associated with the content referred 67 | void addKeyWord(String keyword) { 68 | keywords.add(keyword); 69 | } 70 | 71 | ///Remove a keyword associated with the content referred 72 | void removeKeyWord(String keyword) { 73 | keywords.remove(keyword); 74 | } 75 | 76 | ///Get the keywords associated with this BranchUniversalObject 77 | List getKeywords() { 78 | return keywords; 79 | } 80 | 81 | Map toMap() { 82 | Map ret = {}; 83 | if (!kIsWeb) { 84 | if (canonicalIdentifier.isNotEmpty) { 85 | ret["canonicalIdentifier"] = canonicalIdentifier; 86 | } 87 | 88 | if (canonicalUrl.isNotEmpty) ret["canonicalUrl"] = canonicalUrl; 89 | 90 | if (title.isNotEmpty) ret["title"] = title; 91 | 92 | if (contentDescription.isNotEmpty) { 93 | ret["contentDescription"] = contentDescription; 94 | } 95 | 96 | if (imageUrl.isNotEmpty) ret["imageUrl"] = imageUrl; 97 | 98 | if (keywords.isNotEmpty) ret["keywords"] = keywords; 99 | 100 | ret["creationDate"] = _creationDateTimeStamp; 101 | 102 | if (expirationDateInMilliSec > 0) { 103 | ret["expirationDate"] = expirationDateInMilliSec; 104 | } 105 | 106 | ret["locallyIndex"] = locallyIndex; 107 | ret["publiclyIndex"] = publiclyIndex; 108 | 109 | if (contentMetadata != null && contentMetadata!.toMap().isNotEmpty) { 110 | ret["contentMetadata"] = contentMetadata!.toMap(); 111 | } 112 | } else { 113 | if (canonicalIdentifier.isNotEmpty) { 114 | ret["\$canonical_identifier"] = canonicalIdentifier; 115 | } 116 | 117 | if (canonicalUrl.isNotEmpty) ret["\$canonicalUrl"] = canonicalUrl; 118 | 119 | if (title.isNotEmpty) ret["\$og_title"] = title; 120 | 121 | if (contentDescription.isNotEmpty) { 122 | ret["\$og_description"] = contentDescription; 123 | } 124 | 125 | if (imageUrl.isNotEmpty) ret["\$og_image_url"] = imageUrl; 126 | 127 | if (keywords.isNotEmpty) ret["\$keywords"] = keywords; 128 | 129 | ret["\$creation_timestamp"] = _creationDateTimeStamp; 130 | 131 | if (expirationDateInMilliSec > 0) { 132 | ret["\$exp_date"] = expirationDateInMilliSec; 133 | } 134 | 135 | ret["\$locally_indexable"] = locallyIndex; 136 | ret["\$publicly_indexable"] = publiclyIndex; 137 | 138 | Map contentMetadata = {if (this.contentMetadata != null) ...this.contentMetadata!.toMapWeb()}; 139 | 140 | if (contentMetadata.containsKey('customMetadata')) { 141 | var customMetadata = contentMetadata['customMetadata']; 142 | contentMetadata.remove('customMetadata'); 143 | contentMetadata.addAll(customMetadata); 144 | ret.addAll(contentMetadata); 145 | } else { 146 | ret.addAll(contentMetadata); 147 | } 148 | } 149 | 150 | if (ret.isEmpty) { 151 | throw ArgumentError('Branch Universal Object is required'); 152 | } 153 | return ret; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /lib/src/objects/content_meta_data.dart: -------------------------------------------------------------------------------- 1 | part of 'branch_universal_object.dart'; 2 | 3 | enum BranchCondition { OTHER, NEW, GOOD, FAIR, POOR, USED, REFURBISHED, EXCELLENT } 4 | 5 | enum BranchCurrencyType { 6 | AED, 7 | AFN, 8 | ALL, 9 | AMD, 10 | ANG, 11 | AOA, 12 | ARS, 13 | AUD, 14 | AWG, 15 | AZN, 16 | BAM, 17 | BBD, 18 | BDT, 19 | BGN, 20 | BHD, 21 | BIF, 22 | BMD, 23 | BND, 24 | BOB, 25 | BOV, 26 | BRL, 27 | BSD, 28 | BTN, 29 | BWP, 30 | BYN, 31 | BYR, 32 | BZD, 33 | CAD, 34 | CDF, 35 | CHE, 36 | CHF, 37 | CHW, 38 | CLF, 39 | CLP, 40 | CNY, 41 | COP, 42 | COU, 43 | CRC, 44 | CUC, 45 | CUP, 46 | CVE, 47 | CZK, 48 | DJF, 49 | DKK, 50 | DOP, 51 | DZD, 52 | EGP, 53 | ERN, 54 | ETB, 55 | EUR, 56 | FJD, 57 | FKP, 58 | GBP, 59 | GEL, 60 | GHS, 61 | GIP, 62 | GMD, 63 | GNF, 64 | GTQ, 65 | GYD, 66 | HKD, 67 | HNL, 68 | HRK, 69 | HTG, 70 | HUF, 71 | IDR, 72 | ILS, 73 | INR, 74 | IQD, 75 | IRR, 76 | ISK, 77 | JMD, 78 | JOD, 79 | JPY, 80 | KES, 81 | KGS, 82 | KHR, 83 | KMF, 84 | KPW, 85 | KRW, 86 | KWD, 87 | KYD, 88 | KZT, 89 | LAK, 90 | LBP, 91 | LKR, 92 | LRD, 93 | LSL, 94 | LYD, 95 | MAD, 96 | MDL, 97 | MGA, 98 | MKD, 99 | MMK, 100 | MNT, 101 | MOP, 102 | MRO, 103 | MUR, 104 | MVR, 105 | MWK, 106 | MXN, 107 | MXV, 108 | MYR, 109 | MZN, 110 | NAD, 111 | NGN, 112 | NIO, 113 | NOK, 114 | NPR, 115 | NZD, 116 | OMR, 117 | PAB, 118 | PEN, 119 | PGK, 120 | PHP, 121 | PKR, 122 | PLN, 123 | PYG, 124 | QAR, 125 | RON, 126 | RSD, 127 | RUB, 128 | RWF, 129 | SAR, 130 | SBD, 131 | SCR, 132 | SDG, 133 | SEK, 134 | SGD, 135 | SHP, 136 | SLL, 137 | SOS, 138 | SRD, 139 | SSP, 140 | STD, 141 | SYP, 142 | SZL, 143 | THB, 144 | TJS, 145 | TMT, 146 | TND, 147 | TOP, 148 | TRY, 149 | TTD, 150 | TWD, 151 | TZS, 152 | UAH, 153 | UGX, 154 | USD, 155 | USN, 156 | UYI, 157 | UYU, 158 | UZS, 159 | VEF, 160 | VND, 161 | VUV, 162 | WST, 163 | XAF, 164 | XAG, 165 | XAU, 166 | XBA, 167 | XBB, 168 | XBC, 169 | XBD, 170 | XCD, 171 | XDR, 172 | XFU, 173 | XOF, 174 | XPD, 175 | XPF, 176 | XPT, 177 | XSU, 178 | XTS, 179 | XUA, 180 | XXX, 181 | YER, 182 | ZAR, 183 | ZMW 184 | } 185 | 186 | String getCurrencyTypeString(BranchCurrencyType currencyType) { 187 | return currencyType.toString().split('.').last; 188 | } 189 | 190 | enum BranchProductCategory { 191 | ANIMALS_AND_PET_SUPPLIES, 192 | APPAREL_AND_ACCESSORIES, 193 | ARTS_AND_ENTERTAINMENT, 194 | BABY_AND_TODDLER, 195 | BUSINESS_AND_INDUSTRIAL, 196 | CAMERAS_AND_OPTICS, 197 | ELECTRONICS, 198 | FOOD_BEVERAGES_AND_TOBACCO, 199 | FURNITURE, 200 | HARDWARE, 201 | HEALTH_AND_BEAUTY, 202 | HOME_AND_GARDEN, 203 | LUGGAGE_AND_BAGS, 204 | MATURE, 205 | MEDIA, 206 | OFFICE_SUPPLIES, 207 | RELIGIOUS_AND_CEREMONIAL, 208 | SOFTWARE, 209 | SPORTING_GOODS, 210 | TOYS_AND_GAMES, 211 | VEHICLES_AND_PARTS, 212 | } 213 | 214 | /* 215 | Class for describing metadata for a piece of content represented by a FlutterBranchUniversalObject 216 | */ 217 | class BranchContentMetaData { 218 | /// Schema for the qualifying content item. Please see [BranchContentSchema] 219 | BranchContentSchema? contentSchema; 220 | 221 | /// Quantity of the thing associated with the qualifying content item 222 | double quantity = 0; 223 | 224 | /// Any price associated with the qualifying content item 225 | double price = 0; 226 | 227 | /// Currency type associated with the price 228 | BranchCurrencyType? currencyType; 229 | 230 | /// Holds any associated store keeping unit 231 | String sku = ''; 232 | 233 | /// Name of any product specified by this metadata 234 | String productName = ''; 235 | 236 | /// Any brand name associated with this metadata 237 | String productBrand = ''; 238 | 239 | /// Category of product if this metadata is for a product 240 | /// Value should be one of the enumeration from {@link ProductCategory} 241 | BranchProductCategory? productCategory; 242 | 243 | /// Condition of the product item. Value is one of the enum constants from {@link CONDITION} 244 | BranchCondition? condition; 245 | 246 | /// Variant of product if this metadata is for a product 247 | String productVariant = ''; 248 | 249 | /// Rating for the qualifying content item 250 | double rating = 0; 251 | 252 | /// Average rating for the qualifying content item 253 | double ratingAverage = 0; 254 | 255 | /// Total number of ratings for the qualifying content item 256 | int ratingCount = 0; 257 | 258 | ///Maximum ratings for the qualifying content item 259 | double ratingMax = 0; 260 | 261 | /// Street address associated with the qualifying content item 262 | String _addressStreet = ''; 263 | 264 | /// City name associated with the qualifying content item 265 | String _addressCity = ''; 266 | 267 | /// Region or province name associated with the qualifying content item 268 | String _addressRegion = ''; 269 | 270 | /// Country name associated with the qualifying content item 271 | String _addressCountry = ''; 272 | 273 | /// Postal code associated with the qualifying content item 274 | String _addressPostalCode = ''; 275 | 276 | /// Latitude value associated with the qualifying content item 277 | double? _latitude; 278 | 279 | /// Latitude value associated with the qualifying content item 280 | double? _longitude; 281 | 282 | List _imageCaptions = const []; 283 | final Map _customMetadata = {}; 284 | 285 | String? _getProductConditionString(BranchCondition? productCondition) { 286 | if (productCondition == null) return null; 287 | return productCondition.toString().split('.').last; 288 | } 289 | 290 | String? _getProductCategoryString(BranchProductCategory? productCategory) { 291 | if (productCategory == null) return null; 292 | switch (productCategory) { 293 | case BranchProductCategory.ANIMALS_AND_PET_SUPPLIES: 294 | return "Animals & Pet Supplies"; 295 | case BranchProductCategory.APPAREL_AND_ACCESSORIES: 296 | return "Apparel & Accessories"; 297 | case BranchProductCategory.ARTS_AND_ENTERTAINMENT: 298 | return "Arts & Entertainment"; 299 | case BranchProductCategory.BABY_AND_TODDLER: 300 | return "Baby & Toddler"; 301 | case BranchProductCategory.BUSINESS_AND_INDUSTRIAL: 302 | return "Business & Industrial"; 303 | case BranchProductCategory.CAMERAS_AND_OPTICS: 304 | return "Cameras & Optics"; 305 | case BranchProductCategory.ELECTRONICS: 306 | return "Electronics"; 307 | case BranchProductCategory.FOOD_BEVERAGES_AND_TOBACCO: 308 | return "Food, Beverages & Tobacco"; 309 | case BranchProductCategory.FURNITURE: 310 | return "Furniture"; 311 | case BranchProductCategory.HARDWARE: 312 | return "Hardware"; 313 | case BranchProductCategory.HEALTH_AND_BEAUTY: 314 | return "Health & Beauty"; 315 | case BranchProductCategory.HOME_AND_GARDEN: 316 | return "Home & Garden"; 317 | case BranchProductCategory.LUGGAGE_AND_BAGS: 318 | return "Luggage & Bags"; 319 | case BranchProductCategory.MATURE: 320 | return "Mature"; 321 | case BranchProductCategory.MEDIA: 322 | return "Media"; 323 | case BranchProductCategory.OFFICE_SUPPLIES: 324 | return "Office Supplies"; 325 | case BranchProductCategory.RELIGIOUS_AND_CEREMONIAL: 326 | return "Religious & Ceremonial"; 327 | case BranchProductCategory.SOFTWARE: 328 | return "Software"; 329 | case BranchProductCategory.SPORTING_GOODS: 330 | return "Sporting Goods"; 331 | case BranchProductCategory.TOYS_AND_GAMES: 332 | return "Toys & Games"; 333 | case BranchProductCategory.VEHICLES_AND_PARTS: 334 | return "Vehicles & Parts"; 335 | } 336 | } 337 | 338 | BranchContentMetaData addImageCaptions(List captions) { 339 | _imageCaptions = captions; 340 | return this; 341 | } 342 | 343 | BranchContentMetaData addCustomMetadata(String key, dynamic value) { 344 | assert(value != null, 'Null value not allowed in CustomMetadata'); 345 | _customMetadata[key] = value; 346 | return this; 347 | } 348 | 349 | BranchContentMetaData setAddress({String? street, String? city, String? region, String? country, String? postalCode}) { 350 | if (street != null) _addressStreet = street; 351 | if (city != null) _addressCity = city; 352 | if (region != null) _addressRegion = region; 353 | if (country != null) _addressCountry = country; 354 | if (postalCode != null) _addressPostalCode = postalCode; 355 | return this; 356 | } 357 | 358 | BranchContentMetaData setLocation(double latitude, double longitude) { 359 | _latitude = latitude; 360 | _longitude = longitude; 361 | return this; 362 | } 363 | 364 | Map toMap() { 365 | Map ret = {}; 366 | if (contentSchema != null) { 367 | ret["content_schema"] = getContentSchemaString(contentSchema); 368 | } 369 | if (quantity > 0) ret["quantity"] = quantity; 370 | if (price > 0) ret["price"] = price; 371 | if (currencyType != null) { 372 | ret["currency"] = getCurrencyTypeString(currencyType!); 373 | } 374 | if (sku.isNotEmpty) ret["sku"] = sku; 375 | if (productName.isNotEmpty) ret["product_name"] = productName; 376 | if (productBrand.isNotEmpty) ret["product_brand"] = productBrand; 377 | if (productCategory != null) { 378 | ret["product_category"] = _getProductCategoryString(productCategory); 379 | } 380 | if (productVariant.isNotEmpty) ret["product_variant"] = productVariant; 381 | if (condition != null) { 382 | ret["condition"] = _getProductConditionString(condition); 383 | } 384 | if (ratingAverage > 0) ret["rating_average"] = ratingAverage; 385 | if (ratingCount > 0) ret["rating_count"] = ratingCount; 386 | if (ratingMax > 0) ret["rating_max"] = ratingMax; 387 | if (rating > 0) ret["rating"] = rating; 388 | if (_addressStreet.isNotEmpty) ret["address_street"] = _addressStreet; 389 | if (_addressCity.isNotEmpty) ret["address_city"] = _addressCity; 390 | if (_addressRegion.isNotEmpty) ret["address_region"] = _addressRegion; 391 | if (_addressCountry.isNotEmpty) ret["address_country"] = _addressCountry; 392 | if (_addressPostalCode.isNotEmpty) { 393 | ret["address_postal_code"] = _addressPostalCode; 394 | } 395 | if (_latitude != null) ret["latitude"] = _latitude; 396 | if (_longitude != null) ret["longitude"] = _longitude; 397 | if (_imageCaptions.isNotEmpty) ret["image_captions"] = _imageCaptions; 398 | if (_customMetadata.isNotEmpty) { 399 | ret["customMetadata"] = _customMetadata; 400 | } 401 | return ret; 402 | } 403 | 404 | Map toMapWeb() { 405 | Map ret = {}; 406 | if (contentSchema != null) { 407 | ret["\$content_schema"] = getContentSchemaString(contentSchema); 408 | } 409 | if (quantity > 0) ret["\$quantity"] = quantity; 410 | if (price > 0) ret["\$price"] = price; 411 | if (currencyType != null) { 412 | ret["\$currency"] = getCurrencyTypeString(currencyType!); 413 | } 414 | if (sku.isNotEmpty) ret["\$sku"] = sku; 415 | if (productName.isNotEmpty) ret["\$product_name"] = productName; 416 | if (productBrand.isNotEmpty) ret["\$product_brand"] = productBrand; 417 | if (productCategory != null) { 418 | ret["\$product_category"] = productCategory.toString().split('.').last; 419 | } 420 | if (productVariant.isNotEmpty) ret["\$product_variant"] = productVariant; 421 | if (condition != null) { 422 | ret["\$condition"] = _getProductConditionString(condition); 423 | } 424 | if (ratingAverage > 0) ret["\$rating_average"] = ratingAverage; 425 | if (ratingCount > 0) ret["\$rating_count"] = ratingCount; 426 | if (ratingMax > 0) ret["\$rating_max"] = ratingMax; 427 | if (rating > 0) ret["\$rating"] = rating; 428 | if (_addressStreet.isNotEmpty) ret["\$address_street"] = _addressStreet; 429 | if (_addressCity.isNotEmpty) ret["\$address_city"] = _addressCity; 430 | if (_addressRegion.isNotEmpty) ret["\$address_region"] = _addressRegion; 431 | if (_addressCountry.isNotEmpty) ret["\$address_country"] = _addressCountry; 432 | if (_addressPostalCode.isNotEmpty) { 433 | ret["\$address_postal_code"] = _addressPostalCode; 434 | } 435 | if (_latitude != null) ret["\$latitude"] = _latitude; 436 | if (_longitude != null) ret["\$longitude"] = _longitude; 437 | if (_imageCaptions.isNotEmpty) { 438 | ret["\$image_captions"] = _imageCaptions; 439 | } 440 | _customMetadata.forEach((key, value) { 441 | ret[key] = value; 442 | }); 443 | return ret; 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /lib/src/objects/content_schema.dart: -------------------------------------------------------------------------------- 1 | part of 'branch_universal_object.dart'; 2 | 3 | enum BranchContentSchema { 4 | COMMERCE_AUCTION, 5 | COMMERCE_BUSINESS, 6 | COMMERCE_OTHER, 7 | COMMERCE_PRODUCT, 8 | COMMERCE_RESTAURANT, 9 | COMMERCE_SERVICE, 10 | COMMERCE_TRAVEL_FLIGHT, 11 | COMMERCE_TRAVEL_HOTEL, 12 | COMMERCE_TRAVEL_OTHER, 13 | GAME_STATE, 14 | MEDIA_IMAGE, 15 | MEDIA_MIXED, 16 | MEDIA_MUSIC, 17 | MEDIA_OTHER, 18 | MEDIA_VIDEO, 19 | OTHER, 20 | TEXT_ARTICLE, 21 | TEXT_BLOG, 22 | TEXT_OTHER, 23 | TEXT_RECIPE, 24 | TEXT_REVIEW, 25 | TEXT_SEARCH_RESULTS, 26 | TEXT_STORY, 27 | TEXT_TECHNICAL_DOC 28 | } 29 | 30 | BranchContentSchema getValueContentSchema(String name) { 31 | BranchContentSchema? schema; 32 | for (BranchContentSchema contentSchema in BranchContentSchema.values) { 33 | if (contentSchema.toString() == name) { 34 | schema = contentSchema; 35 | break; 36 | } 37 | } 38 | return schema!; 39 | } 40 | 41 | String? getContentSchemaString(BranchContentSchema? contentSchema) { 42 | if (contentSchema == null) return null; 43 | return contentSchema.toString().split('.').last; 44 | } 45 | -------------------------------------------------------------------------------- /lib/src/objects/link_properties.dart: -------------------------------------------------------------------------------- 1 | part of 'branch_universal_object.dart'; 2 | /* 3 | * Class for representing any additional information that is specific to the link. 4 | * Use this class to specify the properties of a deep link such as channel, feature etc and any control params associated with the link. 5 | * 6 | */ 7 | 8 | class BranchLinkProperties { 9 | List tags = const []; 10 | final String feature; 11 | final String alias; 12 | final String stage; 13 | final int matchDuration; 14 | final Map _controlParams = {}; 15 | final String channel; 16 | final String campaign; 17 | 18 | BranchLinkProperties( 19 | {this.channel = '', 20 | this.feature = '', 21 | this.alias = '', 22 | this.matchDuration = 0, 23 | this.stage = '', 24 | this.tags = const [], 25 | this.campaign = ''}); 26 | 27 | void addTags(String tag) { 28 | tags.add(tag); 29 | } 30 | 31 | List getTags() { 32 | return tags; 33 | } 34 | 35 | Map getControlParams() { 36 | return _controlParams; 37 | } 38 | 39 | BranchLinkProperties addControlParam(String key, dynamic value) { 40 | assert(value != null, 'Null value not allowed in ControlParam'); 41 | if (value is List) { 42 | throw ArgumentError('List value not allowed in ControlParms '); 43 | } 44 | _controlParams[key] = value.toString(); 45 | return this; 46 | } 47 | 48 | Map toMap() { 49 | Map ret = {}; 50 | 51 | if (tags.isNotEmpty) ret['tags'] = tags; 52 | if (feature.isNotEmpty) ret['feature'] = feature; 53 | if (alias.isNotEmpty) ret['alias'] = alias; 54 | if (stage.isNotEmpty) ret['stage'] = stage; 55 | if (matchDuration > 0) ret['matchDuration'] = matchDuration; 56 | if (_controlParams.isNotEmpty) ret['controlParams'] = _controlParams; 57 | if (channel.isNotEmpty) ret['channel'] = channel; 58 | if (campaign.isNotEmpty) ret['campaign'] = campaign; 59 | if (ret.isEmpty) { 60 | throw ArgumentError('Link Properties is required'); 61 | } 62 | return ret; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.12.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.2" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.4.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.2" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.19.1" 44 | fake_async: 45 | dependency: transitive 46 | description: 47 | name: fake_async 48 | sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.3.2" 52 | flutter: 53 | dependency: "direct main" 54 | description: flutter 55 | source: sdk 56 | version: "0.0.0" 57 | flutter_lints: 58 | dependency: "direct dev" 59 | description: 60 | name: flutter_lints 61 | sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" 62 | url: "https://pub.dev" 63 | source: hosted 64 | version: "5.0.0" 65 | flutter_test: 66 | dependency: "direct dev" 67 | description: flutter 68 | source: sdk 69 | version: "0.0.0" 70 | flutter_web_plugins: 71 | dependency: "direct main" 72 | description: flutter 73 | source: sdk 74 | version: "0.0.0" 75 | leak_tracker: 76 | dependency: transitive 77 | description: 78 | name: leak_tracker 79 | sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec 80 | url: "https://pub.dev" 81 | source: hosted 82 | version: "10.0.8" 83 | leak_tracker_flutter_testing: 84 | dependency: transitive 85 | description: 86 | name: leak_tracker_flutter_testing 87 | sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 88 | url: "https://pub.dev" 89 | source: hosted 90 | version: "3.0.9" 91 | leak_tracker_testing: 92 | dependency: transitive 93 | description: 94 | name: leak_tracker_testing 95 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" 96 | url: "https://pub.dev" 97 | source: hosted 98 | version: "3.0.1" 99 | lints: 100 | dependency: transitive 101 | description: 102 | name: lints 103 | sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" 104 | url: "https://pub.dev" 105 | source: hosted 106 | version: "5.0.0" 107 | matcher: 108 | dependency: transitive 109 | description: 110 | name: matcher 111 | sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 112 | url: "https://pub.dev" 113 | source: hosted 114 | version: "0.12.17" 115 | material_color_utilities: 116 | dependency: transitive 117 | description: 118 | name: material_color_utilities 119 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec 120 | url: "https://pub.dev" 121 | source: hosted 122 | version: "0.11.1" 123 | meta: 124 | dependency: transitive 125 | description: 126 | name: meta 127 | sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c 128 | url: "https://pub.dev" 129 | source: hosted 130 | version: "1.16.0" 131 | path: 132 | dependency: transitive 133 | description: 134 | name: path 135 | sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" 136 | url: "https://pub.dev" 137 | source: hosted 138 | version: "1.9.1" 139 | plugin_platform_interface: 140 | dependency: "direct main" 141 | description: 142 | name: plugin_platform_interface 143 | sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" 144 | url: "https://pub.dev" 145 | source: hosted 146 | version: "2.1.8" 147 | sky_engine: 148 | dependency: transitive 149 | description: flutter 150 | source: sdk 151 | version: "0.0.0" 152 | source_span: 153 | dependency: transitive 154 | description: 155 | name: source_span 156 | sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" 157 | url: "https://pub.dev" 158 | source: hosted 159 | version: "1.10.1" 160 | stack_trace: 161 | dependency: transitive 162 | description: 163 | name: stack_trace 164 | sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" 165 | url: "https://pub.dev" 166 | source: hosted 167 | version: "1.12.1" 168 | stream_channel: 169 | dependency: transitive 170 | description: 171 | name: stream_channel 172 | sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" 173 | url: "https://pub.dev" 174 | source: hosted 175 | version: "2.1.4" 176 | string_scanner: 177 | dependency: transitive 178 | description: 179 | name: string_scanner 180 | sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" 181 | url: "https://pub.dev" 182 | source: hosted 183 | version: "1.4.1" 184 | term_glyph: 185 | dependency: transitive 186 | description: 187 | name: term_glyph 188 | sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" 189 | url: "https://pub.dev" 190 | source: hosted 191 | version: "1.2.2" 192 | test_api: 193 | dependency: transitive 194 | description: 195 | name: test_api 196 | sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd 197 | url: "https://pub.dev" 198 | source: hosted 199 | version: "0.7.4" 200 | vector_math: 201 | dependency: transitive 202 | description: 203 | name: vector_math 204 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 205 | url: "https://pub.dev" 206 | source: hosted 207 | version: "2.1.4" 208 | vm_service: 209 | dependency: transitive 210 | description: 211 | name: vm_service 212 | sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" 213 | url: "https://pub.dev" 214 | source: hosted 215 | version: "14.3.1" 216 | sdks: 217 | dart: ">=3.7.0-0 <4.0.0" 218 | flutter: ">=3.19.0" 219 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_branch_sdk 2 | description: "Flutter Plugin for create deep link using Brach SDK (https://branch.io). This plugin provides a cross-platform (iOS, Android, Web)." 3 | version: 8.5.0 4 | repository: https://github.com/RodrigoSMarques/flutter_branch_sdk 5 | 6 | environment: 7 | sdk: ">=3.3.0 <4.0.0" 8 | flutter: '>=3.19.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | flutter_web_plugins: 14 | sdk: flutter 15 | plugin_platform_interface: ^2.1.8 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | flutter_lints: ^5.0.0 21 | 22 | # For information on the generic Dart part of this file, see the 23 | # following page: https://dart.dev/tools/pub/pubspec 24 | 25 | # The following section is specific to Flutter packages. 26 | flutter: 27 | # This section identifies this Flutter project as a plugin project. 28 | # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) 29 | # which should be registered in the plugin registry. This is required for 30 | # using method channels. 31 | # The Android 'package' specifies package in which the registered class is. 32 | # This is required for using method channels on Android. 33 | # The 'ffiPlugin' specifies that native code should be built and bundled. 34 | # This is required for using `dart:ffi`. 35 | # All these are used by the tooling to maintain consistency when 36 | # adding or updating assets for this project. 37 | plugin: 38 | platforms: 39 | android: 40 | package: br.com.rsmarques.flutter_branch_sdk 41 | pluginClass: FlutterBranchSdkPlugin 42 | ios: 43 | pluginClass: FlutterBranchSdkPlugin 44 | web: 45 | pluginClass: FlutterBranchSdkWeb 46 | fileName: src/flutter_branch_sdk_web.dart 47 | 48 | topics: 49 | - deeplink 50 | - app-links 51 | - universal-links 52 | - custom-url-schemes 53 | - web-to-app -------------------------------------------------------------------------------- /tool/build-apk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This scrip installs the dependencies of the flutter package. 3 | # parse_server_sdk is set to the relative path. 4 | 5 | cd example 6 | flutter config --no-analytics 7 | flutter pub get 8 | flutter build apk -------------------------------------------------------------------------------- /tool/build-web.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This scrip installs the dependencies of the flutter package. 3 | # parse_server_sdk is set to the relative path. 4 | 5 | cd example 6 | flutter config --no-analytics 7 | flutter pub get 8 | #flutter build web --source-maps 9 | #flutter build web --profile --source-maps --dart-define=Dart2jsOptimization=O0 10 | #flutter build web 11 | flutter build web --wasm --source-maps -------------------------------------------------------------------------------- /tool/flutter-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This scrip installs the dependencies of the flutter package. 3 | # parse_server_sdk is set to the relative path. 4 | flutter pub get 5 | --------------------------------------------------------------------------------