从 API 级别 8 开始,您可以允许您的应用程序安装在外部存储器(例如,设备的 SD 卡)上。这是一个可选功能,您可以使用 android:installLocation
清单属性为您的应用程序声明。如果您*不*声明此属性,则您的应用程序将仅安装在内部存储器上,并且无法移动到外部存储器。
要允许系统将您的应用程序安装在外部存储器上,请修改您的清单文件以在 <manifest>
元素中包含 android:installLocation
属性,其值为“preferExternal
”或“auto
”。例如
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" ... >
如果您声明“preferExternal
”,则您请求将您的应用程序安装在外部存储器上,但系统不保证您的应用程序将安装在外部存储器上。如果外部存储器已满,则系统会将其安装在内部存储器上。用户还可以将您的应用程序在这两个位置之间移动。
如果您声明“auto
”,则表示您的应用程序可能安装在外部存储器上,但您没有安装位置的偏好。系统将根据几个因素决定在哪里安装您的应用程序。用户还可以将您的应用程序在这两个位置之间移动。
当您的应用程序安装在外部存储器上时
- 只要外部存储器安装在设备上,对应用程序性能就没有影响。
- 应用程序的
.apk
文件存储在外部存储器上,但所有私有用户数据、数据库、优化的.dex
文件以及提取的原生代码都存储在设备的内部存储器上。 - 存储应用程序的唯一容器使用随机生成的密钥进行加密,只有最初安装该应用程序的设备才能解密该密钥。因此,安装在 SD 卡上的应用程序仅适用于一台设备。
- 用户可以通过系统设置将应用程序移动到内部存储器。
警告:当用户启用 USB 大容量存储功能与计算机共享文件或通过系统设置卸载 SD 卡时,外部存储器会从设备上卸载,并且所有在外部存储器上运行的应用程序都会立即被终止。
向后兼容性
应用程序安装到外部存储器的功能仅在运行 API 级别 8(Android 2.2)或更高版本的设备上可用。在 API 级别 8 之前构建的现有应用程序将始终安装在内部存储器上,并且无法移动到外部存储器(即使在 API 级别为 8 的设备上)。但是,如果您的应用程序设计为支持低于 8 的 API 级别,您可以选择在 API 级别 8 或更高版本的设备上支持此功能,同时仍然与使用低于 8 的 API 级别的设备兼容。
允许安装在外部存储器上并保持与低于 API 级别 8 的版本兼容
- 在
<manifest>
元素中包含android:installLocation
属性,并将其值设置为 "auto
" 或 "preferExternal
"。 - 保持您的
android:minSdkVersion
属性不变(小于“8”),并确保您的应用程序代码仅使用与该级别兼容的 API。 - 为了编译您的应用程序,请将构建目标更改为 API 级别 8。这是必要的,因为旧的 Android 库不理解
android:installLocation
属性,并且在该属性存在时不会编译您的应用程序。
当您的应用程序安装在 API 级别低于 8 的设备上时,android:installLocation
属性将被忽略,并且应用程序将安装在内部存储器上。
注意:尽管旧平台会忽略此类 XML 标记,但您必须注意,在您的 minSdkVersion
小于“8”时,不要使用 API 级别 8 中引入的编程 API,除非您在代码中执行了提供向后兼容性的必要工作。
不应安装在外部存储器上的应用程序
当用户启用 USB 大容量存储功能与计算机共享文件(或以其他方式卸载或移除外部存储器)时,任何安装在外部存储器上且当前正在运行的应用程序都将被终止。在禁用大容量存储功能并将外部存储器重新挂载到设备上之前,系统实际上会不知道该应用程序。除了终止应用程序并使其对用户不可用之外,这还可能以更严重的方式破坏某些类型的应用程序。为了使您的应用程序能够始终如一地按预期运行,如果您使用以下任何功能,不应允许您的应用程序安装在外部存储器上,因为在外部存储器卸载时会出现上述后果。
- 服务
- 当外部存储器重新挂载时,您正在运行的
Service
将被终止,并且不会重新启动。绑定到此服务的应用程序可以注册ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
广播意图,该意图在安装在外部存储器上的应用程序再次对系统可用时通知所有未安装在外部存储器上的应用程序。收到此广播后,应用程序可以尝试绑定到您的服务。 - 闹钟服务
- 使用
AlarmManager
注册的闹钟将被取消。当外部存储器重新挂载时,您必须手动重新注册所有闹钟。 - 输入法引擎
- 您的 IME 将被默认的 IME 替换。当外部存储器重新挂载时,用户可以打开系统设置再次启用您的 IME。
- 动态壁纸
- 您正在运行的 动态壁纸 将被默认的动态壁纸替换。当外部存储器重新挂载时,用户可以再次选择您的动态壁纸。
- 应用程序小部件
- 您的 应用程序小部件 将从主屏幕中移除。当外部存储器重新挂载时,您的应用程序小部件将不会可供用户选择,直到系统重置主应用程序(通常直到系统重新启动)。
- 账户管理器
- 使用
AccountManager
创建的账户将在外部存储器重新挂载之前消失。 - 同步适配器
- 您的
AbstractThreadedSyncAdapter
及其所有同步功能在外部存储器重新挂载之前将无法工作。 - 设备管理员
- 您的
DeviceAdminReceiver
及其所有管理员功能将被禁用,这可能会对设备功能产生不可预见的后果,并且这些后果可能会在外部存储器重新挂载后仍然存在。 - 侦听“启动完成”的广播接收器
- 系统在将外部存储器挂载到设备之前传递
ACTION_BOOT_COMPLETED
广播。如果您的应用程序安装在外部存储器上,则它永远无法接收此广播。
如果您的应用程序使用上述任何功能,则不应允许您的应用程序安装在外部存储器上。默认情况下,系统不会允许您的应用程序安装在外部存储器上,因此您无需担心您的现有应用程序。但是,如果您确定您的应用程序永远不应该安装在外部存储器上,则应通过使用值 "internalOnly
"声明 android:installLocation
来明确说明这一点。虽然这不会更改默认行为,但它明确说明了您的应用程序只能安装在内部存储器上,并提醒您和其他开发人员已做出此决定。
应安装在外部存储器上的应用程序
简单来说,任何不使用上一节中列出的功能的应用程序在安装在外部存储器上时都是安全的。大型游戏通常是应允许安装在外部存储器上的应用程序类型,因为游戏通常在不活动时不提供其他服务。当外部存储器不可用且游戏进程被终止时,当存储器再次可用且用户重新启动游戏时,不应有任何明显的影响(假设游戏在正常的 Activity 生命周期 中正确保存了其状态)。
如果您的应用程序需要 APK 文件占用几兆字节的空间,则应仔细考虑是否启用应用程序安装到外部存储器,以便用户可以保留其内部存储器上的空间。
有关其他相关信息,请参阅: <manifest>