Branch SDK Plugin

Branch

This is a Flutter plugin that implemented Branch SDK.

Branch.io helps mobile apps grow with deep links that power referral systems, sharing links and invites with full attribution and analytics.

Supports Android, iOS and Web.

Implemented functions in plugin:

FunctionAndroidiOSWeb
Test Branch IntegrationXXNot supported
Track usersXXX
Enable / Disable User TrackingXXX
Get First and Last ParametersXXX
Generate Deep Link for Branch Universal Object (BUO)XXX
Show Share Sheet for Branch Universal Object (BUO)XXX
List BUO on Search / Remove BUO from SearchXXNot supported
Register viewXXX
Track User Actions and EventsXXX
Init Branch Session and Deep LinkXXX
Last Attributed Touch DataXXX
QR codesXXX
Share with LPLinkMetadataX

Getting Started

Configure Branch Dashboard

For details see:

Configure Platform Project

Android Integration

Follow the steps on the page https://help.branch.io/developers-hub/docs/android-basic-integration#configure-app, session Configure app:

  • Add Branch to your AndroidManifest.xml

iOS Integration

Follow the steps on the page https://help.branch.io/developers-hub/docs/ios-basic-integration#configure-bundle-identifier, from session Configure bundle identifier:

  • Configure bundle identifier
  • Configure associated domains
  • Configure entitlements
  • Configure Info.plist
  • Confirm app prefix

Note: In Info.plist not add branch_key live and test at the same time.
Use only branch_key and update as needed.

Web Integration

You need add Branch Javascript in your web\index.html at the top of your <body> tag, to be able to use this package.

  <script>
    (function(b,r,a,n,c,h,_,s,d,k){if(!b[n]||!b[n]._q){for(;s<_.length;)c(h,_[s++]);d=r.createElement(a);d.async=1;d.src="https://cdn.branch.io/branch-latest.min.js";k=r.getElementsByTagName(a)[0];k.parentNode.insertBefore(d,k);b[n]=h}})(window,document,"script","branch",function(b,r){b[r]=function(){b._q.push([r,arguments])}},{_q:[],_v:1},"addListener applyCode autoAppIndex banner closeBanner closeJourney creditHistory credits data deepview deepviewCta first getCode init link logout redeem referrals removeListener sendSMS setBranchViewData setIdentity track validateCode trackCommerceEvent logEvent disableTracking".split(" "), 0);
    branch.init('key_live_YOUR_KEY_GOES_HERE');
  </script>

Change key_live_YOUR_KEY_GOES_HERE to match your Branch Dashboard

If branch.init() fails, all subsequent Branch methods will fail.

Full example index.html:

<!DOCTYPE html>
<html>
<head>
  <!--
    If you are serving your web app in a path other than the root, change the
    href value below to reflect the base path you are serving from.

    The path provided below has to start and end with a slash "/" in order for
    it to work correctly.

    Fore more details:
    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
  -->
  <base href="/">

  <meta charset="UTF-8">
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
  <meta name="description" content="Demonstrates how to use the flutter_branch_sdk plugin.">

  <!-- iOS meta tags & icons -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="flutter_branch_sdk_example">
  <link rel="apple-touch-icon" href="icons/Icon-192.png">

  <!-- Favicon -->
  <link rel="icon" type="image/png" href="favicon.png"/>

  <title>flutter_branch_sdk_example</title>
  <link rel="manifest" href="manifest.json">
</head>
<body>
  <script>
    (function(b,r,a,n,c,h,_,s,d,k){if(!b[n]||!b[n]._q){for(;s<_.length;)c(h,_[s++]);d=r.createElement(a);d.async=1;d.src="https://cdn.branch.io/branch-latest.min.js";k=r.getElementsByTagName(a)[0];k.parentNode.insertBefore(d,k);b[n]=h}})(window,document,"script","branch",function(b,r){b[r]=function(){b._q.push([r,arguments])}},{_q:[],_v:1},"addListener applyCode autoAppIndex banner closeBanner closeJourney creditHistory credits data deepview deepviewCta first getCode init link logout redeem referrals removeListener sendSMS setBranchViewData setIdentity track validateCode trackCommerceEvent logEvent disableTracking".split(" "), 0);
    branch.init('key_live_YOUR_KEY_GOES_HERE');
  </script>
  <!-- This script installs service_worker.js to provide PWA functionality to
       application. For more information, see:
       https://developers.google.com/web/fundamentals/primers/service-workers -->
  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('flutter-first-frame', function () {
        navigator.serviceWorker.register('flutter_service_worker.js');
      });
    }
  </script>
  <script src="main.dart.js" type="application/javascript"></script>
