2

I need to implement a deep link or referral system with my flutter application. The theory is

  1. Singup and Signin will be handled by custom backend and not firebase
  2. After a user signs up to my application he will be able to refer the app to others and if others install the app the referrer will gain some points.

Most work in this process will be handled by our custom backend. What I need is when someone uses my referral code I want that code during his/her signup.

So this is the service layer I created:

class DynamicLinkService {
  final dynamicLink = FirebaseDynamicLinks.instance;

  handleDynamicLink() async {
    await dynamicLink.getInitialLink();
    // dynamicLink.onLink(onSuccess: (PendingDynamicLinkData data) async {
    //   // something
    // },
    //   onError: (OnLinkErrorException e) async {
    //     // something
    //   },
    // );
  }

  Future<String> createDynamicLink() async {
    User user = Store.instance.getUser();
    String userId = user.id;
    print("User id = $userId");
    final DynamicLinkParameters dynamicLinkParameters = DynamicLinkParameters(
      uriPrefix: 'https://shoppydev.page.link',
      link: Uri.parse(
        'https://shoppydev.page.link/?invitedBy=$userId',
      ),
      androidParameters: AndroidParameters(
        packageName: 'co.company.app',
        minimumVersion: 0,
      ),
      iosParameters: IOSParameters(
        bundleId: 'co.company.app',
        minimumVersion: '0.0.1',
      ),
      socialMetaTagParameters: SocialMetaTagParameters(
        title: 'Refer A friend',
        description: 'Refer and earn points',
      ),
    );

    final ShortDynamicLink shortDynamicLink = await dynamicLink.buildShortLink(
      dynamicLinkParameters,
    );
    final Uri dynamicUrl = shortDynamicLink.shortUrl;
    print(dynamicUrl.toString());
    return dynamicUrl.toString();
  }

  void handleSuccessfulLinking(PendingDynamicLinkData? data) async {
    final Uri? deepLink = data!.link;
    print(deepLink.toString());
    if (deepLink != null) {
      var isRefer = deepLink.toString().contains('invitedBy');
      if (isRefer) {
        var code = deepLink.toString().split('invitedBy=')[1];
        print(code);
        if (code != null) {
          // code contains the referrer's user id
          // signup with the referrer's id
        }
      }
    }
  }
}

As you can see I tried to create a unique referral link with the user id for now. But most guides I am following as well as some github repos did something like this for handling dynamic link:

     dynamicLink.onLink(onSuccess: (PendingDynamicLinkData data) async {
       // something
     },
       onError: (OnLinkErrorException e) async {
         // something
      },
     );

Which throws: The expression doesn't evaluate to a function, so it can't be invoked.

Other notes that might help:

Inside my app.dart I have:

class App extends StatefulWidget {
  const App({Key? key}) : super(key: key);

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  void initState() {
    super.initState();
    initDynamicLinks(context);
  }

  @override
  Widget build(BuildContext context) {
    final provider = Provider.of<LocaleProvider>(context);
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'App Name',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      onGenerateRoute: buildRouter,
      locale: provider.locale,
      supportedLocales: L10n.all,
      localizationsDelegates: [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
    );
  }

  /*
    Dynamic Links
  */
  void initDynamicLinks(BuildContext context) async {
    final PendingDynamicLinkData? data =
        await FirebaseDynamicLinks.instance.getInitialLink();
    final Uri? link = data?.link;
    if (link != null) {
      Navigator.pushNamed(context, link.path);
    }
  }
}

Issues I have faced till now:

I still haven't found a solid documentation on how to get the referral code(which is need for rewarding the referrer).

I have already checked out this two posts on stack:

  1. Implementing referral rewards in Flutter
  2. Flutter - How to pass custom arguments in firebase dynamic links for app invite feature?

In short, I want to create a unique refer link with my user id. Share the user id with someone else and when he/she registers to my app I want to get the referral code attached to the link.

Example: https://app.page.link/?invitedBy=$userId

When someone installs and registers I want the userId so I can pass it to the invitedBy property of SignUpRequest.

Edit: I think I didn't clarify my question enough. So I will set it up with an example:

I want an unique referral link on my phone which I can give to my friend John. And once he downloads and registers the app I want to get some reward points.

So when he sends his SignUpRequest to the Backend I want my referral code to go with that request, so the request will look like:

SignUpRequest()
..name = "John Doe",
..email = "john@gmail.com"
..invitedBy = "...my referral code goes here"

All the other validation and point giving process will be done in the BE

2 Answers2

0

