將構(gòu)建信息和git提交日志埋入APP

目的

app開(kāi)發(fā)測(cè)試過(guò)程,可能會(huì)發(fā)生以下各種情況:

  1. 測(cè)試機(jī)器上,app會(huì)被不斷替換,需要信息來(lái)定位當(dāng)前app的狀態(tài)。
  2. apk信息僅附加在命名上,安裝后無(wú)法跟蹤。
  3. 版本號(hào)在開(kāi)發(fā)過(guò)程沒(méi)有遞增,并不清楚當(dāng)前測(cè)試的是哪個(gè)版本,也不知道當(dāng)前出現(xiàn)了bug的是哪個(gè)版本。
  4. 雖然版本號(hào)遞增了,但并不清楚版本號(hào)對(duì)應(yīng)的功能點(diǎn)或時(shí)間節(jié)點(diǎn),需要查看構(gòu)建歷史才能定位,如果機(jī)器遠(yuǎn)離辦公室,定位過(guò)程尤為繁瑣,甚至可能需要VPN。
  5. 版本號(hào)需要和commit-id綁定,才能跟蹤當(dāng)前版本號(hào)對(duì)應(yīng)的提交節(jié)點(diǎn)。
  6. commit-id仍舊不夠直觀,在外需要依賴VPN。

以上問(wèn)題,都會(huì)導(dǎo)致測(cè)試過(guò)程出現(xiàn)問(wèn)題但無(wú)法立即定位問(wèn)題,有時(shí)是因?yàn)槭褂昧伺f的版本;有時(shí)是因?yàn)橹型景姹颈惶鎿Q了;有時(shí)它確實(shí)是個(gè)Bug。但無(wú)論如何,定位問(wèn)題不僅浪費(fèi)了測(cè)試的時(shí)間也降低了開(kāi)發(fā)的效率。

給app埋入構(gòu)建信息

在app構(gòu)建時(shí),埋入構(gòu)建的時(shí)間/地點(diǎn)/參數(shù)/版本信息能有助于分析問(wèn)題。

比如,本地構(gòu)建與Jenkins上的構(gòu)建,不同的構(gòu)建使用的環(huán)境和參數(shù)不一樣,構(gòu)建出來(lái)的apk也很有可能不一樣。具體可以有:

  1. Debug/Release
  2. 非混淆/混淆
  3. 本地構(gòu)建/Jenkins構(gòu)建
  4. 構(gòu)建時(shí)間戳
  5. 版本號(hào)
  6. 渠道號(hào)

給app埋入提交日志

除了埋入commit-id,埋入適當(dāng)?shù)娜罩疽彩强梢愿涌旖莸亩ㄎ粏?wèn)題。

比如,看到提交日志信息和最近提交的不一致,則可以立即斷定版本是舊的。通過(guò)commit-id/版本號(hào)等無(wú)法做到立即定位。

提交日志具體可以有:

  1. 當(dāng)前構(gòu)建對(duì)應(yīng)的commit的 id/hash
  2. 當(dāng)前構(gòu)建對(duì)應(yīng)的commit的 提交人(建議拼音)
  3. 當(dāng)前構(gòu)建對(duì)應(yīng)的commit的 提交時(shí)間戳
  4. 當(dāng)前構(gòu)建對(duì)應(yīng)的commit的 具體日志信息

安全意識(shí),提交人建議使用拼音,不要添加郵件。

對(duì)于git,對(duì)應(yīng)的命令行:
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數(shù)量
--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來(lái)顯示App詳細(xì)信息

使用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
    }
    // 轉(zhuǎn)義字符轉(zhuǎn)換
    // 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. 同步后,將會(huì)生成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來(lái)顯示App詳細(xì)信息\n\n";
}
  1. 使用時(shí),直接BuildConfig.GitCommit訪問(wèn)
    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. 字符串轉(zhuǎn)換為gradle屬性值時(shí)進(jìn)行了轉(zhuǎn)義字符的替換。

原因是,gradle的屬性值是直接將字符串打印結(jié)果作為內(nèi)容,直接寫(xiě)到BuildConfig.java里面。舉個(gè)例子。

String commit = "abc\ndef";

轉(zhuǎn)換為gradle屬性,得到的是

"abc
def"

這是字符串的打印結(jié)果,并非原始的字符串。字符串的換行在BuildConfig.java里是

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

這是非法的字符串定義!將導(dǎo)致編譯失??!

所以,我們需要將打印出的換行符轉(zhuǎn)換為常量定義:

"abc\ndef"

所以,將字符串變量轉(zhuǎn)換為常量字符串的格式,才是正確的。問(wèn)題就變成了:知道一個(gè)字符串變量,如何輸出其常量定義?只需要對(duì)轉(zhuǎn)義字符進(jìn)行轉(zhuǎn)換即可。

java中轉(zhuǎn)義字符

\a     
\b
\f
\n
\r
\t
\v
\\
\'     (java中常量輸出 ' 不需要做轉(zhuǎn)義)
\"
\0
\ddd
\xhh

字符轉(zhuǎn)換為對(duì)應(yīng)的轉(zhuǎn)義字符串

'\r'  -> "\\r"      // 要輸出\r,是\\r 
'\n'  -> "\\n"      // 要輸出\n,是\\n
'\'   -> "\\"       // 要輸出\,常量是\\(怎么表示\腳本語(yǔ)言中是'\\')
'"'   -> "\\\""     // 常量字符串\",輸出的是",要輸出\",是"\\\"",對(duì)于腳本語(yǔ)言,可以是'\\"'
'\''  -> "\\'"      // 要輸出\',常量是"\\'"
以此類(lèi)推。

注意的是,腳本語(yǔ)言中,' 與 " 都是表示字符串。但兩者需要轉(zhuǎn)義的符號(hào)不同。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,653評(píng)論 19 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,192評(píng)論 25 708
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,281評(píng)論 6 342
  • Auguries of Innocence To see a world in a grain of sand A...
    wangshuo閱讀 292評(píng)論 0 1
  • 當(dāng)我收拾自己無(wú)比雜亂的抽屜時(shí),恍然意識(shí)到自己遺忘的物品與回憶,原來(lái)花幾分鐘就能讓它這么整潔。從小就喜歡收拾東西,...
    liuyanyolanda閱讀 205評(píng)論 0 1

友情鏈接更多精彩內(nèi)容