ContentProvider 的权限设置

3,319 阅读2分钟

一 自定义权限

ContentProvider端:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.anddle.lifetime">


//声明自定义权限
    <permission
        android:name="com.anddle.provideraccess"
        android:label="provider pomission"
        android:protectionLevel="normal" />

   <application

//设置权限
<provider
    android:name=".MyContentProvider"
    android:authorities="com.anddle.mycontentprovider"
    android:enabled="true"
    android:exported="true"
    android:permission="com.anddle.provideraccess" />
         
<application/>
</manifest>

ContentProvider 客户端

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.anddle.calculator">

//使用权限
    <uses-permission android:name="com.anddle.provideraccess"/>

    <application/>

</manifest>

访问权限

  对于ContentProvider暴露出来的数据,应该是存储在自己应用内存中的数据,对于一些存储在外部存储器上的数据,并不能限制访问权限,使用ContentProvider就没有意义了。对于ContentProvider而言,有很多权限控制,可以在AndroidManifest.xml文件中对节点的属性进行配置,一般使用如下一些属性设置:

  • android:grantUriPermssions:临时许可标志。

  • android:permission:Provider读写权限。

  • android:readPermission:Provider的读权限。

  • android:writePermission:Provider的写权限。

  • android:enabled:标记允许系统启动Provider。

  • android:exported:标记允许其他应用程序使用这个Provider。

  • android:multiProcess:标记允许系统启动Provider相同的进程中调用客户端。

  •   :Provider 指定内容的访问权限

path-permission

我们可以针对其中某个或某部分URI,单独进行权限设 置。除了android:pathPrefix,还可以有android:path和android:pathPatten,例如 android:pathPattern="/hello/.*"(注意,通配符*之前有个‘.’)。

如下:

在ProPermissionClient如果要读取content:content://com.robert.propermission.PrivProvider/hello /1则需要声明整个provider的权限com.robert.READ_CONTENTPROVIDER或者该路径的权限 READ_HELLO_CONTENTPROVIDER。

<provider android:name=".PrivProvider"
    android:authorities="com.robert.propermission.PrivProvider"
    android:readPermission="com.robert.READ_CONTENTPROVIDER"
    android:exported="true" >
    <path-permission android:pathPrefix="/hello" android:readPermission="READ_HELLO_CONTENTPROVIDER" />
</provider>

android:grantUriPermissions

android:grantUriPermissions,管理哪个范围的数据权限需要处理。这个属性其实不用显示的设置,因为如果设置了android:readPermission, android:writePermission ,android:permission中的任意一个android:grantUriPermissions就默认是true了;如果设置了grant-uri-permission,那么android:grantUriPermissions默认就是false;如果都设置了,那么android:grantUriPermissions也是false。

例如:

应用B具有读取应用A content provider的权限,它去调用另一个应用C的activity,但是C没有读 取content provider的权限,B可以将自己的权限通过intent传递给应用C,让其也具有访问content provider的权限。 

对于,相关的content provider为: 

<provider android:name=".PrivProvider" 
    android:authorities="com.robert.propermission.PrivProvider" 
    android:readPermission="com.robert.READ_CONTENTPROVIDER" 
    android:grantUriPermissions="true" 
    android:exported="true" />

 对于应用B,其具有com.robert.permission.READ_CONTENTPROVIDER的权限,而应用C不具备,应用B通过intent调用应用C的代码如下:

Intent intent = new Intent(); 
intent.setClassName("com.robert.example.propermissiongrant", "com.robert.example.propermissiongrant.MainActivity"); 
intent.setData(Uri.parse("content://com.robert.propermission.PrivProvider/world/1")); 
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //传递权限 
startActivity(intent); 

所调用的C的activity具备访问content provider的权限。 如果我们将provider的属性android:grantUriPermissions设置为false,则不允许通过接受传递的权限方式进行访问,即B所调用的C的activity不能读content provider,就会报错

<grant-uri-permission

有时候,我们只希望部分的URI允许grant权限访问,而不是开放整个provider,如下:

 <provider android:name=".PrivProvider" 
    android:authorities="com.robert.propermission.PrivProvider" 
    android:readPermission="com.robert.permission.READ_CONTENTPROVIDER" 
    android:exported="true" >
    <grant-uri-permission android:pathPrefix="/hello" /> 
</provider> 

我们将只允许前缀为hello的部分URI访问。一旦 我们设置了grant-uri-permission,则全局的android:grantUriPermissions属性将无效,无论设置true还 是flase,也都是只允许grant-uri-permission是声明的部分uri可以被grant权限访问。