Skip to content

Commit

Permalink
Added withDeepLink extension function
Browse files Browse the repository at this point in the history
  • Loading branch information
arkivanov committed Apr 25, 2024
1 parent d1f0206 commit cba5ea2
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
4 changes: 4 additions & 0 deletions decompose/api/android/decompose.api
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ public abstract interface class com/arkivanov/decompose/ComponentContextFactoryO
public abstract fun getComponentContextFactory ()Lcom/arkivanov/decompose/ComponentContextFactory;
}

public final class com/arkivanov/decompose/DeeplinkUtilsKt {
public static final fun withDeepLink (Landroid/app/Activity;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
}

public final class com/arkivanov/decompose/DefaultComponentContext : com/arkivanov/decompose/ComponentContext {
public fun <init> (Lcom/arkivanov/essenty/lifecycle/Lifecycle;)V
public fun <init> (Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/essenty/statekeeper/StateKeeper;Lcom/arkivanov/essenty/instancekeeper/InstanceKeeper;Lcom/arkivanov/essenty/backhandler/BackHandler;)V
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.arkivanov.decompose

import android.app.Activity
import android.app.TaskStackBuilder
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.core.os.bundleOf
import androidx.savedstate.SavedStateRegistryOwner

/**
* Extracts a deep link URL from this [Activity] [Intent], calls [block]
* function with the extracted deep link URL (if any) and returns the result.
*
* It is strongly recommended to always use the `standard` (default)
* `launchMode` for the [Activity] when handling deep links. This function takes
* care of restarting the [Activity] task if needed, in which case the returned
* value is `null`.
*
* Example of creating a root component with deep link support.
*
* ```kotlin
* class MainActivity : AppCompatActivity() {
* override fun onCreate(savedInstanceState: Bundle?) {
* super.onCreate(savedInstanceState)
*
* val root =
* withDeepLink { uri ->
* val itemId = uri?.extractItemId() // Parse the deep link
* DefaultRootComponent(
* componentContext = defaultComponentContext(discardSavedState = itemId != null),
* itemId = itemId,
* )
* } ?: return
*
* // Display the root component as usual
* }
*
* private fun Uri.extractItemId(): String? =
* TODO("Extract item id from the deep link")
* }
* ```
*/
@ExperimentalDecomposeApi
fun <A, T : Any> A.withDeepLink(
block: (deepLink: Uri?) -> T,
): T? where A : Activity, A : SavedStateRegistryOwner {
if (restartIfNeeded()) {
return null
}

val savedState: Bundle? = savedStateRegistry.consumeRestoredStateForKey(key = KEY_SAVED_DEEP_LINK_STATE)

@Suppress("DEPRECATION")
val lastDeepLink = savedState?.getParcelable(KEY_LAST_DEEP_LINK) as Uri?

val deepLink = intent.data

savedStateRegistry.registerSavedStateProvider(key = KEY_SAVED_DEEP_LINK_STATE) {
bundleOf(KEY_LAST_DEEP_LINK to deepLink)
}

return block(deepLink.takeUnless { it == lastDeepLink })
}

// Derived from https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt;l=1487-1504?q=Intent.flags&ss=androidx%2Fplatform%2Fframeworks%2Fsupport:navigation%2F
private fun Activity.restartIfNeeded(): Boolean {
if ((intent.flags and Intent.FLAG_ACTIVITY_NEW_TASK == 0) || (intent.flags and Intent.FLAG_ACTIVITY_CLEAR_TASK != 0)) {
return false
}

// Someone called us with NEW_TASK, but we don't know what state our whole
// task stack is in, so we need to manually restart the whole stack to
// ensure we're in a predictably good state.

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
TaskStackBuilder.create(this).addNextIntentWithParentStack(intent).startActivities()
finish()
// Disable second animation in case where the Activity is created twice.
@Suppress("DEPRECATION")
overridePendingTransition(0, 0)

return true
}

private const val KEY_SAVED_DEEP_LINK_STATE = "SAVED_DEEP_LINK_STATE"
private const val KEY_LAST_DEEP_LINK = "LAST_DEEP_LINK"

0 comments on commit cba5ea2

Please sign in to comment.