在上一篇文章中已经提到,Android系统加载应用程序之后,首先会读取该应用程序的AndroidManifest.xml清单文件,之后根据该清单文件加载后边的东西。所以要开发应用程序,自然要先知道清单文件中都记录了什么东西。一般地,在清单文件中声明定义的内容,称为静态注册,相对应地,可以在代码中定义的内容,称为动态注册。

清单文件的存储位置就是应用程序的根目录,而且文件名也是固定的,必须为AndroidManifest.xml,清单文件中所包含的内容在Android官网应用清单文件中可查。其中的内容主要有以下三部分。

应用基本信息

package应用包名属性,该属性要保证系统唯一性,也就是说应用程序所运行的Android机器上,不能有相同包名的两个应用程序。如果想把两个相同包名的应用程序安装到同一台Android机器上,那是连安装这一步都无法成功的。

在开发环境AndroidStudio上,建议清单文件中的package属性与主应用module下的build.gradle文件中的applicationId保持一致,当然官网也给出了不一致的修改方案,但是开发过程中除非有特殊需求,否则不推荐。

versionCodeversionName两个属性分别标记了应用的版本信息,其中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版本要求,该标签下主要有、targetSdkVersionmaxSdkVersiontargetSdkVersion三个属性值,分别对应应用程序所运行AndroidSdk的最低版本,最高版本,目标版本。在开发环境AndroidStudio上,minSdkVersiontargetSdkVersion这两个属性可以通过主应用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应用程序中显示该应用,等待用户点击启动该应用了。

Android系统编程入门系列之清单文件的更多相关文章

  1. Android系统编程入门系列之加载界面Activity

    上回说到应用初始化加载及其生命周期,在Android系统调用Applicaiton.onCreate()之后,继续创建并加载清单文件中注册的首个界面即主Activity,也可称之为入口界面.主Acti ...

  2. Android系统编程入门系列之应用环境及开发环境介绍

        作为移动端操作系统,目前最新的Android 11.0已经发展的比较完善了,现在也到了系统的整理一番的时间,接下来的系列文章将以Android开发者为中心,争取用归纳总结的态度对初级入门者所应 ...

  3. Android系统编程入门系列之硬件交互——通信硬件电信SIM卡

    现在的SIM卡通常具备基站定位.语音通话.短信消息.网络流量这四大功能,而在移动端是无法对SIM卡使用基站定位功能的,所以这里只介绍移动端如何使用SIM卡实现语音通话.短信消息.数据流量三个功能. 语 ...

  4. Android系统编程入门系列之应用数据文件化保存

    应用中关于数据的持久化保存,不管是简单的SharedPreferences还是数据库SQLiteDatabase,本质上都是将数据保存到系统的某种类型的文件中.因此可以直接使用java.io.File ...

  5. Android系统编程入门系列之应用级文件在应用程序间的共享

    在上篇文章了解到应用级文件只能被其所创建的应用程序所访问,那么其他应用程序是不是就无论如何都无法访问了呢?肯定不是的,只要文件经过其创建的应用程序授权,还是可以被其他应用程序所访问的.这也就是应用级文 ...

  6. Android系统编程入门系列之界面Activity响应丝滑的传统动画

    上篇文章介绍了应用程序内对用户操作响应的相关方法位置,简单的响应逻辑可以是从一个界面Activity跳转到另一个界面Activity,也可以是某些视图View的相对变化.然而不管是启动一个界面执行新界 ...

  7. Android系统编程入门系列之加载服务Service

    之前几篇文章简单梳理了在Android系统的四大组件之一,最主要的界面Activity中,使应用程序与用户进行交互响应的相关知识点,那对于应用程序中不需要与用户交互的逻辑,又要用到哪些内容呢?本文开始 ...

  8. Android系统编程入门系列之广播接收者BroadcastReceiver实现进程间通信

    在前边几篇关于Android系统两个重要组件的介绍中,界面Activity负责应用程序与用户的交互,服务Service负责应用程序内部线程间的交互或两个应用程序进程之间的数据交互.看上去这两大组件就能 ...

  9. Android系统编程入门系列之应用间数据共享ContentProvider

    内容提供者ContentProvider与前文的界面Activity.服务Service.广播接收者BroadcastReveiver,并列称为Android的四大组件,均是需要自定义子类继承上述组件 ...

随机推荐

  1. 最新.NET Core面试题汇总

    这几天给.neter们整理了26道.NET Core面试题,初衷也很简单,就是希望在面试的时候能够帮助到大家,减轻大家的负担和节省时间.对于没有跳槽打算的也可以复习一下相关知识点,就当是查缺补漏! 对 ...

  2. CentOS8.2集成的megaraid_sas版本不支持IBM X3850 X5内置RAID卡。需要更新https://docs.broadcom.com/docs/MR_LINUX_DRIVER_7.15-07.715.02.00-1-PUL.tgz

    CentOS8.2集成的megaraid_sas版本不支持IBM X3850 X5内置RAID卡.需要更新https://docs.broadcom.com/docs/MR_LINUX_DRIVER_ ...

  3. linux使用createrepo制作本地yum源

    目录 linux使用createrepo制作本地yum源 安装createrepo软件包 进入本地rpm包目录 执行完后可以看到生成的repodata目录 编辑yum配置文件使用 完成,测试使用 关于 ...

  4. python类内部方法__setattr__ __getattr_ __delattr__ hasattr __getattribute__ __getitem__(),__setitem__(), __delitem__()

    主要讲类的内部方法 __setattr__  __getattr_  __delattr__  hasattr  __getattribute__  __getitem__(),__setitem__ ...

  5. TEB 系统综合误差

    TEB  系统综合误差  和森世籍  聊天得知 该TEB  包括  传感器误差  温度  系统误差等等

  6. nosql数据库之Redis集群

    Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation). Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 ...

  7. python基础之包、模块、命名空间和作用域

    一.模块介绍 模块就是一组功能的集合体,我们的程序可以导入模块来复用模块里的功能. 模块的作用: (1)从文件级别组织程序,更方便管理:随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一 ...

  8. /usr/bin/docker-current: Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused "process_linux.go:245: running exec setns .....

    docker创建容器时报错如下: containerd: start container" error="oci runtime error: container_linux.go ...

  9. Raft: 一点阅读笔记

    前言 如果想要对Raft算法的了解更深入一点的话,仅仅做6.824的Lab和读<In Search of an Understandable Consensus Algorithm>这篇论 ...

  10. Python+Selenium学习笔记19 - 自动发送邮件

    发送简单的邮件 用一个QQ邮箱发送到另一个QQ邮件. 首先设置QQ邮箱,邮箱设置 -> 账号 开启SMTP服务,点击开启按钮,按提示进行操作,需要1毛钱的短信费.开启后如下所示 1 # codi ...