2013-06-13 2 views
30

Я искал широко, но, вероятно, из-за новизны Android Studio и Gradle, я не нашел описания того, как это сделать. Я хочу сделать в основном то, что описано в this post, но с Android Studio, Gradle и Windows, а не Eclipse и Linux.Автоматическая версия Android-проекта от git описана с помощью Android Studio/Gradle

ответ

19

Более правильный и постный способ достижения результата, который набирает обороты в последнее время было бы использовать gradle git integration через Groovy JGit bindings. Поскольку он использует JGit, он даже не требует установки git для работы.

Вот простой пример, показывающий аналогичной (но с некоторой дополнительной информацией в gitVersionName строке) решение:

buildscript { 
    dependencies { 
    classpath 'org.ajoberstar:grgit:1.4.+' 
    } 
} 
ext { 
    git = org.ajoberstar.grgit.Grgit.open() 
    gitVersionCode = git.tag.list().size() 
    gitVersionName = "${git.describe()}" 
} 
android { 
    defaultConfig { 
    versionCode gitVersionCode 
    versionName gitVersionName 
    } 
} 
[...] 

Как вы можете увидеть в Grgit API documentationdescribe operation предоставляют дополнительную информацию, кроме самого последнего тег достижимы в истории:

Find the most recent tag that is reachable from HEAD. If the tag points to the commit, then only the tag is shown. Otherwise, it suffixes the tag name with the number of additional commits on top of the tagged object and the abbreviated object name of the most recent commit.

Во всяком случае, это не скажет, загрязнено ли государство или нет. Эта информация может быть легко добавлена, посмотрев на clean status репо и добавив строку, если она не чистая.

+1

Это отличный ответ, но versionCode является целым числом, вместо этого используйте gitVersionCode = git.tag.list(). Size(). – BitByteDog

35

В файл build.gradle для проекта добавьте следующее. Нет необходимости напрямую изменять манифест: Google предоставил необходимые настройки в свою конфигурацию.

def getVersionCode = { -> 
    try { 
     def code = new ByteArrayOutputStream() 
     exec { 
      commandLine 'git', 'tag', '--list' 
      standardOutput = code 
     } 
     return code.toString().split("\n").size() 
    } 
    catch (ignored) { 
     return -1; 
    } 
} 

def getVersionName = { -> 
    try { 
     def stdout = new ByteArrayOutputStream() 
     exec { 
      commandLine 'git', 'describe', '--tags', '--dirty' 
      standardOutput = stdout 
     } 
     return stdout.toString().trim() 
    } 
    catch (ignored) { 
     return null; 
    } 
} 
android { 
    defaultConfig { 
     versionCode getVersionCode() 
     versionName getVersionName() 
    } 
} 

Обратите внимание, что если мерзавец не установлен на компьютере, или есть какая-то другая ошибка при получении имени версии/кода, он будет по умолчанию, что в вашем андроид манифеста.

+0

Это не работает для меня. Git установлен Хорошо, проект строит Ok, но имя и версия не обновляются в компиляции. Как я могу отлаживать то, что плохо? –

+0

Попробуйте использовать gradle непосредственно за пределами студии android: попробуйте запустить «gradlew assembleDebug» из вашего проекта, если вы используете стандартную платформу для градиента по умолчанию, разработанную android studio. – moveaway00

+3

@ moveaway00 вместо использования 'git tag --list | wc -l' не лучше просто использовать 'git rev-list -first-parent -count master', это дает количество коммитов из начальной версии, которая, на мой взгляд, является кодом версии. Использование тегов более рискованно, так как теги также используют случай использования и бросают ссылки во время rebases/squashes –

26

После просмотра moveaway00's answer и Avinash R's comment on that answer, я в конечном итоге с помощью этого:

apply plugin: 'android' 

def getVersionCode = { -> 
    try { 
     def stdout = new ByteArrayOutputStream() 
     exec { 
      commandLine 'git', 'rev-list', '--first-parent', '--count', 'master' 
      standardOutput = stdout 
     } 
     return Integer.parseInt(stdout.toString().trim()) 
    } 
    catch (ignored) { 
     return -1; 
    } 
} 

