在android studio中生成jar包其實跟生成aar包的過程是一樣的,因爲生成aar包的過程會包含生成jar包,而這個jar包其實就是module的build->intermediates->bundles下的項目中的classes.jar。
所以說apply plugin: 'com.android.library'其實意思是生成庫文件的意思,庫文件在android studio裏面有兩種:jar,aar。
最後需要注意的是applicationId這個東西,這裏涉及到兩個概念:applicationId,packageName。
每一個app的包名都是app在設備和應用商店的唯一標誌。同時,它被用來命名資源類的包和解析類的名稱R文件,Activity文件的包名。
但是我們注意到一個問題,那就是如果發佈多個版本的app,例如debug版本,release,alpha版本,那麼包名如果一樣那麼版本就容易出現更新出錯,或者app被不同版本的app替代的情況。
考慮到不同版本的唯一標識,以及R文件,.java文件的包名。這裏解決的方案就是,在設備以及商店中使用的是applicationId,也就是說,AndroidManifest文件中,以及商店中使用的是applicationId。而apk內部R文件的引用,以及.java的使用使用的是packageName。ps:AndroidManifest文件是一份證明文件,也是apk添加到設備中時,設備作爲參考的文件,設備通過他來詢問使用者是否給予權限,以及記錄apk的問一標誌。
我們可以在build.gradle文件中指定applicationId,例如:defaultConfig{applicationId ‘com.example.administrator.application’}
總的來說,就是applicationId是app的唯一標識,而packageName僅僅是包名!
這裏先講講多渠道打包。多渠道打包需要在先在AndroidManifest中添加例如<meta-data android:name="KEY_CHANNEL" android:value="CHANNEL_ID" />的PlaceHolder,這裏CHANNEL_ID就是渠道標誌,多渠道打包就是讓這個標誌自動發生變化。這裏,其實詳細過程應該如下:
1.AndroidManifest下添加<meta-data android:name="KEY_CHANNEL" android:value="${CHANNEL_ID_VALUE}"的PlaceHolder
2.build.gradle下設置productFlavors,也就是
android{
productFlavors{
han{
manifestPlaceholders=[CHANNEL_ID_VALUE:"han"]
}
baidu{
manifestPlaceholders=[CHANNEL_ID_VALUE:"baidu"]
}
}
}
或者使用另外一種更加簡潔的方式:
android{
productFlavors{
han{}
baidu{}
}
productFlavors.all{
flavor->flavor.manifestPlaceholders=[CHANNEL_ID_VALUE:name]
}
}
其實,整個過程就是使用AndroidManifest的聲明作用,在AndroidManifest中聲明一個key-value,value是一個指針,然後再build.gradle中value指針被賦予一個實際值。然後就可以生成多個apk了。
另外,其實可以在productFlavors的不同版本里面是可以設置applicationId的。
另外,在productFlavors中還可以設置applicationIdSuffix給當前版本的applicationId添加後綴,形成自己的applicationId。
Build Variants窗口裏面會有運行的項目的信息,裏面每個module都會在裏面,我們可以切換每個module的運行方式,一般使用debug,但是可以切換到例如release等其他模式。這在多渠道打包中很有用,需要特別注意!
最後,其實還可以使用variant進行多渠道發佈。採用的是動態替換渠道字符串的方式,生成各渠道的AndroidManifest文件並打包。
前面的步驟是一樣的,最後一步在build.gradle下配置的是如下:
//替換AndroidManifest.xml的UMENG_CHANNEL_VALUE字符串爲渠道名稱 By Remex Huang
android.applicationVariants.all{ variant ->
variant.processManifest.doLast{
//之前這裏用的copy{},我換成了文件操作,這樣可以在v1.11版本正常運行,並保持文件夾整潔
//${buildDir}是指build文件夾
//${variant.dirName}是flavor/buildtype,例如GooglePlay/release,運行時會自動生成
//下面的路徑是類似這樣:build/manifests/GooglePlay/release/AndroidManifest.xml
def manifestFile = "${buildDir}/manifests/${variant.dirName}/AndroidManifest.xml"
//將字符串UMENG_CHANNEL_VALUE替換成flavor的名字
def updatedContent = new File(manifestFile).getText('UTF-8').replaceAll("UMENG_CHANNEL_VALUE", "${variant.productFlavors[0].name}")
new File(manifestFile).write(updatedContent, 'UTF-8')
//將此次flavor的AndroidManifest.xml文件指定爲我們修改過的這個文件
variant.processResources.manifestFile = file("${buildDir}/manifests/${variant.dirName}/AndroidManifest.xml")
}
}
另外,這裏前面使用的方式是:
android.applicationVariants.all{ variant ->
println "${variant.productFlavors[0].name}"
variant.processManifest.doLast{
copy{
from("${buildDir}/manifests"){
include "${variant.dirName}/AndroidManifest.xml"
}
into("${buildDir}/manifests/$variant.name")
filter{
String line -> line.replaceAll("UMENG_CHANNEL_VALUE", "${variant.productFlavors[0].name}")
}
variant.processResources.manifestFile = file("${buildDir}/manifests/${variant.name}/${variant.dirName}/AndroidManifest.xml")
}
}
}
這種方式在gradle1.11裏面無法正常運行,所以才改用上一種方法,其實都是操作字符串跟文件而已。另外需要注意的是,
println "${variant.productFlavors[0].name}"
輸出的是productFlavors裏面的每一個版本的名字,這裏productFlavors[0]是因爲productFlavors可以有多個,而實際上我們只需要一個,所以實際上productFlavors[0]指的是build.gradle文件下的productFlavors{},而name則是裏面的版本元素的名字,所以最後輸出的是版本的名字。
所以這種方法實際上就是操作AndroidManifest,將<meta-data android:name="KEY_CHANNEL" android:value="CHANNEL_ID_VALUE" />元素裏面的value值替換掉。詳細過程是讀取AndroidManifest字符串,然後將字符串的CHANNEL_ID_VALUE替換成版本的名字了。也就是說,這裏AndroidManifest字符串的replaceAll方法相當於productFlavors的manifestPlaceholders。
其實最後這些方法都未必會使用,因爲太麻煩了。最簡單的使用方式是在project structure裏面設置。所以上面這些作爲參考就可以了。