You can do it in several ways, I want to present one of them, using the regular expect/actual
mechanism in Compose Multiplatform.
expect fun parseDeepLinkUrl(url: String): DeepLinkData
also I created DeepLinkManager
to handle the data and let the view model to monitor its flow
// Singleton object to hold the deeplink data
object DeepLinkManager {
private val _deeplinkData = MutableStateFlow<DeepLinkData?>(null)
val deeplinkData: StateFlow<DeepLinkData?> = _deeplinkData
fun processDeeplink(data: DeepLinkData) {
_deeplinkData.value = data
}
}
and you can implement it in Android and iOS this way:
Android:
actual fun parseDeepLinkUrl(url: String): DeepLinkData {
val uri = url.toUri()
return DeepLinkData(
username = uri.getQueryParameter("username") ?: "",
token = uri.getQueryParameter("token") ?: "",
email = uri.getQueryParameter("email") ?: ""
)
}
Android Manifest:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="***put your string here***" android:host="auth-success-for-example" />
</intent-filter>
you can add the below line in activity
to open the same application back, in case you called the browser from the application to do the authentication.
android:launchMode="singleTop"
in MainActivity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
onNewIntent(intent)
setContent {
App()
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
val url = intent.dataString ?: ""
val data = parseDeepLinkUrl(url)
DeepLinkManager.processDeeplink(data)
}
}
iOS:
actual fun parseDeepLinkUrl(url: String): DeepLinkData {
val nsUrl = NSURL.URLWithString(url) ?: return DeepLinkData("", "", "")
val components = NSURLComponents.componentsWithURL(nsUrl, resolvingAgainstBaseURL = true)
// This is the corrected approach - properly cast and access the query items
val params = mutableMapOf<String, String>()
components?.queryItems?.forEach { item ->
val queryItem = item as NSURLQueryItem
queryItem.value?.let { value ->
params[queryItem.name] = value
}
}
return DeepLinkData(
username = params["username"] ?: "",
token = params["token"] ?: "",
email = params["email"] ?: ""
)
}
iOS Info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>org.company.name</string>
<key>CFBundleURLSchemes</key>
<array>
<string>***Your String here***</string>
</array>
</dict>
</array>
inside iOS APP. you can take the URL, call the parser and send it to the Object to be monitored by the Viewmodel:
struct iOSApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL {
url in
let parsedData = ParseDeepLinkUrl_iosKt.parseDeepLinkUrl(url: url.absoluteString)
// Pass the data to the DeepLinkManager
DeepLinkManager.shared.processDeeplink(data: parsedData)
}
}
}
}
of course you can forget about the expect/actual
mechanism and implement reading the deeplink within the MainActivity
and iOSApp
and send the data directly to the object.
last but not least, you can read it from the view model this way:
init {
viewModelScope.launch {
DeepLinkManager.deeplinkData.collect { deepLinkData ->
deepLinkData?.let {
println("Got the Deeplink in Viewmodel: $it")
}
}
}
}
Enjoy!