def getVersionName = { -> 
    try { 
     def stdout = new ByteArrayOutputStream() 
     exec { 
      commandLine 'git', 'describe', '--tags', '--dirty' 
      standardOutput = stdout 
     } 
     return stdout.toString().trim() 
    } 
    catch (ignored) { 
     return null; 
    } 
} 

android { 
    defaultConfig { 
     versionCode getVersionCode() 
     versionName getVersionName() 
    } 
} 

Я редактировал код moveaway00, чтобы также включать комментарий Авинаша R в: код версии теперь число фиксаций так master, так как это должен быть код версии.

Обратите внимание, что мне не нужно указывать код версии и имя версии в манифесте, Gradle позаботился об этом.

+3

Хорошо использовать HEAD вместо имени ветки. Итак, gradle будет использовать подсчет ревизий текущей ветки – Vetalll

+1

Конечно, вы можете заменить 'master' любой желаемой веткой или даже' HEAD' для текущей ветви. –

+1

@Vetalll. В этом случае использовать 'HEAD' нехорошо. Это связано с тем, что если вы разрабатываете подход с разделением по темам (например, git-flow), ветвь темы будет иметь больше коммитов, а это означает, что когда ветка будет объединена с 'master',' versionCode' будет понижен из-за наличия «первого родителя». Поэтому, чтобы позволить вам и вашим коллегам-разработчикам не удалять приложение каждый раз, когда ветвь темы объединяется в master, возьмите 'versionCode' из' master' (или из когда-либо вашей ветви релиза) –

2

Другой способ, с помощью Android-студия (Gradle): Заканчивать этот блог: http://blog.android-develop.com/2014/09/automatic-versioning-and-increment.html

Вот реализация из блога:

android { 
defaultConfig { 
... 
    // Fetch the version according to git latest tag and "how far are we from last tag" 
    def longVersionName = "git -C ${rootDir} describe --tags --long".execute().text.trim() 
    def (fullVersionTag, versionBuild, gitSha) = longVersionName.tokenize('-') 
    def(versionMajor, versionMinor, versionPatch) = fullVersionTag.tokenize('.') 

    // Set the version name 
    versionName "$versionMajor.$versionMinor.$versionPatch($versionBuild)" 

    // Turn the version name into a version code 
    versionCode versionMajor.toInteger() * 100000 + 
      versionMinor.toInteger() * 10000 + 
      versionPatch.toInteger() * 1000 + 
      versionBuild.toInteger() 

    // Friendly print the version output to the Gradle console 
    printf("\n--------" + "VERSION DATA--------" + "\n" + "- CODE: " + versionCode + "\n" + 
      "- NAME: " + versionName + "\n----------------------------\n") 
... 
} 

}

4

Вот еще один решение, которое требует от операторов вместо функций доступа к командной строке. Внимания: * Никс только решение

def gitSha = 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim() 

// Auto-incrementing commit count based on counting commits to master (Build #543) 
def commitCount = Integer.parseInt('git rev-list master --count'.execute([], project.rootDir).text.trim()) 

// I want to use git tags as my version names (1.2.2) 
def gitCurrentTag = 'git describe --tags --abbrev=0'.execute([], project.rootDir).text.trim() 

android { 
    compileSdkVersion 22 
    buildToolsVersion "22.0.1" 

    defaultConfig { 
     applicationId "com.some.app" 
     minSdkVersion 16 
     targetSdkVersion 22 
     versionCode commitCount 
     versionName gitCurrentTag 

     buildConfigField "String", "GIT_SHA", "\"${gitSha}\"" 

    } 
    buildTypes { 
     release { 
      minifyEnabled false 
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
     } 

    } 
} 
+0

Это просто перестало работать? Я использую это навсегда и теперь с последними обновлениями для AS и Gradle, похоже, не получает значения ... right directory для выполнения команды и проверки команды за пределами Gradle, и все работает. – Codeversed

2

Если это может быть любая помощь, я создал пример сценария Gradle, который использует теги Git и Git для достижения этого. Вот код (вы также можете найти его here).

1) Сначала создайте версия.Gradle файл, содержащий:

import java.text.SimpleDateFormat 