Put all of the below code in the App.dart or Splash screen, basically the first screen

initState

@override
void initState() {
  super.initState();
  _initDynamicLinks();
}

_initDynamicLinks - this is from where the dynamic link will be launched

Future<void> _initDynamicLinks() async {
    final PendingDynamicLinkData data = await instance.getInitialLink();
    final Uri deepLink = data?.link;
    _handleDynamicLink(deepLink);

    FirebaseDynamicLinks.instance.onLink.listen((dynamicLink) {
          final uri = dynamicLink.link;
          _handleDynamicLink(uri);
        }).onError((e) {
          print('onLinkError');
          print(e.message);
        });
  }

_handleDynamicLink - this is where you handle the link and parse it

void _handleDynamicLink(Uri deepLink) async {
   if (deepLink != null) {
      final url = deepLink.toString();
      var isRefer = url.contains('invitedBy');
      if (isRefer) {
        var code = url.split('invitedBy=')[1];
        print(code);
        if (code != null) {
          // code contains the referrer's user id
          // signup with the referrer's id
        }
      }
    }
  }
iamdipanshus
  • 492
  • 3
  • 12
  • as a sidenote, this code is not null-safe – iamdipanshus Feb 14 '22 at 20:42
  • for referral code, you'll have to create it from BE, and add it to your user, to validate if it's correct or not – iamdipanshus Feb 14 '22 at 20:46
  • I'm sorry initState of the `App` widget? Where I have written the code for MaterialApp? I have already created the `_initDynamicLinks` function you mentioned. But as I mentioned in my question I am getting `The expression doesn't evaluate to a function, so it can't be invoked`, if I try to do the onSuccess part –  Feb 14 '22 at 20:50
  • And about validating the referral code I will be sending it to the BE, that is why I need to retrieve it on the person (who got the referral link)' s end –  Feb 14 '22 at 20:58
  • ohhh, I didn't notice that... and the same is working for me cuz I'm on an older version... there are some breaking changes from `4.0.0` onward, you can either downgrade or refer to their docs [BREAKING CHANGES](https://pub.dev/packages/firebase_dynamic_links/changelog#400) – iamdipanshus Feb 14 '22 at 20:59
  • I have already checked the guides. Can you please tell me how to retrieve the referral code from the link on a new user's application so that it can be sent to the BE with his/her registration request I have already updated my question with a scenario –  Feb 14 '22 at 21:06
  • your parsing from `DynamicLinkService` is fine, you just have to call it from `initDynamicLinks` and apart from that you'll have to manage the `onLink` as well – iamdipanshus Feb 14 '22 at 21:15
  • You mentioned that earlier, that I should create an `_initLinks` method and call it inside the `initState`, this is the part I am most confused about. Should I call this method inside the `app.dart`(it's in the post) or should I use it inside the `ReferralPage`? –  Feb 14 '22 at 21:20
  • I've updated my answer :) – iamdipanshus Feb 14 '22 at 21:28
  • Ah, thanks man, everything I did was right it seems, just lost my way a bit –  Feb 15 '22 at 07:08
0

I think this way will be more clean

first add this widget

class DynamicLinksWidgetHandler extends StatefulWidget {
  const DynamicLinksWidgetHandler({
    super.key,
    required this.child,
  });

  final Widget child;

  @override
  State<DynamicLinksWidgetHandler> createState() =>
      _DynamicLinksWidgetHandlerState();
}

class _DynamicLinksWidgetHandlerState extends State<DynamicLinksWidgetHandler> {
  @override
  void initState() {
    super.initState();
    _initDynamicLinks();
  }
// _initDynamicLinks - this is from where the dynamic link will be launched

  Future<void> _initDynamicLinks() async {
    final data = await FirebaseDynamicLinks.instance.getInitialLink();
    final Uri? deepLink = data?.link;
    _handleDynamicLink(deepLink);

    FirebaseDynamicLinks.instance.onLink.listen((dynamicLink) {
      final uri = dynamicLink.link;
      _handleDynamicLink(uri);
    }).onError((e) {
      print('onLinkError');
      print(e.message);
    });
  }
// _handleDynamicLink - this is where you handle the link and parse it

  void _handleDynamicLink(Uri? deepLink) async {
    log('_handleDynamicLink:$deepLink');
    final code = deepLink?.queryParameters['invitedby'];
    if (code == null) return;
    // save code to backend
    log(code);
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

and then wrap it on your app widget like this

runApp(
    const DynamicLinksWidgetHandler(
      child: MyApp(),
    ),
  );