時區規則

Android 10 淘汰了以 APK 為基礎的時區資料更新機制 (適用於 Android 8.1 和 Android 9),並改用 APEX 為基礎的模組更新機制。AOSP 8.1 到 13 仍包含 OEM 啟用 APK 型更新所需的平台程式碼,因此升級至 Android 10 的裝置仍可透過 APK 接收合作夥伴提供的時區資料更新。不過,如果正式版裝置也收到模組更新,就不應使用 APK 更新機制,因為 APK 更新會取代 APEX 更新 (也就是說,收到 APK 更新的裝置會忽略 APEX 更新)。

時區更新 (Android 10 以上版本)

Android 10 以上版本支援時區資料模組,可更新 Android 裝置上的日光節約時間和時區,並將因宗教、政治和地緣政治因素而經常變動的資料標準化。

更新程序如下:

  1. IANA 會因應一或多個政府機關變更境內時區規則,發布時區資料庫更新。
  2. Google 或 Android 合作夥伴會準備時區資料模組更新 (APEX 檔案),其中包含更新後的時區。
  3. 使用者裝置會下載更新、重新啟動,然後套用變更,之後裝置的時區資料就會包含更新中的新時區資料。

如要進一步瞭解模組,請參閱「模組化系統元件」。

時區更新 (Android 8.1 至 9)

注意:Android 14 以上版本已完全移除以 APK 為基礎的時區資料更新機制功能,且原始碼中也找不到這項功能。合作夥伴應完全遷移至時區主線模組。

在 Android 8.1 和 Android 9 中,原始設備製造商可以使用 APK 型機制,將更新的時區規則資料推送至裝置,不必更新系統。這項機制可讓使用者及時收到更新 (因此延長 Android 裝置的實用壽命),並讓 Android 合作夥伴獨立測試時區更新,不必等待系統映像檔更新。

Android 核心程式庫團隊會提供必要的資料檔案,以便更新 Android 原廠裝置的時區規則。原始設備製造商 (OEM) 可以選擇在為裝置建立時區更新時使用這些資料檔案,也可以視需要建立自己的資料檔案。在任何情況下,原始設備製造商 (OEM) 都能控管支援裝置的時區規則更新品質保證/測試、時間和發布。

Android 時區原始碼和資料

所有搭載 Android 系統的裝置 (即使未使用這項功能) 都需要時區規則資料,且必須在 /system 分區中預先載入一組時區規則資料。Android 來源樹狀結構中下列程式庫的程式碼會使用這項資料:

  • libcore/ 的受管理程式碼 (例如 java.util.TimeZone) 會使用 tzdatatzlookup.xml 檔案。
  • bionic/ 中的原生程式庫程式碼 (例如適用於 mktime、localtime 系統呼叫) 會使用 tzdata 檔案。
  • external/icu/ 中的 ICU4J/ICU4C 程式庫程式碼會使用 icu.dat 檔案。

這些程式庫會追蹤 /data/misc/zoneinfo/current 目錄中可能存在的疊加檔案。疊加檔案應包含改良的時區規則資料,因此裝置更新時不必變更 /system

需要時區規則資料的 Android 系統元件會先檢查下列位置:

  • libcore/bionic/ 程式碼會使用 tzdatatzlookup.xml 檔案的 /data 副本。
  • ICU4J/ICU4C 程式碼會使用 /data 中的檔案,並針對不存在的資料 (例如格式、本地化字串等) 回溯至 /system 檔案。

發行檔案

發行版 .zip 檔案包含填入 /data/misc/zoneinfo/current 目錄所需的資料檔案。發行檔案也包含中繼資料,可供裝置偵測版本問題。

發行檔案格式取決於 Android 版本,因為內容會隨著 ICU 版本、Android 平台需求和其他版本變更而異。Android 會為每個 IANA 更新提供支援的 Android 版本發行檔案 (除了更新平台系統檔案外)。為確保裝置保持在最新狀態,原始設備製造商 (OEM) 可以使用這些發行版本檔案,或使用 Android 來源樹狀結構 (內含產生發行版本檔案所需的指令碼和其他檔案) 建立自己的檔案。

時區更新元件