</body>
</html>

Installation

To use the plugin, add flutter_branch_sdk as a dependency in your pubspec.yaml file.

How to use

Test Branch Integration

Test your Branch Integration by calling:

FlutterBranchSdk.validateSDKIntegration();

Check logs to make sure all the SDK Integration tests pass.

Example of log for Android:

------------------- Initiating Branch integration verification --------------------------- ... 
1. Verifying Branch instance creation ... 
Passed
2. Checking Branch keys ... 
Passed
3. Verifying application package name ... 
Passed
4. Checking Android Manifest for URI based deep link config ... 
Passed
5. Verifying URI based deep link config with Branch dash board. ... 
Passed
6. Verifying intent for receiving URI scheme. ... 
Passed
7. Checking AndroidManifest for AppLink config. ... 
Passed
8. Verifying any supported custom link domains. ... 
Passed
9. Verifying default link domains integrations. ... 
Passed
10. Verifying alternate link domains integrations. ... 
Passed
Passed
--------------------------------------------
Successfully completed Branch integration validation. Everything looks good!
 
Great! Comment out the 'validateSDKIntegration' line in your app. Next check your deep link routing.
Append '?bnc_validate=true' to any of your app's Branch links and click it on your mobile device (not the Simulator!) to start the test.
For instance, to validate a link like:
https://<yourapp>.app.link/NdJ6nFzRbK
click on:
https://<yourapp>.app.link/NdJ6nFzRbK?bnc_validate=true

Make sure to comment out or remove validateSDKIntegration in your production build.

Read deep link

To listen to the clicks on the deep link and retrieve the data it is necessary to add the code below:

    StreamSubscription<Map> streamSubscription = FlutterBranchSdk.initSession().listen((data) {
      if (data.containsKey("+clicked_branch_link") &&
          data["+clicked_branch_link"] == true) {
         //Link clicked. Add logic to get link data
         print('Custom string: ${data["custom_string"]}');
      }
    }, onError: (error) {
		print('InitSesseion error: ${error.toString()}');
    });

When a deep link is clicked the above method will be called, with the app is open or closed.

Retrieve Install (Install Only) Parameters

If you ever want to access the original session params (the parameters passed in for the first install event only), you can use this line. This is useful if you only want to reward users who newly installed the app from a referral link.

    Map<dynamic, dynamic> params = await FlutterBranchSdk.getFirstReferringParams();

Retrieve session (install or open) parameters

These session parameters will be available at any point later on with this command. If no parameters are available then Branch will return an empty dictionary. This refreshes with every new session (app installs AND app opens).

    Map<dynamic, dynamic> params = await FlutterBranchSdk.getLatestReferringParams();

Retrieve Branch's Last Attributed Touch Data

Allow retrieval of our last attributed touch data (LATD) from the client. This results in an asynchronous call being made to Branch’s servers with LATD data returned when possible.

Last attributed touch data contains the information associated with that user's last viewed impression or clicked link.

BranchResponse response =
        await FlutterBranchSdk.getLastAttributedTouchData();
    if (response.success) {
      print(response.result.toString());
    }

More information here.

Create content reference (Branch Universal Object)

The Branch Universal Object encapsulates the thing you want to share.

    BranchUniversalObject buo = BranchUniversalObject(
      canonicalIdentifier: 'flutter/branch',
      //canonicalUrl: '',
      title: 'Flutter Branch Plugin',
      imageUrl: 'https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/master/assets/branch_logo_qrcode.jpeg',
      contentDescription: 'Flutter Branch Description',
      keywords: ['Plugin', 'Branch', 'Flutter'],
      publiclyIndex: true,
      locallyIndex: true,
      contentMetadata: BranchContentMetaData()..addCustomMetadata('custom_string', 'abc')
          ..addCustomMetadata('custom_number', 12345)
          ..addCustomMetadata('custom_bool', true)
          ..addCustomMetadata('custom_list_number', [1,2,3,4,5 ])
          ..addCustomMetadata('custom_list_string', ['a', 'b', 'c']),
    );

parameter canonicalUrl: If your content lives both on the web and in the app, make sure you set its canonical URL (i.e. the URL of this piece of content on the web) when building any BUO. By doing so, we’ll attribute clicks on the links that you generate back to their original web page, even if the user goes to the app instead of your website! This will help your SEO efforts.

More information about the parameters, verify Android documentation and iOS documentation

