如果您將應用程式發布到 Google Play,應建構並上傳 Android App Bundle。這樣一來,Google Play 會自動針對每位使用者的裝置設定產生及提供最佳化 APK,讓使用者只下載執行應用程式所需的程式碼和資源。如果您不打算發布至 Google Play,但必須自行建構、簽署及管理每個 APK,則發布多個 APK 就很實用。
開發 Android 應用程式時,如果想充分利用 Google Play 上的多個 APK,請務必從一開始就採用一些良好做法,以免在開發過程中遇到不必要的麻煩。本課將說明如何為應用程式建立多個 APK,每個 APK 涵蓋的 API 級別範圍略有不同。您也會獲得一些必要工具,盡可能輕鬆地維護多個 APK 程式碼集。
確認您需要多個 APK
當您嘗試建立可在多個世代 Android 平台上運作的應用程式時,自然希望應用程式能充分利用新裝置的新功能,同時不犧牲向後相容性。一開始可能會覺得支援多個 APK 是最佳解決方案,但實際上並非如此。多個 APK 開發人員指南的「改用單一 APK」一節提供一些實用資訊,說明如何透過單一 APK 達成這項目標,包括使用支援程式庫。您也可以參閱 這篇文章,瞭解如何編寫程式碼,讓程式碼只在單一 APK 的特定 API 級別中執行,而無須使用反射等運算成本高昂的技術。
如果您能妥善管理,將應用程式限制在單一 APK 中,可享有以下多項優勢:
- 發布和測試更輕鬆
- 只需維護一個程式碼集
- 應用程式可因應裝置設定變更而調整
- 跨裝置應用程式還原功能運作正常
- 您不必擔心市場偏好設定、從一個 APK 升級至另一個 APK 的行為,或是哪個 APK 與哪個裝置類別相符
本課程的其餘部分假設您已研究這個主題,並認真吸收連結資源中的內容,並判斷多個 APK 是應用程式的正確路徑。
繪製需求圖表
首先建立簡單的圖表,快速判斷需要多少個 APK,以及每個 APK 涵蓋的 API 範圍。為方便您參考,Android 開發人員網站的「平台版本」頁面會提供相關資料,說明執行特定 Android 平台版本的使用中裝置數量。此外,雖然一開始聽起來很簡單,但要追蹤每個 APK 要指定哪些 API 級別,很快就會變得相當困難,尤其是如果有重疊的情況 (通常會有)。幸好,您可以輕鬆快速地繪製需求表,方便日後參考。
如要建立多個 APK 圖表,請先建立一列代表 Android 平台不同 API 級別的儲存格。在結尾處插入額外儲存格,用來代表未來的 Android 版本。
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | + |
接著,只需在圖表中填入顏色,讓每種顏色代表一個 APK。以下是將每個 APK 套用至特定 API 級別範圍的範例。
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | + |
建立這張圖表後,請分發給團隊成員。專案團隊的溝通方式現在變得更簡單,因為您不必再問「API 級別 3 到 6 的 APK 是如何,呃,您知道,就是 Android 1.x 的 APK。一切順利嗎?只要說出「Blue APK 的進度如何?」即可。
將所有通用程式碼和資源放入程式庫專案
無論您是要修改現有的 Android 應用程式,還是從頭開始建立應用程式,這都是您對程式碼庫應做的第一件事,也是最重要的事。程式庫專案中的所有內容只需更新一次 (例如語言本地化的字串、色彩主題、共用程式碼中修正的錯誤),這麼一來,您就能縮短開發時間,並減少容易避免的錯誤發生機率。
注意:雖然如何建立及加入程式庫專案的實作細節超出本課程範圍,但您可以參閱「建立 Android 程式庫」一文,快速掌握相關資訊。
如果您要將現有應用程式轉換為支援多個 APK,請在程式碼庫中搜尋每個經過本地化的字串檔案、值清單、主題顏色、選單圖示和版面配置 (不會在 APK 之間變更),然後將所有項目放入程式庫專案。不會經常變更的程式碼也應放入程式庫專案中。您可能會擴充這些類別,從 APK 新增一或兩個方法。
另一方面,如果您是從頭開始建立應用程式,請盡可能先在程式庫專案中編寫程式碼,然後只在必要時將程式碼移至個別 APK。長期來說,這比將 Blob 新增至一個、再新增至另一個、再新增至另一個,然後在數月後嘗試判斷 Blob 是否可移至程式庫區段,而不會破壞任何內容,更容易管理。
建立新的 APK 專案
每個要發布的 APK 都應有專屬的 Android 專案。為方便整理,請將程式庫專案和所有相關 APK 專案放在同一個父項資料夾下。另外請注意,每個 APK 都必須有相同的套件名稱,但不一定需要與程式庫共用套件名稱。如果您要依據上述方案建立 3 個 APK,根目錄可能會如下所示:
alexlucas:~/code/multi-apks-root$ ls foo-blue foo-green foo-lib foo-red
建立專案後,請將程式庫專案新增為每個 APK 專案的參照。請盡可能在程式庫專案中定義啟動活動,並在 APK 專案中擴充該活動。在程式庫專案中定義啟動活動,可讓您將所有應用程式初始化作業集中在一個位置,因此每個個別 APK 不必重新實作「通用」工作,例如初始化 Analytics、執行授權檢查,以及任何其他從 APK 到 APK 幾乎不變的初始化程序。
調整資訊清單
當使用者透過 Google Play 下載使用多個 APK 的應用程式時,系統會根據兩個簡單的規則選擇要使用的正確 APK:
- 資訊清單必須顯示特定 APK 符合資格
- 在符合資格的 APK 中,版本號碼最高的 APK 會勝出
舉例來說,我們先前提到的多個 APK 組合,假設我們尚未為任何 APK 設定 API 級別上限。個別來說,每個 APK 的可能範圍如下所示:
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | + |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | + |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | + |
由於 minSdkVersion 較高的 APK 也必須採用較高的版本代碼,因此我們知道,就 versionCode 值而言,紅色 ≥ 綠色 ≥ 藍色。因此,我們可以有效地收合圖表,讓它看起來像這樣:
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | + |
接著,我們進一步假設 Red APK 有其他兩個 APK 沒有的某些需求。Android 開發人員指南的「Google Play 上的篩選器」頁面列出了可能的肇因。舉例來說,假設紅色需要前置鏡頭。事實上,紅色 APK 的用意在於將前置鏡頭與 API 11 中新增的實用新功能結合。但事實上,並非所有支援 API 11 的裝置都有前置鏡頭!太可怕了!
幸運的是,如果使用者透過這類裝置瀏覽 Google Play,Google Play 會查看資訊清單,發現 Red 列出前置鏡頭為必要條件,並在判斷 Red 與該裝置不相容時,悄悄忽略這項條件。接著,您會發現 Green 不僅與搭載 API 11 的裝置相容 (因為未定義 maxSdkVersion),而且也不在乎是否有前置鏡頭!使用者仍可從 Google Play 下載應用程式,因為儘管前置鏡頭發生意外,仍有 APK 支援該特定 API 級別。
為了讓所有 APK 都位於不同的「測試群組」中,請務必採用良好的版本代碼配置。您可以在開發人員指南的「版本代碼」區域中找到建議的版本代碼。由於範例 APK 套組只處理 3 個可能的維度之一,因此只要將每個 APK 分隔 1000,並將前幾位數字設為該特定 APK 的 minSdkVersion,然後從該點開始遞增即可。如下所示:
藍色:03001、03002、03003、03004...
綠色:07001、07002、07003、07004...
紅色:11001、11002、11003、11004...
將所有內容整合後,您的 Android 資訊清單可能會如下所示:
藍色:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="03001" android:versionName="1.0" package="com.example.foo"> <uses-sdk android:minSdkVersion="3" /> ...
綠色:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="07001" android:versionName="1.0" package="com.example.foo"> <uses-sdk android:minSdkVersion="7" /> ...
紅色:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="11001" android:versionName="1.0" package="com.example.foo"> <uses-sdk android:minSdkVersion="11" /> ...
查看正式發布前檢查清單
上傳至 Google Play 前,請仔細檢查下列項目。請注意,這些項目與多個 APK 相關,並非上傳至 Google Play 的所有應用程式完整檢查清單。
- 所有 APK 都必須使用相同的套件名稱
- 所有 APK 都必須使用相同的憑證簽署
- 如果 APK 的平台版本重疊,則 minSdkVersion 較高的 APK 必須採用較高的版本代碼
- 仔細檢查資訊清單篩選器是否有衝突的資訊 (僅支援 XLARGE 螢幕的 APK 不會顯示給任何人)
- 每個 APK 的資訊清單中,至少必須有一個支援的螢幕、OpenGL 紋理或平台版本
- 請嘗試在至少一部裝置上測試每個 APK。除此之外,您還擁有業界最具客製化彈性的裝置模擬器,可在開發機器上使用。盡情享受吧!
您也可以在發布至市場前檢查已編譯的 APK,確保不會有任何意外狀況導致應用程式在 Google Play 上顯示為隱藏狀態。使用「aapt」工具,這其實相當簡單。Aapt (Android 資產封裝工具) 是建構 Android 應用程式及封裝應用程式的建構程序之一,也是檢查應用程式的實用工具。
>aapt dump badging package: name='com.example.hello' versionCode='1' versionName='1.0' sdkVersion:'11' uses-permission:'android.permission.SEND_SMS' application-label:'Hello' application-icon-120:'res/drawable-ldpi/icon.png' application-icon-160:'res/drawable-mdpi/icon.png' application-icon-240:'res/drawable-hdpi/icon.png' application: label='Hello' icon='res/drawable-mdpi/icon.png' launchable-activity: name='com.example.hello.HelloActivity' label='Hello' icon='' uses-feature:'android.hardware.telephony' uses-feature:'android.hardware.touchscreen' main supports-screens: 'small' 'normal' 'large' 'xlarge' supports-any-density: 'true' locales: '--_--' densities: '120' '160' '240'
檢查 aapt 輸出內容時,請務必確認 supports-screens 和 compatible-screens 的值不會互相衝突,且不會因為您在資訊清單中設定的權限而新增意外的「uses-feature」值。在上述範例中,許多裝置都不會顯示 APK。
原因是新增必要權限 SEND_SMS 後,系統會隱含新增 android.hardware.telephony 的功能需求。由於 API 11 是 Honeycomb (專為平板電腦最佳化的 Android 版本),且沒有任何 Honeycomb 裝置內含電話硬體,因此 Google Play 會在所有情況下篩除這個 APK,直到日後推出的裝置 API 級別較高且具備電話硬體為止。
幸好,只要在資訊清單中新增下列內容,就能輕鬆解決這個問題:
<uses-feature android:name="android.hardware.telephony" android:required="false" />
系統也會隱含新增 android.hardware.touchscreen
需求。如果您希望 APK 能在非觸控螢幕裝置的電視上顯示,請在資訊清單中加入下列內容:
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
完成正式發布前檢查清單後,請將 APK 上傳至 Google Play。瀏覽 Google Play 時,應用程式可能需要一點時間才會顯示,但在顯示後,請進行最後一次檢查。請將應用程式下載到任何可能的測試裝置上,確保 APK 指定的裝置正確無誤。恭喜,你已完成設定!