重学AndroidManifest.xml ——manifest和权限

5,735 阅读7分钟

AndroidManifest.xml 是 Android开发中最常用的配置文件,之前一直没有认真了解过,现在来对它的配置做个总结。

概述

每个应用项目必须在项目源设置的根目录中加入 AndroidManifest.xml 文件(且必须使用此名称)。 AndroidManifest.xml会向 Android 构建工具、Android 操作系统等描述应用的基本信息。

manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="string"
        android:sharedUserId="string"
        android:sharedUserLabel="string resource"
        android:versionCode="integer"
        android:versionName="string"
        android:installLocation=["auto" | "internalOnly" | "preferExternal"] >
  . . .
</manifest>

manifestAndroidManifest.xml文件的根元素。它必须包含<application>元素并指定xmlns:android和package属性。

属性

xmlns:android

定义Android命名空间。此属性应始终设置为“http://schemas.android.com/apk/res/android”

package

在将应用构建为最终的应用软件包 (APK) 时,Android 构建工具会使用 package 属性完成两件事情:

  1. 它会将此名称用作应用所生成 R.java 类(用于访问应用资源)的命名空间。

  2. 它会使用此名称解析清单文件中声明的任何相关类名称。 例如:将 <activity android:name=".MainActivity"> 的 Activity 解析为 com.example.myapp.MainActivity

因此,AndroidManifest.xmlpackage 属性中的名称应始终与项目中保存 Activity 和其他应用代码的基础软件包的名称相匹配。 当然,可以在项目中加入其他子软件包,但此类文件必须使用 package 属性的命名空间导入 R.java 类。

APK 编译完成后,package 属性还可表示应用的通用唯一应用 ID。 当构建工具根据 package 名称执行上述任务后,它们会将 package 值替换为项目 build.gradle 文件(用于 Android Studio 项目)中赋予 applicationId 属性的值。清单中的 package 名称与 build.gradle 文件中 applicationId 的区别可以看《Gradle for Android》核心总结(一)Gradle文件

android:sharedUserId

将与其他应用程序共享的Linux用户标识的名称。 默认情况下,Android会为每个应用分配自己唯一的用户ID。 但是,如果此属性设置为两个或多个应用程序的相同值,则它们将共享相同的ID - 前提是它们的证书集相同。 具有相同用户ID的应用程序可以访问彼此的数据,并且如果需要,可以在同一进程中运行。

sharedUserLabel

共享用户标识.注意:必须将标签设置为对字符串资源的引用; 它不能是原始字符串。 此属性是在API级别3中引入的。仅当还设置了sharedUserId属性时才有意义。

android:versionCode

内部版本号。 此数字(只能是正整数)仅用于确定一个版本是否比另一个版本更新,更高的数字表示更新的版本。 这不是向用户显示的版本号;

android:versionName

给用户看的版本号

android:installLocation

设置应用默认的安装位置,有三个值可以选择:internalOnlyautopreferExternal.

参数 意义
internalOnly 该应用必须仅安装在内部设备存储上。 如果设置了此选项,则永远不会在外部存储上安装该应用程序。 如果内部存储空间已满,则系统将不会安装该应用程序。 如果您没有定义android:installLocation,这也是默认行为
auto 该应用程序可能安装在外部存储上,但系统默认会在内部存储上安装该应用程序。 如果内部存储已满,则系统会将其安装在外部存储上。 安装后,用户可以通过系统设置将应用程序移动到内部或外部存储
preferExternal 该应用程序更喜欢安装在外部存储(SD卡)上。 无法保证系统会遵守此请求。 如果外部媒体不可用或已满,则应用程序可能会安装在内部存储上。 安装后,用户可以通过系统设置将应用程序移动到内部或外部存储。

在外部存储上安装应用程序时:.apk文件将保存到外部存储,但任何应用程序数据(如数据库)仍保存在内部设备内存中。 保存.apk文件的容器使用密钥加密,该密钥允许应用程序仅在安装它的设备上运行。 (用户无法将SD卡传输到其他设备并使用卡上安装的应用程序。)但是,多个SD卡可以与同一设备一起使用。 根据用户的请求,可以将应用程序移动到内部存储。

