adjust / ios_sdk

This is the iOS SDK of
http://www.adjust.com
MIT License
617 stars 287 forks source link

adid and idfa completion-based calls #725

Open Semty opened 3 weeks ago

Semty commented 3 weeks ago

Hey!

The question is related to the new completion-based API for retrieving adid and idfa in Adjust v5.0.0.

The problem:

  1. The new behaviour is non-deterministic, e.g. right now if you try to get the values in a simulator, you'll just be waiting forever for the completion handler that will never come back
  2. IMO, it is a no go because it is better to get a null value and continue with the flow rather than freeze the whole flow (before this change the app developers had a choice, now they don't)

The question:

uerceg commented 3 weeks ago

Hey @Semty,

Thanks for the message!

When it comes to these two particular getters, they are different in nature under the hood (synchronous vs. asynchronous), but due to some internal design choices we went with having getters built in async fashion with completion handler.

adid is Adjust identifier for the device. Unique identifier that is generated backend side and which needs to be communicated to the SDK before we're able to provide the value back to the app as part of any getter. So the nature of this field is asynchronous. Initially we made this getter to be synchronous (what you know as [Adjust adid]; from the v4), but I believe that this is one of the decisions that has caused us the most issues and misconceptions among clients down the road. This situation is described in this issue. Over the years we were getting that same question over and over again, wether in GitHub or from client queries via our support teams. It was just super inconvenient to clients to grasp on all that hidden knowledge behind this mechanism and understand how to properly use that getter. Because of that, we have switched to the async paradigm because the most frequent use case for this among our clients is that they want to obtain adid value as soon as app / SDK launches. With this approach we can now deliver this information to them as soon as we obtain it without need to point them to places like session tracking callbacks or ask them to implement some custom retry logic of theirs.

True, if device has no internet connectivity and SDK never gets adid from the backend, then yes, in the current implementation, we will not trigger this method potentially at all or maybe super late down the road when we do manage to get adid. This was a tradeoff we went with because what we got as a pretty clear requirement from the clients was that they would expect completion handler to deliver adid when it becomes available, regardless of when that might be and regardless of whether completion handler never gets triggered because SDK never obtained adid (triggering completion handler with nil or some timeout error value would pretty much bring them back to square one and issue they had with synchronous API).

On the other hand, once adid is obtained by the SDK once, every subsequent invocation of this getter, even though async by method signature is under the hood being done in synchronous manner -> we already have the value stored which we just read and send it right away to completion handler.

When it comes to idfa getter, like mentioned above, due to some internal design decisions, its method signature ended up being also async with completion handler, but under the hood entire logic is fully synchronous. You can easily check that. So when it comes to getting idfa, I would be truly puzzled in case you would never see completion handler being triggered, regardless of whether you'd invoke it on Simulator or real device. Are you seeing the situations in which you invoke idfa getter and you never see completion handler sending the result back? IDFA should always be zeroed on Simulator, regardless of the status of ATT consent and in all of our tests, that's the value on Simulator that is being returned always. I would be curious to hear more about this based on your testing.

Hopefully this makes things a bit clearer now about why we went with this approach. Of course, it doesn't mean that this (or any other approach) fits everyone's needs, so in case you still have concerns about these getters after the explanation from above, we would really like to hear about them and learn about your use case for these getters so that we can also think of potential improvements.

Thank you one more time for the feedback and looking forward to hearing back from you.

Cheers