前言
在寫(xiě) Android 應(yīng)用時(shí),當(dāng)你新建一個(gè) Activity
生闲,Service
媳溺,ContentProvider
,Broadcast
(著名的四大組件)時(shí)跪腹,你是不是經(jīng)常性的寫(xiě)完就直接運(yùn)行褂删,然后程序就崩潰了,通過(guò)查看日志冲茸,你才發(fā)覺(jué)原來(lái)忘記在 AndroidManifest.xml
中進(jìn)行注冊(cè)屯阀。甚至于缅帘,當(dāng)我們代碼運(yùn)行需要某些權(quán)限時(shí),你也要跳轉(zhuǎn)到 AndroidManifest.xml
中進(jìn)行權(quán)限聲明难衰,然后代碼才能正確運(yùn)行钦无,而這些操作,我們往往都會(huì)忘記盖袭。
筆者個(gè)人認(rèn)為失暂,導(dǎo)致我們經(jīng)常性忘記在 AndroidManifest.xml
中進(jìn)行注冊(cè)的一個(gè)主要的原因就在于編寫(xiě)代碼和進(jìn)行注冊(cè)是發(fā)生在兩個(gè)文件中的,也就是我們需要進(jìn)行文件切換鳄虱,這種切換操作對(duì)于我們正在編寫(xiě)程序的思路起到了切斷作用弟塞,所以我們往往在專(zhuān)注于寫(xiě)代碼的時(shí)候,就會(huì)忘記進(jìn)行組件注冊(cè)拙已。
基于以上原因决记,筆者開(kāi)發(fā)了一套開(kāi)源框架:InjectManifest,這套框架致力于解決上面我們提到的編寫(xiě)代碼和進(jìn)行組件注冊(cè)需要進(jìn)行文件切換的不便倍踪,框架提供注解進(jìn)行注冊(cè)系宫,讓我們?cè)诰帉?xiě)相關(guān)需要進(jìn)行注冊(cè)的代碼的同時(shí),可以很方便地直接使用注解進(jìn)行相關(guān)內(nèi)容的注冊(cè)建车,再也無(wú)需切換到 AndroidManifest.xml
去做這些事扩借。
優(yōu)點(diǎn)
- 采用編譯期注解與自定義
Gradle
插件完成注冊(cè)過(guò)程,對(duì)程序運(yùn)行無(wú)任何影響缤至; - 支持注解和原生
AndroidManifest.xml
協(xié)同工作潮罪,最終會(huì)將兩者結(jié)合起來(lái),保留不一致的元素凄杯,相同的元素只保留一份错洁; - 對(duì)支持的標(biāo)簽的所有屬性配置均支持;
缺點(diǎn)
- 在每次使用注解注冊(cè)后戒突,需要
rebuild
一下才能生成新的AndroidManifest.xml
文件,如果采用注解注冊(cè)后描睦,直接運(yùn)行程序膊存,可以看到新的AndroidManifest.xml
也生成了,但是程序此時(shí)使用的是舊的(也就是原生的)AndroidManifest.xml
配置忱叭。這個(gè)地方的原因我猜測(cè)應(yīng)該是processDebugManifest/processReleaseManifest
運(yùn)行在 新的AndroidManifest.xml
生成前隔崎,所以這個(gè)問(wèn)題我猜測(cè)是不是可以有什么辦法把processDebugManifest/processReleaseManifest
放到文件生成后再執(zhí)行····這個(gè)地方我暫時(shí)也沒(méi)找出什么辦法進(jìn)行解決,如果有誰(shuí)知道怎么解決這個(gè)問(wèn)題的韵丑,麻煩跟我講下爵卒,謝謝。 - 目前只支持
manifest
,application
,activity
,service
,receiver
,provider
,uses-permission
標(biāo)簽的解析撵彻,對(duì)于其他標(biāo)簽钓株,無(wú)法進(jìn)行融合实牡,在新生成的AndroidManifest.xml
中這些元素不會(huì)被保留;
示例
-
manifest
標(biāo)簽注冊(cè):
@InjectManifest(
pkName = "com.yn.injectmanifest",
installLocation = INTERNAL_ONLY,
sharedUserId = "android.uid.system"
)
public class App extends Application {
}
rebuild
一下轴合,你就可以看到 AndroidManifest.xml
變成這樣:
manifest
標(biāo)簽的其他屬性 @InjectManifest
均支持创坞。
-
application
標(biāo)簽注冊(cè):
@InjectApp(
name = ".App", //you can full class name or just simply using a .classSimpleName
label = "i am app",
debuggable = TRUE,
metaData = @InjectMetaData(name = "app/meta-data")
)
public class App extends Application {
}
rebuild
一下,你就可以看到 AndroidManifest.xml
變成這樣:
application
標(biāo)簽的其他屬性 @InjectApp
均支持受葛。
-
activity
標(biāo)簽注冊(cè):
@InjectActivity(
name = ".MainActivity",
intentFilter = @InjectIntentFilter(
action = {"android.intent.action.MAIN", "android.intent.action_whyn_test"},
category = {"android.intent.category.LAUNCHER", "android.intent.category.whyn"},
data = @InjectData(mimeType = "image/*")
))
public class MainActivity extends AppCompatActivity {}
rebuild
一下题涨,你就可以看到 AndroidManifest.xml
變成這樣:
activity
標(biāo)簽的其他屬性 @InjectActivity
均支持。
-
service
標(biāo)簽注冊(cè):
@InjectService(
enabled = TRUE,
name = ".FirstService",
label = "Inject Service test",
intentFilter = @InjectIntentFilter(
action = "com.yn.action.FirstService",
category = "com.yn.category.serviceTest",
data = @InjectData(
host = "sdcard",
mimeType = "video/mp4",
path = "/sdcard/1.MP4",
pathPattern = ".*\\.mp4",
pathPrefix = "/sdcard/",
port = "-2",
scheme = "file"
)
),
metaData = @InjectMetaData(name = "com.yn.meta-data.service")
)
public class FirstService extends Service {···}
rebuild
一下总滩,你就可以看到 AndroidManifest.xml
變成這樣:
service
標(biāo)簽的其他屬性 @InjectService
均支持纲堵。
-
receiver
標(biāo)簽注冊(cè):
@InjectReceiver(
name = ".FirstReceiver",
label = "hi i am first receiver",
process = ".remote",
enabled = TRUE
)
public class FirstReceiver extends BroadcastReceiver {···}
rebuild
一下,你就可以看到 AndroidManifest.xml
變成這樣:
receiver
標(biāo)簽的其他屬性 @InjectReceiver
均支持闰渔。
-
provider
標(biāo)簽注冊(cè):
@InjectProvider(
authorities = "com.yn.authorities",
name = ".FirstProvider",
label = "I am ContentProvider"
)
public class FirstProvider extends android.content.ContentProvider {···}
provider
標(biāo)簽的其他屬性 @InjectProvider
均支持婉支。
-
uses-permission
標(biāo)簽注冊(cè):
@InjectUsesPermission({
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.ACCESS_WIFI_STATE,
})
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
rebuild
一下,你就可以看到 AndroidManifest.xml
變成這樣:
uses-permission
標(biāo)簽的其他屬性 @InjectUsesPermission
均支持澜建。
目前暫時(shí)就只支持以上所講的標(biāo)簽向挖,后續(xù)我有時(shí)間就會(huì)不定時(shí)更新下。
下載
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.whyn:injectmanifest-plugin:1.1.0'
}
}
然后炕舵,apply
到你的 module
:
apply plugin: 'com.android.application'
apply plugin: 'com.whyn.plugin.injectmanifest'
注意事項(xiàng):
-
InjectManifest 默認(rèn)會(huì)將生成的
AndroidManifest.xml
替換掉原來(lái)的AndroidManifest.xml
何之,但在替換前,會(huì)將原來(lái)的AndroidManifest.xml
保存為AndroidManifest_old.xml
咽筋,所以溶推,對(duì)于暫時(shí)未支持的xml
標(biāo)簽,新生成的文件無(wú)法保留奸攻,那么你就可以從AndroidManifest_old.xml
中找回蒜危。
如果想更換上面的默認(rèn)行為,那就需要在module
的build.gradle
中增加下面的擴(kuò)展屬性:
manifestConfig {
//the defautl AndroidManifest.xml path
originManifestPath android.sourceSets.main.manifest.srcFile.absolutePath
//the AndroidManifest.xml path generated by annotation processor
genManifestPath "$project.buildDir/generated/source/apt/debug/Collections.xml"
//to save the original AndroidManifest: true -- save,false -- not save
saveOrigin false
}
- 如果你在開(kāi)發(fā)過(guò)程中睹耐,要為注解處理器傳遞參數(shù)辐赞,請(qǐng)記住加上
+
號(hào),代表追加硝训,否則响委,會(huì)導(dǎo)致gradle
插件里面默認(rèn)設(shè)置的注解參數(shù)失效,這樣就不會(huì)合并原生AndroidManifest.xml
了窖梁。
android {
defaultConfig{
···
···
javaCompileOptions {
annotationProcessorOptions {
arguments += [xxxxx: 'yyyyy']
}
}
}
}
- 如果你對(duì)
AndroidManifest.xml
的默認(rèn)路徑進(jìn)行了修改赘风,如果你還希望能合并AndroidManifest.xml
,那你需要手動(dòng)傳遞最新路徑給annotation processor
:
android {
defaultConfig{
···
···
javaCompileOptions {
annotationProcessorOptions {
arguments = [AndroidManifestPath: android.sourceSets.main.manifest.srcFile.absolutePath]
}
}
}
}
附錄
源碼傳送門(mén):InjectManifest
AndroidManifest.xml
應(yīng)用清單官方文檔: here