Skip to content

Commit a69978d

Browse files
committed
feat(android): Handle shared URLs via Android Share Sheet
This commit enables the application to receive and process shared URLs (for `github.com` and `github-store.org`) from other apps through the Android Share Sheet. When a user shares text containing a supported URL with the app, the app will now extract the URL and navigate to the corresponding repository details screen. - **feat(android)**: Added an `intent-filter` for `ACTION_SEND` in `AndroidManifest.xml` to accept `text/plain` and `text/html` content. - **feat(deeplink)**: Implemented `DeepLinkParser.extractSupportedUrl()` to find the first `github.com` or `github-store.org` URL within a given text string. - **refactor(android)**: Updated `MainActivity` to handle `ACTION_SEND` intents, extract the URL from the shared text, and trigger the deep link flow. - **fix(android)**: Corrected the `pathPattern` in the `AndroidManifest.xml` for `github.com` deep links to correctly match repository paths.
1 parent 346513c commit a69978d

6 files changed

Lines changed: 51 additions & 22 deletions

File tree

319 Bytes
Binary file not shown.
316 Bytes
Binary file not shown.

composeApp/src/androidMain/AndroidManifest.xml

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest xmlns:tools="http://schemas.android.com/tools"
3-
xmlns:android="http://schemas.android.com/apk/res/android">
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools">
44

55
<uses-permission android:name="android.permission.INTERNET" />
66

7-
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
7+
<uses-permission
8+
android:name="android.permission.QUERY_ALL_PACKAGES"
89
tools:ignore="PackageVisibilityPolicy,QueryAllPackagesPermission" />
910

10-
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
11+
<uses-permission
12+
android:name="android.permission.REQUEST_INSTALL_PACKAGES"
1113
tools:ignore="RequestInstallPackagesPolicy" />
1214
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
1315

1416
<application
1517
android:name=".app.GithubStoreApp"
1618
android:allowBackup="true"
19+
android:hasFragileUserData="true"
1720
android:icon="@mipmap/ic_launcher"
1821
android:label="@string/app_name"
1922
android:networkSecurityConfig="@xml/network_security_config"
2023
android:roundIcon="@mipmap/ic_launcher_round"
2124
android:supportsRtl="true"
22-
android:hasFragileUserData="true"
23-
tools:targetApi="29"
2425
android:theme="@android:style/Theme.Material.Light.NoActionBar"
25-
android:usesCleartextTraffic="false">
26+
android:usesCleartextTraffic="false"
27+
tools:targetApi="29">
2628

2729
<activity
2830
android:name=".MainActivity"
@@ -56,17 +58,22 @@
5658
android:scheme="githubstore" />
5759
</intent-filter>
5860

61+
<intent-filter>
62+
<action android:name="android.intent.action.SEND" />
63+
<category android:name="android.intent.category.DEFAULT" />
64+
<data android:mimeType="text/plain" />
65+
<data android:mimeType="text/html" />
66+
</intent-filter>
67+
5968
<!-- GitHub repository links: https://github.com/{owner}/{repo} -->
6069
<intent-filter>
6170
<action android:name="android.intent.action.VIEW" />
62-
6371
<category android:name="android.intent.category.DEFAULT" />
6472
<category android:name="android.intent.category.BROWSABLE" />
6573

66-
<data
67-
android:host="github.com"
68-
android:pathPattern="/.*/..*"
69-
android:scheme="https" />
74+
<data android:scheme="https" />
75+
<data android:host="github.com" />
76+
<data android:pathPattern="/.*/.*" />
7077
</intent-filter>
7178

7279
<intent-filter android:autoVerify="true">
@@ -75,10 +82,11 @@
7582
<category android:name="android.intent.category.DEFAULT" />
7683
<category android:name="android.intent.category.BROWSABLE" />
7784

78-
<data
79-
android:host="github-store.org"
80-
android:pathPrefix="/app/"
81-
android:scheme="https" />
85+
<data android:scheme="http" />
86+
<data android:scheme="https" />
87+
<data android:host="github-store.org" />
88+
<data android:pathPrefix="/app/" />
89+
8290
</intent-filter>
8391
</activity>
8492

composeApp/src/androidMain/kotlin/zed/rainxch/githubstore/MainActivity.kt

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,24 @@ import androidx.compose.runtime.setValue
1313
import androidx.compose.ui.tooling.preview.Preview
1414
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
1515
import androidx.core.util.Consumer
16+
import zed.rainxch.githubstore.app.deeplink.DeepLinkParser
1617

1718
class MainActivity : ComponentActivity() {
1819

1920
private var deepLinkUri by mutableStateOf<String?>(null)
2021

2122
override fun onCreate(savedInstanceState: Bundle?) {
2223
installSplashScreen()
23-
2424
enableEdgeToEdge()
2525

2626
super.onCreate(savedInstanceState)
2727

28-
deepLinkUri = intent?.data?.toString()
28+
handleIncomingIntent(intent)
2929

3030
setContent {
3131
DisposableEffect(Unit) {
3232
val listener = Consumer<Intent> { newIntent ->
33-
newIntent.data?.toString()?.let {
34-
deepLinkUri = it
35-
}
33+
handleIncomingIntent(newIntent)
3634
}
3735
addOnNewIntentListener(listener)
3836
onDispose {
@@ -43,6 +41,23 @@ class MainActivity : ComponentActivity() {
4341
App(deepLinkUri = deepLinkUri)
4442
}
4543
}
44+
45+
private fun handleIncomingIntent(intent: Intent?) {
46+
if (intent == null) return
47+
48+
val uriString = when (intent.action) {
49+
Intent.ACTION_VIEW -> intent.data?.toString()
50+
51+
Intent.ACTION_SEND -> {
52+
val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
53+
sharedText?.let { DeepLinkParser.extractSupportedUrl(it) }
54+
}
55+
56+
else -> null
57+
}
58+
59+
uriString?.let { deepLinkUri = it }
60+
}
4661
}
4762

4863
@Preview

composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/Main.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ fun App(deepLinkUri: String? = null) {
3838
)
3939
}
4040

41-
DeepLinkDestination.None -> { /* ignore unrecognized deep links */
41+
DeepLinkDestination.None -> {
42+
/* ignore unrecognized deep links */
4243
}
4344
}
4445
}

composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/deeplink/DeepLinkParser.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,9 @@ object DeepLinkParser {
174174
}
175175
return null
176176
}
177+
178+
fun extractSupportedUrl(text: String): String? {
179+
val regex = """https?://(?:www\.)?(?:github\.com|github-store\.org)[^\s<>"']+""".toRegex(RegexOption.IGNORE_CASE)
180+
return regex.find(text)?.value
181+
}
177182
}

0 commit comments

Comments
 (0)