React Native - 从package.json到android build manifest的自动版本名称

时间:2017-11-26 01:35:39

标签: android node.js gradle react-native gitversion

目前我有一个本机应用程序,我遇到的问题是在每次构建或提交时更新版本都非常耗时。

此外,我启用了Sentry,因此每次构建时,某些版本都会获得相同的版本,因此一些崩溃很难确定它们来自何处。

最后,手动更新版本容易出错。

如何设置构建以在每次构建时生成自动版本并忘记所有这些手动任务?

3 个答案:

答案 0 :(得分:4)

由于我在这方面工作了好几天,所以我决定与大家分享我是如何做到的,因为它可以帮助别人。

使用的工具:

  1. GitVersion:我们将使用GitVersion自动生成一个语义版本,具体取决于当前分支,标签,提交等许多因素.toold做得很好,您可以忘记命名您的版本。当然,如果您将标记设置为提交,它将使用该标记作为名称。
  2. PowerShell:这个由Microsoft构建的命令行操作系统可以从Mac,Linux或Windows运行,我之所以选择它,是因为这些版本可以与操作系统版本无关。例如,我在Windows上开发,但构建机器有MacOS。
  3. 编辑App build.gradle

    app gradle只需在其末尾添加一行。在我的情况下,我有谷歌播放服务gradle,之后我添加了它。

    apply from: 'version.gradle'
    

    version.gradle

    此文件应与您的应用程序gradle位于同一文件夹中,这是内容:

    task updatePackage(type: Exec, description: 'Updating package.json') {
        commandLine 'powershell', ' -command ' , '$semver=(gitversion /showvariable Semver); Set-Content -path version.properties -value semver=$semver; npm version --no-git-tag-version --allow-same-version $semver'  
    }
    preBuild.dependsOn updatePackage
    
    task setVariantVersion {
    
        doLast {
    
            if (plugins.hasPlugin('android') || plugins.hasPlugin('android-library')) {
    
                def autoIncrementVariant = { variant ->
                    variant.mergedFlavor.versionName = calculateVersionName()
                }
    
                if (plugins.hasPlugin('android')){
                    //Fails without putting android. first
                    android.applicationVariants.all { variant -> autoIncrementVariant(variant) }
                }
    
                if (plugins.hasPlugin('android-library')) {
                    //Probably needs android-library before libraryVariants. Needs testing
                    libraryVariants.all { variant -> autoIncrementVariant(variant) }
                }
            }
    
        }
    
    }
    preBuild.dependsOn setVariantVersion
    setVariantVersion.mustRunAfter updatePackage
    
    ext {
        versionFile = new File('version.properties')
        calculateVersionName = {
            def version = readVersion()
            def semver = "Unknown"
            if (version != null){
                semver = version.getProperty('semver')
            }
            return semver
        }
    }
    
    Properties readVersion() {
        //It gets called once for every variant but all get the same version
        def version = new Properties()
        try {
            file(versionFile).withInputStream { version.load(it) }
        } catch (Exception error) {
            version = null
        } 
        return version
    }
    

    现在,让我们回顾一下脚本实际上在做什么:

    1. updatePackage:此任务在构建的最开始(实际上在preBuild之前)运行,并执行gitversion以获取当前版本,然后创建一个version.properties文件,稍后由gradle读取该文件以获取该版本。
    2. setVariantVersion:在每个变体上调用afterEvaluate。这意味着如果您有多个构建,如debug,release,qa,staging等,则所有版本都将获得相同的版本。对于我的用例,这很好,但你可能想要调整它。
    3. 任务顺序:困扰我的一件事是版本在文件生成之前运行。这可以通过使用mustRunAfter标记来解决。
    4. PowerShell脚本说明

      这是首先运行的脚本。让我们回顾一下正在做什么:

      $semver=(gitversion /showvariable Semver);
      Set-Content -path props.properties -value semver=$semver; 
      npm version --no-git-tag-version --allow-same-version $semver
      
      1. 第1行:gitversion有多种类型的版本。如果你在没有任何参数的情况下运行它,你将获得一个包含许多变体的json文件。我们在这里说我们只想要SemVer。 (另见FullSemVer)
      2. 第2行:PowerShell创建文件并将内容保存到其中的方法。这也可以用>进行。但我有编码问题,并没有读取属性文件。
      3. 第3行:此行更新您的package.json版本。默认情况下,它会使用新版本保存对git的提交。 --no-git-tag-version确保你不要覆盖它。
      4. 就是这样。现在,每次进行构建时,都应自动生成版本,更新package.json,并且构建应具有该特定版本名称。

        App Center

        由于我使用App Center进行构建,我将告诉您如何在Build机器中使用它。您只需要使用自定义脚本。

        app-center-pre-build.sh

        #!/usr/bin/env sh
        #Installing GitVersion
        OS=$(uname -s)
        if [[ $OS == *"W64"* ]]; then
            echo "Installing GitVersion with Choco"
            choco install GitVersion.Portable -y
        else 
            echo "Installing GitVersion with Homebrew"
            brew install --ignore-dependencies gitversion
        fi
        

        这是必需的,因为GitVersion目前不是构建机器的一部分。此外,您需要在安装时忽略单声道依赖项,否则当brew尝试链接文件时会出现错误。

答案 1 :(得分:1)

虽然当前接受的答案将起作用,但是有一种更简单,因此更可靠的方法来执行此操作。 实际上,您可以直接从package.json读取build.gradle中设置的值。

修改您的android/app/build.gradle

// On top of your file import a JSON parser
import groovy.json.JsonSlurper

// Create an easy to use function
def getVersionFromNpm() {
    //  Read and parse package.json file from project root
    def inputFile = new File("$rootDir/../package.json")
    def packageJson = new JsonSlurper().parseText(inputFile.text)

    // Return the version, you can get any value this way
    return packageJson["version"]
}

android {
    defaultConfig {
        applicationId "your.app.id"
        versionName getVersionFromNpm()
    }
}

这样,您就不需要预构建脚本或任何其他东西,它就可以工作。

答案 2 :(得分:1)

@MacRusher版本对我来说很好。为了进一步的读者,我必须添加.toInteger()使其起作用。由于我使用yarn version --patch来自动升级package.json中的版本,因此我也只需要使用前两个字符。

这是新版本:

// On top of your file import a JSON parser
import groovy.json.JsonSlurper

def getVersionFromPackageJson() {
    //  Read and parse package.json file from project root
    def inputFile = new File("$rootDir/../package.json")
    def packageJson = new JsonSlurper().parseText(inputFile.text)

    // Return the version, you can get any value this way
    return packageJson["version"].substring(0,2).toInteger()
}

android {
    defaultConfig {
        applicationId "your.app.id"
        versionName getVersionFromPackageJson()
    }
}