React Native - 将版本名称自动从package.json添加到Android构建清单

13
目前我有一个React Native应用程序,问题在于每次构建或提交时更新版本非常耗时。此外,我启用了Sentry,因此每次构建时,某些构建获得相同的版本,因此有些崩溃很难确定它们来自何处。最后,手动更新版本容易出错。我应该如何设置我的构建以生成自动版本并忘记所有这些手动任务呢?
3个回答

24

虽然目前被接受的答案是可行的,但有更简单、更可靠的方法来实现。 你可以直接从build.gradle中读取设置在package.json中的值。

修改你的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()
    }
}
这样,您将不需要预先构建脚本或其他任何东西,它会自动运行。

这样,您将不需要预先构建脚本或其他任何东西,它会自动工作。


这是个很好的补充。请记住,这不会替换整个脚本,因为“魔术”的一部分是它会自动更新package.json的版本。但这将消除中间文件的需求,这是我喜欢的。谢谢! - sebastianf182
我记得我所做的与此不同。你的脚本需要用户手动更新package.json中的版本。而我所做的是运行GitVersion,它会为你计算版本号。这主要适用于进行CD/CI部署的人们。 - sebastianf182
5
你说得对,我的代码片段只是从 package.json 读取版本号。我认为这对很多人可能有用(当我自己寻找这样的解决方案时,我也偶然遇到了你的问题),因为根据项目和使用情况实际设置版本会有很大的不同。有些人可能会使用 npm version 命令,其他人可能像你一样使用 semantic-release 或 GitVersion。 - MacRusher
这个答案对我帮助很大!类似的答案在这里:https://stackoverflow.com/a/58926815/12117541 - Jael

6

由于我已经花了几天的时间在此工作上,所以我决定与大家分享我的做法,因为这可能会帮助其他人。

使用的工具:

  1. GitVersion:我们将使用 GitVersion 根据许多因素(如当前分支、标签、提交等)自动生成语义化版本。该工具表现极佳,您可以不用关心版本命名。当然,如果您对提交设置了标签,它将使用该标签作为名称。
  2. PowerShell:这是由 Microsoft 开发的命令行操作系统,可在 Mac、Linux 或 Windows 上运行,我选择这个工具是因为构建可以不受操作系统版本的限制。例如,我在 Windows 上进行开发,但构建机器却是 MacOS。

编辑 App build.gradle

只需要在 app gradle 的末尾添加一行即可。在我的情况下,我已经使用了 Google Play Services 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. Task Order: 有一件事让我困扰,那就是在生成文件之前就已经运行了版本。这可以通过使用mustRunAfter标签来修复。

PowerShell脚本说明

这是第一个运行的脚本。让我们来看看它在做什么:

$semver=(gitversion /showvariable Semver);
Set-Content -path props.properties -value semver=$semver; 
npm version --no-git-tag-version --allow-same-version $semver
  1. 第一行:gitversion有多种类型的版本。如果不带任何参数运行它,您将得到一个带有许多变量的json文件。在这里,我们说我们只想要SemVer。(另请参见FullSemVer)
  2. 第二行:使用PowerShell创建文件并将内容保存到其中的方式。这也可以用>来实现,但我遇到了编码问题,属性文件无法读取。
  3. 第三行:此行更新您的package.json版本。默认情况下,它会将新版本与git一起保存为提交。--no-git-tag-version确保您不覆盖它。

就是这样。现在,每次构建时,版本应该会自动生成,您的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目前不是构建机器的一部分。此外,在安装时需要忽略mono依赖项,否则当brew尝试链接文件时会出现错误。


2

对我来说,@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()
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接