從 API 8 開始(參考官方文件:App Install Location | Android Developers),你可以將你的應用安裝在外部儲存中(例如,安裝到裝置的 SD 卡上)。這是一個可選的特徵,你可以在你的應用的 AndroidManifest.xml 中宣告 android:installLocation 屬性。如果你沒有宣告這個屬性,你的應用程式將會被安裝在內部儲存,並且不能被移到外接儲存中。
修改 AndroidManifest.xml 檔案中 <manifest> 元素下的 android:installLocation 屬性,賦值為 “preferExternal” 或 “auto”,即可允許系統將應用安裝到外部儲存中。程式碼如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" ... >
如果 android:installLocation 屬性宣告為 preferExternal,意味著你要求應用程式安裝在外接儲存,但是系統不保證你的程式一定會被安裝在外部儲存中。如果外部儲存空間已滿,程式將會被安裝在內部儲存。使用者也可以在兩個儲存之間移動你的應用程式。如果宣告瞭 auto,表明你的應用程式可以安裝在外部儲存,但是你沒有一個安裝位置的偏好。系統會根據一些因素來決定你的應用程式安裝在哪。使用者也可以在兩個儲存之間移動你的程式。
當你的應用被安裝在外部儲存時:
- 只要外部儲存一直掛載在裝置上,就不會對應用的效能造成影響。
- .apk 檔案會儲存在外部儲存中,但所有私有的使用者資料,資料庫,優化的 .dex 檔案,和提取的本地的程式碼都會儲存在內部儲存中。
- 儲存應用的特定容器被一個隨機生成的 Key 加密,並且只能被最初安裝這個應用的裝置解密。這樣就可以保證一個安裝在 SD 卡上的應用只為唯一的裝置服務。
- 使用者可以通過系統設定將應用移到內部儲存中。
▐ 注意:當使用者啟用 USB 大容量儲存與電腦共享檔案或通過系統設定解除安裝 SD 卡時,外部儲存就會從裝置解除安裝同時所有執行在外部儲存的應用會被立即殺死。
Backward Compatibility
只有在執行 API 8(Android 2.2)或更高版本的裝置上才可以將應用安裝到外部儲存中,在 API 8 之前建立的應用只能被安裝到內部儲存中,並且不能移動到外部儲存中(即使在 API 8 的裝置上)。如果要求應用支援 API < 8 的裝置,你可以讓執行 API >= 8 的裝置使用這個特性,也可通過如下的設定來相容 API < 8 的裝置。
- 在 AndroidManifest.xml 檔案 <manifest> 元素中設定的 android:installLocation 屬性為 auto 或 perferExternal。
- 保持 android:minSdkVersion 屬性不變(一個小於8的數)並保證你應用程式碼所使用的 API 與之相符。
- 在編譯你的應用之前,將 build target 的 API 級別修改為 8。因為低版本的 Android 庫不識別 android:installLocation 屬性,因此也就不會在該屬性存在的情況下編譯應用。
當你的應用安裝在一個執行 API < 8 的裝置上時,android:installLocation 屬性會被忽略,並且應用程式會被安裝到內部儲存中。
▐ 注意:儘管通過 XML 標記可以讓低版本的平臺忽略這個問題,但仍然要小心的是,當 minSdkVersion < 8 的時候,不要在程式設計過程中引入級別為 8 的 API,除非你的程式碼需要向後相容。
Applications That Should NOT Install on External Storage
當使用者啟用 USB 大容量儲存與計算機共享檔案(通過其他方式解除安裝或移除外部儲存),任何安裝在外部儲存並正在執行的程式都會被殺死。直到大容量儲存處於不可用狀態,外部儲存重新被掛載到裝置上,系統才會識別這些應用。除了殺死應用使得它對使用者不可用之外,還會通過一些更危險的方式破壞某些型別的應用程式。如果你的應用使用瞭如下特徵,會在外部儲存解除安裝的時出現引用問題,所以你應該禁止你的應用安裝在外部儲存中。
服務(Services)
正在執行的服務會被殺死,並且在外部儲存被重新掛載後也不會重啟。但是你可以註冊一個 ACTION_EXTERNAL_APPLICATIONS_AVAILABLE 的廣播,這樣應用程式就可以在外接儲存可用時接收到通知並重啟服務。
警報服務(Alarm Services)
使用 AlarmManager 註冊的 Alarm Services 將被取消。你必須在外接儲存被重新掛載的時候重新手動的註冊 Alarm Services。
輸入法引擎(Input Method Engines)
你的 IME 將會被替換為預設的 IME。當外部儲存重新掛載的時候,使用者可以在系統設定中啟用自己的 IME。
動態桌布(Live Wallpapers)
動態桌布會被替換為預設的動態桌布。外部儲存重新掛載的時候,使用者可以重新選擇自己之前的桌布。
視窗小部件(App Widgets)
應用程式的 App Widget 會被移除,即使外部儲存重新被掛載,使用者也無法使用該應用的 App Widget,除非系統重置 Home 應用(通常要等到系統重啟)。
賬戶管理器(Account Managers)
通過 AccountManager 建立的賬戶會消失,直到外部儲存重新掛載後在可用。
同步介面卡(Sync Adapters)
AbstractThreadedSyncAdapter 以及它的一切非同步方法將停止工作,同樣也的等到外部儲存重新掛載後才能恢復正常。
裝置管理員(Device Administrators)
你的 DeviceAdminReceiver 及其所有管理功能將被禁用,這可能對裝置造成不可預見的後果。
監聽“啟動完成”的廣播接收者(Broadcast Receivers listening for "boot completed")
系統會在外部儲存掛載到裝置之前發出 ACTION_BOOT_COMPLETED 廣播。如果你的應用程式安裝在外部儲存器,它永遠不會收到此廣播。
如果你的應用程式使用了上面列出的功能,你不應該允許你的應用安裝到外部儲存。預設情況下,系統將不允許你的應用安裝到外部儲存,所以你不需要擔心你現有的應用程式。然而,如果你非常確定你的應用不應該安裝到外部儲存,那麼你應該宣告 android:installLocation 的值為 “internalOnly”。但這並不會改變預設的行為,它只是很明確的提醒你和其他的開發者這個應用只應該被安裝在內部儲存中。
Applications That Should Install on External Storage
簡單來說,只要你的應用沒有使用上節中列出的特性,那麼安裝到外部儲存中就是安全的。大型遊戲通常會允許安裝到外部儲存中,因為遊戲通常不會在閒置狀態提供額外的服務。當外部儲存不可用時,遊戲程式會被殺死,當外接儲存變得可用而且使用者重啟遊戲時,不應該有明顯的影響(假設遊戲在它正常的 Activity 生命週期適當的儲存了狀態)。
如果你應用程式的 APK 檔案佔用很大位元組的儲存空間,你應該仔細的考慮是否將應用安裝到外部儲存中,以便為使用者節省內部儲存空間。