图片 19

Android Studio的两种模式及签名配置

不止一次有用到Android签名相关的知识,每次都几乎从零开始在Google上搜索找,不想在继续这样了,找了个时间好好整理了一下自己用到的一些碎片知识,于是乎放到这里,一是备忘,二是帮助别人。

参考链接:

我们使用Android Studio
运行我们的app,无非两种模式:debug和release模式。

从APK文件中获取签名信息

图片 1编译流程图

debug模式

debug模式使用一个默认的debug.keystore进行签名。

这个默认签名(keystore)是不需要密码的,它的默认位置在C:Users<用户名>.Androiddebug.keystore,如果不存在Android
studio会自动创建它。

例如我的debug.keystore就在C:UsersAdministrator.androiddebug.keystore。

 

使用方法

keytool -list -printcert -jarfile your_apk_file

上图展示了一个典型的 App 编译过程,主要分为以几步:

release模式

在我们正式发布项目的时候是不能使用debug.keystore的。开发过程中我们也可以使用发布模式运行。可以通过如下设置:

BuildVariants-Build Variant-debug/release

图片 2

如果项目需要细分开发dev和生产pro版本,每个版本中都包含debug和release模式,可以这么设置:

图片 3

图片 4

就细分成四种模式:

图片 5

release模式需要配置签名才能运行,这时就需要一个keystore

如果没有就需要创建,已经创建过keystore请跳过此步骤

 

输出信息

  • 签名Owner,Issuer等信息
  • 签名的fingerprints,如md5及sha1等值
  • 签名有效期等信息
  1. 编译器将源代码转化为 DEX 文件,编译资源文件(res 以及 assets
    文件下的资源)。
  2. APK Packager 整合所有的 DEX 文件和编译过的资源文件,并且对 APK
    进行签名。
  3. 签名文件必须使用 Debug 版或者 Release 版,使用 Debug Keystore 生成的
    app 被用来测试和分析,使用 Release Keystore 生成的 app
    可以进行发布供其他用户使用。
  4. 在生成最终的 APK 之前,APK Packager 会使用 zipalign 工具优化整个 app
    ,以便 app 在使用的过程中更加节省内存。

1.创建keystore,并生成我们的apk(打包)

 第一步: Build —>> Generate Signed APK

图片 6

第二步:Create New···(已经创建过keystore选Choose
existing···)

图片 7

第三步:填写相关信息

设置keystore路径、密码,设置key:别名、密码、有效期,证书等

Key store path:存放路径

Key

  Alias:别名

  Validity(years):有效期(一般默认25年)

  Certificate:证书

    First and Last Name:姓名

    Organization Unit:组织单位

    Organization:组织

    City or Locality:城市或地区

    State or Province:州或省

    Country Code(XX):国家代码(XX),中国:86

图片 8

 

第四步:输入key、keystore密码

图片 9

第五步:选择发布app的路径,默认即可 选择release方式发布

图片 10

OK,发布成功,可以到 刚才设置的目标文件夹下面找到发布的apk

 

那对一些人来说,这样也太麻烦了,每次都得输入相关信息,还得进行选择,那么有更简单快捷的方法吗?答案是有的。

我们可以在项目的app目录下的build.gradle中进行签名的配置。 

2.release模式配置keystore

Project
structure-signing,输入已创建的keystore信息

图片 11

使得签名生效需配置Build Types

图片 12

点击OK即可,然后查看对应build.gradle的配置文件应该是这样的。当然了,你也可以通过直接在build.gradle里面写下面这段。

 1 signingConfigs {
 2         release {
 3             keyAlias 'androiddebugkey'
 4             keyPassword 'android'
 5             storeFile file('C:/Users/ssc/.android/debug.keystore')
 6             storePassword 'android'
 7         }
 8     }
 9 