/** 
* This Gradle script relies on Git tags to generate versions for your Android app 
* 
* - The Android version NAME is specified in the tag name and it's 3 digits long (example of a valid tag name: "v1.23.45") 
* If the tag name is not in a valid format, then the version name will be 0.0.0 and you should fix the tag. 
* 
* - The Android version CODE is calculated based on the version name (like this: (major * 1000000) + (minor * 10000) + (patch * 100)) 
* 
* - The 4 digits version name is not "public" and the forth number represents the number of commits from the last tag (example: "1.23.45.178") 
* 
*/ 

ext { 

    getGitSha = { 
     return 'git rev-parse --short HEAD'.execute().text.trim() 
    } 

    getBuildTime = { 
     def df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'") 
     df.setTimeZone(TimeZone.getTimeZone("UTC")) 
     return df.format(new Date()) 
    } 

    /** 
    * Git describe returns the following: [GIT_TAG_NAME]-[BUILD_NUMBER]-[GIT_SHA] 
    */ 
    getAndroidGitDescribe = { 
     return "git -C ${rootDir} describe --tags --long".execute().text.trim() 
    } 

    /** 
    * Returns the current Git branch name 
    */ 
    getGitBranch = { 
     return "git rev-parse --abbrev-ref HEAD".execute().text.trim() 
    } 

    /** 
    * Returns the full version name in the format: MM.mm.pp.ccc 
    * 
    * The version name is retrieved from the tag name which must be in the format: vMM.mm.pp, example: "v1.23.45" 
    */ 
    getFullVersionName = { 
     def versionName = "0.0.0.0" 
     def (tag, buildNumber, gitSha) = getAndroidGitDescribe().tokenize('-') 
     if (tag && tag.startsWith("v")) { 
      def version = tag.substring(1) 
      if (version.tokenize('.').size() == 3) { 
       versionName = version + '.' + buildNumber 
      } 
     } 
     return versionName 
    } 

    /** 
    * Returns the Android version name 
    * 
    * Format "X.Y.Z", without commit number 
    */ 
    getAndroidVersionName = { 
     def fullVersionName = getFullVersionName() 
     return fullVersionName.substring(0, fullVersionName.lastIndexOf('.')) 
    } 

    /** 
    * Returns the Android version code, deducted from the version name 
    * 
    * Integer value calculated from the version name 
    */ 
    getAndroidVersionCode = { 
     def (major, minor, patch) = getAndroidVersionName().tokenize('.') 
     (major, minor, patch) = [major, minor, patch].collect{it.toInteger()} 
     return (major * 1000000) + (minor * 10000) + (patch * 100) 
    } 

    /** 
    * Return a pretty-printable string containing a summary of the version info 
    */ 
    getVersionInfo = { 
     return "\nVERSION INFO:\n\tFull version name: " + getFullVersionName() + 
       "\n\tAndroid version name: " + getAndroidVersionName() + 
       "\n\tAndroid version code: " + getAndroidVersionCode() + 
       "\n\tAndroid Git branch: " + getGitBranch() + 
       "\n\tAndroid Git describe: " + getAndroidGitDescribe() + 
       "\n\tGit SHA: " + getGitSha() + 
       "\n\tBuild Time: " + getBuildTime() + "\n" 
    } 

    // Print version info at build time 
    println(getVersionInfo()); 
} 

2) Затем измените ваш приложение/build.gradle использовать его как это:

import groovy.json.StringEscapeUtils; 

apply plugin: 'com.android.application' // << Apply the plugin 

