将构建信息和git提交日志埋入APP

目的

app开发测试过程,可能会发生以下各种情况:

  1. 测试机器上,app会被不断替换,需要信息来定位当前app的状态。
  2. apk信息仅附加在命名上,安装后无法跟踪。
  3. 版本号在开发过程没有递增,并不清楚当前测试的是哪个版本,也不知道当前出现了bug的是哪个版本。
  4. 虽然版本号递增了,但并不清楚版本号对应的功能点或时间节点,需要查看构建历史才能定位,如果机器远离办公室,定位过程尤为繁琐,甚至可能需要VPN。
  5. 版本号需要和commit-id绑定,才能跟踪当前版本号对应的提交节点。
  6. commit-id仍旧不够直观,在外需要依赖VPN。

以上问题,都会导致测试过程出现问题但无法立即定位问题,有时是因为使用了旧的版本;有时是因为中途版本被替换了;有时它确实是个Bug。但无论如何,定位问题不仅浪费了测试的时间也降低了开发的效率。

给app埋入构建信息

在app构建时,埋入构建的时间/地点/参数/版本信息能有助于分析问题。

比如,本地构建与Jenkins上的构建,不同的构建使用的环境和参数不一样,构建出来的apk也很有可能不一样。具体可以有:

  1. Debug/Release
  2. 非混淆/混淆
  3. 本地构建/Jenkins构建
  4. 构建时间戳
  5. 版本号
  6. 渠道号

给app埋入提交日志

除了埋入commit-id,埋入适当的日志也是可以更加快捷的定位问题。

比如,看到提交日志信息和最近提交的不一致,则可以立即断定版本是旧的。通过commit-id/版本号等无法做到立即定位。

提交日志具体可以有:

  1. 当前构建对应的commit的 id/hash
  2. 当前构建对应的commit的 提交人(建议拼音)
  3. 当前构建对应的commit的 提交时间戳
  4. 当前构建对应的commit的 具体日志信息

安全意识,提交人建议使用拼音,不要添加邮件。

对于git,对应的命令行:
git rev-list --abbrev-commit --max-count=1 --format=%an_%ar_%ai_%n%B%n HEAD

git rev-list HEAD 查看log列表
--abbrev-commit 使用短hash
--max-count 显示commit数量
--format 格式化输出(具体%an %ar %B 等参考git log --help)

输出:

commit b1ab959
jokin_18 hours ago_2018-01-05 17:21:39 +0800_
Merge branch 'f/add_app_info' into 'develop'

[feature] 添加Trick来显示App详细信息

使用gradle给app埋入自定义信息

  1. 在gradle.properties里
MAJOR_VERSION=0
MINOR_VERSION=1
  1. 然后在build.gradle里
def genVersionName() {
    String versionName = System.getenv("MH_VERSION_NAME")
    if (versionName != null) {
        return versionName
    } else {
        return "U."+MAJOR_VERSION+"."+MINOR_VERSION
    }
}

def genVersionCode() {
    String versionCode = System.getenv("MH_VERSION_CODE")
    if (versionCode != null) {
        return Integer.parseInt(versionCode)
    } else {
        return 1
    }
}

def getBuildDate() {
    String date = new Date().format('yyyy-MM-dd HH:mm:ss')
    println date
    return date
}

def getBuildFrom() {
    String tag = System.getenv("BUILD_TAG")
    boolean inJenkins = tag != null && tag.contains("jenkins")
    if (inJenkins) {
        return "Jenkins"
    } else {
        return "Local"
    }
}

def getGitCommit() {
    def stdout = new ByteArrayOutputStream()
    exec {
        commandLine 'git', 'rev-list', '--abbrev-commit', '--max-count=1', '--format=%an_%ar_%ai_%n%B%n', 'HEAD'
        standardOutput = stdout
    }
    // 转义字符转换
    // String commit = "'\'\\a\\sb\\c\\bdfasdf\\/f/d/e\"\n\n\n\n\r\r\r\r\b\b\t\t\f\f\\'''''''\''"
    String commit = stdout.toString().trim();
    commit = commit.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
            .replace('\b', '\\b').replace('\t', '\\t').replace('\f', '\\f').replace('"', '\\"')
    println commit
    return commit
}
  1. 然后在defaultConfig里
defaultConfig {
        versionCode genVersionCode()
        versionName genVersionName()
        buildConfigField "String", "BuildDate", "\"${getBuildDate()}\""
        buildConfigField "String", "BuildFrom", "\"${getBuildFrom()}\""
        buildConfigField "String", "GitCommit", "\"${getGitCommit()}\""
}
  1. 同步后,将会生成BuildConfig.java
public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "platform";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "U.0.1";
  // Fields from default config.
  public static final String BuildDate = "2018-01-06 09:53:37";
  public static final String BuildFrom = "Local";
  public static final String GitCommit = "commit b1ab959\njokin_17 hours ago_2018-01-05 17:21:39 +0800_\nMerge branch 'f/add_app_info' into 'develop'\n\n[feature] 添加Trick来显示App详细信息\n\n";
}
  1. 使用时,直接BuildConfig.GitCommit访问
    private void showAppInfo() {
        String appInfo = "Version: "+BuildConfig.VERSION_NAME
                + "\nBuild At: "+BuildConfig.BuildDate
                + "\nBuild From: "+BuildConfig.BuildFrom
                + "\n\nLatest Commit: "+BuildConfig.GitCommit;
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
        Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
    }

释义

  1. 字符串转换为gradle属性值时进行了转义字符的替换。

原因是,gradle的属性值是直接将字符串打印结果作为内容,直接写到BuildConfig.java里面。举个例子。

String commit = "abc\ndef";

转换为gradle属性,得到的是

"abc
def"

这是字符串的打印结果,并非原始的字符串。字符串的换行在BuildConfig.java里是

public final class BuildConfig {
  public static final String GitCommit = "abc
              def";
}

这是非法的字符串定义!将导致编译失败!

所以,我们需要将打印出的换行符转换为常量定义:

"abc\ndef"

所以,将字符串变量转换为常量字符串的格式,才是正确的。问题就变成了:知道一个字符串变量,如何输出其常量定义?只需要对转义字符进行转换即可。

java中转义字符

\a     
\b
\f
\n
\r
\t
\v
\\
\'     (java中常量输出 ' 不需要做转义)
\"
\0
\ddd
\xhh

字符转换为对应的转义字符串

'\r'  -> "\\r"      // 要输出\r,是\\r 
'\n'  -> "\\n"      // 要输出\n,是\\n
'\'   -> "\\"       // 要输出\,常量是\\(怎么表示\脚本语言中是'\\')
'"'   -> "\\\""     // 常量字符串\",输出的是",要输出\",是"\\\"",对于脚本语言,可以是'\\"'
'\''  -> "\\'"      // 要输出\',常量是"\\'"
以此类推。

注意的是,脚本语言中,' 与 " 都是表示字符串。但两者需要转义的符号不同。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,724评论 6 342
  • Auguries of Innocence To see a world in a grain of sand A...
    wangshuo阅读 255评论 0 1
  • 当我收拾自己无比杂乱的抽屉时,恍然意识到自己遗忘的物品与回忆,原来花几分钟就能让它这么整洁。从小就喜欢收拾东西,...
    liuyanyolanda阅读 177评论 0 1