Create link reference (BranchLinkProperties)

  • Generates the analytical properties for the deep link.
  • Used for Create deep link and Share deep link.
    BranchLinkProperties lp = BranchLinkProperties(
	   //alias: 'flutterplugin', //define link url,
        channel: 'facebook',
        feature: 'sharing',
        stage: 'new share',
        tags: ['one', 'two', 'three']
    );
    lp.addControlParam('url', 'http://www.google.com');
    lp.addControlParam('url2', 'http://flutter.dev');

parameter alias: Instead of our standard encoded short url, you can specify the vanity alias. For example, instead of a random string of characters/integers, you can set the vanity alias as *.app.link/devonaustin. Aliases are enforced to be unique and immutable per domain, and per link - they cannot be reused unless deleted.

More information about the parameters, verify Android documentation and iOS documentation

Create deep link

Generates a deep link within your app.

    BranchResponse response =
        await FlutterBranchSdk.getShortUrl(buo: buo, linkProperties: lp);
    if (response.success) {
      print('Link generated: ${response.result}');
    } else {
        print('Error : ${response.errorCode} - ${response.errorMessage}');
    }

Show Share Sheet with deep link

Will generate a Branch deep link and tag it with the channel the user selects.

Note: For Android additional customization is possible

    BranchResponse response = await FlutterBranchSdk.showShareSheet(
        buo: buo,
        linkProperties: lp,
        messageText: 'My Share text',
        androidMessageTitle: 'My Message Title',
        androidSharingTitle: 'My Share with');

    if (response.success) {
      print('showShareSheet Sucess');
    } else {
      print('Error : ${response.errorCode} - ${response.errorMessage}');
    }

Show Share Sheet with LPLinkMetadata

Note: Requires iOS 13 or higher, else call showShareSheet function

Will show Share Sheet with customization.

Parameters

  1. Content - verify section Create content reference

  2. Link Reference - verify section Create link reference

  3. Title (String) - Title for Share Sheet

  4. Icon (Uint8List) - Image for Share Sheet. Load image before from Web or assets.

      FlutterBranchSdk.shareWithLPLinkMetadata(
          buo: buo!,
          linkProperties: lp,
          title: "Share With LPLinkMetadata",
          icon: iconData);

Create a QR Code

QR Code Access Required

Access to Branch's QR Code API and SDK requires premium product access. Please reach out to your account manager or https://branch.io/pricing/ to activate.

Will generates a custom QR Code with a unique Branch link which you can deep link and track analytics with.

Parameters

  1. Content - verify section Create content reference

  2. Link Reference - verify section Create link reference

  3. BranchQrCode object (QR Code settings)

