I suspect there's a limitation with Compose's defa...
# compose-android
m
I suspect there's a limitation with Compose's default
UriHandler.openUri
on Android. I've seen crashes with:
AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
I suspect this happens because the internal
AndroidUriHandler
uses a
Context
that might not be recognized as an
Activity
under certain conditions (e.g. inside dialogs, when wrapped, or in split-screen/multi-window modes like Huawei's App Multiplier), and calls
startActivity
without any flags. To work around this, I wrote a helper that catches the exception, extracts/unwraps the context from
AndroidUriHandler
to find the actual
Activity
, and falls back to starting it with
FLAG_ACTIVITY_NEW_TASK
using the application context if that fails. Has anyone else run into this, or is there a better way to handle it?
a
What I normally do in cases like this is: 1. ignore the Compose related APIs completely (so i wouldn't use UriHandler) and do my own expect/actuals solution, so i control the flow on all platforms (like you did, ignoring the original handler path) 2. Open an issue at the Jetpack Compose issue tracker wth the crash so we get this fixed if you believe is a bug EDIT: In other words, there is no point in trying to fight the existing implementation. do your own thing, that you control
👍 2
k
Besides that you probably don't want it to crash, I always wanted the UriHandler to open with FLAG_ACTIVITY_NEW_TASK, so I just override UriHandler:
Copy code
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import androidx.compose.ui.platform.UriHandler
import androidx.core.net.toUri

class AndroidNewTaskUriHandler(private val context: Context) : UriHandler {
    override fun openUri(uri: String) {
        val intent = Intent(Intent.ACTION_VIEW, uri.toUri()).apply {
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        try {
            context.startActivity(intent)
        } catch (e: ActivityNotFoundException) {
            e.printStackTrace()
        }
    }
}
And this in the MainActivity:
Copy code
setContent {
            val context = LocalContext.current
            CompositionLocalProvider(
                LocalUriHandler provides AndroidNewTaskUriHandler(context)
            ) {
                App()
            }
        }
This way the other platforms will still work (in multiplatform environment) and you get the new task. In case you want to know the original UriHandler on Android, here is the code: https://android.googlesource.com/platform//frameworks/support/+/c354fa29007af485641665604612df30199a644a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidUriHandler.android.kt. It really just is a startActivity, nothing fancy.
👍 1