Deep Linking - Universal Links & App Links
Deep linking setup for iOS (Universal Links) and Android (App Links) with GoRouter integration.
When to Use This Skill
- Adding deep link support to a Flutter app
- Configuring Universal Links for iOS
- Configuring App Links for Android
- Handling custom URL schemes
- Integrating deep links with GoRouter
- User asks "add deep linking", "universal links", "app links", or "URL handling"
Questions to Ask
- Domain: What domain will host the deep links? (e.g.,
example.com)
- Paths: Which paths should open the app? (e.g.,
/products/*, /users/*)
- Custom scheme: Need a custom URL scheme fallback? (e.g.,
myapp://)
- Environments: Multiple domains? (e.g., staging.example.com, example.com)
- Backend access: Can you host
.well-known files on the server?
Reference Files
reference/router/deep_link_handler.dart - GoRouter deep link config
templates/ios/Runner.entitlements - Associated Domains
templates/android/android_manifest_deeplinks.xml - Intent filters
See: implementation-guide.md for complete setup.
Workflow
Phase 1: Domain Verification
- Create
apple-app-site-association file (see ios-guide.md)
- Create
assetlinks.json file (see android-guide.md)
- Host files at
https://domain.com/.well-known/
- Verify HTTPS and correct MIME types
Phase 2: iOS Configuration
- Add Associated Domains capability in Xcode
- Add domain to
Runner.entitlements
- Handle links in AppDelegate (if needed)
Phase 3: Android Configuration
- Add intent filters to
AndroidManifest.xml
- Set
autoVerify="true" for App Links
- Generate and add SHA-256 fingerprint to
assetlinks.json
Phase 4: GoRouter Integration
- Configure
GoRouter with deep link paths
- Add route parameter extraction
- Handle unknown deep links gracefully
- Test with
adb and xcrun commands
Core API
// GoRouter handles deep links automatically
GoRouter(routes: [
GoRoute(path: '/products/:id', builder: (context, state) =>
ProductScreen(productId: state.pathParameters['id']!)),
]);
// Manual: GoRouter.of(context).go(Uri.parse(deepLink).path);
URL Types
| Type |
iOS |
Android |
Format |
| Universal/App Links |
Yes |
Yes |
https://domain.com/path |
| Custom Scheme |
Yes |
Yes |
myapp://path |
| Firebase Dynamic Links |
Deprecated |
Deprecated |
Use Universal/App Links |
Domain Verification Files
iOS: apple-app-site-association
Host at: https://domain.com/.well-known/apple-app-site-association
{
"applinks": {
"apps": [],
"details": [{
"appID": "TEAM_ID.com.example.app",
"paths": ["/products/*", "/users/*"]
}]
}
}
Android: assetlinks.json
Host at: https://domain.com/.well-known/assetlinks.json
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": ["SHA256_FINGERPRINT"]
}
}]
Platform Requirements
iOS
- Associated Domains capability enabled
- HTTPS domain with valid certificate
apple-app-site-association file accessible (no redirects)
- MIME type:
application/json
Android
- Intent filters with
autoVerify="true"
- SHA-256 fingerprints (debug, release, Play Store)
assetlinks.json file accessible
- MIME type:
application/json
Testing Commands
xcrun simctl openurl booted "https://example.com/products/123" # iOS
adb shell am start -a android.intent.action.VIEW -d "https://example.com/products/123" com.example.app
adb shell pm get-app-links com.example.app # Verify Android
curl -I https://example.com/.well-known/apple-app-site-association
Guides
| File |
Content |
| ios-guide.md |
Universal Links, Associated Domains, AASA file |
| android-guide.md |
App Links, Intent Filters, Digital Asset Links |
| implementation-guide.md |
GoRouter integration, path handling |
| checklist.md |
Verification checklist |
Common Issues
| Issue |
Cause |
Solution |
| iOS link opens Safari |
AASA not found |
Check .well-known path and MIME type |
| Android shows app chooser |
autoVerify failed |
Verify assetlinks.json and SHA-256 |
| Path not matched |
Wrong pattern |
Check path patterns in AASA/router |
| Works in dev, not prod |
Wrong fingerprint |
Add release/Play Store SHA-256 |
Checklist
Related Skills
/core - GoRouter setup (run first)
/push-notifications - Deep links from notifications
/release - iOS capabilities, Android signing
/testing - Deep link integration tests
1---2name: deep-linking3description: Deep linking with Universal Links (iOS) and App Links (Android). Platform setup, domain verification, GoRouter integration, path-based routing. Use when implementing deep links, URL handling, or app-to-web navigation.4---56# Deep Linking - Universal Links & App Links78Deep linking setup for iOS (Universal Links) and Android (App Links) with GoRouter integration.910## When to Use This Skill1112- Adding deep link support to a Flutter app13- Configuring Universal Links for iOS14- Configuring App Links for Android15- Handling custom URL schemes16- Integrating deep links with GoRouter17- User asks "add deep linking", "universal links", "app links", or "URL handling"1819## Questions to Ask20211. **Domain:** What domain will host the deep links? (e.g., `example.com`)222. **Paths:** Which paths should open the app? (e.g., `/products/*`, `/users/*`)233. **Custom scheme:** Need a custom URL scheme fallback? (e.g., `myapp://`)244. **Environments:** Multiple domains? (e.g., staging.example.com, example.com)255. **Backend access:** Can you host `.well-known` files on the server?2627## Reference Files2829- `reference/router/deep_link_handler.dart` - GoRouter deep link config30- `templates/ios/Runner.entitlements` - Associated Domains31- `templates/android/android_manifest_deeplinks.xml` - Intent filters3233**See:** [implementation-guide.md](implementation-guide.md) for complete setup.3435## Workflow3637### Phase 1: Domain Verification38391. Create `apple-app-site-association` file (see ios-guide.md)402. Create `assetlinks.json` file (see android-guide.md)413. Host files at `https://domain.com/.well-known/`424. Verify HTTPS and correct MIME types4344### Phase 2: iOS Configuration45461. Add Associated Domains capability in Xcode472. Add domain to `Runner.entitlements`483. Handle links in AppDelegate (if needed)4950### Phase 3: Android Configuration51521. Add intent filters to `AndroidManifest.xml`532. Set `autoVerify="true"` for App Links543. Generate and add SHA-256 fingerprint to `assetlinks.json`5556### Phase 4: GoRouter Integration57581. Configure `GoRouter` with deep link paths592. Add route parameter extraction603. Handle unknown deep links gracefully614. Test with `adb` and `xcrun` commands6263## Core API6465```dart66// GoRouter handles deep links automatically67GoRouter(routes: [68 GoRoute(path: '/products/:id', builder: (context, state) =>69 ProductScreen(productId: state.pathParameters['id']!)),70]);71// Manual: GoRouter.of(context).go(Uri.parse(deepLink).path);72```7374## URL Types7576| Type | iOS | Android | Format |77|------|-----|---------|--------|78| **Universal/App Links** | Yes | Yes | `https://domain.com/path` |79| **Custom Scheme** | Yes | Yes | `myapp://path` |80| **Firebase Dynamic Links** | Deprecated | Deprecated | Use Universal/App Links |8182## Domain Verification Files8384### iOS: apple-app-site-association8586Host at: `https://domain.com/.well-known/apple-app-site-association`8788```json89{90 "applinks": {91 "apps": [],92 "details": [{93 "appID": "TEAM_ID.com.example.app",94 "paths": ["/products/*", "/users/*"]95 }]96 }97}98```99100### Android: assetlinks.json101102Host at: `https://domain.com/.well-known/assetlinks.json`103104```json105[{106 "relation": ["delegate_permission/common.handle_all_urls"],107 "target": {108 "namespace": "android_app",109 "package_name": "com.example.app",110 "sha256_cert_fingerprints": ["SHA256_FINGERPRINT"]111 }112}]113```114115## Platform Requirements116117### iOS118119- Associated Domains capability enabled120- HTTPS domain with valid certificate121- `apple-app-site-association` file accessible (no redirects)122- MIME type: `application/json`123124### Android125126- Intent filters with `autoVerify="true"`127- SHA-256 fingerprints (debug, release, Play Store)128- `assetlinks.json` file accessible129- MIME type: `application/json`130131## Testing Commands132133```bash134xcrun simctl openurl booted "https://example.com/products/123" # iOS135adb shell am start -a android.intent.action.VIEW -d "https://example.com/products/123" com.example.app136adb shell pm get-app-links com.example.app # Verify Android137curl -I https://example.com/.well-known/apple-app-site-association138```139140## Guides141142| File | Content |143|------|---------|144| [ios-guide.md](ios-guide.md) | Universal Links, Associated Domains, AASA file |145| [android-guide.md](android-guide.md) | App Links, Intent Filters, Digital Asset Links |146| [implementation-guide.md](implementation-guide.md) | GoRouter integration, path handling |147| [checklist.md](checklist.md) | Verification checklist |148149## Common Issues150151| Issue | Cause | Solution |152|-------|-------|----------|153| iOS link opens Safari | AASA not found | Check `.well-known` path and MIME type |154| Android shows app chooser | `autoVerify` failed | Verify `assetlinks.json` and SHA-256 |155| Path not matched | Wrong pattern | Check path patterns in AASA/router |156| Works in dev, not prod | Wrong fingerprint | Add release/Play Store SHA-256 |157158## Checklist159160- [ ] Domain supports HTTPS with valid certificate161- [ ] `apple-app-site-association` hosted at `.well-known/`162- [ ] `assetlinks.json` hosted at `.well-known/`163- [ ] iOS: Associated Domains capability added in Xcode164- [ ] iOS: Domain added to `Runner.entitlements`165- [ ] Android: Intent filters added to `AndroidManifest.xml`166- [ ] Android: All SHA-256 fingerprints in `assetlinks.json`167- [ ] GoRouter configured with deep link paths168- [ ] Deep links tested on both platforms169- [ ] Unknown paths handled gracefully170171## Related Skills172173- `/core` - GoRouter setup (run first)174- `/push-notifications` - Deep links from notifications175- `/release` - iOS capabilities, Android signing176- `/testing` - Deep link integration tests