android { 

    configurations { 
     // ... 
    } 

    compileSdkVersion 22 
    buildToolsVersion "22.0.1" 

    defaultConfig { 

     minSdkVersion 17 
     targetSdkVersion 22 

     applicationId "app.example.com" 

     versionCode getAndroidVersionCode() // << Use the plugin! 
     versionName getAndroidVersionName() // << Use the plugin! 

     // Build config constants 
     buildConfigField "String", "GIT_SHA", "\"${getGitSha()}\"" 
     buildConfigField "String", "BUILD_TIME", "\"${getBuildTime()}\"" 
     buildConfigField "String", "FULL_VERSION_NAME", "\"${getVersionName()}\"" 
     buildConfigField "String", "VERSION_DESCRIPTION", "\"${StringEscapeUtils.escapeJava(getVersionInfo())}\"" 
    } 

    signingConfigs { 
     config { 
      keyAlias 'MyKeyAlias' 
      keyPassword 'MyKeyPassword' 
      storeFile file('my_key_store.keystore') 
      storePassword 'MyKeyStorePassword' 
     } 
    } 

    buildTypes { 

     debug { 
      minifyEnabled false 
      debuggable true 
     } 

     release { 
      minifyEnabled true 
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
      signingConfig signingConfigs.config 
      debuggable false 
     } 

    } 

    productFlavors { 
     // ... 
    } 

    dependencies { 
     // ... 
    } 

    compileOptions { 
     sourceCompatibility JavaVersion.VERSION_1_7 
     targetCompatibility JavaVersion.VERSION_1_7 
    } 
} 

/** 
* Save a build.info file 
*/ 
task saveBuildInfo { 
    def buildInfo = getVersionInfo() 
    def assetsDir = android.sourceSets.main.assets.srcDirs.toArray()[0] 
    assetsDir.mkdirs() 
    def buildInfoFile = new File(assetsDir, 'build.info') 
    buildInfoFile.write(buildInfo) 
} 

gradle.projectsEvaluated { 
    assemble.dependsOn(saveBuildInfo) 
} 

Наиболее важной частью является применение плагина

apply plugin: 'com.android.application' 

И затем используйте его для имени и кода версии для Android версии

versionCode getAndroidVersionCode() 
versionName getAndroidVersionName() 
+0

ссылка только решение не решение. Пожалуйста, добавьте соответствующий код перед тем, как кто-нибудь изменит ваш ответ. –

1

на основе Léo Lam's answer и мои ранее explorations на тот же раствор для муравьев, я разработал чисто кроссплатформенных раствора с помощью jgit:

(оригинал source)

Файла : git-version.gradle

buildscript { 
    dependencies { 
     //noinspection GradleDynamicVersion 
     classpath "org.eclipse.jgit:org.eclipse.jgit:4.1.1.+" 
    } 
    repositories { 
     jcenter() 
    } 
} 
import org.eclipse.jgit.api.Git 
import org.eclipse.jgit.revwalk.RevWalk 
import org.eclipse.jgit.storage.file.FileRepositoryBuilder 

import static org.eclipse.jgit.lib.Constants.MASTER 

def git = Git.wrap(new FileRepositoryBuilder() 
     .readEnvironment() 
     .findGitDir() 
     .build()) 

ext.readVersionCode = { 
    def repo = git.getRepository() 
    def walk = new RevWalk(repo) 
    walk.withCloseable { 
     def head = walk.parseCommit(repo.getRef(MASTER).getObjectId()) 
     def count = 0 
     while (head != null) { 
      count++ 
      def parents = head.getParents() 
      if (parents != null && parents.length > 0) { 
       head = walk.parseCommit(parents[0]) 
      } else { 
       head = null 
      } 
     } 
     walk.dispose() 
     println("using version name: $count") 
     return count 
    } 
} 

ext.readVersionName = { 
    def tag = git.describe().setLong(false).call() 
    def clean = git.status().call().isClean() 
    def version = tag + (clean ? '' : '-dirty') 
    println("using version code: $version") 
    return version 
} 

Использование будет:

apply from: 'git-version.gradle' 

android { 
    ... 
    defaultConfig { 
    ... 
    versionCode readVersionCode() 
    versionName readVersionName() 
    ... 
    } 
    ... 
} 
8

Еще один способ:

https://github.com/gladed/gradle-android-git-version новый Gradle плагин, который вычисляет андроид дружественных имен версия и версия коды автоматически.

Он обрабатывает много особых случаев, которые не представляется возможным с помощью принятого решения:

  • версия теги для нескольких проектов в том же репо
  • расширенной версии коды, как 1002003 для 1.2.3
  • Gradle задача для простого извлечения информации версии для CI инструментов
  • т.д.

Отказ от ответственности: Я Wr от нее.

+1

Отличный плагин. Спасибо вам за вашу работу! – Henrik

Смежные вопросы