之前沒有設(shè)置過打包的命名,每次打包都是默認(rèn)的"app-realease.apk",之后手動(dòng)修改名字來顯示出它是一個(gè)新版本。
?晚上學(xué)習(xí)了如何配置打包名稱,很簡單,修改build.gradle里的代碼就行。
?詳細(xì)記錄如下:
1、打開app這個(gè)directory下的build.gradle
2、定義打包時(shí)間:
//時(shí)間
def releaseTime() {
??returnnewDate().format("yyyyMMdd", TimeZone.getTimeZone("UTC"))
}
3、自定義發(fā)布時(shí)的版本號(hào)(return的返回值可自行修改,例如1.0、2.0):
//版本號(hào)
def getVersionName(){
??return"2.0"
}
4、自定義打包名稱(代碼中的XYZ可修改為app名字):
//名稱
??applicationVariants.all { variant ->
????variant.outputs.each { output ->
??????def outputFile = output.outputFile
??????def fileName
??????if(outputFile != null&& outputFile.name.endsWith('.apk')) {
????????if(variant.buildType.name.equals('release')) {
??????????variant.mergedFlavor.versionName = getVersionName()
??????????fileName = "XYZ_${variant.mergedFlavor.versionName}_release.apk"
????????} elseif(variant.buildType.name.equals('debug')) {
??????????variant.mergedFlavor.versionName = getVersionName()+"."+releaseTime()
??????????fileName = "XYZ_${variant.mergedFlavor.versionName}_debug.apk"
????????}
????????output.outputFile = newFile(outputFile.parent, fileName)
??????}
????}
??}
5、build.gradle的完整代碼:
apply plugin: 'com.android.application'
//定義時(shí)間
def releaseTime() {
??returnnewDate().format("yyyyMMdd", TimeZone.getTimeZone("UTC"))
}
//設(shè)置發(fā)布時(shí)的版本號(hào)
def getVersionName(){
??return"2.0"
}
android {
??compileSdkVersion 26
??buildToolsVersion "26.0.0"
??defaultConfig {
????applicationId "***"
????minSdkVersion 14
????targetSdkVersion 23
????versionCode 1
????testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
??}
??buildTypes {
????release {
??????buildConfigField("boolean","API_DEBUG","false")
??????minifyEnabled false
??????proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
????}
????debug {
??????buildConfigField("boolean","API_DEBUG","true")
??????minifyEnabled false
??????proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
????}
??}
??//配置打包名稱
??applicationVariants.all { variant ->
????variant.outputs.each { output ->
??????def outputFile = output.outputFile
??????def fileName
??????if(outputFile != null&& outputFile.name.endsWith('.apk')) {
????????if(variant.buildType.name.equals('release')) {
??????????variant.mergedFlavor.versionName = getVersionName()
??????????fileName = "XYZ_${variant.mergedFlavor.versionName}_release.apk"
????????} elseif(variant.buildType.name.equals('debug')) {
??????????variant.mergedFlavor.versionName = getVersionName()+"."+releaseTime()
??????????fileName = "XYZ_${variant.mergedFlavor.versionName}_debug.apk"
????????}
????????output.outputFile = newFile(outputFile.parent, fileName)
??????}
????}
??}
}
dependencies {
??compile fileTree(dir: 'libs', include: ['*.jar'])
??androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
????exclude group: 'com.android.support', module: 'support-annotations'
??})
}
今天升級(jí)了AS3.1以后,在項(xiàng)目編譯的時(shí)候發(fā)現(xiàn)Gradle中報(bào)錯(cuò)了,錯(cuò)誤如下:
Error:(60, 0) Cannot set the value of read-only property 'outputFile' for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=xiaomiRelease, filters=[]}} of type com.android.build.gradle.internal.api.ApkVariantOutputImpl.
<a href="openFile:E:\Studio\MyApplication\CodeBook\build.gradle">Open File</a>
經(jīng)過一番折騰,網(wǎng)上找大牛的解讀,弄明白了output.outputFile變成了只讀屬性,不能再往里面寫東西了,以下是3.0之前的配置:
applicationVariants.all { variant ->????//批量修改Apk名字
????variant.outputs.each { output ->
????????def outputFile = output.outputFile
????????if (outputFile != null && outputFile.name.endsWith('.apk') && 'release'.equals(variant.buildType.name)) {
????????????def fileName = outputFile.name.replace("${variant.flavorName}", "V${defaultConfig.versionName}-${variant.flavorName}")
????????????fileName = fileName.replace('.apk', "-${buildTime()}.apk")
????????????output.outputFile = new File(outputFile.parent, fileName)
????????}
????}
}
下面是經(jīng)過修改之后3.0里面批量修改APK名字的配置:
applicationVariants.all { variant ->????//批量修改Apk名字
????variant.outputs.all { output ->
????????if (!variant.buildType.isDebuggable()) {
????????????//獲取簽名的名字 variant.signingConfig.name
????????????//要被替換的源字符串
????????????def sourceFile = "-${variant.flavorName}-${variant.buildType.name}"
????????????//替換的字符串
????????????def replaceFile = "_V${variant.versionName}_${variant.flavorName}_${variant.buildType.name}_${buildTime()}"
????????????outputFileName = output.outputFile.name.replace(sourceFile, replaceFile);
????????????//遺留問題:如何獲取當(dāng)前module的name,如CodeBooke這個(gè)名字怎么獲取到
????????}
????}
}
問題:對(duì)于如何在gradle中獲取module的name,還是沒有找到相關(guān)的方法,希望有知道的大神留言交流。
2、model下build.gradle
import java.text.SimpleDateFormat
applyplugin:'com.android.application'
android{
? ? compileSdkVersion 28
? ? defaultConfig {
applicationId"ma.mhy.sqliteeditorroot"
minSdkVersion15
targetSdkVersion28
? ? ? ? versionCode getMyVersionCode()
? ? ? ? versionName getMyVersionName()
testInstrumentationRunner"android.support.test.runner.AndroidJUnitRunner"
? ? }
? ? buildTypes {
? ? ? ? release {
minifyEnabledfalse
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),'proguard-rules.pro'
? ? ? ? }
? ? }
? ? compileOptions {
sourceCompatibilityJavaVersion.VERSION_1_8
targetCompatibilityJavaVersion.VERSION_1_8
? ? }
}
dependencies{
implementation fileTree(dir:'libs',include: ['*.jar'])
}
staticdefgetMyVersionCode() {
returnInteger.parseInt(newSimpleDateFormat("yyMMdd").format(newDate()))
}
staticdefgetMyVersionName() {
return"1.0.6."+"git describe --always".execute().getText().trim()//自動(dòng)打包命名區(qū)分新舊版
}
build.gradle中自動(dòng)生成版本號(hào)
Android Studio中,gradle.build里的設(shè)定會(huì)覆蓋AndroidManifest.xml中的設(shè)置。
Gradle中使用的是Groovy語言,這是一種基于JVM的敏捷開發(fā)語言,還算是易學(xué)易用的。
在項(xiàng)目的build.gradle中,android.defaultConfig里,把versionCode和versionName改成自定義函數(shù)getSelfDefinedVersion:
android {? ? compileSdkVersion23buildToolsVersion"23.0.3"defaultConfig {? ? ? ? applicationId"com.example.xxx"minSdkVersion22targetSdkVersion23versionCode getSelfDefinedVersion("code")? ? ? ? versionName getSelfDefinedVersion("name")? ? }? ? buildTypes {? ? ? ? release {? ? ? ? ? ? minifyEnabledfalse}? ? }}
在build.gradle文件底部,統(tǒng)一實(shí)現(xiàn)版本號(hào)自動(dòng)生成管理:
defgetSelfDefinedVersion(type) {intaa =1intbb =0Process process ="git rev-list --count HEAD".execute()? ? process.waitFor()intcccc = process.getText().toInteger()if("code".equals(type)) {? ? ? ? aa *1000000+ bb *10000+ cccc? ? }elseif("name".equals(type)) {? ? ? ? String today =newDate().format("yyMMdd")? ? ? ? process ="git describe --always".execute()? ? ? ? process.waitFor()? ? ? ? String sha1 = process.getText().trim()"$aa.$bb.$cccc.$today.$sha1"}}
這樣雖然比較簡陋,但功能是有了。
打包自動(dòng)版本號(hào)與日期
(build.gradle 文件內(nèi)容,com.android.tools.build:gradle:3.0.0 以下版本)
android{
? ? defaultConfig {...}
? ? 自動(dòng)追加版本號(hào)和版本名稱
? ? android.applicationVariants.all {
? ? ? ? variant->variant.outputs.each {
? ? ? ? ? ? output-> output.outputFile = new File(output.outputFile.parent,"app_device_v"+defaultConfig.versionName+"_"+new Date().format("yyyy-MM-dd")+"_"+buildType.name+".apk")
? ? ? ? }
? ? }
}
如com.android.tools.build:gradle:3.0.0及其以上版本
android{
? ? defaultConfig {...}
//release版本輸出包名自動(dòng)追加版本號(hào)和版本名稱
? ? applicationVariants.all {
? ? ? ? variant ->
? ? ? ? ? ? variant.outputs.all {
? ? ? ? ? ? ? ? if (buildType.name == 'release'){
? ? ? ? ? ? ? ? ? ? outputFileName = "app_v" + defaultConfig.versionName + "_" + new Date().format("yyyy-MM-dd") + "_" + buildType.name + ".apk"
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? }
}
android應(yīng)用程序的版本號(hào)Version name可以在android manifest下手動(dòng)修改,在code中調(diào)用api獲取該版本號(hào)。
? ? 項(xiàng)目中的目標(biāo)是:每編譯一次程序都會(huì)自動(dòng)修改版本號(hào),而不需要手動(dòng)修改,由于中間debug的次數(shù)較多,我打算以每次Build時(shí)的當(dāng)前時(shí)間作為版本號(hào)。
? ? 操作步驟:
? ??1. Android工程目錄的assets文件夾下新建一文件,命名為version
? ? 2. code中通過api獲取assets下的文件內(nèi)容,回顯在activity,基礎(chǔ)android編程知識(shí),不解釋
? ??3.?Android.mk?文件中LOCAL_PATH:= $(call my-dir)下緊接著調(diào)用shell語句:?$(shell date +%Y%m%d%H:%M:%S>$(LOCAL_PATH)/assets/version)
? ? 如果項(xiàng)目對(duì)版本號(hào)或者版本名稱有更復(fù)雜的需求,可以直接寫成shell腳本,再由Android.mk?調(diào)用
? ? 編譯時(shí)自動(dòng)輸出當(dāng)前編譯時(shí)間到version文件,并打包到apk中,done!
感謝https://my.oschina.net/u/659658/blog/84545
import java.text.SimpleDateFormat
applyplugin:'com.android.application'
//設(shè)置發(fā)布時(shí)的版本號(hào)
static def getVersionName() {
int aa =3
? ? int i ="git rev-list --count HEAD".execute().getText().toInteger()//build次數(shù)
? ? String today =new Date().format("yyMMdd")
Process process ="git describe --always".execute()
process.waitFor()
String str = process.getText().trim()
return "$aa.$i.$today.$str"http://"3.276"+str? ? ?//3.1.20181015.內(nèi)容
// return aa+"."+i+"."+"."+today+"."+str
}
//設(shè)置發(fā)布時(shí)的版本碼
static def getVersionCode() {
Process process ="git rev-list --count HEAD".execute()
process.waitFor()
int i = process.getText().toInteger()
return Integer.parseInt(new SimpleDateFormat("yyMMdd").format(new Date()))*10000 +i//今天日期1810150001+次數(shù)
}
android {
compileSdkVersion28
? ? defaultConfig {
applicationId"com.hcsoft.storekeeper"
? ? ? ? minSdkVersion15
? ? ? ? targetSdkVersion28
? ? ? ? versionCodegetVersionCode()
versionName getVersionName()
testInstrumentationRunner"android.support.test.runner.AndroidJUnitRunner"
? ? }
//release版本輸出包名自動(dòng)追加版本號(hào)和版本名稱
? ? applicationVariants.all {
variant ->
variant.outputs.all {
if (buildType.name =='release'){
outputFileName ="app_v" + defaultConfig.versionName +"_" +new Date().format("yyyy-MM-dd") +"_" + buildType.name +".apk"
? ? ? ? ? ? ? ? }
}
}
buildTypes {
release {
buildConfigField("boolean","API_DEBUG","false")
minifyEnabledfalse
? ? ? ? ? ? proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
? ? ? ? }
debug {
buildConfigField("boolean","API_DEBUG","true")
minifyEnabledfalse
? ? ? ? ? ? proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
? ? ? ? }
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
? ? ? ? targetCompatibility JavaVersion.VERSION_1_8
? ? }
}
dependencies{
implementation fileTree(dir:'libs',include: ['*.jar'])
}
原理是獲得打包簽名文件的生成時(shí)間。
? ? /**
? ? * 獲得app的打包時(shí)間
? ? *
? ? * @return
? ? */
? ? private String getAppBuildTime() {
? ? ? ? String result = "";
? ? ? ? try {
? ? ? ? ? ? ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(),0);
? ? ? ? ? ? ZipFile zf = new ZipFile(ai.sourceDir);
? ? ? ? ? ? ZipEntry ze = zf.getEntry("META-INF/MANIFEST.MF");
? ? ? ? ? ? long time = ze.getTime();
? ? ? ? ? ? SimpleDateFormat formatter = (SimpleDateFormat) SimpleDateFormat.getInstance();
? ? ? ? ? ? formatter.applyPattern("yyyy/MM/dd HH:mm:ss");
? ? ? ? ? ? result = formatter.format(new java.util.Date(time));
? ? ? ? ? ? zf.close();
? ? ? ? } catch (Exception e) {
? ? ? ? }
? ? ? ? return result;
? ? }
上述方法貌似在5.0之后不好用,所以現(xiàn)在建議使用Gradle生成打包時(shí)間,然后再引用。核心代碼如下:
buildTypes {
? ? ? ? release {
? ? ? ? ? ? buildConfigField("String", "releaseTime", "\""+new Date().format("yyyy/MM/dd HH:mm:ss")+"\"")
? ? ? ? ? ? minifyEnabled false
? ? ? ? ? ? proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
? ? ? ? }
? ? ....
? }
主要是使用buildConfigField生成打包時(shí)間。?
然后使用 TextView.setText(BuildConfig.releaseTime);