時區規則更新會將發行檔案傳輸至裝置,並安全地安裝檔案中的內容。轉移和安裝程序需要下列項目:

  • 平台服務功能 (timezone.RulesManagerService),預設為停用。原始設備製造商必須透過設定啟用這項功能。 RulesManagerService 會在系統伺服器程序中執行,並透過寫入 /data/misc/zoneinfo/staged 暫存時區更新作業。RulesManagerService 也可以取代或刪除已暫存的作業。
  • TimeZoneUpdater, 無法更新的系統應用程式 (又稱「更新程式」)。如果裝置使用這項功能,原始設備製造商必須在系統映像檔中加入這個應用程式。
  • OEM TimeZoneData:可更新的系統應用程式 (又稱「資料應用程式」),可將發行檔案傳輸至裝置,並提供給 Updater 應用程式使用。使用這項功能的裝置,OEM 必須在系統映像檔中加入這個應用程式。
  • tzdatacheck,這是時區更新正確且安全運作所需的開機時間二進位檔。

Android 來源樹狀結構包含上述元件的通用原始碼,OEM 可選擇直接使用。測試程式碼 可供原始設備製造商自動檢查 是否已正確啟用這項功能。

安裝發行版本

發行版本安裝程序包括下列步驟:

  1. 資料應用程式已更新,可透過應用程式商店下載或側載。系統伺服器程序 (透過 timezone.RulesManagerServer/timezone.PackageTracker 類別) 會監控已設定的 OEM 專屬資料應用程式套件名稱變更。

    資料應用程式更新

    圖 1. 資料應用程式更新。

  2. 系統伺服器程序會將含有專屬一次性權杖的目標意圖廣播至更新程式應用程式,藉此觸發更新檢查。系統伺服器會追蹤最近產生的權杖,以便判斷最近觸發的檢查何時完成;系統會忽略任何其他權杖。

    觸發更新

    圖 2. 觸發更新檢查。

  3. 更新檢查期間,更新程式應用程式會執行下列工作:
    • 呼叫 RulesManagerService,查詢目前的裝置狀態。

      呼叫 RulesManagerService

      圖 3. 資料應用程式更新,呼叫 RulesManagerService。

    • 透過查詢明確定義的 ContentProvider 網址和資料欄規格,查詢 Data 應用程式,以取得發行資訊。

      取得發行資訊

      圖 4. 資料應用程式更新、取得發行資訊。

  4. Updater 應用程式會根據所掌握的資訊採取適當行動。可用的動作包括:
    • 要求安裝。系統伺服器會從資料應用程式讀取 Distro 資料,並傳遞至 RulesManagerService。RulesManagerService 會再次確認發行格式版本和內容是否適合裝置,並準備安裝。
    • 要求解除安裝 (這種情況很少見)。舉例來說,如果 /data 中的更新版 APK 遭到停用或解除安裝,裝置就會還原為 /system 中的版本。
    • 不採取任何行動。當系統發現資料應用程式發布版本無效時,就會發生這種情況。
    在所有情況下,Updater 應用程式都會使用檢查權杖呼叫 RulesManagerService,讓系統伺服器知道檢查已完成且成功。

    檢查完成

    圖 5. 檢查完成。

  5. 重新啟動並執行 tzdatacheck。裝置下次啟動時,tzdatacheck 二進位檔會執行任何已暫存的作業。tzdatacheck 二進位檔可執行下列工作:
    • 在其他系統元件開啟並開始使用檔案前,處理 /data/misc/zoneinfo/current 檔案的建立、取代和/或刪除作業,以執行分階段作業。
    • 確認 /data 中的檔案是否適用於目前的平台版本。如果裝置剛完成系統更新,且發行版本格式已變更,可能就不適用。
    • 確認 IANA 規則版本與 /system 中的版本相同或較新。這樣可避免系統更新後,裝置上的時區規則資料比 /system 映像檔中的資料舊。

可靠性

端對端安裝程序為非同步,並分為三個 OS 程序。安裝期間,裝置可能會沒電、磁碟空間不足或發生其他問題,導致安裝檢查不完整。如果更新失敗,Updater 應用程式會通知系統伺服器更新失敗;如果更新完全失敗,RulesManagerService 則不會收到任何呼叫。

為處理這項問題,系統伺服器程式碼會追蹤觸發的更新檢查是否已完成,以及資料應用程式上次檢查的版本代碼。裝置閒置並充電時,系統伺服器程式碼可以檢查目前狀態。如果發現更新檢查不完整或資料/應用程式版本異常,就會自動觸發更新檢查。

