ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Precise Intent Resolution -Android 15

Header image

In this article, we will discuss some new improvements to the intent filter in Android 15

A UriRelativeFilterGroup contains a set of UriRelativeFilter objects that form a set of Intent matching rules that must be satisfied — [URL fragments, query params, etc.]

We can define these new rules in AndroidManifest file with the new <uri-relative-filter-group> tag

  • With this tag, we can use data tags with existing attributes as well as the new [android:fragment, android:query, android:allow]
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:host="developer.android.com" />

<uri-relative-filter-group android:allow="true">
<data android:pathPrefix="/samples" />
<data android:query="language=kotlin" />
</uri-relative-filter-group>

<uri-relative-filter-group android:allow="false">
<data android:pathPrefix="/reference" />
<data android:fragment="jetpack" />
</uri-relative-filter-group></intent-filter>

Implementation

In the AndroidManifest file, add intent-filter to the Activity tag to handle deep links 🔗

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">


<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Android15Samples"
tools:targetApi="31">


<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.Android15Samples">

<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:host="developer.android.com" />

<uri-relative-filter-group android:allow="true">
<data android:pathPrefix="/samples" />
<data android:query="language=kotlin" />
</uri-relative-filter-group>

<uri-relative-filter-group android:allow="false">
<data android:pathPrefix="/reference" />
<data android:fragment="jetpack" />
</uri-relative-filter-group>

<!-- https://developer.android.com/reference#jetpack-->
</intent-filter>
</activity>

</application>

</manifest>

Activity that shows the Uri from the deep link 🔗 intent

class MainActivity : ComponentActivity() {

private var uri = mutableStateOf("")

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
Android15SamplesTheme {
Content(modifier = Modifier.fillMaxSize(), uri = uri)
}
}
handleIntent(intent)
}

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntent(intent)

}

private fun handleIntent(intent: Intent) {
val uri = intent.data
this.uri.value = uri?.toString().orEmpty()
}
}

@Composable
fun Content(uri: State<String>, modifier: Modifier = Modifier) {
Scaffold(modifier = modifier) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = R.drawable.img_android_15_logo),
modifier = Modifier.size(200.dp),
contentDescription = "Android15 Logo"
)
Spacer(modifier = Modifier.size(32.dp))
Android15ContentHeader(
modifier = Modifier.padding(innerPadding)
)
if (uri.value.isNotEmpty()) {
Spacer(modifier = Modifier.size(32.dp))
UriInfoFromLink(
uri = uri.value,
modifier = Modifier.padding(innerPadding)
)
}
}
}
}

@Composable
fun Android15ContentHeader(modifier: Modifier = Modifier) {
Text(
text = "Android15 - Samples",
modifier = modifier,
style = MaterialTheme.typography.headlineMedium
)
}

@Composable
fun UriInfoFromLink(uri: String, modifier: Modifier = Modifier) {
Text(
text = "Uri from intent: $uri",
modifier = modifier,
style = MaterialTheme.typography.labelLarge
)
}

UI — Composable Preview

Composable preview

Demo

  • android:query tag and android:allow set to true
<!--  https://developer.android.com/samples?language=kotlin-->

<uri-relative-filter-group android:allow="true">
<data android:pathPrefix="/samples" />
<data android:query="language=kotlin" />
</uri-relative-filter-group>
Demo — android:query tag and android:allow set to true
  • android:fragment tag and android:allow set to false

<!-- https://developer.android.com/reference#jetpack-->

<uri-relative-filter-group android:allow="false">
<data android:pathPrefix="/reference" />
<data android:fragment="jetpack" />
</uri-relative-filter-group>
android:fragment tag and android:allow set to false

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Nav Singh

Google Developer Expert for Android | Mobile Software Engineer at Manulife | Organizer at GDG Montreal

No responses yet

Write a response