【android 應用】gradle 中定製化編譯,以及相關設置

最近需求說要做一個定製化編譯,然後就開始研究gradle。以前以爲很簡單就是個編譯工具,偶爾配置下就好了。最後被打臉了,發現對其一點都不瞭解---一無所知。研究了三天只研究了個皮毛,寫下來總結下以後方便查閱。


一、gradle簡介

1.Android Gradle基礎

android應用程序使用開源工具Gradle構建。Gradle一種藝術API,非常容易的支持定製,並且在java世界有着廣泛的應用。Android爲了實現編譯、打包等,開發者開發了Android插件爲Gradle添加了一系列的新特徵,特別是在構建Android app上的應用,包括:構建類型、多樣化、簽名配置、庫文件工程等等功能。

Gradle中,每一個待編譯的工程都叫一個Project。每一個Project在構建的時候都包含一系列的Task。

1.1 Android Gradle構建文件

在我們使用Android Studio工具開發Android應用的時候,當創建一個新的Android工程,默認的Gradle構建文件包括了setting.gradlebuild.gradleapp/build.gradle。具體位置如圖所示

build.gradle:配置其他子Project的,添加任務。

settings.gradle:它裏邊用來告訴Gradle,這個multiprojects包含多少個子Project。

二、任務Task建立

2.1、添加和執行任務

1、添加

在根目錄或者app目錄下的build.gradle中添加

task startDelTask {
    doLast {
        //remove "ijkplayer-java/"
        println "this is startDelTask"
    }
}

2、運行

通過圖形界面運行

雙擊圖形界面中的startDelTask即可。我的Task是添加在根目錄下的所以在根目錄下中other目錄(也可隨便點一個,輸入查找,選中後直接輸入即可查找)

通過命令運行

gradlew startDelTask

2.2、在編譯前執行

1、每一個編譯都行

task startDelTask {
    doLast {
        //remove "ijkplayer-java/"
        println "this is startDelTask"
    }
}
tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn startDelTask
}

2、要判斷名稱

project.tasks.whenTaskAdded { Task theTask ->
    if (theTask.name == 'assembleDebug') {
        theTask.dependsOn(tangTangTest)
        theTask.mustRunAfter(tangTangTest)				// diyTask在assembleRelease之前執行
    }
}

2.3、在任務後執行

Task diyTask = project.task('diyTask') {
    doLast {
        Utils.println("diy task run")
    }
}

project.tasks.whenTaskAdded { Task theTask ->
    if (theTask.name == 'assembleRelease') {
        theTask.dependsOn(diyTask)            // 編譯完apk之後再執行自定義task
    }
}

三、多渠道定製化

多渠道還可以定製很多東西詳細這裏就不介紹了。還有什麼佔位符修改androidmaniface.xml修改也沒有介紹,網上很多資料,感興趣的可以去網上學習下。

