android gradle自動化打包方案完整總結(jié)

簡介

3ac8c26a-0fa1-4bc2-b12a-d9c78d7c0a6e.png

以前知道自動化打包,最近分享點東西,根據(jù)官方和一些參考文檔褥琐,做一下簡單的總結(jié)逗堵,簡單做了張圖,知識點文章都會介紹到谦趣,做了個demo,對各功能做個測試。

build生成apk方式

1.android sutidio 菜單欄蛆挫,build-》generate signed apk 隨后可以選擇編譯方式和產(chǎn)品風味
2.在android根目錄下命令行

  • ./gradlew assemble{BuildType} 對應編譯方式所有productflavor都會輸出
  • ./gradlew assemble{productFlavor}{BuildType} 指定構(gòu)建體輸出文件
  • ./gradlew assemble全部構(gòu)建變體都會輸出。

PS:打產(chǎn)品包用Release方式

  • ./gradlew assembleRelease 或者簡寫./gradlew aR打包所有產(chǎn)品風味的包
  • ./gradlew assemblerelease_normalRelease指定產(chǎn)生release_normal產(chǎn)品風味的包

install方式

1.android sutidio 直接菜單欄的Run綠色按鈕妙黍。左下腳菜單Build Variants悴侵,可以選擇不同的構(gòu)建變體
2.在android目錄下運行命令
./gradlew install{productFlavor}{buildType}
注意:這種方式如果build自增體現(xiàn)在輸出的apk文件名上,可能會報找不到apk文件的錯誤拭嫁。

簽名不在版本控制中

正常情況下會在build.gradle 下面配置簽名文件的位置和密碼可免,但是簽名文件和密碼會在版本控制中做粤,不安全浇借,至少密碼在版本控制中是不安全的。
推薦兩種方式
1.自定義存儲簽名密碼文件怕品,并自定義函數(shù)讀取簽名密碼和簽名文件位置妇垢。
2.在本地~/.gradle/gradle.properties全局文件中配置簽名密碼和簽名文件位置

自定義讀取簽名密碼文件

單獨建立一個簽名密碼的文件,在工程目錄下新建signingfiles文件夾肉康,在里面存儲簽名文件和簽名密碼文件

  • keystore.properties
  • guanmai-release-key.keystore

簽名密碼文件

STORE_FILE=../signingfiles/guanmai-release-key.keystore
KEY_ALIAS=guanmai-key-alias
STORE_PASSWORD=guanmai
KEY_PASSWORD=guanmai

在版本控制.gitignore中將密碼文件或者簽名文件忽略掉,在build.gradle中讀取簽名密碼文件闯估。
在android{}函數(shù)外部增加設置簽名的函數(shù)

