BranchMetrics / android-branch-deep-linking-attribution

The Branch Android SDK for deep linking and attribution. Branch helps mobile apps grow with deep links / deeplinks that power paid acquisition and re-engagement campaigns, referral programs, content sharing, deep linked emails, smart banners, custom user onboarding, and more.
https://docs.branch.io/pages/apps/android/
MIT License
395 stars 155 forks source link

Provide modern SDK #880

Open markchristopherng opened 3 years ago

markchristopherng commented 3 years ago

Hi,

Can the SDK be modernised to use co routines the the asynchronous technology that Google recommends and OKHttp which is used by most Android apps for network requests. Currently the Android Branch SDK is using AsyncTask which is now depreciated and will be removed in future versions of Android. It doesn't allows tasks to be cancelled and adopting co routines would make it more flexible for developers to use the SDK how they want. There are been many issues raised with the SDK about network timeouts. By using OKHttp you would allow developer's to set their own timeouts per request and even add tools such as Chuck so they can get visibility when these network requests as they occur. Using coroutines would also allow users the option to put a timeout over the whole initialisation instead of per network requests. By improving the SDK you would allow customers to decide how they want to their deeplink flows to work whether they want synchronous or asynchronous deeplinking during startup.

 viewModelScope.launch {
            try {
                withTimeout(getTimeOut()) {
                    Branch.init()    //This would be modified to return branchUniversalObject
                }
            } catch (error: TimeoutCancellationException) {
                  //forget about deeplinking and proceed normally
            }
        }

A bonus would be enhancing the library for Kotlin.

markchristopherng commented 3 years ago

Using suspendCancellableCoroutine we were able to wrap the callback as follows;

 lifecycleScope.launchWhenStarted {
            branchManager.init(this@StartActivity) { branchUniversalObject, _, _ ->
                         // process branch link here
                }
            }
        }
@Singleton
class BranchManager {

    suspend fun init(activity: Activity, listener: Branch.BranchUniversalReferralInitListener) = coroutineScope {
        try {
            withTimeout(TIMEOUT_BRANCH_INIT) {
                initBranchSession(activity, listener)
            }
        } catch (e: Exception) {
            Timber.e("Failed to init Branch session ${e.localizedMessage}")
        }
    }

    private suspend fun initBranchSession(activity: Activity, listener: Branch.BranchUniversalReferralInitListener): Unit = suspendCancellableCoroutine { coroutine ->
        Branch.sessionBuilder(activity)
            .withCallback { branchUniversalObject, linkProperties, error ->
                listener.onInitFinished(branchUniversalObject, linkProperties, error)
                if (coroutine.isActive) coroutine.resume(Unit)
            }
            .withData(activity.intent?.data)
            .init()
    }

    companion object {
        private const val TIMEOUT_BRANCH_INIT = 2000L
    }
}
jf-branch commented 2 years ago

Hi @markchristopherng,

This feedback is greatly appreciated. The team is currently evaluating the AsyncTask replacement as well as how the Branch SDK handles its threading, queues, closures, etc. We will update you through this thread when with updates.

Thank you