Android要求所有已安装的应用程序都使用数字证书做数字签名, 数字证书的私钥由应用开发者持有. Android使用证书作为标识应用程序作者的一种方式, 并在应用程序之间建立信任关系. 证书并不用来控制用户能否安装哪个应用. 证书不需要由证书认证中心签名: 完全可以使用自签名证书(self-signed certificates).
理解Android应用签名的要点有:
没有正确签名的应用, Android系统不会安装或运行. 此规则适用于在任何地方运行的Android系统, 不管是在模拟器还是真实设备上. 因为这个原因, 在真机或模拟器上运行或者调试应用前, 必须为其设置好签名.
在调试期间, Androi SDK工具协助你为应用做好签名工作. Eclipse的ADT插件和Ant build工具都提供2种签名模式 – debug 模式和 release 模式.
一旦应用完成签名, 不要忘了为APK运行zipalign来完成额外的优化.
应用程序签名的一些方面可能会影响应用程序的开发过程, 尤其是当你计划发布多个应用时. 通常情况下, 对于所有开发者而言, 推荐的策略是:在应用程序的整个生命周期,所有的应用程序使用相同的证书签名.
为什么这么做的原因:
另一个影响签名策略的重要考量是, 如何设置签名应用的key的有效期.
当设计的时候, 须牢记这些要点, 以确保使用合适的证书来签名应用程序.
在开始之前, 应当确保Keytool对 SDK build tools 可用. 在大多数情况下, 我们可以通过设置JAVA_HOME环境变量来引用一个合适的JDK, 告诉SDK build tools如何找到Keytool. 或者, 可以添加 Keytool的JDK版本到 PATH 环境变量.
如果在某个自带GNU Java编译器版本的Linux下开发, 请确认系统使用的是JDK版本的Keytool, 而不是 gcj 版本. 如果 Keytool 已经存在于 PATH, 它可能会指向一个 /usr/bin/keytool 的符号链接. 在这种情况下, 检查符号链接目标, 确保它指向JDK中的Keytool.
如果将公开发布应用程序, 还需要 Jarsigner 工具. Jarsigner 和 Keytool 都包含在 JDK 中.
Android build tools 提供了debug签名模式, 帮助简化应用的开发和调试, 而仍然符合Android系统签名.apk的需求. 当使用debug模式来构建app时, SDK 工具调用 Keytool来自动创建一个用于debug的 keystore 和 key. 然后这个debug key被用来自动签名 .apk, 所以不必用自己的key来签名包.
SDK 工具使用预定义的 名称/密码 来创建keystore/key :
如有必要, 可以更改 debug keystore/key 的 location/name 或自己提供一个自定义的 debug keystore/key. 然而, 任何自定义的debug keystore/key必须使用和默认debug key(如之前所述)相同的debug keystore/key 名称和密码. (Eclipse/ADT中, Windows > Preferences > Android > Build)
注意: 当用debug证书签名时, 应用程序不能对外发布.
如果使用 Eclipse/ADT (并且根据之前"签名基础设置"一节所述设置好了Keytool), debug模式下的签名是默认开启的. 运行或者调试程序时, ADT自动使用debug证书对.apk进行签名, 并对安装包使用zipalign, 然后将它安装到选定的模拟器或者连接的设备上. 这一切不用我们亲自动手, ADT可以自行访问Keytool.
如果使用Ant来构建.apk文件, debug签名模式通过ant命令(假设使用由android tool生成的build.xml文件)下使用debug选项开启. 当运行ant debug来编译app时, build脚本生成一个 keystore/key 并为.apk做签名. 然后脚本也会使用zipalign工具优化.apk. 仍然不需要你做额外的事情.
用于debug模式(Eclipse/ADT和Ant的默认值)签名的自签名证书, 有效期为创建之日起的365天. 当证书过期, 将得到一个build错误.
使用Ant时, 错误看起来如下所示:
debug: [echo] Packaging bin/samples-debug.apk, and signing it with a debug key... [exec] Debug Certificate expired on 8/4/08 3:43 PM
在 Eclipse/ADT 中, 将在Android控制台看到类似的错误.
要修正这个问题, 只需删除 debug.keystore 文件. AVDs默认存储的位置是: OS X 和 Linux : ~/.android/ , Windows XP: C:\Documents and Settings\<user>\.android\ , Windows Vista 和 Windows 7: C:\Users\<user>\.android\
下次build时, 工具会重新生成一个新的keystore和debug key.
注意, 如果你的开发机使用的是非公历语言环境(non-Gregorian locale), build工具可能会错误地生成一个已过期的debug证书, 因此在编译的时候你会得到一个错误.
具体的错误解决办法,请查阅查官方相关文档.
当应用准备好对外发布, 必须:
如果使用Eclipse+ADT插件进行开发, 可以使用Export Wizard来处理整个的编译, 签名, 和优化过程. 在处理过程中, Export Wizard甚至允许生成一个新的keystore和私钥.
在给应用程序签名的准备阶段, 必须首先确保有一个用于签名的合适的私钥. 合适的私钥有如下要求:
密钥可以是自签名的. 如果没有一个合适的密钥, 必须使用Keytool生成一个.
要通过Keytool生成一个自签名的key, 使用keytool命令行工具, 并传入下面的任何一个参数选项(以及任何其他需要的参数.)
警告: 需要保证私钥的安全. 在运行Keytool之前, 请确认已经阅读了 保证你的私钥安全 一节. 通常情况下, 生成key时, 对于key和keystore应当使用强密码.
Keytool 选项 | 描述 |
---|---|
-genkey | 生成一个key pair (公钥和私钥) |
-v | 允许详细内容输出. |
-alias <alias_name> | key的别名. 只会用到前8个字符. |
-keyalg <alg> | 生成key时的加密算法. 支持 DSA 和 RSA. |
-keysize <size> | 生成的key的大小(bits). 如果不提供, Keytool使用默认的Key大小:1024. 通常情况下,我们推荐使用 2048或者更大的key尺寸. |
-dname <name> | 描述key的创建者的标识名称. 在自签名证书中, 本参数会出现在发布者和主题字段. 注意, 不要在命令行下指定这个选项. 此时 Jarsigner会提示你输入每一个标识名称字段(CN, OU,等) |
-keypass <password> | key的密码. 安全起见, 不要在命令行中包含这个选项. 此时Keytool会提示你输入密码. 这种方式中, 密码不会被保存在shell历史数据中. |
-validity <valdays> | key的有效期, 以天数为单位. 注意: 推荐使用10000或更大的数字. |
-keystore <keystore-name>.keystore | 保存私钥的keystore名称. |
-storepass <password> | keystore的密码. 安全起见, 不要在命令行中包含这个选项. 此时, Keytool会提示输入这个密码. 在这种方式中, 密码不会被保存在shell历史数据中. |
一个使用Keytool命令生成私钥的例子:
$ keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
运行上面的命令行例子, Keytool会提示输入keystore和key的密码, 以及key的标识名称字段. 然后它为keystore生成一个文件 my-release-key.keystore. keystore和key由输入的密码保护. keystore包含一个单个的key, 有效期10000天. 别名是以后将用到的名称, 当为应用签名时, 来指定这个keystore.
关于Keytool的更多信息, 参考文档: http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security
为了向用户发布应用程序, 必须在release模式编译. 在release模式下, 编译好的应用程序默认是没签名的, 需要用私钥为它签名.
警告: 不能发布一个没有签名或者用debug key签名的应用程序.
要从Eclipse导出一个未签名的 .apk, 在Package Explorer中的project上点击鼠标右键, 选择Android Tools > Export Unsigned Application Package. 然后给未签名的.apk指定一个文件路径. (或者在Eclipse中打开AndroidManifest.xml文件, 点开Overview标签, 然后点击Export an unsigned .apk.)
注意, 完全可以在Export Wizard中执行整个的编译和签名步骤. 参见: 使用Eclipse ADT编译和签名.
如果使用Ant, 可以通过ant命令行的release选项开启release模式.
举个例子, 如果从build.xml文件的目录中运行Ant, 命令行看起来将是这样:
ant release
默认地, build脚本编译应用程序.apk时不做签名. 项目中 bin/ 下的的输出文件将是: <your_project_name>-unsigned.apk. 因为应用程序.apk仍然是未签名的, 必须人工使用私钥为它签名, 然后使用zipalign优化它.
然而, 如果在项目的build.properties文件中提供了keystore的路径和key的别名, 那么Ant build 脚本也可以处理签名和优化(align)过程, 在提供了相关信息的情况下, 当执行ant release, build脚本将提示输入keystore和别名的密码, 然后它将为包签名, 并进行优化. bin/中的最后输出将是 <your_project_name>-release.apk.
使用这些自动化步骤, 可以跳过下面的人工处理过程(第3和4步).
当准备好一个应用程序包, 在确保机器上Jarsigner工具和keystore里的私钥有效的情况下. 可以使用Jarsigner工具来对它做签名.
运行Jarsigner对应用签名, 同时引用应用的.apk和用来签名.apk的私钥的keystore. 下面的表列出了可以使用的选项.
Jarsigner选项 | Description |
---|---|
-keystore <keystore-name>.keystore | 包含私钥的keystore的名称. |
-verbose | 允许详细输出. |
-storepass <password> | keystore的密码, 安全起见, 不要把此参数包含在命令行中. 此时, Jarsigner提示输入密码. 这种方式下,密码不会被保存在shell的历史记录中. |
-keypass <password> | 私钥的密码. 安全起见, 不要把此参数包含在命令行中. 此时, Jarsigner提示输入密码. 这种方式下,密码不会被保存在shell的历史记录中. |
下面是使用Jarsigner的例子,签名 my_application.apk, 使用之前创建的例子keystore.
$ jarsigner -verbose -keystore my-release-key.keystore my_application.apk alias_name
运行上面的命令行例子, Jarsigner会提示输入keystore和key的密码. 然后它修改.apk文件作签名. 注意, 可以多次用不同的key签名一个.apk文件.
要验证.apk是否已签名, 可以使用如下命令:
$ jarsigner -verify my_signed.apk
如果.apk确实已经正确地签名, Jarsigner输出"jar verified". 如果想要知道更多明细, 你可以尝试如下几个命令:
$ jarsigner -verify -verbose my_application.apk
或
$ jarsigner -verify -verbose -certs my_application.apk
上面的命令, 使用 -certs 参数, 将显示 "CN=" 行, 描述是谁创建了key.
注意: 如果看到 "CN=Android Debug", 这意味着 .apk 是由Android SDK生成的debug key签名的. 如果想发布你的应用, 必须用你的私钥签名, 而不是debug key.
Jarsigner的更多信息, 请参见文档: http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security
一旦使用你的私钥对.apk做了签名, 紧接着请对文件运行zipalign. 这个工具确保所有的未压缩数据相对于文件起始位置以特定的字节对齐方式开始. 当安装在某个设备上时, 确保4字节边界对齐的方式, 提供了性能上的优化. 当对齐后, 如果它们包含有对齐限制的二进制数据, Android系统甚至可以使用mmap()读取文件, 而不是从包里复制所有的数据. 另一个好处是在运行程序时, 减少了内存消耗.
zipalign 工具由Android SDK提供, 在 tools/ 目录中. 要调整对齐签名后的.apk, 执行如下命令:
zipalign -v 4 your_project_name-unaligned.apk your_project_name.apk
-v 标志开启详细输出(可选). 4是字节对齐(不要使用4以外的值). 第一个文件参数是签名后的.apk(输入), 第二个文件是目标.apk文件(输出). 如果要覆盖现存的.apk, 可以使用 -f 标志.
警告: 在使用zipalign优化包之前, 输入的.apk 必须使用私钥签名过. 如果在zipalign之后签名, 将使之前优化对齐操作无效, 回到未优化的状态.
如果使用Eclipse和ADT插件, 可以用Export Wizard来导出一个签名的.apk(如果必要,甚至可以创建一个新的keystore.) Export Wizard为你处理所有Keytool和Jarsigner的交互操作, 这允许使用一个GUI界面来操作签名包的过程, 而不必人工处理各种编译, 签名, 以及优化对齐工作. 一旦向导编译并签名完.apk包, 它将也使用zipalign对包进行优化对齐处理. 因为Export Wizard使用到Keytool和Jarsigner, 应当确保在电脑上可以访问到这2样工具.
若要在Eclipse中创建一个签名并优化对齐后的.apk:
对于你和你的用户来说, 维护你的私钥的安全相当关键和重要. 如果你允许别人使用你的key, 或者如果你将keystore和密码放在一个不安全的地方, 以至于第三方可以找到并使用它们, 那么你的作者身份和用户信任度将受到连累.
如果第三方在你不知情或没得到你的允许的情况下控制和使用你的key, 那么随便一个人就都可以签名和发布恶意的应用程序来替换你发布的应用, 或者干脆取代你的应用. 然后这个人可以用你的身份签名和发布应用程序, 攻击其他应用甚至直接攻击系统, 以及损坏或偷取用户数据.
开发者(或团体)的名声取决于你对你的私钥的适当保密, 任何时候, 直到key过期. 下面是一些保证key的安全性的小提示.
通常情况下, 当生成,使用和保存你的key时, 如果根据常识做了提前的预防, 那么它将会保证安全.
文档信息