Android系统编程入门系列之清单文件
在上一篇文章中已经提到,android系统加载应用程序之后,首先会读取该应用程序的androidmanifest.xml清单文件,之后根据该清单文件加载后边的东西。所以要开发应用程序,自然要先知道清单文件中都记录了什么东西。一般地,在清单文件中声明定义的内容,称为静态注册,相对应地,可以在代码中定义的内容,称为动态注册。
清单文件的存储位置就是应用程序的根目录,而且文件名也是固定的,必须为androidmanifest.xml,清单文件中所包含的内容在android官网应用清单文件中可查。其中的内容主要有以下三部分。
应用基本信息
package应用包名属性,该属性要保证系统唯一性,也就是说应用程序所运行的android机器上,不能有相同包名的两个应用程序。如果想把两个相同包名的应用程序安装到同一台android机器上,那是连安装这一步都无法成功的。
在开发环境androidstudio上,建议清单文件中的package属性与主应用module下的build.gradle文件中的applicationid保持一致,当然官网也给出了不一致的修改方案,但是开发过程中除非有特殊需求,否则不推荐。
versioncode和versionname两个属性分别标记了应用的版本信息,其中versioncode可以在android系统的设置-应用设置-该应用信息中展示,而versionname只能在应用内部显示调用展示。
在开发环境androidstudio上,这两个属性可以通过主应用module下的build.gradle文件直接配置。
上边这些作为基本信息,在android系统加载该应用时首先加载使用。简而言之,package保证了android系统上运行的软件与软件之间的唯一性,而versioncode保证了android系统上所运行的同一个软件在不同版本之间的唯一性。有了这些基础信息,就可以确定下边要加载的其他内容了。
权限声明
应用程序可能需要联网操作,或者访问android系统上的系统级应用中的内容,比如通讯录信息,这些可能涉及到用户隐私的操作和数据,统一归纳为应用权限。
应用程序所使用到的权限都要在清单文件中以<uses-permisson />标签形式声明,在name属性值中填入相关权限名。这里的权限名不仅可以使用android系统已经提供的权限,还可以使用当前应用程序的自定义权限和其他应用程序的自定义权限。自定义权限同样是在清单文件这里定义,使用<permission>标签填写相关信息即可。
值得注意的是,从android6.0开始,应用程序用到的危险权限不仅要在清单文件中声明,而且在涉及该危险权限的代码调用之前也要动态检查申请。可查询android官网权限列表中protection level: dangerous类型的权限即为危险权限。
在动态申请权限时,可使用checkselfpermission(string permission)
检查应用是否获得相关权限,如果用户没有授权,就需要使用requestpermission(@nonnull string[] permissions, int requestcode)
申请相关权限,并在activity中重载onrequestpermissionsresult(int requestcode, @nonnull string[] permissions, @nonnull int[] grantresults)
以获得用户对权限申请的处理结果。
在android系统检查并授予当前应用相关权限之后,就可以启动当前应用程序了。每个应用程序对应androidsdk中的android.app.application
类,application
的生命周期即从应用程序启动开始,当android系统因为内存过低或电源优化时,被动杀死应用程序结束,也可能是应用程序主动退出结束。
设备兼容
android系统所搭载的硬件设备是千差万别的,而且同一个应用也可能在不同的androidsdk的版本上运行,这也就是经常谈到的碎片化问题。如果能在清单文件中声明当前应用程序需要具备哪些基础硬件,或者可以在哪些androidsdk版本上运行,那就可以在不符合要求的android系统上禁止安装该应用程序。
使用<users-feature />标签可以声明应用程序所需要的一些硬件要求。
使用<users-sdk />标签可以声明应用程序所需要的androidsdk版本要求,该标签下主要有、targetsdkversion、maxsdkversion、targetsdkversion三个属性值,分别对应应用程序所运行androidsdk的最低版本,最高版本,目标版本。在开发环境androidstudio上,minsdkversion和targetsdkversion这两个属性可以通过主应用module下的build.gradle文件直接配置。
组件声明
android系统的实现就是为了更好的和人类交流,交流的途径主要有四种方式,分别是界面操作(以android.app.activity
类为载体),后台服务(以android.app.service
类为载体),广播通知(以android.app.broadcastreceiver
类为载体),数据交换(以android.app.contentprovider
类为载体),将这四种交流方式所依赖的载体统一称为应用组件,应用组件是依赖于当前应用application
的,所以组件的生命周期只能小于等于当前应用生命周期。
application
对应于清单文件中的<application></application>标签。该标签下有icon属性加载资源文件下的图标,作为应用程序在android系统的显示图标;label属性则是加载资源文件下的字符串,作为应用程序在android系统中显示的应用名;name属性作为可填项,可以使用继承自android.app.application
的自定义类,如果不填该属性值,则默认为android.app.application
。另外还有其他几个属性值都可以在android官网清单文件-application标签中查询,通过这些属性值配置,可以更方便的指导android系统管理当前应用程序。
在当前应用确定以后,就需要分别加载该应用下的组件信息了,应用程序只有一个,但是组件可以有多个,只要名称不冲突即可,所以组件的声明是嵌套在<application></application>标签内部的,下面是每种组件在androidmanifest.xml中对应的标签名。
组件名 | activity | service | broadcastreceiver | contentprovider |
---|---|---|---|---|
清单文件标签名 | activity | service | receiver | provider |
组件标签内必须要有name属性,以指向代码中自定义的组件类,值得注意的是,一个应用程序中,可以有多个界面,多个服务,多个广播接收器,多个数据提供者,所以name属性就是为了区分多个相同种类组件的。
provider标签中还必须要有authorities属性值,这是由于contentprovider
是对其他应用提供数据,这就好像该应用将数据保存到一个保险箱中提供给其他应用,而其他应用必须有该保险箱的密码才能打开保险箱以访问该应用的数据,而authorities正是起到这个密码的类似效果。
activity标签,service标签,provider标签,还可以内嵌<intent-filter><\intent-filter>
标签作为组件内信息,使用意图过滤标记的组件,可以在代码中快速响应该意图,执行响应后逻辑。
启动应用程序后,必须要加载一个activity
界面,而加载哪一个呢?这也就用到<intent-filter><\intent-filter>
标签了,只有在该标签内嵌套了<action android:name="android.intent.action.main" />
和<category android:name="android.intent.category.launcher" />
两个固定标签内容的<activity><\activity>
,才允许作为第一个界面加载。所以很自然的想到,一个<application><\application>
标签内只允许有一个<activity><\activity>
可以嵌套上面的意图过滤器内容。
至此,android系统对应用程序的清单文件基本解析之后,就获取了该应用的所有静态信息,当应用安装之后,就可以在桌面launcher应用程序中显示该应用,等待用户点击启动该应用了。