針對不同 GL 材質建立多個 APK

如果您將應用程式發布到 Google Play,應建構並上傳 Android App Bundle。這樣一來,Google Play 就會針對每位使用者的裝置設定自動產生並提供最佳化 APK,讓使用者只下載執行應用程式所需的程式碼和資源。如果您未將應用程式發布到 Google Play,發布多個 APK 是非常實用的做法,但您必須自行建構、簽署及管理各個 APK。

開發 Android 應用程式時,如果想善用 Google Play 上的多個 APK,請務必從一開始就採行一些良好做法,避免在開發過程中遇到不必要的麻煩。本課程說明如何建立應用程式的多個 APK,每個 APK 支援不同的 OpenGL 紋理格式子集。您也會獲得一些必要工具,盡可能輕鬆地維護多個 APK 程式碼集。

確認您需要多個 APK

嘗試建立可在所有可用 Android 裝置中運作的應用程式時,自然會希望您的應用程式在個別裝置上都能呈現最佳外觀,無論其規格為何都不支援相同的 GL 紋理組合。乍看之下,多個 APK 支援可能是最佳解決方案,但這通常並非如此。多個 APK 開發人員指南的「改用單一 APK」一節提供一些實用資訊,說明如何透過單一 APK 達成這項目標,包括如何在執行階段偵測支援的紋理格式。視情況而定,您可能會發現,將所有格式與應用程式一起封裝,然後在執行階段選擇要使用的格式,會比較容易。

如果您可以管理,將應用程式限制在單一 APK 中,可享有以下幾項優點:

  • 發布和測試更輕鬆
  • 只需維護一個程式碼集
  • 應用程式可因應裝置設定變更而調整
  • 跨裝置應用程式還原功能運作正常
  • 您不必擔心市場偏好設定、從一個 APK 到另一個 APK 的「升級」行為,或是哪個 APK 與哪個裝置類別相符

本課程的其餘部分假設您已研究過主題,原本就吸收連結資源中的內容,並判定多個 APK 是應用程式的正確路徑。

繪製需求圖表

Android 開發人員指南在 supports-gl-texture 頁面上提供一些常見的支援紋理,方便您參考。本頁面也提供一些提示,說明哪些手機 (或手機系列) 支援特定紋理格式。請注意,一般來說,建議您讓其中一個 APK 支援 ETC1,因為所有支援 OpenGL ES 2.0 規格的 Android 裝置都支援該紋理格式。

由於大多數 Android 裝置都支援多種紋理格式,因此您需要建立偏好順序。請建立圖表,包含應用程式即將支援的所有格式。最左側的儲存格會優先處理優先順序最低 (可能為 ETC1,這在效能和相容性方面是非常固定的預設選項)。接著,請在圖表中顏色,讓每個儲存格都代表一個 APK。

ETC1 ATI 電源 VR

在圖表中加入顏色不僅可讓本指南不那麼單調,還能讓團隊內部溝通更為順暢。現在,您可以直接將每個 APK 稱為「藍色」、「綠色」或「紅色」,而非「支援 ETC1 紋理格式的 APK」等。

將所有通用程式碼和資源放入程式庫專案

無論您要修改現有的 Android 應用程式還是從頭開始,首先在程式碼集執行之前,最需要做的就是。加入程式庫專案中的所有項目只需更新一次 (例如本地化字串、色彩主題,以及在共用程式碼中修正的錯誤),這可以改善開發時間,並減少可能避免的錯誤可能。

注意:雖然如何建立及加入程式庫專案的實作細節超出本課程範圍,但您可以參閱「建立 Android 程式庫」一文,快速掌握相關資訊。

如果您要轉換現有應用程式使用多個 APK 支援功能,請針對每個本地化字串檔案檢查程式碼集、值清單、主題顏色、選單圖示和版面配置 (不會因 APK 變更) 而全部加入程式庫專案。不會經常變更的程式碼也應放入程式庫專案。您可能會擴充這些類別,從 APK 新增一或兩個方法。

