| name | deep-linking |
| description | Universal links and deep linking skill for implementing iOS Universal Links, Android App Links, custom URL schemes, and deferred deep linking across mobile platforms. |
| allowed-tools | Read, Grep, Write, Bash, Edit, Glob, WebFetch |
| graph | {"domains":["domain:mobile"],"specializations":["specialization:mobile-development"],"skillAreas":["skill-area:deep-linking","skill-area:react-native-development"],"roles":["role:mobile-engineer"],"workflows":["workflow:feature-development","workflow:release-management"],"topics":["topic:accessibility"]} |
Deep Linking Skill
Comprehensive deep linking implementation for iOS and Android, including Universal Links, App Links, custom URL schemes, and deferred deep linking.
Overview
This skill provides capabilities for implementing deep linking across mobile platforms, enabling users to navigate directly to specific content within your app from external sources like web links, notifications, emails, and other apps.
Capabilities
iOS Universal Links
- Configure apple-app-site-association (AASA) file
- Set up Associated Domains entitlement
- Implement NSUserActivity handling
- Validate Universal Links configuration
- Handle fallback to App Store
Android App Links
- Configure assetlinks.json (Digital Asset Links)
- Set up intent filters for App Links
- Implement deep link handling
- Verify App Links configuration
- Handle fallback to Play Store
Custom URL Schemes
- Register custom URL schemes
- Handle URL scheme callbacks
- Parse URL parameters
- Implement scheme validation
- Cross-app communication
Deferred Deep Linking
- Configure Branch.io or Firebase Dynamic Links
- Handle first-open attribution
- Pass deep link data through install
- Track deep link conversions
- Implement fallback flows
Deep Link Routing
- Design URL structure and routing
- Implement in-app navigation
- Handle authentication requirements
- Manage deep link state persistence
- Track deep link analytics
Prerequisites
iOS Development
Android Development
// No additional dependencies for basic App Links
// For Firebase Dynamic Links:
dependencies {
implementation platform('com.google.firebase:firebase-bom:32.7.0')
implementation 'com.google.firebase:firebase-dynamic-links'
}
// For Branch.io:
dependencies {
implementation 'io.branch.sdk.android:library:5.+'
}
Web Server Requirements
Usage Patterns
Apple App Site Association (AASA) File
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAMID.com.example.app",
"paths": [
"/products/*",
"/users/*",
"/orders/*",
"NOT /admin/*"
]
}
]
},
"webcredentials": {
"apps": ["TEAMID.com.example.app"]
}
}
iOS Universal Links Implementation (SwiftUI)
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
handleDeepLink(url)
}
}
}
func handleDeepLink(_ url: URL) {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
let host = components.host else {
return
}
let path = components.path
let queryItems = components.queryItems ?? []
switch (host, path) {
case ("example.com", let p) where p.hasPrefix("/products/"):
let productId = String(p.dropFirst("/products/".count))
DeepLinkRouter.shared.navigateTo(.product(id: productId))
case ("example.com", let p) where p.hasPrefix("/users/"):
let userId (p.dropFirst(.count))
.shared.navigateTo(.profile(userId: userId))
(, ):
.shared.navigateTo(.orders)
:
.shared.navigateTo(.home)
}
}
}
: {
shared ()
currentDestination: .home
: {
home
product(id: )
profile(userId: )
orders
}
( : ) {
.main.async {
.currentDestination destination
}
}
}
iOS Universal Links (UIKit)
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL else {
return
}
handleUniversalLink(url)
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else { return }
handleCustomScheme(url)
}
private func handleUniversalLink(_ url: URL) {
let router = DeepLinkRouter.shared
router.route(url: url)
}
private func handleCustomScheme(_ : ) {
url.scheme { }
router .shared
router.route(url: url)
}
}
Android assetlinks.json
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"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"
]
}
}
]
Android App Links Implementation (Kotlin)
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIntent(intent)
setContent {
MyApp()
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent?) {
val action = intent?.action
val data = intent?.data
if (action == Intent.ACTION_VIEW && data != ) {
handleDeepLink()
}
}
{
path = uri.path ?:
host = uri.host
{
path.startsWith() -> {
productId = path.removePrefix()
navigateToProduct(productId)
}
path.startsWith() -> {
userId = path.removePrefix()
navigateToProfile(userId)
}
path == -> {
navigateToOrders()
}
-> {
navigateToHome()
}
}
}
}
Jetpack Compose Navigation with Deep Links
import androidx.navigation.compose.*
import androidx.navigation.navDeepLink
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
composable("home") {
HomeScreen()
}
composable(
route = "product/{productId}",
deepLinks = listOf(
navDeepLink {
uriPattern = "https://example.com/products/{productId}"
},
navDeepLink {
uriPattern = "myapp://product/{productId}"
}
)
) { backStackEntry ->
val productId = backStackEntry.arguments?.getString("productId")
ProductScreen(productId = productId)
}
composable(
route = "profile/{userId}",
deepLinks = listOf(
navDeepLink {
uriPattern = "https://example.com/users/{userId}"
}
)
) { backStackEntry ->
val userId = backStackEntry.arguments?.getString("userId")
ProfileScreen(userId = userId)
}
}
}
React Native Deep Linking
import { Linking } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
const linking = {
prefixes: ['https://example.com', 'myapp://'],
config: {
screens: {
Home: '',
Product: 'products/:productId',
Profile: 'users/:userId',
Orders: 'orders',
},
},
};
function App() {
return (
<NavigationContainer linking={linking}>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Product" component={ProductScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name= = />
);
}
( {
= () => {
url = event.;
};
.(, handleDeepLink);
.().( {
(url) {
({ url });
}
});
{
.(, handleDeepLink);
};
}, []);
Integration with Babysitter SDK
Task Definition Example
const deepLinkTask = defineTask({
name: 'deep-link-setup',
description: 'Configure deep linking for mobile app',
inputs: {
platform: { type: 'string', required: true, enum: ['ios', 'android', 'both'] },
domain: { type: 'string', required: true },
paths: { type: 'array', items: { type: 'string' }, required: true },
customScheme: { type: 'string' },
projectPath: { type: 'string', required: true }
},
outputs: {
aasaFile: { type: 'string' },
assetlinksFile: { type: 'string' },
appConfiguration: { type: 'object' },
verificationSteps: { type: 'array' }
},
async run(inputs, taskCtx) {
return {
: ,
: ,
: {
: ,
: {
: ,
: inputs.,
: inputs.,
: inputs.,
: inputs.,
: inputs.
}
},
: {
: ,
:
}
};
}
});
Verification Commands
iOS Universal Links Verification
curl -I https://example.com/.well-known/apple-app-site-association
curl https://example.com/.well-known/apple-app-site-association | jq
curl "https://app-site-association.cdn-apple.com/a/v1/example.com"
Android App Links Verification
curl -I https://example.com/.well-known/assetlinks.json
curl https://example.com/.well-known/assetlinks.json | jq
adb shell pm get-app-links com.example.app
adb shell pm set-app-links --package com.example.app 0 all
adb shell pm verify-app-links --re-verify com.example.app
Best Practices
- Validate Server Configuration: Ensure AASA and assetlinks.json are properly served
- Handle All States: Deep links should work in foreground, background, and cold start
- Implement Fallbacks: Redirect to web or app store if app not installed
- Secure Deep Links: Validate deep link parameters before acting on them
- Track Analytics: Log deep link sources and conversions
- Test Thoroughly: Test all paths and edge cases before deployment
References