AndroidManifest 是什么,对不起,我不需要 ^-^

前言

在写 Android 应用时,当你新建一个 ActivityServiceContentProviderBroadcast(著名的四大组件)时,你是不是经常性的写完就直接运行,然后程序就崩溃了,通过查看日志,你才发觉原来忘记在 AndroidManifest.xml 中进行注册。甚至于,当我们代码运行需要某些权限时,你也要跳转到 AndroidManifest.xml 中进行权限声明,然后代码才能正确运行,而这些操作,我们往往都会忘记。

笔者个人认为,导致我们经常性忘记在 AndroidManifest.xml 中进行注册的一个主要的原因就在于编写代码和进行注册是发生在两个文件中的,也就是我们需要进行文件切换,这种切换操作对于我们正在编写程序的思路起到了切断作用,所以我们往往在专注于写代码的时候,就会忘记进行组件注册。

基于以上原因,笔者开发了一套开源框架:InjectManifest,这套框架致力于解决上面我们提到的编写代码和进行组件注册需要进行文件切换的不便,框架提供注解进行注册,让我们在编写相关需要进行注册的代码的同时,可以很方便地直接使用注解进行相关内容的注册,再也无需切换到 AndroidManifest.xml 去做这些事。

优点

  • 采用编译期注解与自定义 Gradle 插件完成注册过程,对程序运行无任何影响;
  • 支持注解和原生 AndroidManifest.xml 协同工作,最终会将两者结合起来,保留不一致的元素,相同的元素只保留一份;
  • 对支持的标签的所有属性配置均支持;

缺点

  • 在每次使用注解注册后,需要 rebuild 一下才能生成新的 AndroidManifest.xml文件,如果采用注解注册后,直接运行程序,可以看到新的 AndroidManifest.xml 也生成了,但是程序此时使用的是旧的(也就是原生的)AndroidManifest.xml配置。这个地方的原因我猜测应该是 processDebugManifest/processReleaseManifest 运行在 新的 AndroidManifest.xml 生成前,所以这个问题我猜测是不是可以有什么办法把processDebugManifest/processReleaseManifest 放到文件生成后再执行····这个地方我暂时也没找出什么办法进行解决,如果有谁知道怎么解决这个问题的,麻烦跟我讲下,谢谢。
  • 目前只支持 manifest,application,activity,service,receiver,provider,uses-permission 标签的解析,对于其他标签,无法进行融合,在新生成的 AndroidManifest.xml 中这些元素不会被保留;

示例

  1. manifest 标签注册
@InjectManifest(
        pkName = "com.yn.injectmanifest",
        installLocation = INTERNAL_ONLY,
        sharedUserId = "android.uid.system"
)

public class App extends Application {
}

rebuild 一下,你就可以看到 AndroidManifest.xml 变成这样:

@InjectManifest

manifest 标签的其他属性 @InjectManifest 均支持。

  1. application 标签注册
@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 变成这样:

@InjectApp

application 标签的其他属性 @InjectApp 均支持。

  1. activity 标签注册
@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 变成这样:

@InjectActivity

activity 标签的其他属性 @InjectActivity 均支持。

  1. service 标签注册
@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 变成这样:

@InjectService

service 标签的其他属性 @InjectService 均支持。

  1. receiver 标签注册
@InjectReceiver(
        name = ".FirstReceiver",
        label = "hi i am first receiver",
        process = ".remote",
        enabled = TRUE
)
public class FirstReceiver extends BroadcastReceiver {···}

rebuild 一下,你就可以看到 AndroidManifest.xml 变成这样:

@InjectReceiver

receiver 标签的其他属性 @InjectReceiver 均支持。

  1. provider 标签注册
@InjectProvider(
        authorities = "com.yn.authorities",
        name = ".FirstProvider",
        label = "I am ContentProvider"
)
public class FirstProvider extends android.content.ContentProvider {···}
@InjectProvider

provider 标签的其他属性 @InjectProvider 均支持。

  1. uses-permission 标签注册
    @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 变成这样:

@InjectUsesPermission

uses-permission 标签的其他属性 @InjectUsesPermission 均支持。

目前暂时就只支持以上所讲的标签,后续我有时间就会不定时更新下。

下载

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'

注意事项:

  • InjectManifest 默认会将生成的 AndroidManifest.xml 替换掉原来的 AndroidManifest.xml,但在替换前,会将原来的 AndroidManifest.xml 保存为 AndroidManifest_old.xml,所以,对于暂时未支持的 xml 标签,新生成的文件无法保留,那么你就可以从 AndroidManifest_old.xml 中找回。
    如果想更换上面的默认行为,那就需要在 modulebuild.gradle 中增加下面的扩展属性:
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
}
  • 如果你在开发过程中,要为注解处理器传递参数,请记住加上 + 号,代表追加,否则,会导致 gradle 插件里面默认设置的注解参数失效,这样就不会合并原生 AndroidManifest.xml 了。
android {
    defaultConfig{
    ···
    ···
        javaCompileOptions {
            annotationProcessorOptions {
                arguments += [xxxxx: 'yyyyy'] 
            }
        }
    }
}
  • 如果你对 AndroidManifest.xml 的默认路径进行了修改,如果你还希望能合并 AndroidManifest.xml,那你需要手动传递最新路径给 annotation processor
android {
    defaultConfig{
    ···
    ···
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AndroidManifestPath: android.sourceSets.main.manifest.srcFile.absolutePath] 
            }
        }
    }
}

附录

源码传送门:InjectManifest
AndroidManifest.xml 应用清单官方文档: here

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,434评论 25 707
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,733评论 6 342
  • 如有雷同,不是巧合。 大环境仍然是稳定,国家政策是稳健的货币政策和积极的财政政策,说白了就是不放水,搞...
    十二月的阳光阅读 166评论 0 0
  • 已经过去十天了,距离苏荷在网上发布筹款开始。这期间,她每天都抱着那部有些破旧的手机查看银行卡余额,然后将筹款一笔一...
    茶丁故事阅读 922评论 6 23