如果是從頭開始建立應用程式,請盡可能盡量在程式庫專案中編寫程式碼,再視需要將其移至個別 APK。長期執行相比,比起新增 ID 來更輕鬆管理,接著幾個月後嘗試確定能否將此 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 中列出的紋理格式「任一」在市售裝置上支援,該裝置就會視為符合資格

就 GL 紋理而言,最後一項規則非常重要。換句話說,您應該務必在同一個應用程式中使用不同的 GL 格式。如果您 99% 的時間都使用 PowerVR,但使用 ETC1 做為啟動畫面,您的資訊清單就必須指出支援這兩種格式。系統會將「僅」支援 ETC1 的裝置視為相容,因此會下載您的應用程式,而使用者會看到一些令人驚恐的當機訊息。一般來說,如果您使用多個 APK 專門針對不同裝置指定 GL 材質支援功能,每個 APK 都會有一個紋理格式。

這其實讓紋理支援與其他兩個多重 APK 維度 (API 級別和螢幕大小) 略有不同。任何裝置都只有一個 API 級別和一個螢幕大小,而 APK 則負責支援這些級別和大小的範圍。使用紋理時,APK 一般會支援一種紋理,而裝置會支援多種紋理。在支援多個 APK 的裝置上,通常會出現重疊的情況,但解決方法相同:版本代碼。

舉例來說,請選取幾部裝置,看看先前定義的 APK 有多少個可用於每部裝置。

FooPhone Nexus S 埃沃
ETC1 ETC1 ETC1
PowerVR ATI TC

假設 PowerVR 和 ATI 格式在可用時都優先於 ETC1,根據「最高版本號碼優先」規則,如果我們在每個 APK 中設定 versionCode 屬性,以便紅色 ≥ 綠色 ≥ 藍色,那麼在支援紅色和綠色的裝置上,系統一律會選擇紅色和綠色,如果有裝置同時支援紅色和綠色,系統會選擇紅色。

為了讓所有 APK 都位於不同的「發布途徑」,請務必採用良好的版本代碼配置。您可以在開發人員指南的「版本代碼」區域中找到建議的代碼。由於示例 APK 套組只處理 3 種可能的維度之一,因此只要將每個 APK 分開 1000 次,然後從該值開始遞增即可。如下所示:

藍色:1001、1002、1003、1004...
綠色:2001、2002、2003、2004...
紅色:3001、3002、3003、3004...

將所有內容整合後,您的 Android 資訊清單可能會如下所示:

藍色:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="1001" android:versionName="1.0" package="com.example.foo">
    <supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
    ...

綠色:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="2001" android:versionName="1.0" package="com.example.foo">
    <supports-gl-texture android:name="GL_AMD_compressed_ATC_texture" />
    ...

紅色:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="3001" android:versionName="1.0" package="com.example.foo">
    <supports-gl-texture android:name="GL_IMG_texture_compression_pvrtc" />
    ...

查看正式發布前檢查清單

上傳至 Google Play 前,請仔細檢查下列項目。請注意,這些項目與多個 APK 特別相關,絕非上傳至 Google Play 的所有應用程式完整檢查清單。

  • 所有 APK 都必須使用相同的套件名稱
  • 所有 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: 'xlarge'
supports-any-density: 'true'
locales: '--_--'
densities: '120' '160' '240'

檢查 aapt 輸出內容時,請務必確認 supports-screens 和 compatible-screens 的值不會互相衝突,且不會因為您在資訊清單中設定的權限而新增非預期的「uses-feature」值。在上例中,如果不是所有裝置,至少大多數裝置都會看不到 APK。

原因是新增必要權限 SEND_SMS 後,系統會隱含新增 android.hardware.telephony 的功能需求。由於大多數 (但非全部) 特大尺寸裝置都是沒有電話功能的平板電腦,因此 Google Play 會在這些情況下篩除這個 APK,直到日後推出的裝置同時具備足夠大的螢幕 (可回報為特大尺寸) 和電話功能。

幸好,只要在資訊清單中新增下列內容,就能輕鬆解決這個問題:

<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 指定的裝置正確無誤。恭喜!你已完成設定。