打包系列教程目錄:
純ant命令行打包android
apk之圖文從原理角度完全詳解android打包過程(打包系列教程之一)
用ant的build.xml構建自動化打包android
apk 完全詳解(打包系列教程之二)
Android
多渠道打包之混淆文件ProGuard技術詳解-特別篇(打包系列教程之三)
android
studio gradle 多渠道打包之完全詳解(打包系列教程之四)
android
studio gradle 多版本多apk打包(打包系列教程之五)
詳解高速神器python腳步打包android apk,超級快!!(打包系列教程之六)
好久沒更新了,最近自己有點私事,所以一直沒時間寫博客,今天就來更新一下打包系列教程,通過前面3篇內容的學習,相信大家對Android打包的流程和混淆操作已相當瞭解了。本篇我們就來分析多渠道自動化打包android的apk。(平臺:mac;工具:android studio)
這裏我們先了解一下爲什麼要多渠道打包?現在國內android應用市場特別多,我們每次發佈app時都會根據公司的要求,把我們生成的簽名包發佈到相應的應用市場上,這時我們就需要把不同應用市場上的包標記上不同的渠道,比如說發佈在360應用市場,這時這個包的渠道就是必須標記爲360相關的標誌,如果發佈在騰訊的應用寶就必須標記爲應用寶相關標誌,那這個渠道標誌又有啥用呢?這裏舉個例子,我公司用的是友盟多渠道打包,當渠道包都發布到相應的渠道應用市場後,我們可以通過友盟後臺的渠道數據來判斷我們的應用在那個市場上下載活躍量比較高,從而採取相應的策略,對app進行特定渠道的推廣或者優化。當然我們在這裏只是舉例其中的一個功能而已,其實友盟還有很多其他的功能,這裏不過多闡述。
這裏爲了演示更加有說服力,我們可以先集成一下友盟的統計分析功能,至於如何集成,大家直接看官網,官網的教程說得很明白(友盟官網地址:http://dev.umeng.com)。集成完成後,我們就可以開始寫我們的打包程序了,這是我主要說明的是使用android studio配合gradle進行多渠道打包,現在就開始吧;
首先我們看一下集成後的AndroidManifest.xml文件:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.zejian.application">
- <!--友盟渠道的權限-->
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.INTERNET"></uses-permission>
- <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <!--友盟渠道app_key-->
- <meta-data android:value="56cfb5a3e0f55abed60023fd " android:name="UMENG_APPKEY"></meta-data>
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name"
- android:theme="@style/AppTheme.NoActionBar">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <!--友盟渠道渠道號-->
- <meta-data
- android:name="UMENG_CHANNEL"
- android:value="${UMENG_CHANNEL_VALUE}" />
- </application>
- </manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zejian.application">
<!--友盟渠道的權限-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--友盟渠道app_key-->
<meta-data android:value="56cfb5a3e0f55abed60023fd " android:name="UMENG_APPKEY"></meta-data>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--友盟渠道渠道號-->
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}" />
</application>
</manifest>
其他不用看,我們可以先看:
<!--友盟渠道渠道號-->
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}" />
${UMENG_CHANNEL_VALUE}這個就是我們要用於多渠道打包的,需要要被替換成渠道名稱的佔位符字段,現在先知道這點就行,後面我們會說明。
要配置多渠道打包,我們首先需要一個打包key,這個大家自己提前準備好就行,我這是使用的是我用來測試的key-->debug4zj.jks。然後配置在gradle文件中,如下:
然後在構建類型(buildTypes)中配置我們的要打包的信息:
這些都搞定後,我們就需要來配置渠道了,gradle多渠道打包是通過productFlavors來配置的,如下:
在這裏需要說明一下就是productFlavors中配置的每一個flavors都代表着一個渠道的apk信息,如haiwei渠道號就代表着華爲渠道的apk。那麼這個渠道號又是如何替換的呢?我們可以看到manifestPlaceholders這個字段,其實可以把它理解爲一個HashMap的鍵值對容器,通過這個鍵值對容器,我們就可以替換AndroidManifest.xml裏面的友盟渠道配置信息即前面所說過的${UMENG_CHANNEL_VALUE}佔位符字段的值,要注意名稱配置一定要跟gadle中的名稱一致。這樣就完成了多渠道的替換循環工作,當然多渠道打包的工作也就完成了。上面的多渠道打包配置是不是很明朗也很清晰,但卻略帶麻煩,其實還有下面一種多渠道配置寫法,顯得相當簡潔,不過就是不太明朗罷了,各自選擇吧:
到此gradle多渠道打包的配置已經完成,我們打開as的命令行,直接執行./gradlew assembleDebug4zj,然後回車,打包就開始執行了。打包完成log如下:
接下來我們就用友盟渠道來測試一下,看看渠道號是否集成成功,這裏我們使用友盟的集成測試功能,因爲這個功能是實時的,方便我們觀察,至於友盟集成測試功能如何使用,請大家自行參考官方文檔哈。集成後我們就來進行測試吧,我使用的測試機以及未測試的數據如下:
我們以360,豌豆莢,百度的apk安裝到我們的測試機器上,然後再觀察友盟後臺的數據,如下:
可以看到數據都實時顯示出來了,說明我的多渠道打包apk沒問題。到這裏本該結束,但我們最後再來嘮叨一下一個概念Buid
Variants ,這個又是什麼呢?我們先來認識一下assemble這個命令,還記得剛纔我們打包所用的命令嘛?./gradlew assembleDebug4zj,對於assemble這個命令,它可以結合構建類型(buildTypes)去創建task,如下根據我們的gradle文件的buildTypes類型,我們可以創建兩種Task:
assembleDebug4zj這個就是我們剛纔打包執行的任務。如果我們執行assembleRelease這個任務的話,as就會根據gradle配置的構建類型去執行相應的操作。除了這個外assemble還可以結合Buid
Variants來創建新的Task,而對於Buid Variants則是projectFlavors+buildTypes的結合,舉個例子,比如我們想打百度渠道debug4zj版本的包,則可以在命令行輸入如下命令:./
gradlew assembleBaiduDebug4zj 這樣就會單獨打出這個版本的包,其他包都不會有:
至爲什麼每次都會打出一個未zipaligned的包,我也還沒搞清楚原因(知道原因的給我留一下言哈,謝了)。但簽名好的包只有百度版本的渠道包,這點肯定是沒錯的。當然我們也可只打百度版本的而不區分構建類型也就是debug4zj和release版本都打,我們可以這樣輸入命令:
./gradlew assembleBaidu ,這樣就會出現debug4zj和release版本的百度渠道包了。
最後獻上完整的grdlew文件:
- apply plugin: 'com.android.application'
- def releaseTime() {
- return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
- }
- android {
- signingConfigs {
- debug4zj {
- keyAlias 'debug4zj'
- keyPassword 'debug4zj'
- storeFile file('/Users/zejian/Documents/android-studio-workplace/debug4zj.jks')
- storePassword 'debug4zj'
- }
- }
- compileSdkVersion 23
- buildToolsVersion "23.0.2"
- defaultConfig {
- applicationId "com.zejian.application"
- minSdkVersion 15
- targetSdkVersion 23
- versionCode 1
- versionName "1.0"
- // dex突破65535的限制
- multiDexEnabled true
- }
- buildTypes {
- debug {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- debug4zj {
- // 不顯示Log
- buildConfigField "boolean", "LOG_DEBUG", "false"
- //是否混淆
- minifyEnabled true
- //是否進行zipalign優化
- zipAlignEnabled true
- // 移除無用的resource文件
- shrinkResources true
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- signingConfig signingConfigs.debug4zj
- applicationVariants.all { variant ->
- variant.outputs.each { output ->
- def outputFile = output.outputFile
- if (outputFile != null && outputFile.name.endsWith('.apk')) {
- // 輸出apk名稱爲zejian_v1.0_2015-01-15_wandoujia.apk
- def fileName = "zejian_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
- output.outputFile = new File(outputFile.parent, fileName)
- }
- }
- }
- }
- }
- //配置多渠道
- productFlavors {
- zejian {
- manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
- }
- huawei {
- manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
- }
- _360 {
- manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
- }
- baidu {
- manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
- }
- wandoujia {
- manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
- }
- }
- //
- // productFlavors {
- // zejian {}
- // huawei {}
- // _360 {}
- // baidu {}
- // wandoujia {}
- // }
- //
- // productFlavors.all {
- // flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
- // }
- }
- dependencies {
- compile fileTree(include: ['*.jar'], dir: 'libs')
- testCompile 'junit:junit:4.12'
- compile 'com.android.support:appcompat-v7:23.1.1'
- compile 'com.android.support:design:23.1.1'
- compile files('libs/umeng-analytics-v5.6.4.jar')
- }
apply plugin: 'com.android.application'
def releaseTime() {
return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}
android {
signingConfigs {
debug4zj {
keyAlias 'debug4zj'
keyPassword 'debug4zj'
storeFile file('/Users/zejian/Documents/android-studio-workplace/debug4zj.jks')
storePassword 'debug4zj'
}
}
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.zejian.application"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
// dex突破65535的限制
multiDexEnabled true
}
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug4zj {
// 不顯示Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//是否混淆
minifyEnabled true
//是否進行zipalign優化
zipAlignEnabled true
// 移除無用的resource文件
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug4zj
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
// 輸出apk名稱爲zejian_v1.0_2015-01-15_wandoujia.apk
def fileName = "zejian_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
}
}
//配置多渠道
productFlavors {
zejian {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
huawei {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
_360 {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
baidu {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
wandoujia {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}
//
// productFlavors {
// zejian {}
// huawei {}
// _360 {}
// baidu {}
// wandoujia {}
// }
//
// productFlavors.all {
// flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
// }
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
compile files('libs/umeng-analytics-v5.6.4.jar')
}