功能與政策
大多數實際應用程式都需要適應不同裝置與平台的 功能與政策。本頁將提供在程式碼中 處理這些情境的建議。
針對每種裝置類型的優勢進行設計
#請考慮不同裝置的獨特優勢與劣勢。 除了螢幕尺寸與輸入方式(如觸控、滑鼠、鍵盤)之外, 還有哪些獨特的功能可以加以利用? Flutter 讓您的程式碼能在不同裝置上「執行」, 但良好的設計不僅僅是讓程式碼能執行。 請思考每個平台最擅長的部分, 並尋找是否有獨特的功能可以發揮。
例如:Apple 的 App Store 與 Google 的 Play Store 有不同的規範需要應用程式遵守。 不同的主機作業系統隨著時間推移, 以及彼此之間,也會有不同的功能。
另一個例子是利用 Web 極低的分享門檻。 如果您要部署 Web 應用程式, 請決定要支援哪些深層連結 (deep links), 並以此設計導覽路由。
Flutter 建議的做法是,根據這些獨特功能, 為您的應用程式建立一組 Capability 和 Policy 類別。
功能(Capabilities)
#「功能」(capability)定義了程式碼或裝置「能夠」做什麼。 功能的例子包括:
- API 的存在
- 作業系統強制的限制
- 實體硬體需求(如相機)
政策(Policies)
#「政策」(policy)定義了程式碼「應該」做什麼。
政策的例子包括:
- 應用程式商店的指引
- 設計偏好
- 參照主機裝置的資源或文案
- 伺服器端啟用的功能
如何組織政策相關程式碼
#最簡單的機械式方式是使用 Platform.isAndroid、 Platform.isIOS 和 kIsWeb。這些 API 可以機械式地 告知您程式碼執行的位置,但隨著應用程式可執行的平台增加, 以及主機平台功能的擴充,這種做法會出現一些問題。
以下指南說明了在開發應用程式功能與政策時的最佳實踐:
避免使用 Platform.isAndroid 及類似函式 來做版面配置決策或對裝置功能做出假設。
取而代之,請在方法中描述您想要分支的條件。
舉例:您的應用程式在網站上有一個購買連結, 但基於政策考量,您不希望在 iOS 裝置上顯示該連結。
bool shouldAllowPurchaseClick() {
// Banned by Apple App Store guidelines.
return !Platform.isIOS;
}
...
TextSpan(
text: 'Buy in browser',
style: new TextStyle(color: Colors.blue),
recognizer: shouldAllowPurchaseClick ? TapGestureRecognizer()
..onTap = () { launch('<some url>') : null;
} : null,加入額外一層間接層(indirection)後,你得到了什麼? 這段程式碼能更清楚地說明為什麼會有分支路徑存在。 這個方法可以直接存在於類別(class)中,但很有可能 程式碼的其他部分也會需要這個相同的檢查。 如果是這樣,請將這段程式碼放在一個類別中。
class Policy {
bool shouldAllowPurchaseClick() {
// Banned by Apple App Store guidelines.
return !Platform.isIOS;
}
}將這段程式碼放入類別後,任何元件(Widget)測試都可以模擬 Policy().shouldAllowPurchaseClick 並獨立驗證其行為, 無論裝置運行於何處。 這也意味著,日後如果你決定 讓 Android 使用者不再透過網頁購買, 你只需更改實作, 而針對可點擊文字的測試則無需調整。
能力(Capabilities)
#有時你希望程式碼執行某些操作,但 API 並不存在,或是你依賴的外掛功能 尚未在所有支援的平台上實作。 這就是裝置「能」做什麼的限制。
這些情境與上文所述的政策決策類似, 但這類情況稱為「能力(capabilities)」。 為什麼要將政策類別(policy classes)與能力類別(capabilities)分開, 即使它們的類別結構相似? Flutter 團隊在實際應用中發現, 將應用程式「能做」什麼與「應該做」什麼做出邏輯區分, 有助於大型產品在初始程式碼撰寫後, 因應平台功能變動或平台需求改變, 以及你自身偏好時,能更靈活地調整。
舉例來說,假設某個平台新增了一項權限, 要求使用者在你的程式碼呼叫敏感 API 前, 必須先與系統對話框互動。 你的團隊針對平台 1 完成相關工作,並建立了一個 名為 requirePermissionDialogFlow 的能力。 之後,若平台 2 也新增了類似需求, 但僅適用於新 API 版本, 則 requirePermissionDialogFlow 的實作 就可以檢查 API 等級,並在平台 2 上回傳 true。 如此一來,你就能重複利用既有的開發成果。
政策(Policies)
#我們建議一開始就建立 Policy 類別, 即使你認為政策決策不會太多。 隨著類別複雜度提升或輸入數量增加, 你可能會考慮依功能或其他標準, 將政策類別拆分。
在政策實作上,你可以選擇編譯時、 執行時,或以遠端程序呼叫(RPC)為基礎的實作方式。
編譯時政策檢查適用於偏好不太可能變動的平台, 且意外更改值可能帶來重大影響的情境。 例如,若某平台要求不得 連結至 Play 商店,或要求你根據應用內容 使用特定的支付服務供應商。
執行時檢查則適合判斷 使用者是否有可用的觸控螢幕。Android 有相關功能可檢查, 而你的網頁實作則可檢查最大觸控點數。
以 RPC 為基礎的政策變更,則適合漸進式功能上線 或未來可能改變的決策。
小結
#使用 Capability 類別來定義程式碼「能」做什麼。 你可能會檢查 API 是否存在、 作業系統強制的限制, 以及實體硬體需求(如相機)。 能力(capability)通常涉及編譯時或執行時檢查。
使用 Policy 類別(或依複雜度拆分多個類別) 來定義程式碼「應該」做什麼,以符合 應用商店規範、設計偏好, 以及需參照主機裝置的資源或文案。 政策(policy)可以是編譯時、執行時或 RPC 檢查的混合。
透過模擬能力與政策來測試分支程式碼, 如此一來,當能力或政策變動時, 元件(Widget)測試無需更動。
在能力與政策類別中,請根據其分支邏輯命名方法, 而非依據裝置類型命名。