gradle知識匯總

本人用Android studio也已經一年多了,現在回過頭來寫寫gradle相關的知識點,希望能給新手帶來些許幫助,大神勿噴

1、gradle的基本配置

每次新建一個module,在build.gradle文件中,都會自動生成如下配置:


我們知道,在eclipse開發中,應用程序包名是由manifest下的package屬性決定的:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xxx.xxxx">

然而在使用gradle構建的項目中,卻多了一個applicationId屬性,并且應用程序包名是由這個applicationId決定的:

defaultConfig {
    applicationId "com.xxx.xxxx"
}

通常gradle中的 applicationId 和Manifest中的 package 是一樣的,當然也可以不一樣,官方對兩者的界定給出的解釋是:
applicationId是應用在商店的唯一標識;
package是引用資源的路徑名,也就是R文件的包名.

2、gradle的簽名配置

關于簽名的概念不懂得,可以參考這篇blog:Android從零單排之簽名打包

簽名配置的語法在項目的【Project Structure】中可以找到:

如上圖所示補全簽名信息就可以在build.gradle中自動生成簽名配置.

當然,更一般的配置方法是在build.gradle中手動書寫簽名配置:

android {
    signingConfigs {
        config_release {
            keyAlias 'releaseKey'
            keyPassword '123456'
            storePassword '123456'
            storeFile file('key/releaseKey.jks')
        }

        config_debug {
            keyAlias 'debugKey'
            keyPassword '123456'
            storePassword '123456'
            storeFile file('key/debugKey.jks')
        }
    }
    ......//省略其他配置
}

這里配置了兩個簽名,簽名文件都放在app下面的key文件夾中,所以使用的是相對路徑.

如果將簽名密碼直接寫在gradle中顯然并不是很安全的做法,我們最好還是做點保密措施:在gradle中隱藏Keystore密碼

3、 配置buildTypes

語法在項目的【Project Structure】中也能找到:

這里可配置的信息很多,一般是在buildTypes{ }里面配置兩個(release和debug):

buildTypes {
    release {
        signingConfig signingConfigs.config_release
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
        signingConfig signingConfigs.config_debug
    }
}

4、 配置productFlavor

多渠道打包,關鍵就在于productFlavor:

productFlavors {
    flavor_1 {
        minSdkVersion 14
        signingConfig signingConfigs.config_release
        targetSdkVersion 23
        versionCode 2
        versionName '2.0.1'
        applicationId 'com.huaihuai.android.one'
    }
    flavor_2 {
        minSdkVersion 10
        signingConfig signingConfigs.config_debug
        versionCode 1
        versionName '1.0.0'
        applicationId 'com.huaihuai.android.two'
    }
}

我們這里給不同渠道配置不同的applicationId,就可以打包出多個不同渠道不同包名的apk.

這樣有一個應用場景就是:包名不同的apk可以共存在一個手機上,利用這點我們可以在測試機上運行多個版本的apk以方便測試.

productFlavors{ } 與 buildTypes{ }里面的配置是多對多的關系.
比如:

android {
    buildTypes {
        release {...}
        debug {...}
    }
    productFlavors {
        flavor_1 {...}
        flavor_2 {...}
    }
}

這時的配置可以打出4個apk,分別是:

#5、打包命令

強烈推薦使用gradlew命令行進行打包,因為gradle下很多方便的配置只有以命令行的方式才能正常打包,后面會講到.

比如我們打包flavor_1渠道下對應的release和debug版本:

當然,我們也不用去背這些gradle命令,因為在Android studio的右側會有【Gradle】tab頁面,里面包含了我們常用的命令:

6、manifest占位符

在打包多個版本的時候,會遇到修改應用名稱等需求。不同的flavor有要求不同的名稱. 此時可以在Manifest文件中使用占位符,然后在build.gradle中替換占位符就行了.

首先定義占位符:

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="${APP_NAME}"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".app.MainActivity"
        android:configChanges="orientation|keyboardHidden|screenSize"
        android:label="${APP_NAME}"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

在build.gradle中替換:

buildTypes {
    release {
        signingConfig signingConfigs.config_release
        minifyEnabled false
        manifestPlaceholders = [APP_NAME: "@string/app_name1"]
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
        signingConfig signingConfigs.config_debug
        manifestPlaceholders = [APP_NAME: "@string/app_name2"]
    }
}

productFlavors {
    flavor_1 {
        minSdkVersion 14
        signingConfig signingConfigs.config_release
        targetSdkVersion 23
        versionCode 2
        versionName '2.0.1'
        applicationId 'com.huaihuai.android.1'
        manifestPlaceholders = [APP_NAME: "@string/app_name1"]
    }
    flavor_2 {
        minSdkVersion 10
        signingConfig signingConfigs.config_debug
        versionCode 1
        versionName '1.0.0'
        applicationId 'com.huaihuai.android.2'
        manifestPlaceholders = [APP_NAME: "@string/app_name2"]
    }
}

如上,如果在productFlavors和buildTypes里面都進行了替換,那么是以productFlavors里面的為準.

如果不區分productFlavors和buildTypes的話,只是單純修改應用名稱的話,也可以在defaultConfig里進行替換:

