简体   繁体   English

React Native - 从 package.json 到 android 构建清单的自动版本名称

[英]React Native - Automatic version name from package.json to android build manifest

Currently I have a react native app and the issue that I have is that is very time consuming to update the version on every build or commit.目前我有一个 react native 应用程序,我遇到的问题是在每次构建或提交时更新版本非常耗时。

Also, I have Sentry enabled so every time I build, some builds get the same version so some crashes are hard to determine where they came from.另外,我启用了 Sentry,所以每次我构建时,有些构建得到相同的版本,所以有些崩溃很难确定它们来自哪里。

Lastly, updating the version manually is error prone.最后,手动更新版本容易出错。

How can I setup my builds to generate an automatic version every time I build and forget about all of this manual task?我如何设置我的构建以在每次构建并忘记所有这些手动任务时生成自动版本?

While the currently accepted answer will work, there is a much simpler, and therefore more reliable way to do it.虽然目前接受的答案可行,但有一种更简单、因此更可靠的方法来做到这一点。 You can actually read the value set in package.json right from build.gradle .您实际上可以直接从build.gradle读取package.json设置的值。

Modify your android/app/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()
    }
}

This way you won't need a pre-build script or anything, it will just work.这样你就不需要预构建脚本或任何东西,它就可以工作。

Since I was working with this for several days, I decided to share with everyone how I did it, because it could help others.由于我为此工作了几天,所以我决定与大家分享我是如何做到的,因为它可以帮助其他人。

Tools used:使用的工具:

  1. GitVersion : We will use GitVersion to generate a semantic version automatically depending on many factors like current branch, tags, commits, etc. The toold does an excellent job and you can forget about naming your versions. GitVersion :我们将使用 GitVersion 根据当前分支、标签、提交等许多因素自动生成语义版本。该工具做得非常好,您可以忘记命名版本。 Of course, if you set a tag to a commit, it will use that tag as name.当然,如果您将标签设置为提交,它将使用该标签作为名称。
  2. PowerShell : This command line OS built by Microsoft has the ability to be run from Mac, Linux or Windows, and I chose it because the builds can be agnostic of the OS version. PowerShell :这个由 Microsoft 构建的命令行操作系统能够在 Mac、Linux 或 Windows 上运行,我选择它是因为构建可以与操作系统版本无关。 For example I develop on Windows but the build machine has MacOS.例如我在 Windows 上开发,但构建机器有 MacOS。

Edit App build.gradle编辑 App build.gradle

The app gradle only needs one line added at the end of it.应用程序 gradle 只需要在它的末尾添加一行。 In my case I have the Google Play Services gradle and I added it after that.就我而言,我有 Google Play Services gradle,然后我添加了它。

apply from: 'version.gradle'

version.gradle版本.gradle

This file should be in the same folder as your app gradle and this is the content:此文件应与您的应用程序 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
}

Now, let's review what the script is actually doing:现在,让我们回顾一下脚本实际在做什么:

  1. updatePackage: This task runs at the very beginning of your build (actually before preBuild) and it executes gitversion to get the current version and then creates a version.properties file which later be read by gradle to take the version. updatePackage:此任务在构建的最开始运行(实际上是在 preBuild 之前),它执行 gitversion 以获取当前版本,然后创建一个 version.properties 文件,稍后由 gradle 读取该文件以获取版本。
  2. setVariantVersion: This is called afterEvaluate on every variant. setVariantVersion:在每个变体上调用 afterEvaluate。 Meaning that if you have multiple builds like debug, release, qa, staging, etc, all will get the same version.这意味着如果您有多个构建版本,如调试、发布、qa、暂存等,所有版本都将获得相同的版本。 For my use case this is fine, but you might want to tweak this.对于我的用例,这很好,但您可能想要调整它。
  3. Task Order: One thing that bothered me was that the version was being run before the file was generated.任务顺序:困扰我的一件事是版本在生成文件之前正在运行。 This is fixed by using the mustRunAfter tag.这是通过使用 mustRunAfter 标记修复的。

PowerShell Script Explained PowerShell 脚本解释

This is the script that gets run first.这是首先运行的脚本。 Let's review what is doing:让我们回顾一下正在做什么:

$semver=(gitversion /showvariable Semver);
Set-Content -path props.properties -value semver=$semver; 
npm version --no-git-tag-version --allow-same-version $semver
  1. Line 1: gitversion has multiple type of versions.第 1 行:gitversion 有多种类型的版本。 If you run it without any parameter you will get a json file with many variants.如果你在没有任何参数的情况下运行它,你会得到一个包含许多变体的 json 文件。 Here we are saying that we only want the SemVer.在这里,我们说我们只想要 SemVer。 (See also FullSemVer) (另见 FullSemVer)
  2. Line 2: PowerShell way to create a file and save the contents to it.第 2 行:PowerShell 创建文件并将内容保存到其中的方法。 This can be also made with > but I had encoding issues and the properties file was not being read.这也可以用 > 来完成,但我遇到了编码问题并且没有读取属性文件。
  3. Line 3: This line updates your package.json version.第 3 行:此行更新您的 package.json 版本。 By default it saves a commit to git with the new version.默认情况下,它使用新版本保存对 git 的提交。 --no-git-tag-version makes sure you don't override it. --no-git-tag-version 确保您不会覆盖它。

And that is it.就是这样。 Now every time you make a build, the version should be generated automatically, your package.json updated and your build should have that specific version name.现在每次进行构建时,都应该自动生成版本,更新 package.json 并且构建应该具有特定的版本名称。

App Center应用中心

Since I am using App Center to make the builds, I will tell you how you can use this in a Build machine.由于我使用App Center进行构建,因此我将告诉您如何在构建机器中使用它。 You only need to use a custom script.您只需要使用自定义脚本。

app-center-pre-build.sh 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

This is needed because GitVersion is not currently a part of the build machines.这是必需的,因为 GitVersion 当前不是构建机器的一部分。 Also, you need to ignore the mono dependency when installing, otherwise you get an error when brew tries to link the files.此外,安装时需要忽略单声道依赖项,否则在 brew 尝试链接文件时会出现错误。

The @MacRusher version was fine for me. @MacRusher 版本对我来说很好。 Just for further readers, I had to add .toInteger() to make it work.只是为了进一步的读者,我不得不添加 .toInteger() 以使其工作。 Since I'm using yarn version --patch to automatically upgrade the version in package.json I also had to take only the two first characters.由于我使用 yarn version --patch 自动升级 package.json 中的版本,因此我也只需要取前两个字符。

Here is the new version:这是新版本:

// 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()
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM