Android Permission那些事
在Android App开发中我们经常会在AndroidManifest中见到<uses-permission>,<permission>等标签,这些标签是什么?有什么用?今天给大家讲讲关于Android Permission的那些事。
谈到Android Permission,得先来说下Android系统的安全体系。Android构建了一套安全体系,以保证平台上各App之间数据访问的安全性。同时Android是基于Linux内核的,自然也沿用了Linux中的一套安全机制。Linux系统基于用户ID和群组ID建立了一个沙箱机制,这样可以避免数据在不同的用户和群组之间的非法访问。在Android系统系统中,每个App在安装时被分配了一个uid和gid,这样每个App下面的数据就只能被当前App访问。但是,在系统中经常会出现多个App之间需要相互访问的场景,比如访问通讯录,短信,电话记录等,这种该怎么解决呢?Android系统了增加了一个sharedUserId的机制,只要两个App拥有同样的sharedUserId,就可以访问对方的数据了,但是像通讯录,短信和电话这种非常重要的用户隐私数据,用户并不希望直接提供给其他App使用,而是希望在获得用户许可的前提下访问。因此,Android系统增加了一套Permission机制来实现该需求,同时由于Android App是由四大组件构成,Permission机制可以单独添加个单个组件上,这样使得权限的控制力度更加细化和灵活。
Android的权限分为两种:
- 系统权限。其主要用于限制其他App对系统资源或者系统内置应用资源的访问,比如通讯录,短信,传感器,相册,相机等。
- 自定义权限。其主要用于限制其他App对自身App内部资源的访问。
如何自定义权限?
在AndroidManifest文件中添加<permission>标签,下面细说下这个标签的几个属性:
<permission-group
android:name="com.xiaofei.permission.GROUP"
android:description="@string/group_desc"
android:label="@string/group_label"/>
<permission
android:name="com.xiaofei.permission.VIEW_PAGE1"
android:description="@string/perm1_desc"
android:label="@string/perm1_label"
android:permissionGroup="com.xiaofei.permission.GROUP"
android:protectionLevel="dangerous"/>
<permission
android:name="com.xiaofei.permission.VIEW_PAGE2"
android:description="@string/perm2_desc"
android:label="@string/perm2_label"
android:permissionGroup="com.xiaofei.permission.GROUP"
android:protectionLevel="dangerous"/>
android:name为权限的名字,必须保证系统内无重复,一般以当前App包名为前缀。当我们在申请权限时需要用到,比如:
ActivityCompat.requestPermissions(MainActivity.this, new String[]{"com.xiaofei.permission.VIEW_PAGE1"}, 0);
android:description 为权限描述,当弹出权限提示框时会显示该描述。如下图:
android:label 为权限标签,在设置->应用->权限中会显示。如下图:
android:permissionGroup 为权限分组,我们可以将权限进行逻辑分组,在设置->应用->权限中会显示。如下图:
android:protectionLevel 为权限的安全级别,不同的级别对应着不同的权限获取行为,这里按从低到高的顺序有以下四种:
- normal:普通权限,优先级最低,需要在应用安装时提示用户授权,否则无法安装,而一旦允许,后面APP在运行过程中将一直拥有该权限。
- dangerous:危险权限,比如通讯录,短信等,该权限在6.0以下,表现行为与normal无异,但在6.0及以上需要在APP运行过程中动态申请。
- signature:获取该权限,必须保证请求方和接收方使用同一个签名文件,在安装时默认授权,不会提示用户。该权限一般用于系统内置应用,或者同一个公司的多个APP中。
- signatureOrSystem:相比signature多了一个条件,当请求方为系统应用时默认拥有该权限,一般用于系统内置应用。
接下来说说如何使用权限?
首先,我们必须在AndroidManifest中使用<uses-permission>,来声明App在使用中需要用到的权限。示例代码如下:
<uses-permission android:name="com.xiaofei.permission.VIEW_PAGE1"/>
<uses-permission android:name="com.xiaofei.permission.VIEW_PAGE2"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
其次,由于android在6.0系统之前和之后对权限的处理行为不一样,因此我们需要根据当前系统版本做区别处理。好在support v4包中已经提供了ActivityCompat类以方便我们对权限的处理,这里给出使用ActivityCompat获取权限的例子:
if (ActivityCompat.checkSelfPermission(MainActivity.this, "com.xiaofei.permission.VIEW_PAGE1") == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{"com.xiaofei.permission.VIEW_PAGE1"}, 0);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// Todo
}
前面我们提到,Android的权限机制可以让应用数据的访问粒度变得更细,那么这里的粒度细化到什么程度呢?那就是可以通过Permission控制四大组件的访问。比方说:
<activity
android:name=".MainActivity"
android:permission="com.xiaofei.permission.VIEW_PAGE1">
</activity>
这里我们在访问MainActivity的时候,就需要提前获取com.xiaofei.permission.VIEW_PAGE1权限,否则系统会禁止访问该页面。当然如果是App内部组件之间的访问,默认已经拥有了该权限,不需要显式获取。
通过权限机制我们就可以很容易的控制第三方App对自己App内部数据的访问,从而可以安全的共享数据。另外这里再提一个属性android:exported,它也是用来控制组件是否可以被第三方App使用的,默认该属性为false,如果设置为true,则第三方App可以通过intent的方式访问该组件。示例代码如下:
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>