defaultConfig {
    applicationId "com.huaihuai.android"
    minSdkVersion 14
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
    manifestPlaceholders = [APP_NAME: "@string/app_name"]
}

其實defaultConfig也是productFlavors的一個子集.

7、添加自定義字段

我們有時候需要運行的時候有不同的表現.
比如,release版本不顯示log信息,debug版本顯示log信息

這時候我們可以通過buildConfigField、resValue在gradle里面自定義一些字段:

buildConfigField "boolean", "showLog", '"false"'
resValue "String", "build_time", '"11110000"'

添加完畢之后,就可以在代碼中使用了:

System.out.println(BuildConfig. showLog);
System.out.println(getString(R.string.build_time))

注意兩者使用方法并不相同,resValue定義的字段更像是資源文件*.xml下定義的字段,此外它們還有以下區別:
1、buildConfigField可定義字段為基本數據類型
2、buildConfigField定義的字段會顯示在BuildConfig類中
3、resValue可定義字段有:string(待補充)
4、resValue定義的字段會顯示在generated.xml中

8、動態設置一些額外信息

假如想把當前的編譯時間、編譯的機器、最新的commit版本添加到apk,而這些信息又不好寫在代碼里,強大的gradle給了我創造可能的自信:

android {
    defaultConfig {
        resValue "string", "build_time", buildTime()
        resValue "string", "build_host", hostName()
        resValue "string", "build_revision", revision()
    }
}

def buildTime() {
    return new Date().format("yyyy-MM-dd HH:mm:ss")
}

def hostName() {
    return System.getProperty("user.name") + "@" + InetAddress.localHost.hostName
}

def revision() {
    def code = new ByteArrayOutputStream()
    exec {
        commandLine 'git', 'rev-parse', '--short', 'HEAD'
        standardOutput = code
    }
    return code.toString()
}

這個地方,如何從命令行讀取返回結果,很有意思.

9、給自己留個”后門”: 點七下

為了調試方便,我們往往會在debug版本留一個顯示我們想看的界面(記得之前微博的一個iOS版本就泄露了一個調試界面),如何進入到一個界面,我們可以仿照android開發者選項的方式,點七下才顯示,我們來實現一個:

private int clickCount = 0;
private long clickTime = 0;

sevenClickView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (clickTime == 0) {
            clickTime = System.currentTimeMillis();
        }
        if (System.currentTimeMillis() - clickTime > 500) {
            clickCount = 0;
        } else {
            clickCount++;
        }
        clickTime = System.currentTimeMillis();
        if (clickCount > 6) {
            // 點七下條件達到,跳到debug界面
        }
    }
});

release版本肯定是不能暴露這個界面的,也不能讓人用am在命令行調起,如何防止呢,可以在release版本把這個debug界面的exported設為false.

10、自定義導出APK的名稱

兩種方式實現:

/*applicationVariants.all {
            variant ->
                variant.outputs.each {
                    output ->
                        def outputFile = output.outputFile
                        if (outputFile != null && outputFile.name.endsWith('.apk')) {
                            def apkType = ""
                            if (variant.flavorName.equals("flavor_1")) {
                                apkType = "flavor_1"
                            } else if (variant.flavorName.equals("flavor_2")) {
                                apkType = "flavor_2"
                            }
                            def fileName = new File(output.outputFile.getParent(),
                                    "app-" + apkType + "-${variant.versionName}.apk")
                            output.outputFile = fileName
                        }
                }
        }*/
applicationVariants.all {
    variant ->
        variant.outputs.each {
            output ->
                def outputFile = output.outputFile
                if (outputFile != null && outputFile.name.endsWith('.apk')) {
                    def fileName = outputFile.name.replace(".apk",
                                    "-${defaultConfig.versionCode}-${defaultConfig.versionName}.apk")
                    output.outputFile = new File(outputFile.parent, fileName)
                }
         }
}

這里就不多講了,大家運行測試一下就明白了.

至此,文章結束,希望此文能幫助到你,如果對此文有不同見解,歡迎直接評論!

參考文案:
Gradle的神奇之處
Android項目中如何用好構建神器Gradle?
Android 使用Android Studio + Gradle 或 命令行 進行apk簽名打包

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1.介紹 如果你正在查閱build.gradle文件的所有可選項,請點擊這里進行查閱:DSL參考 1.1新構建系統...
    Chuckiefan閱讀 12,171評論 8 72
  • 在 Android Studio 構建的項目中,基于 Gradle 進行項目的構建,同時使用 Android DS...
    Ant_way閱讀 7,423評論 0 16
  • 0x01 基本項目結構 使用Android Studio創建的Android項目會劃分成三個層級: project...
    銀小古兒閱讀 1,975評論 1 2
  • Gradle配置最佳實踐 本文會不定期更新,推薦watch下項目。如果喜歡請star,如果覺得有紕漏請提交issu...
    Solang閱讀 1,659評論 0 4
  • 你在夜里 在有星星、有月光的夜里 彈了一首勾動我心弦的曲 動聽、愜意、藏著心事 我在聽、在聽 關于我們所有的故事 ...
    在生命的盡頭微笑閱讀 265評論 0 4