ParameterTypeDefinition
primaryColorColorColor name ou Hex color value
backgroundColorColorColor name ou Hex color value of the background of the QR code itself.
marginInteger (Pixels)The number of pixels you want for the margin. Min 1px. Max 20px.
widthInteger (Pixels)Output size of QR Code image. Min 300px. Max 2000px. (Only applicable to JPEG/PNG)
imageFormatBranchImageFormatJPEG, PNG
centerLogoUrlString (HTTP URL)URL to the image you want as a center logo e.g. https://raw.githubusercontent.com/RodrigoSMarques/flutter_branch_sdk/master/assets/branch_logo_qrcode.jpeg
    BranchResponse responseQrCodeImage =
        await FlutterBranchSdk.getQRCodeAsImage(
            buo: buo!,
            linkProperties: lp,
            qrCode: BranchQrCode(
                primaryColor: Colors.black,
                //primaryColor: const Color(0xff443a49), //Hex colors
                centerLogoUrl: imageURL,
                backgroundColor: Colors.white,
                imageFormat: BranchImageFormat.PNG));

    if (response.success) {
      print('QrCode Success');
      showQrCode(this.context, responseQrCodeImage.result);
 		/*
        Image(
          image: responseQrCodeImage.result,
          height: 250,
          width: 250,
        ),
      */
    } else {
      print('Error : ${response.errorCode} - ${response.errorMessage}');

  • Method getQRCodeAsImage returns the QR code as a Image.
  • Method getQRCodeAsData returns the QR code as Uint8List. Can be stored in a file or converted to image.

List content on Search

  • For Android list BUO links in Google Search with Firebase App Indexing API and locally in Google In Apps search
  • For iOs list BUO links in Spotlight
    bool success = await FlutterBranchSdk.listOnSearch(buo: buo);
    print(success);

Remove content from Search

Privately indexed Branch Universal Object can be removed.

    bool success = await FlutterBranchSdk.removeFromSearch(buo: buo);
    print('Remove sucess: $success');

Register Event VIEW_ITEM

Mark the content referred by this object as viewed. This increment the view count of the contents referred by this object.

FlutterBranchSdk.registerView(buo: buo);

Tracking User Actions and Events

Use the BranchEvent interface to track special user actions or application specific events beyond app installs, opens, and sharing. You can track events such as when a user adds an item to an on-line shopping cart, or searches for a keyword, among others. The BranchEvent interface provides an interface to add contents represented by BranchUniversalObject in order to associate app contents with events. Analytics about your app's BranchEvents can be found on the Branch dashboard, and BranchEvents also provide tight integration with many third party analytics providers.

BranchEvent eventStandart = BranchEvent.standardEvent(BranchStandardEvent.ADD_TO_CART);
FlutterBranchSdk.trackContent(buo: [buo], branchEvent: eventStandart);

You can use your own custom event names too:

BranchEvent eventCustom = BranchEvent.customEvent('Custom_event');
FlutterBranchSdk.trackContent(buo: [buo], branchEvent: eventCustom);

Extra event specific data can be tracked with the event as well:

    eventStandart.transactionID = '12344555';
    eventStandart.currency = BranchCurrencyType.BRL;
    eventStandart.revenue = 1.5;
    eventStandart.shipping = 10.2;
    eventStandart.tax = 12.3;
    eventStandart.coupon = 'test_coupon';
    eventStandart.affiliation = 'test_affiliation';
    eventStandart.eventDescription = 'Event_description';
    eventStandart.searchQuery = 'item 123';
    eventStandart.adType = BranchEventAdType.BANNER;
    eventStandart.addCustomData(
        'Custom_Event_Property_Key1', 'Custom_Event_Property_val1');
    eventStandart.addCustomData(
        'Custom_Event_Property_Key2', 'Custom_Event_Property_val2');
    FlutterBranchSdk.trackContent(buo: [buo], branchEvent: eventStandart);

trackContent accepts a list of Branch Universal Object.

You can register logs in BranchEvent without Branch Universal Object (BUO) for tracking and analytics:

BranchEvent eventStandart = BranchEvent.standardEvent(BranchStandardEvent.ADD_TO_CART);
FlutterBranchSdk.trackContentWithoutBuo(branchEvent: eventStandart);

You can use your own custom event names too:

BranchEvent eventCustom = BranchEvent.customEvent('Custom_event');
FlutterBranchSdk.trackContentWithoutBuo(branchEvent: eventCustom);

Track users

Sets the identity of a user (email, ID, UUID, etc) for events, deep links, and referrals.

//login
FlutterBranchSdk.setIdentity('user1234567890');
//logout
FlutterBranchSdk.logout();
//check if user is identify
 bool isUserIdentified = await FlutterBranchSdk.isUserIdentified();

Enable or Disable User Tracking

If you need to comply with a user's request to not be tracked for GDPR purposes, or otherwise determine that a user should not be tracked, utilize this field to prevent Branch from sending network requests. This setting can also be enabled across all users for a particular link, or across your Branch links.

FlutterBranchSdk.disableTracking(false);
FlutterBranchSdk.disableTracking(true);

You can choose to call this throughout the lifecycle of the app. Once called, network requests will not be sent from the SDKs. Link generation will continue to work, but will not contain identifying information about the user. In addition, deep linking will continue to work, but will not track analytics for the user.

More information here

Set Request Meta data

Add key value pairs to all requests

FlutterBranchSdk.setRequestMetadata(requestMetadataKey, requestMetadataValue);

Set time window (in Hours) for SKAdNetwork callouts (iOS only)

By default, Branch limits calls to SKAdNetwork to within 72 hours after first install.

FlutterBranchSdk.setIOSSKAdNetworkMaxTime(24);

Apple Search Ads

Branch can help track your Apple Search Ad campaigns by fetching the search ad attribution from Apple at app install.

Add KEY branch_check_apple_ads in INFO.PLIST to enable checking for Apple Search Ads before Branch initialization.

In ios/Runner/Info.plist, you should have something like:

 	<key>branch_check_apple_ads</key>
	<true/>

iOS 14+ App Tracking Transparency

Starting with iOS 14.5, iPadOS 14.5, and tvOS 14.5, you’ll need to receive the user’s permission through the AppTrackingTransparency framework to track them or access their device’s advertising identifier. Tracking refers to the act of linking user or device data collected from your app with user or device data collected from other companies’ apps, websites, or offline properties for targeted advertising or advertising measurement purposes. Tracking also refers to sharing user or device data with data brokers.

See: https://developer.apple.com/app-store/user-privacy-and-data-use/

New methods have been made available to deal with App Tracking Transparency.

First, update Info.plist file located in ios/Runner directory and add the NSUserTrackingUsageDescription key with a custom message describing your usage.

    <key>NSUserTrackingUsageDescription</key>
    <string>App would like to access IDFA for tracking purpose</string>

Show tracking authorization dialog and ask for permission

AppTrackingStatus status = await FlutterBranchSdk.requestTrackingAuthorization();
print(status);

Note: After the user's response, call the handleATTAuthorizationStatus Branch SDK method to monitor the performance of the ATT prompt.

App tracking dialog

Get tracking authorization status

AppTrackingStatus status = await FlutterBranchSdk.getTrackingAuthorizationStatus();
print(status);
Values available for AppTrackingStatus
enum AppTrackingStatus {
  /// The user has not yet received an authorization request dialog
  notDetermined,

  /// The device is restricted, tracking is disabled and the system can't show a request dialog
  restricted,

  /// The user denies authorization for tracking
  denied,

  /// The user authorizes access to tracking
  authorized,

  /// The platform is not iOS or the iOS version is below 14.0
  notSupported,
}

Get Device Advertising Identifier

AppTrackingStatus status = await FlutterBranchSdk.getTrackingAuthorizationStatus();
print(status);

See: https://developer.apple.com/documentation/adsupport/asidentifiermanager/1614151-advertisingidentifier

Enable Logging

Use the Branch test key instead of the live key.

Logging is enabled by default in debug mode and disabled in release mode.

To enable/disable logging update INFO.PLIST on iOS or AndroidManifest.xml on Android:

For iOS add to INFO.PLIST:

To disable:

	<key>branch_enable_log</key>
	<false/>

To enable:

	<key>branch_enable_log</key>
	<true/>

For Android add to AndroidManifest.xml:

To disable:

    <meta-data android:name="branch_enable_log"
        android:value="false" />

To enable:

    <meta-data android:name="branch_enable_log"
        android:value="true" />

Enabled Clipboard Deferred Deep Linking in iOS

Use iOS pasteboard to enable deferred deep linking.

To enable Clipboard Deferred Deep Linking update INFO.PLIST on iOS

Add to INFO.PLIST:

	<key>branch_check_pasteboard</key>
	<true/>

Facebook App Install Ads

Branch links can be used together with Facebook App Install Campaign ads, allowing you to track ad-driven installs on the Branch dashboard and deep link those new users directly to content the first time they open your app.

Follow the instructions on the link https://help.branch.io/using-branch/docs/facebook-app-install-ads.

To read Facebook App Install deep links update INFO.PLIST on iOS or AndroidManifest.xml on Android as in the example:

For iOS add to INFO.PLIST:

	<key>branch_enable_facebook_ads</key>
	<true/>

For Android add to AndroidManifest.xml:

    <meta-data android:name="branch_enable_facebook_ads"
        android:value="true" />

Follow the instructions to install Facebook Android / iOS SDK:

iOS:

https://developers.facebook.com/docs/ios/use-cocoapods

Android:

https://developers.facebook.com/docs/android/getting-started

Getting Started

See the example directory for a complete sample app using Branch SDK.

Example app

See example in Flutter Web: https://flutter-branch-sdk.netlify.app/

Branch Universal Object best practices

Here are a set of best practices to ensure that your analytics are correct, and your content is ranking on Spotlight effectively.

  1. Set the canonicalIdentifier to a unique, de-duped value across instances of the app
  2. Ensure that the title, contentDescription and imageUrl properly represent the object
  3. Initialize the Branch Universal Object and call FlutterBranchSdk.registerView(buo: buo); on initState()
  4. Call showShareSheet and getShortUrl later in the life cycle, when the user takes an action that needs a link
  5. Call the additional object events (purchase, share completed, etc) when the corresponding user action is taken

Practices to avoid:

  1. Don't set the same title, contentDescription and imageUrl across all objects.
  2. Don't wait to initialize the object and register views until the user goes to share.
  3. Don't wait to initialize the object until you conveniently need a link.
  4. Don't create many objects at once and register views in a for loop.

Deep links with Short Links

More information here

Deep links with Long links

More information here

Branch Documentation

Read the iOS or Android documentation for all Branch object parameters:

Author

This project was authored by Rodrigo S. Marques. You can contact me at rodrigosmarques@gmail.com

Libraries

flutter_branch_sdk