We can create a new project and then generate a new signature file.
Generally speaking, after these operations, we can package by clicking Build - > Generate Signed APK - > Next in the upper left corner, and then selecting the corresponding Build Type.
That's too much trouble for some people. They have to input relevant information and make choices every time. How can they bear it?
So is there a simpler and faster way? The answer is yes.
We can configure signatures in build.gradle under the app directory of the project.
First, we find android {} under build.gradle. The default configuration is as follows
Next, we can change the preview mode of the project to Project, or unchanged, just put the signature file we just generated into the corresponding directory. My approach is to put it directly under the project, as shown in the figure.
Then, go back to build.gradle under app and add this code to it.
signingConfigs { debug { storeFile file('../test.jks')//Signature file path storePassword "123456" keyAlias "test" keyPassword "123456" //Signature password println("====== signingConfigs.debug ======") } release { storeFile file('../test.jks')//Signature file path storePassword "123456" keyAlias "test" keyPassword "123456" //Signature password println("====== signingConfigs.release ======") } }
Let me explain that storeFile file corresponds to the path of the signature file key. Our signature is placed under the direct subpath of the project, while build.gradle is under test/app, so we need to find the root path of the project with... and then through / find the path of the corresponding signature file. Of course, you can also configure the address of the signature file, as long as you can find it.
At this point, we can see our packaged APK in app/build/outputs under the project path, and the name shows that the APK has been signed. That is to say, using code configuration can achieve the same effect as using graphical interfaces.
By the way, one thing to note here is that the signing Configs code block must be written in front of buildTypes, otherwise the following error will be reported: Can not find property'debug Config'on Signing Config Container.
So far, our buildTypes configuration can be as follows:
buildTypes { debug { println("====== buildTypes.debug ======") signingConfig signingConfigs.debug } release { //Is there any confusion? minifyEnabled false //Whether to remove useless resources zipAlignEnabled true println("====== buildTypes.release ======") signingConfig signingConfigs.release //Confused configuration files proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }
You can now manipulate it arbitrarily from the command line, or pack it in multiple channels.
However, the above configuration is simple, but there is insecurity. If your project is open source, you write the configuration password of the signature file and other information in clear text in build.gradle, is that not safe?
So we can do that. Create a new. properties file under the project path, or add relevant information directly under local.properties.
We can add directly under this document: (fill in the relevant information)
keystore.path=../test.jks //Replace with your signature path keystore.password=123456 keystore.alias=test keystore.alias_password=123456
So, under build.gradle, in order not to display in plaintext, we first need to get the key configuration, so we can add the code under app's build.gradle.
def keystoreFilepath = '' def keystorePSW = '' def keystoreAlias = '' def keystoreAliasPSW = '' // default keystore file, PLZ config file path in local.properties def keyfile = file('s.keystore.temp') Properties properties = new Properties() // local.properties file in the root director properties.load(project.rootProject.file('local.properties').newDataInputStream()) keystoreFilepath = properties.getProperty("keystore.path") if (keystoreFilepath) { keystorePSW = properties.getProperty("keystore.password") keystoreAlias = properties.getProperty("keystore.alias") keystoreAliasPSW = properties.getProperty("keystore.alias_password") keyfile = file(keystoreFilepath) }
First, we assign default values to keys, then we get the configuration information of signature files according to the configuration file of Properties, and then we get the configuration information of signature files according to our configuration parameter keystore.password under local.properties.
Here's a point to emphasize. Gitversion control In the project, we can see a. gitignore file under our project. The configuration is as follows.
We can see / local.properties, which means that local.properties are not added to version control by default, because local.properties store some information about our environment resources, such as the path of sdk. So we can configure signature information under local.properties without worrying about key leakage. It's very good for open source projects.
So, at this point in time, we can change signing Configs under app/build.gradle to:
signingConfigs { debug { storeFile keyfile storePassword keystorePSW keyAlias keystoreAlias keyPassword keystoreAliasPSW println("====== signingConfigs.debug ======") } myConfig { storeFile keyfile storePassword keystorePSW keyAlias keystoreAlias keyPassword keystoreAliasPSW println("====== signingConfigs.release ======") } }
Correspondingly, buildTypes can also be configured like this
buildTypes { debug { println("====== buildTypes.debug ======") signingConfig signingConfigs.debug } release { //Is there any confusion? minifyEnabled false //Whether to remove useless resources zipAlignEnabled true //Confusion Configuration proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //If a signature file exists, it will sign if (keyfile.exists()) { println("WITH -> buildTypes -> release: using jks key") signingConfig signingConfigs.myConfig }else { println("WITH -> buildTypes -> release: using default key") } applicationVariants.all { variant -> variant.outputs.each { output -> def outputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.apk')) { // The output APK name is ruijie_v1.0_wandoujia.apk def fileName = "ruijie_v${defaultConfig.versionName}_${variant.productFlavors[0].name}.apk" output.outputFile = new File(outputFile.parent, fileName) } } } }
In this way, when our project is open source, then we will not upload signature files. We use the code keyfile.exists() to determine whether there is a signature, then the APK packaged by others is unsigned. So it can guarantee the security of apk signature.
Add a note: build.gradle configuration:
Sometimes when we package, we display lint errors, so we can add
lintOptions { abortOnError false }
dx tool (android converts jar package to dex format binary jar package tool)
This will apply all task s that use dex. Resolve configuration of 65535
dexOptions { incremental true javaMaxHeapSize "4g" //Turn off precompilation preDexLibraries = false }
Or specify a compiled version of JDK
compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }
Packing ignores the same files as third-party jar s
packagingOptions { exclude 'META-INF/DEPENDENCIES.txt' exclude 'META-INF/LICENSE.txt' exclude 'META-INF/NOTICE.txt' exclude 'META-INF/NOTICE' exclude 'META-INF/LICENSE' exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/notice.txt' exclude 'META-INF/license.txt' exclude 'META-INF/dependencies.txt' exclude 'META-INF/LGPL2.1' }
Finally, attach the relevant code of the build.gradle configuration:
apply plugin: 'com.android.application' apply plugin: 'me.tatarka.retrolambda' apply plugin: 'android-apt' def keystoreFilepath = '' def keystorePSW = '' def keystoreAlias = '' def keystoreAliasPSW = '' // default keystore file, PLZ config file path in local.properties def keyfile = file('s.keystore.temp') Properties properties = new Properties() // local.properties file in the root director properties.load(project.rootProject.file('local.properties').newDataInputStream()) keystoreFilepath = properties.getProperty("keystore.path") if (keystoreFilepath) { keystorePSW = properties.getProperty("keystore.password") keystoreAlias = properties.getProperty("keystore.alias") keystoreAliasPSW = properties.getProperty("keystore.alias_password") keyfile = file(keystoreFilepath) } android { compileSdkVersion 24 buildToolsVersion "24.0.2" defaultConfig { applicationId "com.example.vizax.with" minSdkVersion 15 targetSdkVersion 24 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } // This is the code to resolve the lint error. lintOptions { abortOnError false } dexOptions { incremental true javaMaxHeapSize "4g" //Turn off precompilation preDexLibraries = false } /*android { productFlavors { kuan { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "kuan"] } xiaomi { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"] } qh360 { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "qh360"] } baidu { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"] } wandoujia { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"] } } }*/ android { productFlavors { kuan {} xiaomi {} qh360 {} baidu {} wandoujia {} yingyongbao {} } productFlavors.all { flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] } } signingConfigs { debug { storeFile keyfile storePassword keystorePSW keyAlias keystoreAlias keyPassword keystoreAliasPSW println("====== signingConfigs.debug ======") } myConfig { storeFile keyfile storePassword keystorePSW keyAlias keystoreAlias keyPassword keystoreAliasPSW println("====== signingConfigs.release ======") } /*release { storeFile file('../with.jks') //Signature file path storePassword "with123456" keyAlias "with" keyPassword "with123456" //Signature password }*/ } //Packing ignores the same files as third-party jar s packagingOptions { exclude 'META-INF/DEPENDENCIES.txt' exclude 'META-INF/LICENSE.txt' exclude 'META-INF/NOTICE.txt' exclude 'META-INF/NOTICE' exclude 'META-INF/LICENSE' exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/notice.txt' exclude 'META-INF/license.txt' exclude 'META-INF/dependencies.txt' exclude 'META-INF/LGPL2.1' } /*signingConfigs The code block must be written in front of buildTypes, otherwise the following error will be reported: Could not find property 'debugConfig' on SigningConfig container. Signature passwords are not safe to write in gradle, so it's better to comment out the relevant code when it's packaged online.*/ buildTypes { debug { println("====== buildTypes.debug ======") signingConfig signingConfigs.debug } release { //Is there any confusion? minifyEnabled false zipAlignEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' if (keyfile.exists()) { println("WITH -> buildTypes -> release: using jks key") signingConfig signingConfigs.myConfig }else { println("WITH -> buildTypes -> release: using default key") } applicationVariants.all { variant -> variant.outputs.each { output -> def outputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.apk')) { // The output APK name is ruijie_v1.0_wandoujia.apk def fileName = "ruijie_v${defaultConfig.versionName}_${variant.productFlavors[0].name}.apk" output.outputFile = new File(outputFile.parent, fileName) } } } } } /* Open Terminal in the lower left corner and enter the command line If we want to pack the release version of wandoujia channel, just execute the following command: gradlew assembleWandoujiaRelease If we want to pack the debug version of wandoujia channel, just execute the following command: gradlew assembleWandoujiaDebug If we only play the wandoujia channel version, then: gradlew assembleWandoujia This command generates Release and Debug versions of the wandoujia channel Similarly, I would like to call all Release versions: gradlew assembleRelease*/ }
As for confusing configuration, I'll explain it in detail in my next blog.
If you have any questions, please leave a message. Thank you.