├── .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