deep-linking

timequity's avatarfrom timequity

Universal Links, App Links, and URL scheme configuration.

⭐0stars🔀0forks📁View on GitHub🕐Updated Dec 18, 2025

When & Why to Use This Skill

This Claude skill provides comprehensive guidance and boilerplate configurations for implementing deep linking in mobile applications. It simplifies the complex process of setting up Universal Links for iOS, App Links for Android, and custom URL schemes, ensuring seamless navigation between web content and mobile apps while supporting modern frameworks like Expo Router.

Use Cases

  • Configuring custom URL schemes in Expo's app.json to enable basic app-to-app communication and redirection.
  • Generating apple-app-site-association (AASA) files to support iOS Universal Links for a seamless web-to-app transition.
  • Setting up Android App Links with intent filters and assetlinks.json for secure, verified deep linking without disambiguation dialogs.
  • Implementing dynamic routing and parameter handling using Expo Router to map web URLs directly to specific app screens.
  • Providing ready-to-use CLI commands for testing deep link triggers on both iOS Simulators and Android Emulators.
namedeep-linking
descriptionUniversal Links, App Links, and URL scheme configuration.

Deep Linking

URL Schemes

// app.json
{
  "expo": {
    "scheme": "myapp"
  }
}
// Handle myapp://path
import * as Linking from 'expo-linking';

const url = Linking.createURL('path/to/screen', {
  queryParams: { id: '123' },
});
// myapp://path/to/screen?id=123
// app.json
{
  "expo": {
    "ios": {
      "associatedDomains": ["applinks:example.com"]
    }
  }
}
// /.well-known/apple-app-site-association
{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "TEAM_ID.com.example.app",
        "paths": ["/product/*", "/user/*"]
      }
    ]
  }
}
// app.json
{
  "expo": {
    "android": {
      "intentFilters": [
        {
          "action": "VIEW",
          "autoVerify": true,
          "data": [
            {
              "scheme": "https",
              "host": "example.com",
              "pathPrefix": "/product"
            }
          ],
          "category": ["BROWSABLE", "DEFAULT"]
        }
      ]
    }
  }
}
// /.well-known/assetlinks.json
[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.app",
    "sha256_cert_fingerprints": ["..."]
  }
}]

Expo Router

// app/_layout.tsx
export default function Layout() {
  return (
    <Stack>
      <Stack.Screen name="product/[id]" />
    </Stack>
  );
}

// app/product/[id].tsx
export default function ProductScreen() {
  const { id } = useLocalSearchParams();
  // https://example.com/product/123 -> id = "123"
}

Testing

# iOS Simulator
xcrun simctl openurl booted "myapp://product/123"

# Android Emulator
adb shell am start -a android.intent.action.VIEW -d "myapp://product/123"