10     ·········
11 
12 buildTypes {
13         release {
              //是否混淆
14             minifyEnabled false
              //是否移除无用资源
15             zipAlignEnabled true
              //混淆的配置文件
16             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17             signingConfig signingConfigs.release
18         }
19 }

 

上述的配置虽然配置简单,但是存在不安全性,假如你的项目是开源的,你把签名文件的配置密码之类的信息用明文写在build.gradle里面,那是不是很不安全呢?

可以将签名文件的配置密码之类的信息直接写在local.properties下,因为在Git版本控制的项目中,我们可以看到我们项目project模式根目录下有一个.gitignore的文件,里面的配置大概如下所示

图片 13图片 14

我们可以看到/local.properties,意思就是说local.properties默认是不添加到版本控制里面的,因为local.properties存储的是我们环境资源的一些相关信息,如sdk的路径。故我们可以在local.properties下配置签名信息而不用担心密钥外泄。对于开源项目来说,是非常好的。

在local.properties下直接添加相关信息

图片 15

在build.gradle里,为了不用明文显示,我们首先要获得key的相关配置,所以我们可以在app的build.gradle里

android {}之上新增代码

图片 16图片 17

 1 def keystoreFilepath = ''
 2 def keystorePSW = ''
 3 def keystoreAlias = ''
 4 def keystoreAliasPSW = ''
 5 // default keystore file, PLZ config file path in local.properties
 6 def keyfile = file('s.keystore.temp')
 7 
 8 Properties properties = new Properties()
 9 // local.properties file in the root director
10 properties.load(project.rootProject.file('local.properties').newDataInputStream())
11 keystoreFilepath = properties.getProperty("keystore.path")
12 
13 if (keystoreFilepath) {
14     keystorePSW = properties.getProperty("keystore.password")
15     keystoreAlias = properties.getProperty("keystore.alias")
16     keystoreAliasPSW = properties.getProperty("keystore.alias_password")
17     keyfile = file(keystoreFilepath)
18 }

View Code

app/build.gradle下的signingConfigs可以改为:

 signingConfigs {
        release {
            keyAlias keystoreAlias
            keyPassword keystoreAliasPSW
            storeFile keyfile
            storePassword keystorePSW
        }
    }

  

设置后Signing中keystore值无需关心

图片 18

相应的,buildTypes也可以配置成这样

 1 buildTypes {
 2         release {
 3             minifyEnabled false
 4             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 5 //            signingConfig signingConfigs.release
 6             //签名文件存在,则签名
 7             if (keyfile.exists()) {
 8                 println("WITH -> buildTypes -> release: using jks key")
 9                 signingConfig signingConfigs.release
10             } else {
11                 println("WITH -> buildTypes -> release: using default key")
12             }
13             23       }
24     }

到此,前面配置完成。

 本文为博主原创文章,请尊重版权,未经博主允许不得转载,转载请注明出处:

附:查询keystore的相关信息,如查看sha1的值;可以在运行窗口,定位到keystore所在的路径,执行cd
C:Usersssc.android

执行这条语句后就能显示Key的所有信息(以android默认keystore为例)

keytool -list -v -keystore xxx.jks

图片 19

 

 

 

示例效果

16:29 $ keytool -list -printcert -jarfile akoi_1.2.apk
Signer #1:

Signature:

Owner: CN=Andrew Wallace, OU=droidyue.com, O=droidyue.com, L=Beijing, ST=Beijing, C=86
Issuer: CN=Andrew Wallace, OU=droidyue.com, O=droidyue.com, L=Beijing, ST=Beijing, C=86
Serial number: 11a8a4a3
Valid from: Tue Feb 10 18:07:43 CST 2015 until: Sun Jun 13 18:07:43 CST 3013
Certificate fingerprints:
   MD5:  46:C5:BE:EF:B5:C9:00:E1:FA:42:50:50:57:54:CA:15
   SHA1: C1:14:5D:0A:C2:BF:F6:06:43:20:AE:2C:07:12:97:58:C2:1B:39:D1
   SHA256: 0E:88:7D:C2:4C:D6:84:A7:58:D4:24:1E:9D:38:F9:05:98:1E:B2:A2:D7:CB:0F:81:74:60:5B:38:89:FF:21:1C
   Signature algorithm name: SHA256withRSA
   Version: 3

