Flutter 實作 DeepLink 完整指南 ⎮ Part 2: Android 與 iOS 設定
不可忽略的 Deep Link 體驗
在第一章中,我們介紹了 Deep Link 的基本觀念,並討論了它對行動應用的好處。快速了解深度連結在提升用戶體驗、改善行銷效果、簡化新用戶入門流程、獲得更佳分析數據以及與其他應用程式整合方面的作用。
在本章中,我們將深入 Android 和 iOS 應用程式的 Deep Link 設定。整理了每一步驟的細節說明,以確保大家在實作上可以輕鬆且無障礙的完成它們。
Android (Web Link)
使用 http
和 https
兩種 scheme,稱為 App Links / In-app Links
互動流程
- 點擊 URI 連結
- 發出意圖 Intent
- Android System
- 發出意圖 Intent
- Flutter MainActivity
- Flutter App
前置作業
AndroidManifest.xml
需要設定 URI 以處理 Deep Link,Flutter 針對指定 URI 開啟 APP- 資源驗證檔案
assetlinks.json
需要放置在 domain server 上
專案設置與流程
首先開啟 AndroidManifest.xml
檔案
1️⃣ 新增 <meta-data>
設置 flutter_deeplinking_enabled
,代表允許 Flutter 可以處理 Deep Link,value
為 true
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
2️⃣ 新增 <intent-filter>
處理 URI Intent,啟動畫面,autoVerify
為 true,此設定代表可以略過開啟應用的選擇對話框,節省步驟後直接跳轉並啟動目標 APP。
當使用者安裝應用程式時,Android 會看到包含 autoVerify
屬性的 <intent-filter>
,並查看 <data>
中指定URL下的驗證檔案,檢查是否包含目前當前 APP,如果包含,Android 就認為該網址已經過驗證,允許 APP 開啟 Web links 連結。
📍新增 <action>
,代表可執行的動作,其中 android.intent.action.VIEW,允許讓 Google 搜尋
📍新增 <category>
,允許對隱性意圖為預設,android.intent.category.DEFAULT
📍新增 <category>
,從網路瀏覽器可觸發意圖,android.intent.category.BROWSABLE
📍新增 <data>
,可與 APP 或畫面互動的 Uri 設定
scheme
→ 通常為 http、https,或是自定義的 scheme,例如:yiihost
→ domain,例如:flutter.compath
→ URI 路徑,例如:/users
請保持每一種 Domain 設定使用一個 <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="https" android:host="cat.example"/>
</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="https" android:host="vc.cat.example" android:path="/campaigns"/>
</intent-filter>
以幾種設置方式:
- 第一種 →
host
給予完整路徑
<data
android:scheme="https"
android:host="vibz.cool" />
2. 第二種 → host
不包含後方的路徑,新增 pathPattern
來設置路徑
<data
android:scheme="https"
android:host="vibz.cool"
android:pathPattern="/download"/>
3. 第三種 → 不同 Domain、host 請將他們分開,否則 path 相關設定會一起套用,導致後台檢驗時會納入混濁的格式。也可以同時提升可讀性
<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="vc.vibz.cool" android:pathPattern="/"/>
<data android:scheme="https" android:host="vc.vibz.cool" android:pathPattern="/campaigns"/>
</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="https" android:host="share.vibz.cool" android:pathPattern="/"/>
<data android:scheme="https" android:host="share.vibz.cool" android:pathPattern="/share" />
</intent-filter>
4. 第四種 → 動態路徑的配置,可使用 path
、pathPrefix
、和 pathPattern
表示
- 添加一個
path
,例如:/、/campaigns - 添加一個
pathPattern
,後面給予*
,代表動態內容,可能是數字ID。例如:/campaigns/.* 可代表 /campaigns/100、/campaigns/play - 添加一個
pathPattern
,支援路徑有部分變動。例如:/.*\\.html
例如,需要一個活動連結,點擊後直接跳轉到頁面。如果頁面路徑的後方需要帶入動態資訊,就需要額外設置一個 pathPattern
,動態的部分給予 ..*
,完成後連結才會正常運行。
有明確意義、類型的內容,最好定義指定路徑,新增階層式巢狀結構。可讓 intent-filter 明確指向,並且讓 Android 擷取到精確的網址
// Good
https:share.vibz.cool/campaigns/xxxxxx
// Avoid
https:share.vibz.cool/xxxxxx
實際 URI:https://share.vibz.cool/campaigns/dthm31/claim?openExternalBrowser=1&claim_code=bmljZQ==
<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="share.vibz.cool" android:pathPattern="/campaigns"/>
<data android:pathPattern="/campaigns/..*"/>
</intent-filter>
詳細的定義方式,可查看官方 https://developer.android.com/guide/topics/manifest/data-element?hl=zh-tw
3️⃣ launchMode 設置
在外部、第三方應用打開連結時,如果目標 APP 是在來源 APP 上呈現,可以在 AndroidManifest.xml
調整 launchMode
為 singleTask,讓目標 APP 獨立出來。根據 launchMode
設定可以決定 APP 的運行模式。
驗證資源設置(Digital Asset Links)
主要目的是確保用戶在開啟網站連結後,打開設備裡對應的應用程式,而不是開啟一般網頁。
- 讓應用程式知道可以處理哪種類型的 URL,確保網域將應用程式識別為可信任的
- 應用和網域兩者之間需要建立關聯。您必須在 Domain 上儲存
assetlinks.json
(Google Digital Asset Links) 檔案,才能進行驗證。 - 驗證元素包含 URI、APP 簽名、package_name,透過它們證明是 Domain 擁有者,可以進行互動。避免其他應用劫持跳轉請求
Google DAL 是一種通訊協定和 API,定義其他應用程式和網站的可驗證資訊
sha256 證書指紋可透過 keytool CLI 取得,存取原本我們創建的 keystore 檔案
keytool -list -v -keystore <release-key>.keystore
或是直接從 Google Play Console 查看,如果有上傳並生成 Production App 簽名,就可以從 App signing 頁面找到。
接著直接從 Google Play Console 的 App signing 取得 assetlinks.json
內容,儲存下來後放置到 Server。
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.yiichen.example",
"sha256_cert_fingerprints": [
"07:64:58:7A:F4:5C:04:16:D5:35:A7:1B:44:C7:98:84:DV:38:C5:8F:29:EC:6A:3A:A2:2A:FC:69:5B:BB:24:CA",
"2A:96:21:4D:A8:F1:D6:4D:AC:1A:B4:7D:68:F9:6C:EB:A1:9F:66:73:68:75:CE:DF:18:7D:4D:EA:0F:A3:AF:21",
]
}
}
]
請記住,此步驟僅適用於 Web links (HTTP/HTTPS Links),不適用於 Custom Scheme
💡 非必要的本地設置,如果需要從本地驗證 Web links 連結,可以取得 local debug 證書指紋,將它設置到 assetlinks.json
裡面,更新到 Server 上。
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
Google Play Console / Deep links
快速瀏覽 App 中有設定的 Web links 資訊,包含 Domain 與詳細路徑
在 Web links 區塊中,如果有自定義的 scheme,Android 不會驗證所以會有錯誤訊息,但這部分可忽略。(後面會說明 Custom scheme link )
下方的 Custom schemes 會顯示我們自定義的名稱,這裡的狀態就會是正常的囉。有打勾也就代表連結可以使用,當用戶點擊後能跟 APP 互動
Android (Custom Link)
- 自定義 Scheme 的連結,稱為 Deep Links。
scheme
的設置方式基本上都差不多,而設有自訂配置的連結是很常見的 DeepLink 類型,容易實作- 適合沒有網域的開發者,節省驗證的步驟。不過也代表第三方應用都能跟自家應用進行互動
<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="yii" android:host="cat.example" />
</intent-filter>
實際的連結:
yii://cat.example
iOS (Web Link)
使用 http 和 https 兩種 scheme,稱為 Universal Links
前置作業
- 專案的
Associated Domains
需要設定 URI 以處理 Deep Link,讓 Flutter 針對指定 URI 格式開啟 APP - 放置驗證資源
apple-app-site-association
到 Domain Server,讓 APP 進行驗證,包含 Link details、APP ID、bundleID,證明 APP 是 Domain 互動對象,跟 Android 設定方式類似
專案設置與流程
- 首先開啟
info.plist
檔案,新增FlutterDeepLinkingEnabled
為 true。代表開啟了Flutter DeepLink 功能
2. 針對每個執行環境,要設定 Associated Domains 互動連結,在 Runner → Signing & Capabilities
新增。請注意每個環境、設定檔都需要添加,確保在每個情境都能正常運作
3. 新增有 applinks: 開頭的連結設定,後面為 domain,假設 URL 為 https://vibz.cool,就改成 applinks:vibz.cool。將相關路徑都添加上去,一樣每個環境、模式都要設定完整
驗證資源設置
建立一個名為 apple-app-site-association
的檔案,內容通常包含 APP 資訊也有 Link 的相關路徑 。如果不限制路徑的情境下,主要調整 appId
、paths
兩個欄位。必須確保檔案為 application/json 格式,但是不需要給副檔名。
appID
→ Apple Team ID 與 Bundle ID 組裝paths
→ 設置允許的指定路徑。也可以使用*
表示全部或任意長度的字元,代表不需要過濾。?
可代表任意一個字元components
→ 非必要設置,可以提供完整的路徑資訊,包含路徑與相關描述,針對指定的部分才會處理
// 1.
{
"applinks": {
"apps": [],
"details": [
{
"appID": "SXX342XG9.com.yiichen.hello",
"paths": [
"*",
"/user/*",
],
"components":[
{
"/":"/sign-in",
"comment":"Let URL bring users to /sign-in page"
},
{
"/":"/profile/*",
"comment":"Let URL bring users to check the profile of someone"
},
]
}
]
}
}
// 2. Multiple APP exmaple
{
"applinks": {
"apps": [],
"details": [
{
"appID": "SDZ342XG9.com.yiichen.hello",
"paths": [
"*"
]
},
{
"appID": "ABC123456.com.yiichen.hello",
"paths": [
"/product/*"
]
}
]
}
}
Team ID 在 Apple Developer 的 account 頁面可以找到,查看 Membership details
將檔案編輯後放置到我們的網域路徑儲存,等待應用透過它進行驗證,以範例來看就是 https://vc.vibz.cool/
,透過網址存取時就能直接查看到內容。
<https://vc.vibz.cool/.well-known/apple-app-site-association>
Apple Developer Console 設置
針對產品的 BundleID 進行設定,包含每個 flavor
環境的身分證,勾選 Associated Domains,允許 APP 與連結進行互動。
iOS (Custom Link)
- 自定義 URI Scheme,稱為 custom URL scheme。可選擇任何的 scheme,只要個人和團隊喜歡即可
- 對於沒有網域、網站但想實現 DeepLink 的效果,那麼此方法非常方便
注意:
- 如果 APP 沒有安裝在設備,打開連結時就會顯示錯誤,不會像 Web Link 一樣開啟對應網頁
- 缺點是它不太安全,因為任何應用程式取得 scheme 後都可以嘗試打開你的連結,也就是 APP。當然大家也可以使用相同的 scheme
如果 APP 有自己的自定義 scheme 會需要以下的 Info.plist
設定。
- 新增一個 URL type
- 設置 CFBundleURLName,身分證
- 設置 CFBundleURLSchemes,自定義 scheme 名稱
Code:
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>xyz.passion.vibz</string>
<key>CFBundleURLSchemes</key>
<array>
<string>vibz</string>
</array>
</dict>
</array>
也可以透過 Runner 的 Info 介面設定,新增 URL Type,將 Identifier
和 URL Schemes
補上即可。
以上步驟只有自定義方案才需要,如果是使用 Web links (HTTP/HTTPS Links) 則可忽略
Conclusion
在本文中我們了解 Android 和 iOS 的深度連結設定,在使用連結吸引用戶之前,這是很重要的前置工作。才能確保應用程式無縫引導使用者至正確的內容、有效推動轉化並培養忠實的用戶群。
第三章,即將進入重頭性,Flutter 開發階段。透過套件工具來協助 Deep Link 的實現。看過後你也覺得不難了!
- Flutter 實作 DeepLink 完整指南 ⎮ Part 1: 基本介紹
- Flutter 實作 DeepLink 完整指南 ⎮ Part 3: Flutter 開發
- Flutter 實作 DeepLink 完整指南 ⎮ Part 4: 適配與掌握社交平台
Other Articles
- Flutter June 2024 💙 Flutter Monthly
- What can I do with “Extension Types” in Dart?
- Flutter May 2024 💙 Flutter Monthly
- Flutter April 2024 💙 Flutter Monthly
- Flutter March 2024 💙 Flutter Monthly
- Flutter February 2024 💙 Flutter Monthly
- Flutter 3.19 & Dart 3.3 改版重點!
- Flutter January 2024 💙 Flutter Monthly
- Use Dart 3 to Improve Development Skills. More Examples and Tips.
- Flutter December 2023 💙 Flutter Monthly
- Flutter November 2023 💙 Flutter Monthly
- Get Familiar with Dart 3, Make your Life Easier!
- Flutter 3.16 & Dart 3.2 重點整理來了!
- Flutter October 2023 💙 Flutter Monthly
- Flutter September 2023 💙 Flutter Monthly
- Flutter August 2023 💙 Flutter Monthly
- Flutter July 2023 💙 Flutter Monthly
- 添加預覽影片到 App Store,提升品牌形象
- Fluttercon 2023 技術研討會
- Flutter 六月大小事
- Wow! Flutter runs on Apple Vision Pro!
- 這次 Flutter 3.10 與 Dart 3 又強大了多少?Google IO 告訴你
- Flutter Meetup #1 聚會有什麼?還有 Flutter 四月大小事!
- 提升開發效率的好物,Mason 讓你輕鬆撰寫自定義模板!
- 教你製作強大的 Rive 動畫,完成一隻 Flutter Dash,在 APP 跟它互動!
- Flutter 如何根據 Flavor 多環境載入對應的 Firebase Config
- Isolates 在 Flutter 3.7 & Dart 2.19 的升級,你該知道一下!
- 讓人驚艷的 Flutter Forward,釋出 Flutter 3.7 和 Dart 2.19
- 學會運用 Flutter Widgetbook,該管好自己和公司的元件庫了!