应用安装位置

从 API Level 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 Level 8 (Android 2.2) 或更高版本的设备上可用的功能。在 API Level 8 之前构建的现有应用将始终安装到内部存储,并且无法移动到外部存储(即使在 API Level 8 的设备上)。但是,如果您的应用设计用于支持低于 8 的 API Level,您可以选择为 API Level 8 或更高版本的设备支持此功能,同时仍然与使用低于 8 的 API Level 的设备兼容。

允许安装到外部存储并保持与低于 API Level 8 的版本兼容

  1. <manifest> 元素中包含 android:installLocation 属性,其值为 "auto" 或 "preferExternal"。
  2. 保持您的 android:minSdkVersion 属性不变(小于 "8"),并确保您的应用代码仅使用与该级别兼容的 API。
  3. 为了编译您的应用,请将您的构建目标更改为 API Level 8。这是必要的,因为旧的 Android 库不理解 android:installLocation 属性,并且当它存在时不会编译您的应用。

当您的应用安装在 API Level 低于 8 的设备上时,android:installLocation 属性将被忽略,应用将安装在内部存储中。

注意:尽管此类 XML 标记将被旧平台忽略,但您必须小心,在您的 minSdkVersion 小于 "8" 时,不要使用在 API Level 8 中引入的编程 API,除非您执行必要的工作在您的代码中提供向后兼容性。

不应安装到外部存储的应用

当用户启用 USB 大容量存储以与计算机共享文件(或以其他方式卸载或移除外部存储)时,所有安装在外部存储上且当前正在运行的应用都将被终止。系统将不再识别该应用,直到大容量存储被禁用且外部存储在设备上重新挂载。除了终止应用并使其对用户不可用之外,这还会以更严重的方式破坏某些类型的应用。为了使您的应用始终按预期运行,如果您的应用使用以下任何功能,则不应允许将其安装到外部存储,因为在外部存储卸载时会产生以下后果:

服务
您正在运行的 Service 将被终止,并且在外部存储重新挂载时不会重新启动。绑定到此服务的应用可以注册 ACTION_EXTERNAL_APPLICATIONS_AVAILABLE 广播 Intent,当安装在外部存储上的应用再次对系统可用时,此 Intent 会通知所有安装在外部存储上的应用。收到此广播后,应用可以尝试绑定到您的服务。
闹钟服务
您使用 AlarmManager 注册的闹钟将被取消。您必须在外部存储重新挂载时手动重新注册任何闹钟。
输入法引擎
您的IME将被默认 IME 替换。当外部存储重新挂载时,用户可以打开系统设置再次启用您的 IME。
动态壁纸
您正在运行的动态壁纸将被默认动态壁纸替换。当外部存储重新挂载时,用户可以再次选择您的动态壁纸。
应用小部件
您的应用小部件将从主屏幕中移除。当外部存储重新挂载时,您的应用小部件将无法供用户选择,直到系统重置主页应用(通常直到系统重新启动)。
帐户管理器
您使用 AccountManager 创建的帐户将消失,直到外部存储重新挂载。
同步适配器
您的 AbstractThreadedSyncAdapter 及其所有同步功能在外部存储重新挂载之前将无法工作。
设备管理员
您的 DeviceAdminReceiver 及其所有管理功能将被禁用,这可能对设备功能产生不可预见的后果,这些后果可能在外部存储重新挂载后仍然存在。
监听“启动完成”的广播接收器
系统在外部存储挂载到设备之前发送 ACTION_BOOT_COMPLETED 广播。如果您的应用安装在外部存储上,它将永远无法接收此广播。

如果您的应用使用上述任何功能,则不应允许您的应用安装到外部存储。默认情况下,系统不会允许您的应用安装到外部存储,因此您无需担心现有应用。但是,如果您确定您的应用绝不应安装到外部存储,那么您应该通过声明 android:installLocation 并将其值设置为 "internalOnly" 来明确这一点。尽管这不会改变默认行为,但它明确指出您的应用只能安装到内部存储,并提醒您和其他开发者已做出此决定。

应安装到外部存储的应用

简单来说,任何不使用上一节中列出的功能的程序在安装到外部存储时都是安全的。大型游戏通常是应该允许安装到外部存储的应用类型,因为游戏在不活动时通常不提供额外服务。当外部存储不可用且游戏进程被终止时,当存储再次可用且用户重新启动游戏时(假设游戏在正常的Activity 生命周期中正确保存了其状态),应该没有可见影响。

如果您的应用需要几兆字节的 APK 文件,您应该仔细考虑是否允许应用安装到外部存储,以便用户可以保留内部存储空间。

有关其他相关信息,请参阅: <manifest>