Android Studio 的 gradle 插件方便我们在以下几个方面配置我们的编译选项:

从签名文件中获取签名信息

Build Types – 编译类型

编译类型,包括我们最熟悉的 release 和 debug
两种类型,我们可以根据这两种类型定义出更多的类型。配置对应的
build.gradle 文件在 moudle 下,需要添加新的或者修改 Build Type
,只需要在 android{ ... }里面操作。一个示例如下:

android { ... defaultConfig {...} buildTypes { release { //开启混淆 minifyEnabled true //混淆规则文件 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { //apk的后缀 applicationIdSuffix ".debug" } //debug的一个扩展 jnidebug { // 复制debug的属性和签名配置 initWith debug applicationIdSuffix ".jnidebug" //开启Jni调试 jniDebuggable true } }}

其中 initWith 可以方便我们继承其他的配置,只需要添加需要的部分。

使用方法

keytool -list -v -keystore your_kestore_file

注意,上述命令执行后,会提示输入密码,其实输入错误也没有关系,不影响结果。

Product Flavors – 构建不同版本

配置 apk 的版本信息,可以为每一个版本指定不同的 applicationId
和版本名称。关于 applicationId ,可以把它也理解为包名,不过和 Manifest
文件中的包名作用不同,它是用来给应用商店和设备区分不同的 app ,而
Manifest 中的 pakage 属性用来在源代码中引用 R 类和其他类。即同一份代码
applicationId 可以让它变成不同的 app 。示例配置如下:

android { ... defaultConfig {...} buildTypes {...} productFlavors { demo { applicationId "com.example.myapp.demo" versionName "1.0-demo" } full { applicationId "com.example.myapp.full" versionName "1.0-full" } }}

通过上面的配置之后,如果 buildTypes 里面配置了两个编译类型,假如是 debug
和 release ,将会产生四个 apk 文件,每一种 buildType 都会和每种 flavor
进行组合拼接,进而产生不同的变种版本(Build
Variant),上面对应的四个不同的变种版本分别是:demoDebug、demoRelease、fullDebug、fullRelease。

输出信息

  • 签名Owner,Issuer等信息
  • 签名的fingerprints,如md5及sha1等值
  • 签名有效期等信息

Mutiple Manifest Files – 合并多个清单文件

配置多个 Manifest 文件。经常会在项目中依赖其他项目,这个时候就会有多个
Manifest
文件,那在编译的时候该如何处理呢?这个时候需要进行合并,而且还必须有一套相应的合并规则解决和避免合并冲突。对于不同的
Manifest
文件中同一个属性的不同值,在合并的时候还需要优先级来进行判断,用高优先级的去覆盖低优先级的。关于优先级定义如下:

  • 最高优先级:buildType 的设置
  • 次高优先级:productFlavor 的设置
  • 中等优先级:在 src/main 目录下的 Manifest 文件
  • 最低优先级:各种依赖和第三方库的设置

合并规则:概括来说是这样:

  1. 合并之前,先将每个 module 里面的 buildType 内容写到 Manifest
    里面去,比如你在 buildType 里面的 minSdkVersion 和targetSdkVersion
    以及 versionCode 和 VersionName 等等(此时合并后的 Manifest
    文件可以在 app/intermediates/manifests/* 目录下查看)。
  2. 对于同一个属性,当高优先级和低优先级都为非默认值时,如果可以匹配,那直接合并,不能匹配,就会产生冲突(这种是针对两个不同的
    module 来说),下面会专门给出例子。
  3. 不管高优先级还是低优先级,如果其中一个没有设置该属性或者设置为默认的属性值,而另外一个设置了非默认的属性值,则合并的结果就是非默认的属性值,在项目编译后,可以查看
    Manifest
    的合并记录,该文件目录为:app/intermediates/outputs/logs/manifest*.txt。

示例:现在给出一些例子说明上述规则,我的主 module 名为 app
,新建一个依赖的 module 叫 uisdk ,现在分别给出两个 module 的
build.gradle 文件:app/build.gradle

apply plugin: 'com.android.application'android { compileSdkVersion 24 buildToolsVersion "24.0.0" defaultConfig { applicationId "com.example.rth.study" minSdkVersion 15 targetSdkVersion 24 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } productFlavors { demo { minSdkVersion 7 applicationId "com.rth.app" } }}dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:24.0.0' compile project}

uisdk/build.gradle

apply plugin: 'com.android.library'android { compileSdkVersion 24 buildToolsVersion "24.0.0" defaultConfig { minSdkVersion 8 targetSdkVersion 24 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:24.0.0'}

在 app/build.gradle 里面,defaultConfig 的 minSdkVersion
为15,但我在变种版本(productFlavors 里的 demo)里设置的 minSdkVersion
为7,最终 app 的 Manifest 的 minSdkVersion 就为7,再看 uisdk 里面的
build.gradle ,minSdkVersion 为8,就是说 app 这个 module 和 uisdk 这个
module library 在同一个属性上使用了不同的非默认值,而且 library 的
Manifest
属于最低优先级,它设置的值又比优先级比它高的值还要高,就会出错,出错信息的描述也很清晰:

Error:Execution failed for task ':app:processDemoDebugManifest'.Manifest merger failed : uses-sdk:minSdkVersion 7 cannot be smaller than version 8 declared in library ...Suggestion: use tools:overrideLibrary="com.example.uisdk" to force usage

根据错误信息,我们有两种方式解决这个问题:

  1. 把 app 里面的值调高,或者把 uisdk 里面的值调低。
  2. 就像上面建议的那样,使用 overrideLibrary
    这个标签。该标签的作用在名字上已经体现出来了,就是直接覆盖 library
    里面的设置,现在我们在 app/src/main/Manifest 里面加上这么一句:

<uses-sdk tools:overrideLibrary="com.example.uisdk"/>

就能编译通过了,这适用于比较特殊的情况,就是在依赖库里可能要适用一些新特性,这些特性在
app 的 minSdkVersion 下不能使用,而且 app 的 minSdkVersion
已经不能更改了。

标记选择器(Marker Selectors) :选择器的功能可以让一些属性在某些
libary 里面无效,比如就拿上面的例子来说,我想让 uisdk 只处理 ui
上的东西,不想让他具有网络访问的功能,那么我可以这么设置:

<uses-permission android:name="android.permission.INTERNET" tools:node="remove" tools:selector="com.example.uisdk" />

其中 tools:node 标签表示删除该权限,tools:selector
标签选择在哪个依赖库里执行 tools:node 表示的动作。

可以看出这些配置还是挺灵活的。

示例效果

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: droidyue.com
Creation date: Feb 10, 2015
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Andrew Wallace, OU=droidyue.com, O=droidyue.com, L=Beijing, ST=Beijing, C=86
Issuer: CN=Andrew Wallace, OU=droidyue.com, O=droidyue.com, L=Beijing, ST=Beijing, C=86
Serial number: 11a8a4a3
Valid from: Tue Feb 10 18:07:43 CST 2015 until: Sun Jun 13 18:07:43 CST 3013
Certificate fingerprints:
   MD5:  46:C5:BE:EF:B5:C9:00:E1:FA:42:50:50:57:54:CA:15
   SHA1: C1:14:5D:0A:C2:BF:F6:06:43:20:AE:2C:07:12:97:58:C2:1B:39:D1
   SHA256: 0E:88:7D:C2:4C:D6:84:A7:58:D4:24:1E:9D:38:F9:05:98:1E:B2:A2:D7:CB:0F:81:74:60:5B:38:89:FF:21:1C
   Signature algorithm name: SHA256withRSA
   Version: 3

Configure dependencies – 配置依赖

这个应该是最熟悉的了,项目中经常要依赖第三方库,一个典型了例子如下:

android {...}...dependencies { //将本地 module library 编译到项目中 compile project(":mylibrary") //编译远程依赖 compile 'com.android.support:appcompat-v7:23.4.0' //编译本地 jar 包 compile fileTree(dir: 'libs', include: ['*.jar'])}

上面主要用到的方式是 compile ,gradle 支持6种编译方式:

  • compile:对所有 buildType 以及 flavors 进行编译并打包到 apk 。
  • provided:和 compile
    相似,但只在编译时使用,几只参与编译,不打包到最终 apk 。
  • apk:只会打包到 apk
    中,不参与编译,所以不能在项目代码中使用相应库中的方法。
  • test compile:相比于 compile ,仅仅针对单元测试的代码编译打包。
  • debug compile:仅针对 debug 模式编译打包。
  • release compile:仅针对 release 模式编译打包。

另外在进行 sdk 开发时,一般为了减小 sdk 体积,一些依赖库会用 provided
的方式,同时需要注意的是,对于远程依赖,compile 和 provided
的效果一样,都不会打包到 jar 包或者 arr 包中,但对于本地的 jar 包或者
arr 包的依赖,compile 和 provided 就有区别了。

重新签名APK

在没有源码情况下,我们就能对apk进行更换签名。

Configure Sigining – 配置签名

在用 gradle 配置 release 版本的签名信息时,需要下面三个步骤:

  1. 生成一个 keystore ,一个二进制文件保存一些私钥,这个必须好好保存。
  2. 生成一个私钥,用于开发者或者公司与这个 app 建立对应关系。
  3. 将生成的信息配置到 moudle 层的 build.gradle 里。示例如下:

android { ... defaultConfig {...} signingConfigs { release { storeFile file("myreleasekey.keystore") storePassword "password" keyAlias "MyReleaseKey" keyPassword "password" } } buildTypes { release { ... signingConfig signingConfigs.release } }}

上面的配置中直接显示了一些敏感信息,比如各种密码,一种更加安全的方式是通过环境变量的方式获取:

storePassword System.getenv("KSTOREWD");keyPassword System.getenv;

或者如果使用命令行的方式编译,还可以让用户在命令行输入密码:

storePassword System.console().readLine("nKeystore password: ")keyPassword System.console().readLine("nKey password: ")

暂时就总结到这么多了,再次说明,如果发现理解错的地方欢迎指正!!!

脚本

  • signapk.sh
  • 备用地址

使用方法

bash signapk.sh your_apk_file your_keystore_file keystore_pass keystore_alias

示例效果

16:57 $ bash signapk.sh weixin6313android740.apk ~/Documents/baidu_disk/百度云同步盘/droidapp/mykiki 123456 droidyue.com
param1 weixin6313android740.apk
param2 /Users/androidyue/Documents/droidapp/mykiki
param3 123456
param4 droidyue.com
deleting: META-INF/MANIFEST.MF
deleting: META-INF/DROIDYUE.SF
deleting: META-INF/DROIDYUE.RSA
   adding: META-INF/MANIFEST.MF
   adding: META-INF/DROIDYUE.SF
   adding: META-INF/DROIDYUE.RSA
......
Verification succesful

生成的文件会放在当前目录,其文件名相对输入文件,增加了signed_前缀,比如对weixin6313android740.apk进行上述操作得到的输出文件是signed_weixin6313android740.apk

Gradle build生成签名APK

想要在执行gradle build时生成指定签名的apk,需要在build.gradle中如下修改

android {

    signingConfigs {
        release {
            storeFile file("myrelease.keystore")
            storePassword "********"
            keyAlias "******"
            keyPassword "******"
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注