安全性

啟用後,系統伺服器中的 RulesManagerService 程式碼會執行多項檢查,確保系統使用安全無虞。

  • 如果系統映像檔設定不當,裝置就無法啟動。舉例來說,可能是更新程式或資料應用程式設定有誤,或是更新程式或資料應用程式不在 /system/priv-app 中。
  • 如果安裝的「資料」應用程式有問題,裝置仍可開機,但無法觸發更新檢查。舉例來說,可能是缺少必要的系統權限,或是「資料」應用程式未在預期 URI 上公開 ContentProvider。

系統會使用 SELinux 規則強制執行 /data/misc/zoneinfo 目錄的檔案權限。與任何 APK 一樣,資料應用程式必須使用與 /system/priv-app 版本相同的金鑰簽署。資料應用程式應有專屬的 OEM 特定套件名稱和金鑰。

整合時區更新

如要啟用時區更新功能,原始設備製造商通常會採取下列做法:

  • 建立自己的「資料」應用程式。
  • 在系統映像檔建構作業中加入「更新程式」和「資料」應用程式。
  • 設定系統伺服器,啟用 RulesManagerService。

準備

開始之前,原始設備製造商應詳閱下列政策、品質保證和安全性注意事項:

  • 為資料應用程式建立專用的應用程式專屬簽署金鑰。
  • 為時區更新建立發布和版本控管策略,瞭解哪些裝置會更新,以及如何確保更新只會安裝在需要更新的裝置上。舉例來說,原始設備製造商可能會想為所有裝置提供單一「資料」應用程式,也可能選擇為不同裝置提供不同的「資料」應用程式。這項決策會影響套件名稱的選擇、可能使用的版本代碼,以及品質保證策略。
  • 瞭解他們是否要使用 AOSP 的 Android 時區資料,或自行建立時區資料。

建立資料應用程式

Android 開放原始碼計畫包含在 packages/apps/TimeZoneData 中建立資料應用程式所需的所有原始碼和建構規則,以及 AndroidManifest.xml 和其他檔案的指示和範本,位於 packages/apps/TimeZoneData/oem_template 中。範本範例包括實際資料應用程式 APK 的建構目標,以及用於建立資料應用程式測試版本的額外目標。

原始設備製造商可以自訂「資料」應用程式的圖示、名稱、翻譯和其他詳細資料。不過,由於無法啟動「資料」應用程式,因此圖示只會顯示在「設定」>「應用程式」畫面中。

資料應用程式應使用 tapas 建構版本建構,產生適合新增至系統映像檔 (用於初始版本) 的 APK,並透過應用程式商店簽署及發布 (用於後續更新)。如要瞭解如何使用 Tapas,請參閱「使用 Tapas 建立資料應用程式」。

原始設備製造商 (OEM) 必須在裝置的系統映像檔中安裝預先建構的「資料」應用程式。/system/priv-app如要在系統映像檔中加入預先建構的 APK (由 tapas 建構程序產生),原始設備製造商 (OEM) 可以複製 packages/apps/TimeZoneData/oem_template/data_app_prebuilt 中的範例檔案。範例範本也包含建構目標,可在測試套件中加入 Data 應用程式的測試版本。

在系統映像檔中加入 Updater 和 Data 應用程式

原始設備製造商 (OEM) 必須將 Updater 和 Data 應用程式 APK 放在系統映像檔的 /system/priv-app 目錄中。如要這麼做,系統映像檔建構作業必須明確包含 Updater 應用程式和 Data 應用程式預先建構目標。

Updater 應用程式應使用平台金鑰簽署,並納入為任何其他系統應用程式。目標定義於 packages/apps/TimeZoneUpdater 中,如 TimeZoneUpdater 所示。資料應用程式的納入作業是 OEM 專屬,且取決於預先建構所選的目標名稱。

設定系統伺服器

如要啟用時區更新功能,原始設備製造商可以覆寫 frameworks/base/core/res/res/values/config.xml 中定義的設定屬性,藉此設定系統伺服器。