//從../signingfiles/keystore.properties下讀取簽名文件的位置和密碼
//如果沒有相關(guān)文件或者參數(shù)不對將拋出異常
def setSigningProperties(){
    def propFile = file('../signingfiles/keystore.properties')
    if (propFile.canRead()){
        def Properties props = new Properties()
        props.load(new FileInputStream(propFile))
        if (props!=null && props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {
            android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
            android.signingConfigs.release.storePassword = props['STORE_PASSWORD']
            android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
            android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']
        } else {
            println 'signing.properties found but some entries are missing'
            throw new Exception("signing.properties found but some entries are missing")
            //android.buildTypes.release.signingConfig = null
        }
    }else {
        println 'signing.properties not found'
        throw new Exception("signing.properties not found:" + propFile.absolutePath)
        //android.buildTypes.release.signingConfig = null
    }
}

signingconfigs讀取并設置密碼和簽名文件路徑

    signingConfigs {
        release {
            setSigningProperties()
        }
    }

本地配置簽名密碼

rn官網(wǎng)曾提到的方法http://reactnative.cn/docs/0.42/signed-apk-android.html#content
簽名配置文件放在全局的本地~/.gradle/gradle.properties中,簽名文件也放到自己的本地~/.gradle/release-key.keystore吼和。

MYAPP_RELEASE_STORE_FILE=~/.gradle/release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=key-alias
MYAPP_RELEASE_STORE_PASSWORD=pass
MYAPP_RELEASE_KEY_PASSWORD=pass

build.gradle中配置簽名

    signingConfigs {
        release {
            storeFile file(MYAPP_RELEASE_STORE_FILE)
            storePassword MYAPP_RELEASE_STORE_PASSWORD
            keyAlias MYAPP_RELEASE_KEY_ALIAS
            keyPassword MYAPP_RELEASE_KEY_PASSWORD
        }
    }

這樣簽名文件與與密碼都不在版本控制中睬愤,尤其是工作中正式app簽名用的都是一個,會很方便纹安。

查看簽名文件

//查看簽名文件的屬性
keytool -list -keystore 簽名文件

//查看 apk 的簽名尤辱,需要提前解壓 apk ,獲取 CERT.RSA(位于解壓目錄下 /META-INF 下)
//以下命令行是在 apk 解壓目錄下執(zhí)行
keytool -printcert -file META-INF/CERT.RSA

版本名命名VersionName

VersionName是一個字符串厢岂,例如 "1.2.0"光督,這個是給人看的版本名,系統(tǒng)并不關(guān)心這個值塔粒,但是合理的版本名结借,對后期的維護和 bug 修復也非常重要。

參考
版本號規(guī)則
https://developer.android.com/studio/publish/versioning.html
主流app版本號
http://www.ifeegoo.com/recommended-mobile-application-version-name-management-specification.html

版本versionName主要采用形式
v1.0.0.buildnum
1.版本號
<major>.<minor>.<point>

  • major是主版本號卒茬,當項目在進行了重大修改或局部修正累積較多船老,而導致項目整體發(fā)生全局變化時咖熟,主版本號加 1;
  • minor是次版本號,一般在軟件有新功能時增長
  • point是修正版本號柳畔,一般在軟件有主要的問題修復后增長

2.buidnum為build次數(shù)
可以采用build次數(shù)記錄自增的方式馍管,參考下面的VersionCode
在文件gradle.properties文件中build.num變量

如何賦值versionCode

版本號,是一個大于 0 的整數(shù)薪韩,相當于 Build Number确沸,隨著版本的更新,這個必須是遞增的俘陷。大的版本號罗捎,覆蓋更新小的版本號。那么除了手動增加外拉盾,還有其他自增的方案

方案

build次數(shù)自增

1.要實現(xiàn)這個功能桨菜,首先得有個變量記錄次數(shù),在工程根目錄下的gradle.properties增加build.num屬性

build.num=1

2.需要讀取個屬性捉偏,定義讀取這個build.num的函數(shù)

def getBuildNum() {
    def buildFile = file('../gradle.properties')

    if (buildFile.exists()) {
        def Properties buildPop = new Properties()
        buildPop.load(new FileInputStream(buildFile))
        def buildNum = buildPop['build_num'].toInteger()
        println('Current version code is ' + buildNum.toString())
        return buildNum
    } else {
        throw new GradleException("Could not find " + buildFile.absolutePath)
    }
}

3.此外我們還得能夠賦值這個屬性倒得,定義自增函數(shù)

//加一標志,確保一次編譯不管生成幾個apk告私,都只增加一
def add_flage = false
//非'Debug'編譯方式,自增
def addBuildNum() {
    def runTasks = gradle.startParameter.taskNames.toString()
    println("runtasks!: " + runTasks)
    if ((runTasks.contains('Debug'))) {
        return
    }

    def File buildFile = file('../gradle.properties')
    if (buildFile.exists()) {
        def Properties versionProps = new Properties()
        versionProps.load(new FileInputStream(buildFile))
        def buildNum = versionProps['build_num'].toInteger()
        buildNum++
        versionProps['build_num'] = buildNum.toString()
        versionProps.store(buildFile.newWriter(), null)
        println('Updated build number to ' + buildNum.toString())
    } else {
        throw new GradleException("Could not find " + buildFile.absolutePath)
    }
}

4.在合適條件下build先自增承桥,然后在再給versionNameVesionCode賦值

        //所有編譯方式BuildType都會遍歷flavors
        productFlavors.all { flavor ->
            //buid自增,一次編譯只增一次
            if (!add_flage ){
                addBuildNum()
                add_flage = true;
            }

            //build自增后 重新賦值 versionname;versionCode
            versionName "v1.2.1.${getBuildNum()}"
            versionCode getBuildNum()
        }

git commit 次數(shù)自增

參考http://www.race604.com/android-auto-version/

發(fā)布時間

通過發(fā)布時間函數(shù)

def releaseTime() {
    return new Date().format("yyMMddhhmm", TimeZone.getTimeZone("UTC"))
}

將返回的字符串轉(zhuǎn)換為int值驻粟,作為versionCode,versionCode為整數(shù)有長度限制凶异,忘記了多少蜀撑,自行查看官網(wǎng)。

多應用安裝

https://developer.android.com/studio/build/build-variants.html
實現(xiàn)多應用的安裝應該有的步驟
1.首先要讓編譯有不同產(chǎn)品的編譯剩彬,定義不同產(chǎn)品風味productFlavors
2.有了不同的產(chǎn)品編譯酷麦,生成了apk,要定義不同的文件名喉恋,生成不同的apk沃饶。
3.生成不同名子的apk,如果ApplicationId一樣的話轻黑,也不能同時安裝在一臺機器上糊肤,要在productFlavors定義不同的ApplicationId

產(chǎn)品風味productFlavors氓鄙,生成多個apk

  • env 發(fā)布測試環(huán)境
  • release_normal 正式發(fā)布正常升級
  • company_{公司關(guān)鍵詞} 不同公司版本
  • 渠道 不同渠道版本

在構(gòu)建的變體里 可以設置不同的build參數(shù)馆揉,如applicationId、渠道號抖拦、versionName等
注意:android studio 正常運行可以選擇構(gòu)建方式(debug簽名文件跟release不一樣)升酣,可以在左下角的Build Variants 菜單中選擇構(gòu)建方式舷暮,注意點看輸出文件

輸出文件

輸出的文件名可以根據(jù)的自己需要自定義例如
${profix}_${projectName}_${variant.versionName}
在 applicationVariants.all定義輸出文件名

    //輸出文件參數(shù)設置
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            //只定義release編譯方式的apk文件名
            if (outputFile != null && outputFile.name.endsWith('.apk') && 'release'.equals(variant.buildType.name)) {

                def flavor =  variant.productFlavors[0].name;

                //不同的falvor,定義不同的輸出的apk文件名前綴
                def profix
                if (flavor.equals("release_normal")){
                    profix = "gm"
                } else if (flavor.equals('env')){
                    profix = "test_gm"
                }else if (flavor.contains("company_")){
                    profix = flavor.replace("company_","");
                }else {
                    profix = "gm_" + flavor
                }

                //定義輸出apk文件名
                def fileName = "${profix}_${projectName}_${variant.versionName}.apk".toLowerCase()
                output.outputFile = new File(outputFile.parent, fileName)
            }
        }
    }

