Android App打包自动生成版本号Versin Name与Version Code方法之完美方案
2016-03-30 09:44
555 查看
本文主要介绍了三个方案用于使用使用Gradle自动化生成VersionCode与VersionName,最终使用VersionName与git版本库关联,并且区分开发版本与发布版本的解决方案。
我们公司Android研发团队Coding共8人,负责多个项目的开发,其中有一个App需要至少6人都参与其中Coding
手机客户端升级部署在umeng上,每次通过测试后要上传新版本,umeng sdk根据versionCode对比是否让手机弹出框提示升级.
手机客户端集成了fabric sdk用于错误分析。
测试人员或者根据市场反馈情况要去umeng或者fabric查看最近的崩溃日志,并转交给研发人员。
研发人员签名App之前,对发布的App中的VersionCode、VersionName定义没有规范,经常出现重复情况。
测试人员看到Crash日志之后,无法直接确定是历史上线版本、当前测试版本、研发内部版本,经常被忽悠
研发人员对于正式上线版本的版本号例如V1.3.21,在git repo里面无法找到对应的代码。
在git提交之前实际上并无新的git commit id出来,在这期间(开发调测期间)打的包要与之前的包区分开。
这本身是个细心能解决的问题,但是例如强制打Tag,强制写发布日志,但是是人都会犯错,而技术是工具,技术就是应该去降低别人犯错误的机会
在打包操作时(不是run),解析
只是修改VersionCode
当然如果需要同时修改VersionName那么无非在此优化下
尼玛两个人一起用的时候,就没卵用了。该方案只适合个人开发者
引入外部文件存储versionCode,然后该文件一起上传到git repo。
创建文件version.properties,放置在build.gradle同级目录,并在文件中写入VERSION_CODE=8
该方法DEMO项目地址
操作复杂,无法关联git日志,verionCode只能用于升级操作。
首先是介绍两个git的命令行
仓库提交总数
git rev-list --all是列出当前版本库的所有commit,也就是.git目录里面的refs/下的所有提交,与当前的分支无关。--count就是wc -l 统计总共个数。
当前分支提交总数
上面的会返回当前所在分支的提交总数。
生成版本号
这个是git里面吊炸天的显示距离最近提交的数量以及自动命名的命令行
当然使用这个命令的前提是你有至少1个tag在你的repo里面。
例如:
输出的所有版本号是
V1.4.6_279
V1.4.7
V1.4.7.1
V1.4.8
V1.4.9
输出:
分段解释下:
我第一次执行这个命令后就惊呆了,git居然有这么人性化又智能的东西。
有了这几个git命令行就可以写gradle脚本了。
定义变量获取versionCode与versionName
配置打包的versionCode与versionName
方案三完整demo点击这里
首先为当前版本打个tag,然后run运行一下,然后查看下生成的版本号与版本名称。大功告成!
注意,在git提交时要提交下本地的tag
以后在umeng或者fabric中看到一个V1.4.9-50-gad266df的崩溃日志,马上就可以定位到是哪个哥们写的代码,并且是在哪个文件哪一行造成的,后期是否修复也都可以在git的log里面看到。如果是dirty结尾的,就一定是内部开发的,基本都可以忽略掉。所有研发人员都可以不用管到底如何命名版本的问题,专心干该干的事。
并且如果大版本更新,重新本地打个新tag提交即可。
结束语:这篇文章写了将近2周时间,因为2周前我的女儿降生了,然后因为突然当爹一直感慨人生、感慨生命之神奇。。。没有进入工作状态。后面我觉得要自己鼓励自己把写博客的习惯坚持下去。
http://my.oschina.net/mengshuai/blog/551356
需求背景
我们公司Android研发团队Coding共8人,负责多个项目的开发,其中有一个App需要至少6人都参与其中Coding手机客户端升级部署在umeng上,每次通过测试后要上传新版本,umeng sdk根据versionCode对比是否让手机弹出框提示升级.
手机客户端集成了fabric sdk用于错误分析。
测试人员或者根据市场反馈情况要去umeng或者fabric查看最近的崩溃日志,并转交给研发人员。
面临问题
研发人员签名App之前,对发布的App中的VersionCode、VersionName定义没有规范,经常出现重复情况。测试人员看到Crash日志之后,无法直接确定是历史上线版本、当前测试版本、研发内部版本,经常被忽悠
研发人员对于正式上线版本的版本号例如V1.3.21,在git repo里面无法找到对应的代码。
在git提交之前实际上并无新的git commit id出来,在这期间(开发调测期间)打的包要与之前的包区分开。
解决方案
这本身是个细心能解决的问题,但是例如强制打Tag,强制写发布日志,但是是人都会犯错,而技术是工具,技术就是应该去降低别人犯错误的机会
方案1
技术原理
在打包操作时(不是run),解析AndroidManifest.xml,将versionCode在每次gradle打包时自加1
代码实现
只是修改VersionCodetask('increaseVersionCode') << { def manifestFile = file("AndroidManifest.xml") def pattern = Pattern.compile("versionCode=\"(\\d+)\"") def manifestText = manifestFile.getText() def matcher = pattern.matcher(manifestText) matcher.find() def versionCode = Integer.parseInt(matcher.group(1)) def manifestContent = matcher.replaceAll("versionCode=\"" + ++versionCode + "\"") manifestFile.write(manifestContent) } tasks.whenTaskAdded { task -> if (task.name == 'generateReleaseBuildConfig') { task.dependsOn 'increaseVersionCode' } }
当然如果需要同时修改VersionName那么无非在此优化下
import java.util.regex.Pattern task('increaseVersionCode') << { def manifestFile = file("src/main/AndroidManifest.xml") def pattern = Pattern.compile("versionCode=\"(\\d+)\"") def manifestText = manifestFile.getText() def matcher = pattern.matcher(manifestText) matcher.find() def versionCode = Integer.parseInt(matcher.group(1)) def manifestContent = matcher.replaceAll("versionCode=\"" + ++versionCode + "\"") manifestFile.write(manifestContent) } task('incrementVersionName') << { def manifestFile = file("src/main/AndroidManifest.xml") def patternVersionNumber = Pattern.compile("versionName=\"(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)\"") def manifestText = manifestFile.getText() def matcherVersionNumber = patternVersionNumber.matcher(manifestText) matcherVersionNumber.find() def majorVersion = Integer.parseInt(matcherVersionNumber.group(1)) def minorVersion = Integer.parseInt(matcherVersionNumber.group(2)) def pointVersion = Integer.parseInt(matcherVersionNumber.group(3)) def buildVersion = Integer.parseInt(matcherVersionNumber.group(4)) def mNextVersionName = majorVersion + "." + minorVersion + "." + pointVersion + "." + (buildVersion + 1) def manifestContent = matcherVersionNumber.replaceAll("versionName=\"" + mNextVersionName + "\"") manifestFile.write(manifestContent) } tasks.whenTaskAdded { task -> if (task.name == 'generateReleaseBuildConfig' || task.name == 'generateDebugBuildConfig') { task.dependsOn 'increaseVersionCode' task.dependsOn 'incrementVersionName' } }
缺陷
尼玛两个人一起用的时候,就没卵用了。该方案只适合个人开发者
方案二
技术原理
引入外部文件存储versionCode,然后该文件一起上传到git repo。
代码实现
创建文件version.properties,放置在build.gradle同级目录,并在文件中写入VERSION_CODE=8该方法DEMO项目地址
android { compileSdkVersion 18 buildToolsVersion "18.1.0" def versionPropsFile = file('version.properties') if (versionPropsFile.canRead()) { def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) def code = versionProps['VERSION_CODE'].toInteger() + 1 versionProps['VERSION_CODE']=code.toString() versionProps.store(versionPropsFile.newWriter(), null) defaultConfig { versionCode code versionName "1.1" minSdkVersion 14 targetSdkVersion 18 } } else { throw new GradleException("Could not read version.properties!") } // rest of android block goes here }
缺陷
操作复杂,无法关联git日志,verionCode只能用于升级操作。
终极解决方案三
技术原理
首先是介绍两个git的命令行仓库提交总数
git rev-list --all --count
git rev-list --all是列出当前版本库的所有commit,也就是.git目录里面的refs/下的所有提交,与当前的分支无关。--count就是wc -l 统计总共个数。
当前分支提交总数
git rev-list --count HEAD
上面的会返回当前所在分支的提交总数。
生成版本号
这个是git里面吊炸天的显示距离最近提交的数量以及自动命名的命令行
git describe --tags --dirty
当然使用这个命令的前提是你有至少1个tag在你的repo里面。
例如:
git tag
输出的所有版本号是
V1.4.6_279
V1.4.7
V1.4.7.1
V1.4.8
V1.4.9
git describe --tags --dirty
输出:
V1.4.9-50-gad266df-dirty
分段解释下:
V1.4.9代表我最近打的一个tag的名称
-50是距离这个tag有50次提交
-gad266df是我最后一次提交的commit hash是ad266dfd22846d627f6cac7543ada4ed3de45759,取前几位,前面的g不算。
-dirty是说我修改了代码没有执行git commit。。也就是尼玛程序员开发过程中的调试版本。
我第一次执行这个命令后就惊呆了,git居然有这么人性化又智能的东西。
有了这几个git命令行就可以写gradle脚本了。
代码实现
定义变量获取versionCode与versionNamedef getVersionCode = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
//此处可以根据实际情况使用git rev-list --all --countcommandLine 'git', 'rev-list', '--first-parent', '--count', 'HEAD'
standardOutput = stdout
}
//+300是因为与之前的版本命名区分开,不会与之前的重复
return Integer.parseInt(stdout.toString().trim())+300
}
catch (ignored) {
println "===================error code!"
return -1;
}
}
def getVersionName = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'describe', '--tags', '--dirty'
standardOutput = stdout
}
return stdout.toString().trim()
}
catch (ignored) {
println "===================error name!"
return null;
}
}
配置打包的versionCode与versionName
android { .... defaultConfig { ... versionName getVersionName() versionCode getVersionCode() } .... }
方案三完整demo点击这里
首先为当前版本打个tag,然后run运行一下,然后查看下生成的版本号与版本名称。大功告成!
注意,在git提交时要提交下本地的tag
以后在umeng或者fabric中看到一个V1.4.9-50-gad266df的崩溃日志,马上就可以定位到是哪个哥们写的代码,并且是在哪个文件哪一行造成的,后期是否修复也都可以在git的log里面看到。如果是dirty结尾的,就一定是内部开发的,基本都可以忽略掉。所有研发人员都可以不用管到底如何命名版本的问题,专心干该干的事。
并且如果大版本更新,重新本地打个新tag提交即可。
结束语:这篇文章写了将近2周时间,因为2周前我的女儿降生了,然后因为突然当爹一直感慨人生、感慨生命之神奇。。。没有进入工作状态。后面我觉得要自己鼓励自己把写博客的习惯坚持下去。
http://my.oschina.net/mengshuai/blog/551356
相关文章推荐
- 一个数组dataArr,我现在拿到一个对象A,想判断在数组中有没有这个对象A,如果存在则从数组dataArr中删除A,如果不存在则将A加入到数组dataArr中
- 关于 android 中 postDelayed方法的讲解
- Android项目重构之路:实现篇
- opengles RGB数组及Android Bitmap中int color[] RGB存储顺序
- iOS-关于Certificate、Provisioning Profile、App ID的介绍及其之间的关系
- 【Android】【转】查看内存
- Android-使用WebView显示网页
- Android-使用WebView显示网页
- C#读写App.config配置文件
- 国外干货!6个方法助你设计出优秀的APP
- android 用 XML 自定义边框(只上下边框有色)
- Application tried to push a nil view controller on target
- iOS 搜索框
- 详解iOS App中图片的线段涂鸦功能的添加方法
- Android开发之5.0特性深入理解(一)
- android 得到缩略图
- android 解析XML 工具类
- C# stringbuilder的基本用法 sb.AppendFormat
- Android签名机制之---签名过程详解
- NSObject的内省方法