屬性 說明 是否需要覆寫?
config_enableUpdateableTimeZoneRules
必須設為 true,才能啟用 RulesManagerService。
config_timeZoneRulesUpdateTrackingEnabled
必須設為 true,系統才會監聽資料應用程式的變更。
config_timeZoneRulesDataPackage
OEM 專用資料應用程式的套件名稱。
config_timeZoneRulesUpdaterPackage
預設為 Updater 應用程式設定。只有在提供不同的 Updater 應用程式實作時,才需要變更。
config_timeZoneRulesCheckTimeMillisAllowed
從 RulesManagerService 觸發更新檢查,到安裝、解除安裝或不執行任何動作之間允許的時間。此時可能會產生自發性可靠性觸發程序。
config_timeZoneRulesCheckRetryCount
連續更新檢查失敗次數上限,一旦超出上限,RulesManagerService 就不會再產生更多檢查。

設定覆寫應位於系統映像檔中 (而非供應商或其他),因為設定錯誤的裝置可能會拒絕啟動。如果設定覆寫位於供應商映像檔中,更新為沒有資料應用程式的系統映像檔 (或使用不同的資料應用程式/更新程式應用程式套件名稱),就會視為設定錯誤。

xTS 測試

xTS 是指任何類似於標準 Android 測試套件的 OEM 專屬測試套件,使用 Tradefed (例如 CTS 和 VTS)。如果原始設備製造商有這類測試套件,可以新增下列位置提供的 Android 時區更新測試:

  • packages/apps/TimeZoneData/testing/xts 包含基本自動功能測試所需的程式碼。
  • packages/apps/TimeZoneData/oem_template/xts 包含範例目錄結構,用於在類似 Tradefed 的 xTS 套件中加入測試。與其他範本目錄一樣,OEM 應複製並根據自身需求自訂。
  • packages/apps/TimeZoneData/oem_template/data_app_prebuilt 包含建構時間設定,用於納入測試所需的預先建構測試 APK。

建立時區更新

IANA 發布新時區規則後,Android 核心程式庫團隊會產生修補程式,更新 Android 開放原始碼計畫 (AOSP) 中的版本。使用 Android 系統和發行檔案的原始設備製造商可以挑選這些提交內容,用來建立新版「資料」應用程式,然後發布新版本,更新生產裝置。

由於資料應用程式包含與 Android 版本密切相關的發行檔案,因此 OEM 必須為要更新的每個支援 Android 版本建立新版資料應用程式。舉例來說,如果原始設備製造商想為 Android 8.1、9 和 10 裝置提供更新,就必須完成三次程序。

步驟 1:更新系統/時區和外部/icu 資料檔案

在這個步驟中,原始設備製造商會從 AOSP 的發布開發分支版本中,取得 system/timezoneexternal/icu 的股票 Android 提交內容,並將這些提交內容套用至 Android 原始碼副本。

系統/時區 AOSP 修補程式包含 system/timezone/input_datasystem/timezone/output_data 中的更新檔案。如需進行額外的本機修正,OEM 可以修改輸入檔案,然後在 system/timezone/input_dataexternal/icu 中使用這些檔案,在 output_data 中產生檔案。

最重要的檔案是 system/timezone/output_data/distro/distro.zip,建立 Data 應用程式 APK 時會自動納入這個檔案。

步驟 2:更新「資料」應用程式的版本代碼

在這個步驟中,原始設備製造商會更新「資料」應用程式的版本代碼。建構作業會自動挑選 distro.zip,但「資料」應用程式的新版本必須有新的版本代碼,才能識別為新版本,並用來取代預先載入的「資料」應用程式,或先前更新在裝置上安裝的「資料」應用程式。

使用從 package/apps/TimeZoneData/oem_template/data_app 複製的檔案建構資料應用程式時,您可以在 Android.mk 中找到套用至 APK 的版本代碼/版本名稱:

TIME_ZONE_DATA_APP_VERSION_CODE :=
TIME_ZONE_DATA_APP_VERSION_NAME :=

testing/Android.mk中也有類似項目 (但測試版版本代碼必須高於系統映像檔版本)。詳情請參閱版本代碼策略範例配置。如果使用範例配置或類似配置,測試版版本代碼保證會高於實際版本代碼,因此不需要更新。

步驟 3:重建、簽署、測試及發布

