skills/deep-linking/SKILL.md
Deep linking patterns for mobile - Android App Links, iOS Universal Links, intent filters, URI handling, deferred deep links, and navigation integration.
npx skillsauth add ahmed3elshaer/everything-claude-code-mobile deep-linkingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Design a consistent URI scheme before implementation:
myapp:// # App root
myapp://home # Home screen
myapp://product/{id} # Product detail
myapp://profile/{userId} # User profile
myapp://settings/notifications # Nested settings
myapp://search?q={query} # Query parameters
Keep paths RESTful, lowercase, and predictable. Use path segments for hierarchy and query params for filters.
<activity
android:name=".MainActivity"
android:exported="true">
<!-- Custom URI scheme -->
<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="myapp"
android:host="product"
android:pathPrefix="/" />
</intent-filter>
<!-- App Links (HTTPS verified) -->
<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"
android:host="www.myapp.com"
android:pathPrefix="/product" />
</intent-filter>
</activity>
Host at https://www.myapp.com/.well-known/assetlinks.json:
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.myapp.android",
"sha256_cert_fingerprints": [
"AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"
]
}
}]
Get your certificate fingerprint:
keytool -list -v -keystore my-release-key.keystore -alias my-key-alias
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleDeepLink(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleDeepLink(intent)
}
private fun handleDeepLink(intent: Intent) {
val uri = intent.data ?: return
val path = uri.path ?: return
val segments = path.split("/").filter { it.isNotEmpty() }
when {
segments.firstOrNull() == "product" -> {
val productId = segments.getOrNull(1)
navigateToProduct(productId)
}
segments.firstOrNull() == "profile" -> {
val userId = segments.getOrNull(1)
navigateToProfile(userId)
}
}
}
}
NavHost(navController, startDestination = "home") {
composable(
route = "product/{productId}",
arguments = listOf(navArgument("productId") { type = NavType.StringType }),
deepLinks = listOf(
navDeepLink { uriPattern = "myapp://product/{productId}" },
navDeepLink { uriPattern = "https://www.myapp.com/product/{productId}" }
)
) { backStackEntry ->
val productId = backStackEntry.arguments?.getString("productId")
ProductScreen(productId = productId)
}
}
Use Firebase Dynamic Links or AppsFlyer for deferred deep links that survive app install:
Firebase.dynamicLinks
.getDynamicLink(intent)
.addOnSuccessListener { pendingDynamicLinkData ->
val deepLink: Uri? = pendingDynamicLinkData?.link
deepLink?.let { handleDeepLink(it) }
}
Host at https://www.myapp.com/.well-known/apple-app-site-association:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAMID.com.myapp.ios",
"paths": ["/product/*", "/profile/*", "/settings/*"]
}
]
}
}
Enable Associated Domains in Xcode: applinks:www.myapp.com
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
<key>CFBundleURLName</key>
<string>com.myapp.ios</string>
</dict>
</array>
// SceneDelegate (iOS 13+)
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else { return }
DeepLinkRouter.shared.handle(url: url)
}
// Universal Links
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard let url = userActivity.webpageURL else { return }
DeepLinkRouter.shared.handle(url: url)
}
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
DeepLinkRouter.shared.handle(url: url)
}
}
}
}
// iOS Router
final class DeepLinkRouter: ObservableObject {
static let shared = DeepLinkRouter()
@Published var destination: Destination?
enum Destination: Equatable {
case product(id: String)
case profile(userId: String)
case settings
}
func handle(url: URL) {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { return }
let pathSegments = components.path.split(separator: "/").map(String.init)
switch pathSegments.first {
case "product":
destination = .product(id: pathSegments[safe: 1] ?? "")
case "profile":
destination = .profile(userId: pathSegments[safe: 1] ?? "")
default:
break
}
}
}
# Android - test custom scheme
adb shell am start -a android.intent.action.VIEW -d "myapp://product/123"
# Android - test App Links
adb shell am start -a android.intent.action.VIEW -d "https://www.myapp.com/product/123"
# iOS Simulator - test URL scheme
xcrun simctl openurl booted "myapp://product/123"
# iOS Simulator - test Universal Link
xcrun simctl openurl booted "https://www.myapp.com/product/123"
Track deep link opens with source attribution:
fun trackDeepLinkOpen(uri: Uri, source: String) {
analytics.logEvent("deep_link_opened") {
param("uri", uri.toString())
param("source", source) // "notification", "email", "social", "qr_code"
param("path", uri.path ?: "")
param("has_referrer", (uri.getQueryParameter("ref") != null).toString())
}
}
data-ai
SQLDelight patterns for Kotlin Multiplatform - .sq file definitions, platform drivers, type adapters, migrations, and shared database access.
data-ai
Room database patterns for Android - entity definitions, DAO interfaces, Database class, migrations, TypeConverters, and Flow integration.
tools
Push notification patterns - FCM setup for Android, APNs for iOS, notification channels, payload handling, foreground/background behavior, and rich notifications.
content-media
Pagination patterns for mobile - Paging 3 for Android (PagingSource, RemoteMediator, LazyPagingItems), cursor-based and offset-based strategies.