给APP添加构建信息
这两天在琢磨一个问题,一个APP是怎么知道自己是怎么来的呢? 一个应用得知道自己是怎么来的,这样出了问题才知道该找谁。举个例子,当应用发生了一个线上crash,崩溃信息收集上来,然后我们打开堆栈一看懵了——这个发生崩溃的`v5.c`是哪个类呢?

给APP添加构建信息

这两天在琢磨一个问题,一个APP是怎么知道自己是怎么来的呢? 一个应用得知道自己是怎么来的,这样出了问题才知道该找谁。举个例子,当应用发生了一个线上crash,崩溃信息收集上来,然后我们打开堆栈一看懵了——这个发生崩溃的v5.c是哪个类呢?

crash

显然,代码被混淆过,我们要拿到编译时生成的mapping.txt来还原堆栈,如图

retrace

**然而,我们编译了很多次,客官您要的是哪次的mapping文件呢?**显然,我们不仅要保留每次构建的相关信息,还得能准确区分开每次构建的产物,能做到有问题立即查询到对应构建信息。

应用需要知道自己是“怎么来的”。

区分不同构建结果

  1. 可以收集当前commit id,commit不同一定是不同构建。
  2. 可以生成一个较长的随机数每次构建不同。

看上去前者更优雅,但一个commit id上并不一定只有一个成功的构建,比如你做一应用叫“快音”,测试通过后调整了一些编译选项打出线上包,此时只根据commit id就无法确定是对应测试包的构建还是线上包了。

所以,最实在的方法还是后者。

fun runShellCommand(command: String): String {
    val byteOut = ByteArrayOutputStream()
    project.exec {
        commandLine = command.split(" ")
        standardOutput = byteOut
    }
    return String(byteOut.toByteArray())
}
val buildNumber = UUID.randomUUID()
val gitBranch = runShellCommand("git branch --show-current").trim()
val gitCommitId = runShellCommand("git rev-parse HEAD").trim()
val buildTimeMILLIS = System.currentTimeMillis()

将信息传给应用

不知道大家有没有这种习惯,在开发时加一些测试代码时判断只在Debug版本生效,即

if (BuildConfig.DEBUG) {
    Toast.makeText(applicationContext, "test", Toast.LENGTH_SHORT).show()
}

这样即使我真的忘记删除这段代码也不会影响到线上,让用户看到个“test”感到莫名其妙。这里用的BuildConfig就是在Gradle构建时生成的一个类,里面包含了一些有关当前构建的信息1

而幸运的是,官方也提供了方法让我们可以往BuildConfig里面自己加东西,于是

android {
    defaultConfig {
        buildConfigField("String", "BUILD_NUMBER", "\"$buildNumber\"")
        buildConfigField("String", "GIT_BRANCH", "\"$gitBranch\"")
        buildConfigField("String", "GIT_COMMIT_ID", "\"$gitCommitId\"")
        buildConfigField("Long", "BUILD_TIME_MILLIS", "${buildTimeMILLIS}L")
    }
}

然后这些字段就会出现在BuildConfig

BuildConfig自定义字段

我们在报告崩溃信息时就可以带上,这样排查时就知道从何开始找起了。

保存构建信息

自定义一个task来进行发布,反正都是Kotlin代码,怎么保存这里不展开了。最终我们的服务端不但记录每一次构建时的最终产物,还记录了mapping.txt文件,记录了buildNumber,当后面排查问题时就能比较简单复现场景了。

tasks.create("apkReleaseAndUpload") {
    dependsOn(tasks["assemble"])
    doLast {
        println("发布任务开始(构建版本号$buildNumber)")
        // 保存构建信息
    }
}

进行到这里,我们就做到了之前说的目标,应用知道自己是怎么来的(保留了构建相关信息),我们排查问题也有个大概方向。


  1. 与应用代码共享自定义字段和资源值 ↩︎


最后修改于 2022-01-16