在這個步驟中,原始設備製造商會使用 tapas 重建 APK、簽署產生的 APK,然後測試及發布 APK:

  • 如果是未發布的裝置 (或準備為已發布的裝置進行系統更新),請在 Data 應用程式預先建構的目錄中提交新的 APK,確保系統映像檔和 xTS 測試使用最新的 APK。原始設備製造商應測試新檔案是否正常運作 (即通過 CTS 和所有原始設備製造商專屬的自動與手動測試)。
  • 如果已發布的裝置不再收到系統更新,簽署的 APK 可能只會透過應用程式商店發布。

OEM 必須負責更新後「資料」應用程式的品質保證和測試,並在裝置上發布。

資料應用程式版本代碼策略

資料應用程式必須採用適當的版本控管策略,確保裝置收到正確的 APK。舉例來說,如果系統更新包含的 APK 版本比從應用程式商店下載的版本舊,則應保留應用程式商店版本。

APK 版本代碼應包含下列資訊:

  • 發行版本格式 (主要 + 次要)
  • 遞增 (不透明) 版本號碼

目前平台 API 級別與發行版本格式版本密切相關,因為每個 API 級別通常都與新版 ICU 相關聯 (這會導致發行版本檔案不相容)。日後 Android 可能會變更這項設定,讓發行檔案適用於多個 Android 平台版本 (且 Data 應用程式版本代碼架構不會使用 API 級別)。

版本代碼策略範例

這個版本編號架構範例可確保較高版本的發行格式會取代較低版本的發行格式。AndroidManifest.xml 會使用 android:minSdkVersion,確保舊裝置不會收到版本高於其可處理的發布格式版本。

版本檢查

圖 6. 版本代碼策略範例。

範例 目的
Y 保留 允許日後使用替代架構/測試 APK。一開始 (隱含) 為 0。由於基礎類型是帶正負號的 32 位元 int 類型,這個配置最多支援兩項未來編號配置修訂版本。
01 主要格式版本 追蹤 3 位數十進位主要格式版本。發行格式支援 3 個十進位數字,但這裡只使用 2 個數字。由於每個 API 級別的預期增量很大,因此不太可能達到 100。主要版本 1 等同於 API 級別 27。
1 次要格式版本 追蹤 3 位數小數格式版本。發行格式支援 3 個小數位數,但這裡只使用 1 個小數位數。不太可能達到 10 分。
X 保留 正式版發布的應用程式為 0,測試 APK 可能不同。
ZZZZZ 不透明版本號碼 系統會視需求分配十進位數字。包括間隙,可視需要更新插頁式廣告。

如果使用二進位而非十進位,這個配置可能會更緊密,但這個配置的優點是使用者可讀。如果完整號碼範圍用盡,Data 應用程式套件名稱可能會變更。

版本名稱是使用者可解讀的詳細資料表示法,例如 major=001,minor=001,iana=2017a, revision=1,respin=2。下表列出幾個範例。

# 版本代碼 minSdkVersion {主要格式版本},{次要格式版本},{IANA 規則版本},{修訂版本}
1 11000010 O-MR1 major=001,minor=001,iana=2017a,revision=1
2 21000010 P major=002,minor=001,iana=2017a,revision=1
3 11000020 O-MR1 major=001,minor=001,iana=2017a,revision=2
4 11000030 O-MR1 major=001,minor=001,iana=2017b,revision=1
5 21000020 P major=002,minor=001,iana=2017b,revision=1
6 11000040 O-MR1 major=001,minor=001,iana=2018a,revision=1
7 21000030 P major=002,minor=001,iana=2018a,revision=1
8 1123456789 - -
9 11000021 O-MR1 major=001,minor=001,iana=2017a,revision=2,respin=2
  • 範例 1 和 2 顯示同一個 2017a IANA 版本的兩個 APK 版本,但主要格式版本不同。2 在數值上高於 1,這是為了確保新裝置能接收較高格式版本。minSdkVersion 可確保系統不會將 P 版本提供給 O 裝置。
  • 範例 3 是範例 1 的修訂/修正版本,且數值高於 1。
  • 範例 4 和 5 顯示 O-MR1 和 P 的 2017b 版本。由於數字較高,因此會取代先前 IANA 發布/Android 修訂的對應前身。
  • 範例 6 和 7 顯示 O-MR1 和 P 的 2018a 版本。
  • 範例 8 說明如何使用 Y 完全取代 Y=0 配置。
  • 範例 9 說明如何利用 3 和 4 之間留下的間隙,重新旋轉 APK。

