JeandeCampredon/react-native-referrer

Unsure when it is safe to call getReferrer()

Closed this issue · 9 comments

Hello, thanks for writing this! Definitely the simplest solution out there.
I'm having some trouble getting this to work in a stable manner. It works most of the time, but in one case it doesn't work.

If I install my app from the Google Play Store, and hit "Open" immediately when it appears, my app reports no referrer from getReferrer(). That is, the promise is resolved with undefined. But if I install it and wait a moment after "Open" appears before hitting it and opening the app, everything works fine. I'm sure this is a problem with where/when in my app getReferrer() is called.

So when in a react-native app can I be sure that getReferrer() will be work every time?

Thanks!

Thanks pal !

While the ReferrerReceiver haven't received the signal the referrer isn"t assigned ....

  public void onReceive(Context context, Intent intent) {
    String referrerString = intent.getStringExtra("referrer");
    setReferrer(referrerString);
  }

I am quite a beginner in android, I guess I need some equivalent to promise resolution ...
I guess I could fix that by the end of the week or so .... I ll keep you updated 👍

Promise resolution sounds right to me! I'll take a swing at that this evening as well.

I was able to get this working. Unfortunately I'm not in a position to make a PR, but here is the code I used:

In ReferrerReceiver.java:

package com.jdc.reactlibrary;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.facebook.react.bridge.Promise;

public class ReferrerReceiver extends BroadcastReceiver {
  private static String referrer = "";
  private static boolean isSet = false;
  private static Promise referrerPromise;

  public static String getReferrer() {
    return referrer;
  }

  private synchronized static void setReferrer(String value) {
    referrer = value;
    isSet = true;

    // If the promise was provided before the value was set, it's now ready
    if (referrerPromise != null)
    {
      referrerPromise.resolve(referrer);
    }
  }

  public synchronized static void setReferrerPromise(Promise promise) {
    referrerPromise = promise;

    // If the value is ready, resolve the new promise
    if (isSet) {
      referrerPromise.resolve(referrer);
    }
  }

  @Override
  public void onReceive(Context context, Intent intent) {
    String referrerString = intent.getStringExtra("referrer");
    setReferrer(referrerString);
  }
}

In RNReferrerModule.java, simply changed

promise.resolve(ReferrerReceiver.getReferrer());

to

ReferrerReceiver.setReferrerPromise(promise);

Note the new synchronized on the set methods, due to the possible race condition where setReferrerPromise and setReferrer are called at the same time. If they weren't synchronized, there's a small possibility the promise wouldn't be set.

I hope you can verify this and push it into the NPM module soon so I can get rid of my hacked version :-D

I guess I d like better to always resolve the js promise with a promise to avoid those synchronizedand flagsisSet but I ll give it a shot soon
(btw if you wanna make a PR you should fork my repo ;) )

Hi, was just wondering if this has been resolved and would like to know, what if in a case the user minimizes PlayStore right after clicking on install, and after install is complete clicks on the app icon and not the open button on PlayStore, will the referrer still be available in such a scenario?
By the way, this package is an awesome simple solution to the issue and I was going to ask 😅is there going to be an ios version available soon? I really wish I knew how to write in Java or swift, I would have loved the idea of giving a hand.

I've had no issue with my workaround.

I believe the InstallReferrer is part of the installation, not due to hitting the Open button in Play Store post-install. So, I think that's not an issue.

Can't speak to iOS solution.

@reedspool Alright, thanks I really appreciate!

@reedspool I have finally made some time to have a closer look. So Actually the closest library I could find would be Future the get is blocking through ... Then I ll need to share the promise ...

Also I might take your solution with a slight changes, I ll store a list of promises and no Boolean is possible ...

...
private static String referrer = null;
private static Promise<> requests;

private synchronized static void setReferrer(String value) {
    referrer = value;
    length = requests.size()


    if (length == 0) {
      return;
    }

    for (int i=0; i<requests.size(); i++) {
        requests.get(i).resolve(value);
    }
  }

public synchronized static void request(Promise promise) {
    requests.add(promise);
}
...

Or I could export a pure javascript patch:

  private static String referrer = null;

  private static void setReferrer(String value) {
    if (value == null) 
    referrer = value;
  }
import { NativeModules } from 'react-native';

const { RNReferrer } = NativeModules;

export const  getSafeReferrer = (...args) => RNReferrer.getReferrer(...args).then(value => (value !== null) ? value : getSafeReferrer())

export default  RNReferrer;

wdyt ?

@thecodecafe from what I remember the referrer intent is always received whatever the way you open the app so I am pretty sure it's ok ... obviously the referrer obtention evolved a lot ...
For the iOS, there is no referrer equivalent. I know it has been a pain in the ass for many and the only choice was a mix of deeplinking and sharedCookies. But I have heard about URLReferrer lately ... so might be it