Dynamic And Deep Links
Step by Step Guide on Deep Links
How to debug/add/update Deeplinks
1. Check associated files on the domain (Android & iOS)
A. Identifying Files:
- There are two primary files to check
- Android: assetlinks.json
- iOS: apple-app-site-association (without extension)
B. Location
- Both files should be located in the .well-known directory of your domain's root directory. For example, if your domain is yourapp.com, the complete file paths would be:
- Toolstation Domain Example
- https://www-pre-prod.toolstation.dev/.well-known/assetlinks.json (Android)
- https://www.gke.pre-prod.toolstation.dev/.well-known/assetlinks.json (Android)
- https://www-uat.gke.pre-prod.toolstation.dev/.well-known/assetlinks.json (Android)
- https://www-pre-prod.toolstation.dev/.well-known/apple-app-site-association (iOS)
- https://www.gke.pre-prod.toolstation.dev/.well-known/apple-app-site-association (iOS)
- https://www-uat.gke.pre-prod.toolstation.dev/.well-known/apple-app-site-association (iOS)
- For Toolstation: assetlinks.json and apple-app-site-association files are not hosted along with the website but using Google Cloud Storage/ Bucket
C. Verification Methods:
- Manual Check: Use a web browser to navigate to the URLs mentioned above.
- If the files exist, your browser will likely display the contents in a text format.
- If the files are not found, you'll encounter an error message.
- Checking for Regex (Android - assetlinks.json):
- The assetlinks.json file uses a JSON format. Look for the key "targets" which is an array of objects.
- Within each object in the "targets" array, find the key "app_name" (string) and "link_match" (object).
- The "link_match" object typically contains a key "URL" (string) which might have your deep link pattern embedded. This could be an exact match or use regular expression notation.
{ "targets": [ { "app_name": "YourAppName", "link_match": { "url": "yourapp://path/to/content.*" } } ] }
- Checking for Regex (iOS - apple-app-site-association):
- The apple-app-site-association file uses a more complex format.
- Within "applinks" there might be a key "details" containing an array of objects. These objects may have a key "paths" containing an array with your deep link patterns. These patterns can use wildcard characters or full URLs.
- Again, compare these patterns to your intended deep link structure for verification.
{ "details": [ { "appID": "your-app-id", "paths": [ "/articles/*", // Matches any article content (wildcard) "/products/:id" // Matches product details with dynamic ID ] } ] }
D. Additional Notes:
- The content of these files will vary depending on your specific deep link setup.
- These files should not be publicly editable; ensure proper access permissions are set on your server.
- By following these steps, you can confirm if the necessary deep link association files are present on your domain for both Android and iOS apps.
2. Updating Manifest and Entitlements for Associated Domains (Android & iOS)
- Associated Domains allow your app to handle deep links from specific website domains.
- Understanding Associated Domains:
- Android: Associated Domains are declared within the app manifest file.
- iOS: Associated Domains are configured in the app's entitlements file, typically a .entitlements file.
Updating Android Manifest
- Locate your app's manifest file (usually AndroidManifest.xml).
- BE
- android/app/src/bePreProd/AndroidManifest.xml
- android/app/src/beProd/AndroidManifest.xml
- FR
- android/app/src/frPreProd/AndroidManifest.xml
- android/app/src/frProd/AndroidManifest.xml
- NL
- android/app/src/nlPreProd/AndroidManifest.xml
- android/app/src/nlProd/AndroidManifest.xml
- UK
- android/app/src/uk/AndroidManifest.xml
- android/app/src/ukPreProd/AndroidManifest.xml
- In Android, Associated Domains are declared within the app manifest file using
<intent-filter>tags within an<activity>element. - Find the
<activity>tag corresponding to your main activity or the activity that should handle deep links. - Within the
<activity>tag, locate the existing<intent-filter>tags that define how your app responds to android.intent.action.VIEW intents (these are typically used for deep links). - Specify Path Patterns: To handle deep links with specific paths within your domain, add
<data>tags within the<intent-filter>
<activity android:name=".MainActivity">
<!-- Start App Links -->
<intent-filter android:autoVerify="true" tools:ignore="UnusedAttribute">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Associated Domains -->
<data android:scheme="https" android:host="example.com" android:pathPattern="/product/.*" />
<data android:scheme="https" android:host="alpha.example.com" android:pathPattern="/product/.*" />
<data android:scheme="https" android:host="beta.example.com" android:pathPattern="/product/.*" />
<!-- End Associated Domains -->
</intent-filter>
<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="example.com"/>
</intent-filter>
<!-- End App Links -->
</activity>
Updating iOS Entitlements
- Locate your app's entitlements file (usually a .entitlements file). This file might be within your Xcode project or managed separately.
- BE
- ios/Runner/entitlements/Runner-bePreProd.entitlements
- ios/Runner/entitlements/Runner-beProd.entitlements
- FR
- ios/Runner/entitlements/Runner-frPreProd.entitlements
- ios/Runner/entitlements/Runner-frProd.entitlements
- NL
- ios/Runner/entitlements/Runner-nlPreProd.entitlements
- ios/Runner/entitlements/Runner-nlProd.entitlements
- UK
- ios/Runner/entitlements/Runner-ukPreProd.entitlements
- ios/Runner/entitlements/Runner-ukProd.entitlement
- BE
- Add a key named associated-domains under the aps-environment key (if it exists) or at the top level of the entitlements dictionary.
- The value for associated-domains should be an array containing your website domain(s) used for deeplinks:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "<http://www.apple.com/DTDs/PropertyList-1.0.dtd>">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.associated-domains</key>
<array>
<!-- applinks links -->
<string>applinks:example.com</string>
<string>applinks:alpha.example.com</string>
<string>applinks:beta.example.com</string>
<!-- webcredentials links -->
<string>webcredentials:example.com</string>
<string>webcredentials:alpha.example.com</string>
<string>webcredentials:beta.example.com</string>
</array>
<!-- Entitlement used in iOS app development for enabling In-App Purchases -->
<key>com.apple.developer.in-app-payments</key>
<array>
<string>merchant.com.appname.apple-pay-dev</string>
</array>
<!-- Entitlement that allows multiple apps developed by the same team to share data securely. -->
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.appname.mobile-app.dummy</string>
</array>
</dict>
</plist>
3. Verifying Signing Keys and Team ID Before Building (Android & iOS)
Please ensure your signing keys and Team ID match the ones registered for deep links on Domains (assetlinks.json & apple-app-site-association), before building your Android and iOS apps.
Android
assetlinks.json
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.company.appname",
"sha256_cert_fingerprints": [
"FP - One",
"FP - Two"
// Example: "AE:FB:45:32:12:C3:2F:GE:98:DE:F4:56:78:CB:90:AB:CD:EF:12:34:56"
]
}
}
]
- Match the SHA-256 with the signing keys you're using.
- For Toolstation We can say that all the local builds by devs/testers will not match these SHA keys (assetlinks.json), so all the builds from those machines won't support the deep links.
- Either The build has to be done using Github runner -> which uses production environment Signing keys (SHA keys)
- Or using the Fastlane (which will fail for devs/testers who don't have production environment Signing keys - For now production environment Signing keys are accessible to Teamlead (Larsson) Only)
iOS
apple-app-site-association
{
"applinks": {
"details": [
{
"appID": "TEAMID0000.com.example.app",
"paths": ["/category/*", "/product/*"]
},
{
"appIDs": ["TEAMID0000.com.example.app"],
"components": [
{
"#": "no_universal_links",
"exclude": true,
"comment": "Matches any URL whose fragment equals no_universal_links and instructs the system not to open it as a universal link"
},
{
"/": "/category/*",
"comment": "Matches URLs starting with /category/[category-id] to allow the user to check category in the app."
},
{
"/": "/product/*",
"comment": "Matches URLs starting with /product/[product-id] to allow the user to check product in the app."
}
]
}
]
},
"webcredentials": {
"apps": ["TEAMID0000.com.example.app"]
}
}
- Match the Team ID with the Xcode signing Team ID
- Open XCode project
- Navigate to signing and capabilities
- Check the team ID under team section
- If any mismatch in Team ID, Deeplinks won't work
4. Deeplink Routing
Completing the previous steps ensures your app opens upon clicking a deep link. However, handling the deep link data and performing actions within the Flutter app requires additional code configuration.
- We use app_links package.
- All the link catching code and RegEx matching code remain in lib/backend/repositories/deep_link_repository.dart
- All the routing/action code remains in
- lib/features/main/bloc/main_page_bloc.dart >
_handleDeepLink - lib/features/main/main_page.dart >
_onMainPageEvent
- lib/features/main/bloc/main_page_bloc.dart >