一機多應用安裝

根據(jù)不同的產(chǎn)品風味ProductFlavors噩茄,定義不同applicationId

//以company開頭 加入不同公司版
//在這里我可以更改包名 app在手機中可以和其他flavor編譯的app共存
company_xnv{
    applicationId "com.versiontest.xnv"
    manifestPlaceholders = [PGYER_APPID_VALUE: "other PGYER_APPID_VALUE"]
}

不同編譯擁有不同資源文件

在 main 的同級目錄下創(chuàng)建以productFlavors或者buildTpye名命名的文件夾下面,然后創(chuàng)建資源文件,然后打包的時候 gradle 就會自己替換或者合并資源巢墅。
例如诸狭, App 的默認 string.xml 路徑為main\res\value\string.xml,那么 相應的構(gòu)建變體路徑 env\res\value\string.xml 君纫,打包 env 構(gòu)建變體的時候會自動替換當中的字符串驯遇。
在android studio 中右鍵選擇new->android resources directory 彈出對話框 ==source set==選項,選擇相應的構(gòu)建變體蓄髓,以及相應的資源文件類型叉庐,確定就會自動新建相應的目錄了。

main 目錄中:

<resources>
    <string name="app_name">GuanmaiDemoGradle</string>
</resources>

env 目錄中

<resources>
    <string name="app_name">DemoGradle</string>
</resources>

那么用env構(gòu)建apk会喝,apk的名字就會變成DemoGradle

代碼中不同編譯方式得到不同變量

在實際項目陡叠,我們可能需要通過不同的構(gòu)建變體,得到一些不同的變量肢执,產(chǎn)生不同的業(yè)務邏輯枉阵,例如想打一個測試環(huán)境包,就想得到一個環(huán)境變量预茄,賦值不同url前綴兴溜。
大約三種方式,
1.resValue
2.buildConfigField耻陕,
3.<meta data>方式拙徽,也是經(jīng)常看到渠道方式诗宣,除了渠道外膘怕,很多更改第三方appId等,都可參考召庞。

“resValue”string.xml中增加變量

