最近在弄android应用,不可避免的要涉及到版本号的问题,还需要定制化库,删除某些不需要到库文件,裁剪apk的大小。本篇就是记录一下版本号自动生成问题和裁剪库文件的解决方案。
一、命名规则
本文采取一下命名规则。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionName="aa.bb.cccc.yymmdd.xxxxx"
android:versionCode="aabbcccc"
package="com.example.xxx">
说明:
- aa是大版本号,bb是小版本号,最多2位,不足不补0。
- cccc是Git库的提交次数,xxxxx是Git库HEAD的SHA1码前5位。
- yymmdd是日期,yy是年的后两位,mm是月,dd是日,不足补0。
二、编译脚本build.gradle中实现自动生成版本号
根据git信息自动生成版本号,命令如下:
git rev-list --count HEAD # This is cccc
git describe --always # This is short SHA1
在build.gradle文件中的defaultconfig写入规则versionCode getSelfDefinedVersion()获取
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "com.example.xxx"
minSdkVersion 22
targetSdkVersion 23
versionCode getSelfDefinedVersion("code")
versionName getSelfDefinedVersion("name")
}
buildTypes {
release {
minifyEnabled false
}
}
}
在build.gradle文件文件中实现函数getSelfDefinedVersion(),大小版本号通过传参方式传入。
def getVersionValue(type) {
if ("big".equals(type)) {
return hasProperty("APP_BIG_VERSION") ? APP_BIG_VERSION : "2"
} else if ("small".equals(type)) {
return hasProperty("APP_SMALL_VERSION") ? APP_SMALL_VERSION : "0"
}
}
def getSelfDefinedVersion(type) {
int aa = getVersionValue("big").toInteger() //大版本号
int bb = getVersionValue("small").toInteger() //小版本号
printf("getversion version : $aa.$bb \n")
Process process = "git rev-list --count HEAD".execute()
process.waitFor()
int cccc = process.getText().toInteger()
if ("code".equals(type)) {
aa * 1000000 + bb * 10000 + cccc
} else if ("name".equals(type)) {
String today = new Date().format("yyMMdd")
process = "git describe --always".execute()
process.waitFor()
String sha1 = process.getText().trim()
"$aa.$bb.$cccc.$today.$sha1"
}
}
三、编译测试
gradlew assembleJUMPRelease -PAPP_BIG_VERSION=2 -PAPP_SMALL_VERSION=1
有两个版本号是因为在system/app下面有一个apk,本次安装是在data/app目录下的。
四、裁剪库文件
我编写了一个task,在即将打包时,把正常的so文件删除多余的so文件
def getChannelValue() {
return hasProperty("CHANNEL") ? CHANNEL : "TEST"
}
task clearLibs() {
doLast{
def channel = getChannelValue()
println "-------clear some libs------"
if ("TEST".equals(getChannelValue())) {
def dir = new File("build/intermediates/transforms/")
fileTree(dir).each { file ->
if("libijkffmpeg.so".equals(file.name)||"libijkplayer.so".equals(file.name)||"libijksdl.so".equals(file.name)){
delete file.path
println file.path
}
}
}
}
}
afterEvaluate {
tasks.matching {
it.name.startsWith('process') && (it.name.endsWith('ReleaseJavaRes') || it.name.endsWith
('DebugJavaRes'))
}.each { tk ->
tk.dependsOn(clearLibs)
}
}
实现了clearLibs先于以process开头以ReleaseJavaRes或DebugJavaRes结尾的标准task执行(当然还可以写成it.name.equals(***),语法类似Java)。
五、整个build.grade文件源码
apply plugin: 'com.android.application'
String getManifestPath() {
def channel = getChannelValue()
if("TEST".equals(channel)){
return "src/main/AndroidManifestTEST.xml"
}
return "src/main/AndroidManifest.xml"
}
def getChannelValue() {
return hasProperty("CHANNEL") ? CHANNEL : "TEST"
}
def getVersionValue(type) {
if ("big".equals(type)) {
return hasProperty("APP_BIG_VERSION") ? APP_BIG_VERSION : "2"
} else if ("small".equals(type)) {
return hasProperty("APP_SMALL_VERSION") ? APP_SMALL_VERSION : "0"
}
}
def getSelfDefinedVersion(type) {
int aa = getVersionValue("big").toInteger() //大版本号
int bb = getVersionValue("small").toInteger() //小版本号
printf("getversion version : $aa.$bb \n")
Process process = "git rev-list --count HEAD".execute()
process.waitFor()
int cccc = process.getText().toInteger()
if ("code".equals(type)) {
aa * 1000000 + bb * 10000 + cccc
} else if ("name".equals(type)) {
String today = new Date().format("yyMMdd")
process = "git describe --always".execute()
process.waitFor()
String sha1 = process.getText().trim()
"$aa.$bb.$cccc.$today.$sha1"
}
}
android {
... ...
defaultConfig {
... ...
versionCode getSelfDefinedVersion("code")
versionName getSelfDefinedVersion("name")
... ...
}
... ...
sourceSets {
main {
manifest.srcFile getManifestPath()
}
}
applicationVariants.all { variant ->
variant.outputs[0].processManifestProvider.get().doLast {
//渠道与配置名
String variantName = variant.name.capitalize()
//写死为JUMP_COMMON以后该渠道号,需要一起改掉
//JUMP_COMMON_USER渠道的为普通用户,没有SYSTEM权限
if (variant.productFlavors[0].name == "JUMP_COMMON_USER") {
//要替换的manifest文件
def manifestFile = "${projectDir}${File.separator}build${File.separator}intermediates${File.separator}merged_manifests${File.separator}${variantName}${File.separator}AndroidManifest.xml"
//源文件
def srcManifact = "${projectDir}${File.separator}configs${File.separator}${variant.productFlavors[0].name}.xml"
//通过源文件内容替换
def updatedContent = new File(srcManifact).getText('UTF-8')
new File(manifestFile).write(updatedContent, 'UTF-8')
}
}
}
productFlavors {
... ...
}
productFlavors.all {
flavor -> flavor.manifestPlaceholders = [CHANNEL_VALUE: name]
}
}
dependencies {
... ...
}
task clearLibs() {
doLast{
def channel = getChannelValue()
println "-------clear some libs------"
if ("TEST".equals(getChannelValue())) {
def dir = new File("build/intermediates/transforms/")
fileTree(dir).each { file ->
if("libijkffmpeg.so".equals(file.name)||"libijkplayer.so".equals(file.name)||"libijksdl.so".equals(file.name)){
delete file.path
println file.path
}
}
}
}
}
afterEvaluate {
tasks.matching {
it.name.startsWith('process') && (it.name.endsWith('ReleaseJavaRes') || it.name.endsWith
('DebugJavaRes'))
}.each { tk ->
tk.dependsOn(clearLibs)
}
}
结束语
以上就是本次分享的android应用开发中,gradle编译时应用版本号自动生成和裁剪库文件(build.grade)。最后惯例给大家推介一下我们的技术工作号,欢迎大家来交流技术问题,谢谢!