adjust / flutter_sdk

This is the Flutter SDK of
MIT License
58 stars 49 forks source link

Impossible to get Adid immediately after call Adjust.start(config). Need async start method #97

Closed al-tush closed 1 year ago

al-tush commented 1 year ago

Actual for adjust_sdk 4.32.0 It is impossible to get Adid immediately after call Adjust.start(config). Minimal reproducible example:

final config = AdjustConfig(some_token, AdjustEnvironment.sandbox);
Adjust.start(config);
print(await Adjust.getAdid() ?? 'no_id');

always return 'no_id' for all app sessions.

Possible solution: make Adjust.start async.

uerceg commented 1 year ago

Hi @al-tush,

Sorry for delay in replying on this one. Indeed, what you are trying to achieve will most probably give you null in majority of cases because it takes some time for SDK upon initialization to track install session package and get response from backend where adid will be send to SDK for the first time. From that moment on, adid will be available to be obtained.

Problem with current implementation of the getAdid getter in Flutter is that even though it's implemented in async fashion, it is actually just pinging synchronous native getter for adid and returns whatever that sync getter returns. Which, in case of your example where you're pinging the getter right after calling Adjust.start method, is going to be null most probably.

Proper solution to this issue is to change the nature of the underlying native getters to be async (and actually provide information about adid once SDK obtains it) and not to make start method async (like the PR is suggesting). Obtaining of the adid under the hood happens completely asynchronously and completion of start method is no guarantee at all that SDK will be in possession of adid at that moment (it might, but I don't think we can guarantee that for all the cases).

We are actually working on this change in next major SDK update we're planning to ship next year. But for the time being, what you can do is pretty much to subscribe to session tracking success callback because that callback is the place where adid will be delivered immediately once SDK obtains it from backend side. Once obtained in there, you can be assured that getAdid getter should be returning the non-null value. It's not the greatest approach, but it should work until we ship new major SDK update where we will change the current API and make it more meaningful for this particular case.

Thank you for opening the PR and the issue. I'll close them for now, but in case you have any further questions, feel free to comment / reopen.

Cheers

taboulot commented 1 year ago

Hi there 👋,

@uerceg I also have a problem with 4.33.1. Can you confirm that it has not been fixed yet? If not, is it plan in your roadmap?

uerceg commented 1 year ago

Hi @taboulot,

Yes, I can confirm that. Things written in this comment from above are still pretty much the current state of things.

We are working on next major SDK release (v5) where this will be addressed and the behavior of this getter changed to be natively async by nature and provide behavior one would expect from it nowadays.

Sorry for the current inconvenience.

taboulot commented 1 year ago

@uerceg,

Thank you for the answer!

Have tried your workaround with the following code:

/// When I start my app
AdjustWrapper.initialize(config, environment);
final adjustAdvertisingId = await AdjustWrapper.getAdid();
/// My Wrapper
class AdjustWrapper {
  static void initialize(Config config, Environment environment) {
    final adjustConfig = AdjustConfig(
      config.adjustApiKey,
      environment.map(
        dev: () => AdjustEnvironment.sandbox,
        staging: () => AdjustEnvironment.sandbox,
        prod: () => AdjustEnvironment.production,
      ),
    );

    if (AppPlatform.currentPlatform == AppPlatform.android) {
      adjustConfig.playStoreKidsAppEnabled = true;
      adjustConfig.coppaCompliantEnabled = true;
    }

    adjustConfig.logLevel = AdjustLogLevel.verbose;

    adjustConfig.sessionSuccessCallback = (successData) {
      if (successData.adid != null) {
        print('ID succeed');
      }
    };

    adjustConfig.sessionFailureCallback = (failureData) {
      if (failureData.adid != null) {
        print('ID failed');
      }
    };

    adjustConfig.eventSuccessCallback = (successData) {
      if (successData.adid != null) {
        print('ID succeed');
      }
    };

    adjustConfig.eventFailureCallback = (failureData) {
      if (failureData.adid != null) {
        print('ID failed');
      }
    };

    Adjust.start(adjustConfig);
  }
}

But when I put a breakpoint in all callbacks I never reached them. Do you know why? Am I doing something wrong?

PS: If I perform an HotRestart, adjustAdvertisingId is defined but I still do not reach my callback's breakpoint.

uerceg commented 1 year ago

Is it not working in any of the callbacks (session && event)? Like even if you track event, do you still see no callback being triggered? Session is a specific package which our SDK sends to backend when it's launched for the first time and then next time the session is to be sent to backend is only if you put an app to background for 30+ minutes and then put it back to foreground. So unless you wait for that long, chance to see session being tracked is only if you reinstall your app pretty much. Also, what is the platform you're seeing this issue with - iOS or Android or both?

taboulot commented 1 year ago

At the moment I only see the issue on Android. I'm currently doing an integration of Adjust inside Purchasely. It needs the adid in order to track purchases correctly. In my case, I call getAdid when my app starts. I store it in a provider & use it when the user proceeds to a payment. One possible workaround is to call getAdid when I need it. It means when my user proceeds to a payment. At this moment, Adjust should have been started since a long time ;)