更多信息可以见android官方教程

权限

uses-permission

指定用户必须授予的系统权限,以便应用正常运行

<uses-permission android:name="string"
        android:maxSdkVersion="integer" />
  • android:name

要申请权限的名称。

  • android:maxSdkVersion

此权限应授予应用的最高 API 级别。如果从某个 API 级别开始不再需要应用所需的权限,则设置此属性非常有用。 例如,从 Android 4.4(API 级别 19)开始,应用在外部存储空间写入其特定目录(getExternalFilesDir() 提供的目录)时不再需要请求 WRITE_EXTERNAL_STORAGE 权限。但 API 级别 18 和更低版本需要此权限。因此,您可以使用如下声明,声明只有 API 级别 18 及以前版本才需要此权限:

这样,从 API 级别 19 开始,系统将不再向您的应用授予 WRITE_EXTERNAL_STORAGE 权限。

此属性为 API 级别 19 中的新增属性。

权限分为两种:普通权限和系统权限。对于普通权限,只要在AndroidManifest.xml申明权限就行(android 6以上一些需要动态申请),系统权限有WRITE_SETTINGS(修改系统设置)SYSTEM_ALERT_WINDOW(设置悬浮窗)

uses-permission-sdk-23

指明应用需要特定权限,但仅当应用在 Android 6.0(API 级别 23)或更高版本的设备上安装时才需要。如果设备运行的是 API 级别 22 或更低版本,则应用没有指定的权限。 当您更新应用以包含需要其他权限的新功能时,此元素很有用。如果用户在运行 API 级别 22 或更低版本的设备更新应用,系统在安装时会提示用户授予在该更新中声明的所有新权限。如果某个新功能无关紧要,您可能想同时在这些设备上停用该功能,以便用户不需要授予额外权限即可更新应用。如果使用 元素而非 ,则仅当应用在支持运行时权限模式(用户在应用运行时向其授予权限)的平台上运行时才可请求权限。

属性值和uses-permission相同

uses-feature

声明应用实现功能所需的条件,例如摄像机应用需要摄像头。详情见文档

permission

用来自定义权限,示例如下:

在AndroidManifest.xml文件中声明自己的权限

<permission android:name="com.demo.mytest" //自定义权限名
    android:label="@string/my_lable"       //设置权限的标签
    android:description="@string/my_describetion" //设置权限的描述
    android:protectionLevel="dangerous" //设置权限的类型,有许多种(normal普通权限 dangerous危险权限 signature 根据签名来决定是否同意)
    android:permissionGroup=""//设置权限组,权限组也可以自定义
    android:icon=""//设置权限的图标,在申请危险权限,请求用户同意的的时候才会展示
/>

资源文件

<string name="my_lable">我的自定义权限</string>
    <string name="my_describetion">没啥用</string>

注意一定要用资源文件来引用字符串,不能直接设置值,比如android:label="我的自定义权限",不然会报错

  • 在AndroidManifest.xml中为< activity>< service>< provider>< receiver>添加权限访问
<activity android:name=".MyPermissionTest.PermissionTestActivity"
                  android:permission="com.demo.mytest" //这里设置访问权限
                  android:exported="true"  //true表示外面的应用可以启动这个activity
            >
        <intent-filter>
            <action android:name="callmenow"/> //用于其他的应用通过隐式Intent来启动这个Activity
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
        </activity>

在< service>< provider>< receiver>中也是一样的

  • 其他应用启动这个Activity

1.在AndroidManifest.xml中加入权限<uses-permission android:name="com.demo.mytest"/>

2.如果这个权限是危险权限,则要询问用户是否授予权限(与普通的权限申请一样),如果是普通权限,则只要在AndroidManifest.xml中申明即可

 if (ContextCompat.checkSelfPermission(MainActivity.this,"com.demo.test")== PackageManager.PERMISSION_DENIED){
                   ActivityCompat.requestPermissions(MainActivity.this,new String[]{"com.demo.mytest"},1);
               }else{
                   test();
               }

private void test(){
        Intent intent1=new Intent();
        intent1.setAction("callmenow");
        startActivity(intent1);
    }

效果如下图:

图片
图片