美文网首页程序员
AndroidManifest 是什么,对不起,我不需要 ^-^

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

作者: Whyn | 来源:发表于2017-09-09 11:58 被阅读291次

    前言

    在写 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

    相关文章

      网友评论

        本文标题:AndroidManifest 是什么,对不起,我不需要 ^-^

        本文链接:https://www.haomeiwen.com/subject/fovwjxtx.html