Android 自動化打包實踐 gradle打包並推送到git遠端庫

weixin_34247155發表於2016-09-08

我們希望在打包的時候能夠做到:

  1. 使用 Android studio ,使用 gradle 進行構建;
  2. 在實際開發中,需要配置我們的 gradle 指令碼以支援引數化的方式;
  3. 想獲得一個可配置打包指令碼的方法,允許配置人員根據需要修改伺服器地址,versionCode, versionName等;
  4. 隔離的原始碼的配置,使用者在shell指令碼里進行配置。

在閱讀本文之前,一些關於gradle的配置項,可以通過這篇文章複習瞭解
Android使用gradle打包的各種配置

一.自動打包和推送git的shell指令碼

XXX_autoReleaseToGit.sh
這個指令碼會順序執行打包指令碼XXX_assemble.sh和git操作指令碼XXX_PUSH_APK.sh,結果是可以根據使用者的選擇打包出發布版本、測試版本(極光正式key)和測試版本(極光測試key)。當然,你也可以通過修改指令碼,一次性打包出以上版本。

# 自動打包和推送git的shell指令碼
# 開啟自動打包工具目錄
# 執行打包指令碼
cd 你的自動打包工具目錄
echo "進入自動化打包指令碼目錄..."
pwd
#使用gradle命令進行打包
echo "使用gradle命令開始打包..."
`dirname ${0}`/XXX_assemble.sh
#推送到git遠端庫
echo "git操作開始..."
`dirname ${0}`/XXX_PUSH_APK.sh

****執行shell指令碼進行自動打包****
XXX_assembleRelease.sh
這個指令碼包含了程式碼分支更新、程式碼更新、選擇打包環境和第三方服務(極光推送)的操作。

引數都是自定義的,這裡寫入了多個引數,有指定的各個伺服器地址,apk輸入檔案路徑,和環境標識字尾名、極游標識。

project_path="你的工程根目錄"
gradlew_path="${project_path}/gradlew"
# 切換到專案目錄
cd ${project_path}
echo "切換到專案目錄..."
pwd

# 進行程式碼分支選擇 
echo "正在更新程式碼分支資訊..."

# 更新分支資訊
git fetch -p

