In this blog we will be focusing on deeplinking integration right from creating. onelink in appsflyer dashboard and configuring flutter app to fetch the deeplink and utilise it to open the app.
Deeplink plays a crucial role in app user management it might be redirecting user’s to your offers, new feature alerts driving new app installs which all together boosts your app reach.
Let’s start configuring your app first then i will also provide you the deep drive on creating a OneLink, and implementing the same.
Android :
As we deal with flutter app there needs to be some customisations done on android level to handle these deeplinks which we are going to see in below steps
AndroidManifest.xml :
<meta-data android:name="com.appsflyer.sdk.AF_DEV_KEY" android:value="your_dev_key"/>
<meta-data android:name="com.appsflyer.sdk.ONE_LINK_ID" android:value="your_one_link_id"/>
<intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="https" android:host="your_host"/> </intent-filter>
iOS :
Now we need to have iOS app to be configured to be able to handle deeplink. Here we are making server side changes even to make app get auto configured once it’s installed by default.
In android we did the same in manual way you can find it explained in detail android tutorial.
apple-app-site-association
{ "applinks": { "apps": [], "details": [ { "appID": "P4K5RYADAL.com.abhi.appsflyer.flutterAppsflyer", "paths": [ "/product/*" ] } ] } }
Android :
iOS :
home.dart
import 'package:flutter/material.dart'; import 'main.dart'; import 'util.dart'; class Home extends StatelessWidget { const Home(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Home Screen"), ), body: Center( child: TextButton( onPressed: () { Util().logEvents(appsflyerSdk); }, child: const Text("Home"), ), ), ); } }
profile.dart
import 'package:flutter/material.dart'; class Profile extends StatelessWidget { const Profile({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Profile"), ), body: const Center( child: Text("Profile Screen"), ), ); } }
util.dart
import 'package:app_tracking_transparency/app_tracking_transparency.dart'; import 'package:device_info_plus/device_info_plus.dart'; class Util{ void getIDFV() async { final deviceInfo = DeviceInfoPlugin(); final iosInfo = await deviceInfo.iosInfo; final idfv = iosInfo.identifierForVendor; final androidInfo = await deviceInfo.androidInfo; print("IDFV : $idfv"); print("androidId : $androidInfo"); } void requestAtt() async { final status = await AppTrackingTransparency.trackingAuthorizationStatus; if (status == TrackingStatus.notDetermined) { await AppTrackingTransparency.requestTrackingAuthorization(); } getIDFA(); } void getIDFA() async { final status = await AppTrackingTransparency.trackingAuthorizationStatus; if (status == TrackingStatus.authorized) { final idfa = await AppTrackingTransparency.getAdvertisingIdentifier(); print("IDFA : $idfa"); } else { print("Tracking not authorized : $status"); } } void logEvents(appsflyerSdk) { appsflyerSdk.logEvent("Home_Screen", { "btn_click": "add_to_cart", "favourites": "pen_drives", "platform": "android" }).then((result) { print("Events Sent : $result"); }); } }
main.dart
import 'dart:async'; import 'package:appsflyer_sdk/appsflyer_sdk.dart'; import 'package:flutter/material.dart'; import 'package:flutter_appsflyer/profile.dart'; import 'home.dart'; import 'util.dart'; void main() { runApp(MyApp()); } late AppsflyerSdk appsflyerSdk; late final StreamSubscription _sub; final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override void initState() { super.initState(); init(); } @override void dispose() { _sub.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return MaterialApp( navigatorKey: navigatorKey, initialRoute: "/", routes: { '/': (context) => const Home(), '/profile': (context) => const Profile() }, debugShowCheckedModeBanner: false, ); } void init() { appsflyerSdk = AppsflyerSdk(AppsFlyerOptions( afDevKey: "dTUckosyNHAywNJJXAgNvH", appId: "111106547", showDebug: true, timeToWaitForATTUserAuthorization: 0, )); appsflyerSdk.initSdk( registerOnDeepLinkingCallback: true ); appsflyerSdk.onDeepLinking((DeepLinkResult result){ final status = result.status; final deepLinkData = result.deepLink; if((status == Status.FOUND) && deepLinkData != null){ final data = deepLinkData.clickEvent; final deepLinkValue = data['deep_link_sub1'] as String?; _handleIncomingLink(deepLinkValue); }else { print(" Deeplink status is ${status.toString()} or data is null"); } }); Util().getIDFV(); // requestAtt(); } } void _handleIncomingLink(String? path){ print("DeepLinkValue $path"); switch(path) { case 'home_screen': navigatorKey.currentState?.pushNamed('/'); break; case 'profile_screen': navigatorKey.currentState?.pushNamed('/profile'); break; default : navigatorKey.currentState?.pushNamed('/'); break; } }