2018-10-15【Android打包版本号设置方法】

之前没有设置过打包的命名,每次打包都是默认的”app-realease.apk”,之后手动修改名字来显示出它是一个新版本。

 晚上学习了如何配置打包名称,很简单,修改build.gradle里的代码就行。

 详细记录如下:

1、打开app这个directory下的build.gradle

2、定义打包时间:

//时间

def releaseTime() {

  returnnewDate().format(“yyyyMMdd”, TimeZone.getTimeZone(“UTC”))

}

3、自定义发布时的版本号(return的返回值可自行修改,例如1.0、2.0):

//版本号

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’

//定义时间

def releaseTime() {

  returnnewDate().format(“yyyyMMdd”, TimeZone.getTimeZone(“UTC”))

}

//设置发布时的版本号

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’

  })

}

今天升级了AS3.1以后,在项目编译的时候发现Gradle中报错了,错误如下:

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>

经过一番折腾,网上找大牛的解读,弄明白了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)

        }

    }

}

下面是经过修改之后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);

            //遗留问题:如何获取当前module的name,如CodeBooke这个名字怎么获取到

        }

    }

}

问题:对于如何在gradle中获取module的name,还是没有找到相关的方法,希望有知道的大神留言交流。

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()//自动打包命名区分新旧版

}

build.gradle中自动生成版本号

Android Studio中,gradle.build里的设定会覆盖AndroidManifest.xml中的设置。

Gradle中使用的是Groovy语言,这是一种基于JVM的敏捷开发语言,还算是易学易用的。

在项目的build.gradle中,android.defaultConfig里,把versionCode和versionName改成自定义函数getSelfDefinedVersion:

android {    compileSdkVersion23buildToolsVersion”23.0.3″defaultConfig {        applicationId”com.example.xxx”minSdkVersion22targetSdkVersion23versionCode getSelfDefinedVersion(“code”)        versionName getSelfDefinedVersion(“name”)    }    buildTypes {        release {            minifyEnabledfalse}    }}

在build.gradle文件底部,统一实现版本号自动生成管理:

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″}}

这样虽然比较简陋,但功能是有了。

打包自动版本号与日期

(build.gradle 文件内容,com.android.tools.build:gradle:3.0.0 以下版本)

android{

    defaultConfig {…}

    自动追加版本号和版本名称

    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版本输出包名自动追加版本号和版本名称

    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应用程序的版本号Version name可以在android manifest下手动修改,在code中调用api获取该版本号。

    项目中的目标是:每编译一次程序都会自动修改版本号,而不需要手动修改,由于中间debug的次数较多,我打算以每次Build时的当前时间作为版本号。

    操作步骤:

    1. Android工程目录的assets文件夹下新建一文件,命名为version

    2. code中通过api获取assets下的文件内容,回显在activity,基础android编程知识,不解释

    3. Android.mk 文件中LOCAL_PATH:= $(call my-dir)下紧接着调用shell语句: $(shell date +%Y%m%d%H:%M:%S>$(LOCAL_PATH)/assets/version)

    如果项目对版本号或者版本名称有更复杂的需求,可以直接写成shell脚本,再由Android.mk 调用

    编译时自动输出当前编译时间到version文件,并打包到apk中,done!

感谢https://my.oschina.net/u/659658/blog/84545

import java.text.SimpleDateFormat

applyplugin:’com.android.application’

//设置发布时的版本号

static def getVersionName() {

int aa =3

    int i =”git rev-list –count HEAD”.execute().getText().toInteger()//build次数

    String today =new Date().format(“yyMMdd”)

Process process =”git describe –always”.execute()

process.waitFor()

String str = process.getText().trim()

return “$aa.$i.$today.$str”//”3.276″+str     //3.1.20181015.内容

// return aa+”.”+i+”.”+”.”+today+”.”+str

}

//设置发布时的版本码

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+次数

}

android {

compileSdkVersion28

    defaultConfig {

applicationId”com.hcsoft.storekeeper”

        minSdkVersion15

        targetSdkVersion28

        versionCodegetVersionCode()

versionName getVersionName()

testInstrumentationRunner”android.support.test.runner.AndroidJUnitRunner”

    }

//release版本输出包名自动追加版本号和版本名称

    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’])

}

原理是获得打包签名文件的生成时间。

    /**

    * 获得app的打包时间

    *

    * @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之后不好用,所以现在建议使用Gradle生成打包时间,然后再引用。核心代码如下:

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生成打包时间。 

然后使用 TextView.setText(BuildConfig.releaseTime);

    原文作者:AI爱因斯坦
    原文地址: https://www.jianshu.com/p/6ddea4081d1e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