# 獲取所有遠端分支資訊
remote_branchs=`git branch -r`
# 分割成陣列後讓使用者選擇打包分支
echo "請選擇待打包分支: "
echo "請選擇待打包分支: "
arr=(${remote_branchs// /})
index=1
for i in ${arr[@]}; do
    #statements
    echo ${index}". "${i:7}
    ((index++))
done

# 讀取使用者資料
read branch_index
echo "你選擇要打包的分支是: ${branch_index} "

if [[ -z ${branch_index} ]]; then
    echo "Error: 選擇的分支序號不合法" 
    echo "Error: 選擇的分支序號不合法"
fi
((branch_index--))
# 切換branch並拉取最新程式碼
echo "切換到該分支並拉取最新程式碼..."
if [[ ${arr[${branch_index}]} =~ "HEAD" ]]; then
    echo "Error: 不能切換到該分支(${arr[${branch_index}]})" 
    echo "Error: 不能切換到該分支(${arr[${branch_index}]})"
    exit 1
fi

# git reset --hard HEAD
#result_code=$?
git checkout ${arr[${branch_index}]:7} 
result_code=$?
git pull 
result_code=$?


if [[ ${result_code} != 0 ]]; then
    echo "Error: 拉取程式碼失敗" 
    echo "Error: 拉取程式碼失敗"
    exit 1
fi

# gradlew檔案增加可執行許可權
chmod u+x ${gradlew_path}

echo "請選擇版本的環境地址"
echo "1:正式環境"
echo "2:測試環境"

read environment


# 執行gradlew.bat 進行打包
# -P表示後面的是自定義引數 如-POUT_PUT_DIR_PARA 表示自定義了一個OUT_PUT_DIR_PARA引數 後面是賦值
# OUT_PUT_DIR_PARA APK輸出目錄
# BASE_URL_PARA 伺服器基本請求地址
# ENVIRONMENT_PARA 伺服器環境表示 1.real 正式環境 2.test 測試環境
# JPUSH_APPKEY_PARA 只要有自定義這個引數 就代表要輸出極光推送的APK
if [[ ${environment} = 1 ]]; then
    #statements
    echo "你選擇要打包的地址是:正式環境"
    ${gradlew_path} assembleRelease -POUT_PUT_DIR_PARA=你的APK輸出目錄 -PBASE_URL_PARA=你的正式環境伺服器地址 -PENVIRONMENT_PARA=real --info --stacktrace
else
    #statements
    echo "你選擇要打包的地址是:測試環境"
    echo "----"
    echo "請選擇版本的極光Key"
    echo "1:正式Key"
    echo "2:測試Key"

    read jpushAppKey
    if [[ ${jpushAppKey} = 1 ]]; then
        #statements
        echo "你選擇要打包的極光Key是:正式Key"
        ${gradlew_path} assembleRelease -POUT_PUT_DIR_PARA=你的APK輸出目錄 -PBASE_URL_PARA=你的測試環境伺服器地址 -PENVIRONMENT_PARA=test --info --stacktrace
    else
        #statements
        echo "你選擇要打包的極光Key是:測試Key"
        ${gradlew_path} assembleRelease -POUT_PUT_DIR_PARA=你的APK輸出目錄 -PBASE_URL_PARA=你的測試環境伺服器地址 -PENVIRONMENT_PARA=test_int -PJPUSH_APPKEY_PARA=1 --info --stacktrace
    fi
fi

二.配置gradle檔案

配置 defaultConfig 節點

defaultConfig {  
   if (project.hasProperty('JPUSH_APPKEY_PARA')) {            
       //如果有指定極光key的自定義引數,那麼就設定極光推送測試key對應的appId                         
        applicationId project.APPLICATIONID_JPUSH        
   } else {            
       //工程本來的appId            
       applicationId project.APPLICATIONID_RELEASE        
   }        
  //最低安裝版本Android 4.0        
  minSdkVersion rootProject.ext.minSdkVersion        
  targetSdkVersion rootProject.ext.targetSdkVersion        
  versionCode rootProject.ext.versionCode        
  versionName rootProject.ext.versionName        
  // dex突破65535的限制        
  multiDexEnabled true        
  manifestPlaceholders = [                
        // 預設是umeng測試的渠道                
        UMENG_CHANNEL_VALUE: "TEST",                
        // 預設是正式的極光key 
        JPUSH_APPKEY: project.JPUSH_APPKEY_VALUE_RELEASE        
  ]        
  //配置 defaultConfig 下的  buildConfigField欄位 ,這是為了 程式碼編譯的方便,使得在各個環境下都有 BASE_URL 這個欄位。        
  //正式伺服器        
  buildConfigField("String", "BASE_URL", "\"" + project.BASE_URL_REAL + "\"")
}

配置debug節點各個伺服器地址的值
同配置defaultConfig節點一樣

debug {
    //測試伺服器請求
    buildConfigField("String", "BASE_URL", "\"" + project.BASE_URL_TEST + "\"")
}

配置release節點
讀取上面XXX_assemble.sh檔案傳入的引數的值作為各個伺服器地址的值。
在讀取引數的時候,我們先檢查引數是否存在,使用程式碼:

project.hasProperty('引數名')

所有通過命令列傳入的引數都或作為 project 內建物件的屬性,我們這裡判斷了指定的引數名是否存在。如何使用引數呢?直接使用即可。

versionCode Integer.parseInt(VERSION_CODE_PARA) //注意這裡,進行了轉型,從字串轉型為 int 型別
versionName VERSION_NAME_PARA

和普通的變數使用方法是一樣的。我們還會遇到在字串中使用的時候,可以使用表示式 來引用,比如:

${引數名}

示例;

fileName = fileName.replace(".apk", "-${android.defaultConfig.versionName}.apk")

詳細如下:

// 定義一個打包時間
def releaseTime() {    
      return new Date().format("yyyyMMdd", TimeZone.getTimeZone("UTC"))
}

android {
  ...

  buildTypes {
      debug {
        ...
      }
      ...    
      release {
        ... 
        if (project.hasProperty('JPUSH_APPKEY_PARA')) {                
            //接收自定義引數的值,指定測試的極光key
            manifestPlaceholders = [
                  JPUSH_APPKEY: project.JPUSH_APPKEY_VALUE_DEBUG
            ]            
         }

        applicationVariants.all { 
            variant ->    variant.outputs.each { output ->        
                def outputFile = output.outputFile        
                if (outputFile != null && outputFile.name.endsWith('.apk')) {           
                    // 輸出apk名稱為XXX20160328_v1.0.0_vc10_XXXX_test.apk        
                    if (project.hasProperty('ENVIRONMENT_PARA') 
                    def fileName=" XXX${releaseTime()}_v${defaultConfig.versionName}_vc${defaultConfig.versionCode}_${variant.productFlavors[0].name}_${ENVIRONMENT_PARA}.apk"                  
                    //控制輸出的APK的存放路徑                
                    if (project.hasProperty('OUT_PUT_DIR_PARA')) {                    
                        File output_dir1 = file("${OUT_PUT_DIR_PARA}");                    
                        output.outputFile = new File(output_dir1, fileName)                    
                         println "輸出檔案位置: " + output.outputFile                
                    } else {                    
                        output.outputFile = new File(outputFile.parent, fileName)                    
                        println "輸出檔案位置: " + output.outputFile                
                    }            
                 }        
              }    
          }
        }

        productFlavors.all { 
            flavor ->    flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
        }
    }
}

三.打包完成之後,將APK提交併推送到git遠端庫

XXX_PUSH_APK.sh

cd 你的APK輸出目錄
pwd
#同步遠端庫
git pull;
#add新增加的APK檔案
git add *;
#提交APK
git commit -m '提交APK';
#推送到遠端庫
git push;

將以上工作做完之後,我們就可以通過執行指令碼來打包了,我們可以打出一系列debug和release的不同伺服器環境的版本,對應不同的第三方服務的版本(如極光推送生產環境和釋出環境的版本)。當然,你可以修改指令碼,寫入定時執行功能,將指令碼完全寫成自動化定時執行的指令碼。

github版本:Android 自動化打包實踐 gradle打包並推送到git遠端庫

相關文章