android{
    ... ...
    defaultConfig {
        ... ...
        flavorDimensions "default"
    }
    ... ...
    productFlavors {
        OTT {
            dimension "default"
            //設置buildConfig參數
            buildConfigField "String", "FLAVORS_TYPE", '"OTT"'
        }
        OTT_DVB {
            dimension "default"
            buildConfigField "String", "FLAVORS_TYPE", '"OTT_DVB"'
        }
    }

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

四、AndroidManifest文件的替換

4.1、通過參數直接配置

首先在/src/main下建兩個文件夾(不一定一樣命名)。debug和release。兩個文件夾中放入不同的AndroidManifest.xml

然後在當前不要打包不同AndroidManifest文件的Module的build.gradle中寫入以下代碼:

判斷條件通過傳參,或者全局定義。

  sourceSets {
        main {
            if (條件判斷) {
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/release/AndroidManifest.xml'
            }
        }
    }

//如下5.1傳參
    sourceSets {
        main {
            println "------>${getTinkerIdValue()}"
            if (getTinkerIdValue().equals("OTT")) {
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/release/AndroidManifest.xml'
            }
        }
    }

4.2、拷貝到編譯目錄上去

編譯目錄:VPSClient\app\build\intermediates\merged_manifests\OTTRelease

android {
    ... ...
    applicationVariants.all { variant ->
        variant.outputs[0].processManifest.doLast {
            //渠道與配置名
            String variantName = variant.name.capitalize()

            //要替換的manifest文件
            def manifestFile = "${projectDir}${File.separator}build${File.separator}intermediates${File.separator}merged_manifests${File.separator}${variantName}${File.separator}AndroidManifest.xml"

            //源文件
            def srcManifact = "${projectDir}${File.separator}configs${File.separator}${variant.productFlavors[0].name}.xml"
            println "src: $srcManifact"

            //通過源文件內容替換
            def updatedContent = new File(srcManifact).getText('UTF-8')
            new File(manifestFile).write(updatedContent, 'UTF-8')
        }
    }
    ... ...
}

4.3、選擇

選擇第二種方式,因爲第一種方式每次都需要傳參或者改gradle源碼及其不方便。第二種方式實現了自動化。

五、參數打包和代碼中使用

5.1、在gradle中多渠道打包時配置BuildConfig

    productFlavors {
        OTT {
            dimension "default"
            buildConfigField "String", "FLAVORS_TYPE", '"OTT"'
        }
        OTT_DVB {
            dimension "default"
            buildConfigField "String", "FLAVORS_TYPE", '"OTT_DVB"'
        }
    }

5.2、設置默認參數時配置BuildConfig

1、app/gradle 配置

android {
    defaultConfig {
        ....
        buildConfigField "String", "FLAVORS_TYPE ", "\"${getTinkerIdValue()}\""
    }
}

//如果沒有參數,就使用 1.0.0_base 作爲名字
def getTinkerIdValue() {
    return hasProperty("FLAVORS_TYPE") ? FLAVORS_TYPE : "OTT1"
}

2、打包命令傳參

gradlew assembleRelease -PFLAVORS_TYPE=OTT

5.3、java文件中使用

// BuildConfig 一定要導入 當前工程包名的,沒有的話 先build一次
((TextView)findViewById(R.id.textView)).setText(BuildConfig.FLAVORS_TYPE);

六、查看打印信息

在任意gradle.build中添加如下代碼:

class EggListener  implements TaskExecutionListener {

    @Override
    void beforeExecute(Task task) {
    }

    @Override
    void afterExecute(Task task, TaskState state) {

    }
}

gradle.addListener(new EggListener ())

七、執行命令

7.1 官方標準

task stopTomcat(type:Exec) {
  workingDir '../tomcat/bin'

  //on windows:
  commandLine 'cmd', '/c', 'stop.bat'

  //on linux
  commandLine './stop.sh'

  //store the output instead of printing to the console:
  standardOutput = new ByteArrayOutputStream()

  //extension method stopTomcat.output() can be used to obtain the output:
  ext.output = {
    return standardOutput.toString()
  }
}

7.2實例

task.dependsOn(exec)


task exec(type:Exec) {
    def outputPath = "${getProjectDir()}\\src\\main\\assets"
//    workingDir '../tomcat/bin'
    //on windows:
    commandLine 'cmd', '/c', "dx  --dex --output ${outputPath}\\vossdk.dex ${outputPath}\\outfile\\classes.jar"
//    commandLine "dx  --dex --output ${getProjectDir()}/src/main/assets/vossdk.dex ${getProjectDir()}/src/main/assets/outfile/classes.jar"
    //store the output instead of printing to the console:
    doLast {
        delete("${getProjectDir()}/src/main/assets/outfile")
    }
    standardOutput = new ByteArrayOutputStream()

    //extension method stopTomcat.output() can be used to obtain the output:
    ext.output = {
        return standardOutput.toString()
    }

}

這個實例其實不合規,可以將命令放進腳本中,運行腳本可以兼容Linux和window兩個系統。

結束語

以上就是本次分享的gradle 中定製化編譯,以及相關設置的實例。最後慣例給大家推介一下我們的技術工作號,歡迎大家來交流技術問題,謝謝!

在這裏插入圖片描述

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章