Gradle๋ก Android ์ฑ์ ๋ง๋ค๊ณ ์์ต๋๋ค. ์ง๊ธ๊น์ง๋ Manifest ํ์ผ์ ์ฌ์ฉํ์ฌ versionCode๋ฅผ ๋์์ง๋ง ์ธ๋ถ ํ์ผ์์ versionCode๋ฅผ ์ฝ๊ณ ๋ฆด๋ฆฌ์ค ๋ฒ์ ์ธ์ง ๋๋ฒ๊ทธ ๋ฒ์ ์ธ์ง์ ๋ฐ๋ผ versionCode๋ฅผ ๋์ด๊ณ ์ถ์ต๋๋ค. ์ถ๊ฐ ์์ฑ์ ์๋ํ์ง๋ง ์ ์ฅํ ์ ์์ต๋๋ค. ์ฆ, ๋ค์์ ๋น๋ ํ ๋ ๋์ผํ versionCode๋ฅผ ์ป๊ฒ๋ฉ๋๋ค. ์ด๋ค ๋์์ด๋ผ๋ ๋๋จํ ๊ฐ์ฌํ๊ฒ ์ต๋๋ค!
project.ext{
devVersionCode = 13
releaseVersionCode = 1
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
}
dependencies {
compile project(':Cropper')
compile "com.android.support:appcompat-v7:18.0.+"
compile "com.android.support:support-v4:18.0.+"
compile fileTree(dir: 'libs', include: '*.jar')
}
def getReleaseVersionCode() {
def version = project.releaseVersionCode + 1
project.releaseVersionCode = version
println sprintf("Returning version %d", version)
return version
}
def getDevVersionCode() {
def version = project.devVersionCode + 1
project.devVersionCode = version
println sprintf("Returning version %d", version)
return version
}
def getLastVersioName(versionCode) {
return "0.0." + versionCode
}
android {
compileSdkVersion 19
buildToolsVersion "19.0.0"
defaultConfig {
minSdkVersion 9
targetSdkVersion 19
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
}
buildTypes {
release {
runProguard true
proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
proguardFile 'proguard.cfg'
debuggable false
signingConfig null
zipAlign false
}
debug {
versionNameSuffix "-DEBUG"
}
}
productFlavors {
dev {
packageName = 'com.swisscom.docsafe.debug'
versionCode getDevVersionCode()
versionName getLastVersioName(project.devVersionCode)
}
prod {
packageName = 'com.swisscom.docsafe'
versionCode getReleaseVersionCode()
versionName getLastVersioName(project.releaseVersionCode)
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '1.8'
}
๋ต๋ณ
์ธ๋ถ ํ์ผ์์ versionCode๋ฅผ ์ฝ๊ณ ์ถ์ต๋๋ค.
๊ฐ๋ฅํ ํด๊ฒฐ์ฑ ์ด ๋ง์ด ์๋ค๊ณ ํ์ ํฉ๋๋ค. ์ฌ๊ธฐ์ ํ๋๊ฐ ์์ต๋๋ค.
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
}
์ด ์ฝ๋๋ version.properties
์ฒซ ๋ฒ์งธ ๋น๋๊ฐ VERSION_CODE=8
.
์ด ์ฝ๋๋ ๋จ์ํ ๊ฐ ๋น๋์ ๋ฒ์ ์ฝ๋๋ฅผ ๋ฒํํฉ๋๋ค. ๊ฐ ๋ฒ์ ์ฝ๋๋ฅผ ์ฒ๋ฆฌํ๋ ค๋ฉด ๊ธฐ์ ์ ํ์ฅํด์ผํฉ๋๋ค.
์ด ์ฝ๋๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ฒ์ ๊ด๋ฆฌ ์ํ ํ๋ก์ ํธ ๋ฅผ ๋ณผ ์ ์์ต๋๋ค .
๋ต๋ณ
์๋์์ ๋ณผ ์์๋ ์ด์ ๋ต๋ณ์ ํ๋ํ๊ฐ ์์ต๋๋ค. ์ด๊ฒ์ Gradle 4.4 ๋ฐ Android Studio 3.1.1์์ ์คํ๋ฉ๋๋ค .
์ด ์คํฌ๋ฆฝํธ์ ๊ธฐ๋ฅ :
- ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ version.properties ํ์ผ์ ์์ฑ ํฉ๋๋ค (์ด ๋ต๋ณ์ด ๋ง์์ ๋ค๋ฉด ์์ด๋์ด๋ฅผ ์ป์ ์๋ Paul Cantrell์ ๋ต๋ณ์ ์ฐฌ์ฑ ํฌํ)
- ๊ฐ ๋น๋, ๋๋ฒ๊ทธ ๋ฆด๋ฆฌ์ค ๋๋ Android ์คํ๋์ค์์ ์คํ ๋ฒํผ์ ๋๋ฅผ ๋๋ง๋ค VERSION_BUILD ๋ฒํธ๊ฐ ์ฆ๊ฐํฉ๋๋ค.
- ๋ฆด๋ฆฌ์ค๋ฅผ ์กฐ๋ฆฝํ ๋๋ง๋ค ํ๋ ์ด ์คํ ์ด ์ Android ๋ฒ์ ์ฝ๋ ๊ฐ ์ฆ๊ฐํ๊ณ ํจ์น ๋ฒํธ๊ฐ ์ฆ๊ฐํฉ๋๋ค.
- ๋ณด๋์ค : ๋น๋๊ฐ ์๋ฃ๋๋ฉด APK๋ฅผ
projectDir/apk
์ ๋ณต์ฌํ์ฌ ๋ ์ฝ๊ฒ ์ก์ธ์ค ํ ์ ์์ต๋๋ค.
์ด ์คํฌ๋ฆฝํธ๋ AppName-v1.3.4.apkv1.3.4 (123)
์ ๊ฐ์ apk ํ์ผ์ ๋น๋ํ๋ ๋ฒ์ ๋ฒํธ๋ฅผ ์์ฑํฉ๋๋ค .
Major version โ โ Build version
v1.3.4 (123)
Minor version โ|โ Patch version
๋ฉ์ด์ ๋ฒ์ : ๋ ํฐ ๋ณ๊ฒฝ์ ์ํด ์๋์ผ๋ก ๋ณ๊ฒฝํด์ผํฉ๋๋ค.
๋ถ ๋ฒ์ : ์ฝ๊ฐ ๋ ํฐ ๋ณ๊ฒฝ์ ์ํด ์๋์ผ๋ก ๋ณ๊ฒฝํด์ผํฉ๋๋ค.
ํจ์น ๋ฒ์ : ์คํ์ ์ฆ๊ฐgradle assembleRelease
๋น๋ ๋ฒ์ : ๋ชจ๋ ๋น๋๋ฅผ ๋๋ฆฝ๋๋ค.
๋ฒ์ ๋ฒํธ : ํจ์น ๋ฒ์ ๊ณผ ๋์ผํ๋ฉฐ , ์ APK ์ ๋ก๋๋ง๋ค Play ์คํ ์ด์์ ์ฆ๊ฐ์์ผ์ผํ๋ ๋ฒ์ ์ฝ๋์ ๋๋ค.
์๋์ 1-3์ผ๋ก ํ์๋ ์ฃผ์์ ๋ด์ฉ์ ๋ณ๊ฒฝํ๋ฉด ๋๋จธ์ง๋ ์คํฌ๋ฆฝํธ๊ฐ ์ํํฉ๋๋ค. ๐
android {
compileSdkVersion 27
buildToolsVersion '27.0.3'
def versionPropsFile = file('version.properties')
def value = 0
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
versionProps['VERSION_PATCH'] = "0"
versionProps['VERSION_NUMBER'] = "0"
versionProps['VERSION_BUILD'] = "-1" // I set it to minus one so the first build is 0 which isn't super important.
versionProps.store(versionPropsFile.newWriter(), null)
}
def runTasks = gradle.startParameter.taskNames
if ('assembleRelease' in runTasks) {
value = 1
}
def mVersionName = ""
def mFileName = ""
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString()
versionProps['VERSION_NUMBER'] = (versionProps['VERSION_NUMBER'].toInteger() + value).toString()
versionProps['VERSION_BUILD'] = (versionProps['VERSION_BUILD'].toInteger() + 1).toString()
versionProps.store(versionPropsFile.newWriter(), null)
// 1: change major and minor version here
mVersionName = "v1.0.${versionProps['VERSION_PATCH']}"
// 2: change AppName for your app name
mFileName = "AppName-${mVersionName}.apk"
defaultConfig {
minSdkVersion 21
targetSdkVersion 27
applicationId "com.example.appname" // 3: change to your package name
versionCode versionProps['VERSION_NUMBER'].toInteger()
versionName "${mVersionName} Build: ${versionProps['VERSION_BUILD']}"
}
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
if ('assembleRelease' in runTasks) {
applicationVariants.all { variant ->
variant.outputs.all { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
outputFileName = mFileName
}
}
}
}
task copyApkFiles(type: Copy){
from 'build/outputs/apk/release'
into '../apk'
include mFileName
}
afterEvaluate {
assembleRelease.doLast {
tasks.copyApkFiles.execute()
}
}
signingConfigs {
...
}
buildTypes {
...
}
}
================================================ ==
์ด๊ธฐ ๋ต๋ณ :
versionName๋ ์๋์ผ๋ก ์ฆ๊ฐํ๊ธฐ๋ฅผ ์ํฉ๋๋ค. ๊ทธ๋์ ์ด๊ฒ์ ์ ์๊ฒ ์๋ฒฝํ๊ฒ ์๋ํ๋ CommonsWare์ ๋ต๋ณ์ ์ถ๊ฐ๋์์ต๋๋ค. ์ด๊ฒ์ ๋๋ฅผ ์ํด ์ผํ๋ ๊ฒ์ ๋๋ค
defaultConfig {
versionCode code
versionName "1.1." + code
minSdkVersion 14
targetSdkVersion 18
}
ํธ์งํ๋ค:
์กฐ๊ธ ๊ฒ์ผ ๋ฅด๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฅํ ํ ์๋์ผ๋ก ๋ฒ์ ๊ด๋ฆฌ๊ฐ ์๋ํ๊ธฐ๋ฅผ ์ํฉ๋๋ค. ๋ด๊ฐ ์ํ๋ ๊ฒ์ ๊ฐ ๋น๋๋ง๋ค ์ฆ๊ฐ ํ๋ ๋น๋ ๋ฒ์ ์ ๊ฐ๋ ๋ฐ๋ฉด, ๋ฒ์ ๋ฒํธ ์ ๋ฒ์ ์ด๋ฆ ์ ๋ฆด๋ฆฌ์ค ๋น๋๋ฅผ ๋ง๋ค ๋๋ง ์ฆ๊ฐํฉ๋๋ค.
์ด๊ฒ์ ๋ด๊ฐ ์๋ ์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ๊ธฐ๋ณธ์ CommonsWare์ ๋ต๋ณ๊ณผ ์ด์ ๋ต๋ณ์ ๋ํ์ฌ ๋ช ๊ฐ์ง ๋ ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ ๋ฒ์ ์ด ์ง์ ๋ฉ๋๋ค.
๋ฒ์ ์ด๋ฆ : 1.0.5 (123) -> Major.Minor.Patch (Build), Major ๋ฐ Minor๋ ์๋์ผ๋ก ๋ณ๊ฒฝ๋ฉ๋๋ค.
build.gradle์์ :
...
android {
compileSdkVersion 23
buildToolsVersion '23.0.1'
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def value = 0
def runTasks = gradle.startParameter.taskNames
if ('assemble' in runTasks || 'assembleRelease' in runTasks || 'aR' in runTasks) {
value = 1;
}
def versionMajor = 1
def versionMinor = 0
def versionPatch = versionProps['VERSION_PATCH'].toInteger() + value
def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
def versionNumber = versionProps['VERSION_NUMBER'].toInteger() + value
versionProps['VERSION_PATCH'] = versionPatch.toString()
versionProps['VERSION_BUILD'] = versionBuild.toString()
versionProps['VERSION_NUMBER'] = versionNumber.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode versionNumber
versionName "${versionMajor}.${versionMinor}.${versionPatch} (${versionBuild}) Release"
minSdkVersion 14
targetSdkVersion 23
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def fileNaming = "apk/RELEASES"
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
output.outputFile = new File(getProject().getRootDir(), "${fileNaming}-${versionMajor}.${versionMinor}.${versionPatch}-${outputFile.name}")
}
}
}
}
} else {
throw new GradleException("Could not read version.properties!")
}
...
}
...
โassembleโ , โassembleReleaseโ ๋๋ โaRโ ์ ์ฌ์ฉ ํ์ฌ ํฐ๋ฏธ๋์ ํตํด ํ๋ก์ ํธ๋ฅผ ์ด์ ๋ธํ๋ฉด ํจ์น ๋ฐ ๋ฒ์ ์ฝ๋๊ฐ ์ฆ๊ฐ ํ์ฌ ํ๋ก์ ํธ ๋ฃจํธ์ apk / RELEASE๋ผ๋ ์ ํด๋๋ฅผ ์์ฑํ๋ฏ๋ก ๋น๋ / ์ถ๋ ฅ์ ์ดํด๋ณผ ํ์๊ฐ ์์ต๋๋ค. / more / more / more์์ APK๋ฅผ ์ฐพ์ผ์ธ์.
๋ฒ์ ์์ฑ์ ๋ค์๊ณผ ๊ฐ์์ผํฉ๋๋ค.
VERSION_NUMBER=1
VERSION_BUILD=645
VERSION_PATCH=1
๋ถ๋ช ํ 0์ผ๋ก ์์ํฉ๋๋ค. ๐
๋ต๋ณ
CommonsWare์ ์ฐ์ํ ๋ต๋ณ์ ์ฝ๊ฐ ๊ฐํ ๋ ๋ฒ์ ์ด ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ ๋ฒ์ ํ์ผ์ ์์ฑํฉ๋๋ค.
def Properties versionProps = new Properties()
def versionPropsFile = file('version.properties')
if(versionPropsFile.exists())
versionProps.load(new FileInputStream(versionPropsFile))
def code = (versionProps['VERSION_CODE'] ?: "0").toInteger() + 1
versionProps['VERSION_CODE'] = code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode code
versionName "1.1"
minSdkVersion 14
targetSdkVersion 18
}
๋ต๋ณ
์ด ์์ ์ ์ํํ๊ธฐ์ํ ๋ช ๊ฐ์ง ์ต์ ์ ์ดํด๋ณธ ๊ฒฐ๊ณผ, versionCode๋ฅผ ์๋์ผ๋ก ์ฆ๊ฐ์์ผ ์์ ๊ด๋ฆฌ ์์คํ ์ ์ฒดํฌ์ธํ๋ ๋์ versionCode์ ํ์ฌ ์๊ฐ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ๊ฐ๋จํ๋ค๊ณ ๊ฒฐ์ ํ์ต๋๋ค.
์ ๋ค์์ ์ถ๊ฐํ์ญ์์ค build.gradle
.
/**
* Use the number of seconds/10 since Jan 1 2016 as the versionCode.
* This lets us upload a new build at most every 10 seconds for the
* next 680 years.
*/
def vcode = (int)(((new Date().getTime()/1000) - 1451606400) / 10)
android {
defaultConfig {
...
versionCode vcode
}
}
๊ทธ๋ฌ๋ 2696 ๋ ์ดํ์ ๋น๋๋ฅผ ์ ๋ก๋ํ๋ ค๋ ๊ฒฝ์ฐ ๋ค๋ฅธ ์๋ฃจ์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ต๋ณ
versionCode
์๋์ผ๋ก ๊ฐ์ ธ ์ค๋ ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ versionCode
์ฒดํฌ ์์ ๋ git
๋ถ๊ธฐ ์ ์ปค๋ฐ ์๋ฅผ ์ค์ ํ๋ ๊ฒ ์
๋๋ค. ๋ค์ ๋ชฉํ๋ฅผ ๋ฌ์ฑํฉ๋๋ค.
versionCode
๋ชจ๋ ์ปดํจํฐ (Continuous Integration
๋ฐ / ๋๋Continuous Deployment
์๋ฒ ํฌํจ)์์ ์๋์ผ๋ก ์ผ๊ด๋๊ฒ ์์ฑ๋ฉ๋๋ค .- ์ด ์ฑ
versionCode
์ GooglePlay์ ์ ์ถํ ์ ์์ต๋๋ค. - ์ ์ฅ์ ์ธ๋ถ์ ํ์ผ์ ์์กดํ์ง ์์ต๋๋ค.
- repo์ ์๋ฌด๊ฒ๋ ํธ์ํ์ง ์์ต๋๋ค.
- ํ์ํ ๊ฒฝ์ฐ ์๋์ผ๋ก ์ฌ์ ์ ํ ์ ์์ต๋๋ค.
์ฌ์ฉ Gradle์-์์ ๋์๊ด์ ์์ ๋ชฉํ๋ฅผ ๋ฌ์ฑํฉ๋๋ค. build.gradle
ํ์ผ /app
๋๋ ํ ๋ฆฌ์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ญ์์ค .
import org.ajoberstar.grgit.Grgit
repositories {
mavenCentral()
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.ajoberstar:grgit:1.5.0'
}
}
android {
/*
if you need a build with a custom version, just add it here, but don't commit to repo,
unless you'd like to disable versionCode to be the number of commits in the current branch.
ex. project.ext.set("versionCodeManualOverride", 123)
*/
project.ext.set("versionCodeManualOverride", null)
defaultConfig {
versionCode getCustomVersionCode()
}
}
def getCustomVersionCode() {
if (project.versionCodeManualOverride != null) {
return project.versionCodeManualOverride
}
// current dir is <your proj>/app, so it's likely that all your git repo files are in the dir
// above.
ext.repo = Grgit.open(project.file('..'))
// should result in the same value as running
// git rev-list <checked out branch name> | wc -l
def numOfCommits = ext.repo.log().size()
return numOfCommits
}
์ฐธ๊ณ :์ด ๋ฐฉ๋ฒ์ด ์๋ํ๋ ค๋ฉด ๋์ผํ ๋ธ๋์น (์ :)์์๋ง Google Play ์คํ ์ด์ ๋ฐฐํฌํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค master
.
๋ต๋ณ
์ต๊ทผ์ ๋๋ versionCode ์ versionName์ ์๋์ผ๋ก ์์ฑํ๋ Android ์ฉ gradle ํ๋ฌ๊ทธ์ธ์ ์์
ํ๊ณ ์์์ต๋๋ค . ๋ง์ ์ฌ์ฉ์ ์ ์๊ฐ ์์ต๋๋ค. ์ฌ๊ธฐ์์ ์์ธํ ์ ๋ณด๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค
https://github.com/moallemi/gradle-advanced-build-version
๋ต๋ณ
๋ ๋ค๋ฅธ ์ต์
์ ์ฆ๊ฐ๋ฅผ ์ํด versionCode
๊ณผ๋ฅผ versionName
, ํ์ ์คํฌํ๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
defaultConfig {
versionName "${getVersionNameTimestamp()}"
versionCode getVersionCodeTimestamp()
}
def getVersionNameTimestamp() {
return new Date().format('yy.MM.ddHHmm')
}
def getVersionCodeTimestamp() {
def date = new Date()
def formattedDate = date.format('yyMMddHHmm')
def code = formattedDate.toInteger()
println sprintf("VersionCode: %d", code)
return code
}
2022 ๋ 1 ์๋ถํฐ formattedDate = date.format ( โyyMMddHHmmโ)์ด ์ ์ ์ฉ๋์ ์ด๊ณผํฉ๋๋ค.