给APP添加构建信息
这两天在琢磨一个问题,一个APP是怎么知道自己是怎么来的呢? 一个应用得知道自己是怎么来的,这样出了问题才知道该找谁。举个例子,当应用发生了一个线上crash,崩溃信息收集上来,然后我们打开堆栈一看懵了——这个发生崩溃的
v5.c
是哪个类呢?
显然,代码被混淆过,我们要拿到编译时生成的mapping.txt
来还原堆栈,如图
**然而,我们编译了很多次,客官您要的是哪次的mapping文件呢?**显然,我们不仅要保留每次构建的相关信息,还得能准确区分开每次构建的产物,能做到有问题立即查询到对应构建信息。
应用需要知道自己是“怎么来的”。
区分不同构建结果
- 可以收集当前commit id,commit不同一定是不同构建。
- 可以生成一个较长的随机数每次构建不同。
看上去前者更优雅,但一个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
中
我们在报告崩溃信息时就可以带上,这样排查时就知道从何开始找起了。
保存构建信息
自定义一个task来进行发布,反正都是Kotlin代码,怎么保存这里不展开了。最终我们的服务端不但记录每一次构建时的最终产物,还记录了mapping.txt
文件,记录了buildNumber,当后面排查问题时就能比较简单复现场景了。
tasks.create("apkReleaseAndUpload") {
dependsOn(tasks["assemble"])
doLast {
println("发布任务开始(构建版本号$buildNumber)")
// 保存构建信息
}
}
进行到这里,我们就做到了之前说的目标,应用知道自己是怎么来的(保留了构建相关信息),我们排查问题也有个大概方向。
最后修改于 2022-01-16