1.在資源文件中新增變量岛心。在你的 gradle 文件 buildTypes 或者 productFlavors 下面,如 release 體內(nèi)寫上類似:
resValue "string", "app_name_build", "Test打包Rn"
就相當于在資源文件string.xml多了
<string name="app_name_build">Test打包Rn</string>
代碼中就可以讀取string.xml中的app_name_build篮灼。

注意: 只能在string.xml中新增加字符對鹉梨,不能改變原有的字符對,或者說不能與原有的字符對重復,會報沖突錯誤穿稳。

“buildConfigField”BuildConfig中新增變量

在BuildConfig中新增變量存皂。在你的 gradle 文件 buildTypes 或者 productFlavors 下賦值新的變量, 例如賦值字符串ENV變量:

buildConfigField "String", "ENV", "\"development\""

在代碼中便可以引用BuildConfig.ENV

<meta data>(渠道)

渠道一般都是通過友盟,以友盟為例來說明渠道方式旦袋。
通過在 AndroidManifest.xml 文件中 application 標簽下指定<mate-data> 設置占位符來實現(xiàn)動態(tài)替換屬性值骤菠。

<meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL}" />

在build.gradle中,是渠道的構(gòu)建變體 ==UMENG_CHANNEL== 為其名字,其他為default

if (name.contains("debug") || name.contains("release"))
    flavor.manifestPlaceholders = [UMENG_CHANNEL: "default"]
else
    flavor.manifestPlaceholders = [UMENG_CHANNEL: name]

讀取application中的<meta data>

  private String getMetaValue(String metaName){
    ApplicationInfo appInfo = null;
    try {
      appInfo = this.getReactApplicationContext().getPackageManager()
              .getApplicationInfo(this.getReactApplicationContext().getPackageName(),
                      PackageManager.GET_META_DATA);
    } catch (PackageManager.NameNotFoundException e) {
      e.printStackTrace();
    }
    String msg=appInfo.metaData.getString(metaName);
    return msg;
  }

如果渠道很多疤孕,就參考下美團和其他github上的多渠道打包
http://www.reibang.com/p/76ab2ff11229

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末商乎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子祭阀,更是在濱河造成了極大的恐慌鹉戚,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件专控,死亡現(xiàn)場離奇詭異抹凳,居然都是意外死亡,警方通過查閱死者的電腦和手機伦腐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門赢底,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人柏蘑,你說我怎么就攤上這事幸冻。” “怎么了咳焚?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵洽损,是天一觀的道長。 經(jīng)常有香客問我革半,道長碑定,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任督惰,我火速辦了婚禮不傅,結(jié)果婚禮上旅掂,老公的妹妹穿的比我還像新娘赏胚。我一直安慰自己,他們只是感情好商虐,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布觉阅。 她就那樣靜靜地躺著,像睡著了一般秘车。 火紅的嫁衣襯著肌膚如雪典勇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天叮趴,我揣著相機與錄音割笙,去河邊找鬼。 笑死,一個胖子當著我的面吹牛伤溉,可吹牛的內(nèi)容都是我干的般码。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼乱顾,長吁一口氣:“原來是場噩夢啊……” “哼板祝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起走净,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤券时,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伏伯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體橘洞,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年舵鳞,在試婚紗的時候發(fā)現(xiàn)自己被綠了震檩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜓堕,死狀恐怖抛虏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情套才,我是刑警寧澤迂猴,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站背伴,受9級特大地震影響沸毁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜傻寂,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一息尺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧疾掰,春花似錦搂誉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拂檩,卻和暖如春侮腹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背稻励。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工父阻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓加矛,卻偏偏與公主長得像钠署,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子荒椭,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,102評論 25 707
  • 1.介紹 如果你正在查閱build.gradle文件的所有可選項猾担,請點擊這里進行查閱:DSL參考 1.1新構(gòu)建系統(tǒng)...
    Chuckiefan閱讀 12,133評論 8 72
  • 這一章主要針對項目中可以用到的一些實用功能來介紹Android Gradle吼蚁,比如如何隱藏我們的證書文件咬崔,降低風險...
    acc8226閱讀 7,610評論 3 25
  • 最近在公司項目中需要利用同一套代碼打包出具有不同皮膚和有一些功能差異的兩個apk包鉴扫,于是學習了一下Android ...
    Alexyz123閱讀 15,206評論 0 14
  • 阿貍,我最愛的東西味悄!很有心的他給我買了好多關(guān)于阿貍的東西草戈,漫畫書,涂鴉本侍瑟,玩偶唐片,都是阿貍!可能在他的心里涨颜,我...
    全世界我想遇見你閱讀 265評論 0 0