由於每部裝置出貨時,系統映像檔中都會預設包含適當版本的 APK,因此不會有 O-MR1 版本安裝在 P 裝置上的風險,因為 O-MR1 的版本號碼低於 P 系統映像檔版本。如果裝置安裝了 O-MR1 版的 /data,然後收到系統更新至 P 版的通知,就會優先使用 /system 版,而非 /data 中的 O-MR1 版,因為 P 版一律高於任何適用於 O-MR1 的應用程式。

使用 tapas 建構「資料」應用程式

OEM 負責管理時區資料應用程式的大部分層面,並正確設定系統映像檔。資料應用程式應使用 tapas 建構版本,產生適合新增至系統映像檔 (用於初始版本) 的 APK,並透過應用程式商店簽署及發布 (用於後續更新)。

Tapas 是 Android 建構系統的精簡版,可使用縮減的來源樹狀結構,產生可發布的應用程式版本。熟悉一般 Android 建構系統的原始設備製造商,應該會認得一般 Android 平台建構作業的建構檔案。

建立資訊清單

通常,減少來源樹狀結構的方法是使用自訂資訊清單檔案,該檔案只會參照建構系統和建構應用程式所需的 Git 專案。按照「建立資料應用程式」中的操作說明進行操作後,OEM 應至少建立兩個 OEM 專屬的 Git 專案,方法是使用 packages/apps/TimeZoneData/oem_template 下的範本檔案:

  • 一個 Git 專案包含應用程式檔案,例如資訊清單和建立應用程式 APK 檔案所需的建構檔案 (例如 vendor/oem/apps/TimeZoneData)。這個專案也包含測試 APK 的建構規則,可供 xTS 測試使用。
  • 一個 Git 專案包含應用程式建構作業產生的已簽署 APK,用於納入系統映像檔建構作業和 xTS 測試。

應用程式建構作業會運用多個其他 Git 專案,這些專案與平台建構作業共用,或包含與原始設備製造商 (OEM) 無關的程式碼程式庫。

下列資訊清單程式碼片段包含支援時區資料應用程式 O-MR1 建構作業所需的最少 Git 專案。原始設備製造商必須將 OEM 專屬的 Git 專案 (通常包含含有簽署憑證的專案) 新增至這個資訊清單,並視需要設定不同分支。

   <!-- Tapas Build -->
    <project
        path="build"
        name="platform/build">
        <copyfile src="core/root.mk" dest="Makefile" />
    </project>
    <project
        path="prebuilts/build-tools"
        name="platform/prebuilts/build-tools"
        clone-depth="1" />
    <project
        path="prebuilts/go/linux-x86"
        name="platform/prebuilts/go/linux-x86"
        clone-depth="1" />
    <project
        path="build/blueprint"
        name="platform/build/blueprint" />
    <project
        path="build/kati"
        name="platform/build/kati" />
    <project
        path="build/soong"
        name="platform/build/soong">
        <linkfile src="root.bp" dest="Android.bp" />
        <linkfile src="bootstrap.bash" dest="bootstrap.bash" />
    </project>

    <!-- SDK for system / public API stubs -->
    <project
        path="prebuilts/sdk"
        name="platform/prebuilts/sdk"
        clone-depth="1" />
    <!-- App source -->
    <project
        path="system/timezone"
        name="platform/system/timezone" />
    <project
        path="packages/apps/TimeZoneData"
        name="platform/packages/apps/TimeZoneData" />
    <!-- Enable repohooks -->
    <project
        path="tools/repohooks"
        name="platform/tools/repohooks"
        revision="main"
        clone_depth="1" />
    <repo-hooks
        in-project="platform/tools/repohooks"
        enabled-list="pre-upload" />

執行 tapas 建構作業

建立來源樹狀結構後,請使用下列指令叫用 tapas 建構:

source build/envsetup.sh
tapas
make -j30 showcommands dist TARGET_BUILD_APPS='TimeZoneData TimeZoneData_test1 TimeZoneData_test2'  TARGET_BUILD_VARIANT=userdebug

建構成功後,系統會在 out/dist 目錄中產生檔案,以供測試。這些檔案可以放入預先建構的目錄,以便納入系統映像檔,和/或透過應用程式商店發布至相容裝置。