无法从其他应用程序访问 customProvider。它说它缺少它已经拥有的权限

Can't access a customProvider from another app. It says it's missing permissions it already has

我正在尝试制作一个应用程序,该应用程序可以从另一个具有自定义内容提供程序的应用程序访问 SQLite table。我收到以下错误:

java.lang.SecurityException: Permission Denial: reading com.example.carlos.gymlog.MiContentProvider uri content://mi.uri.porquesi/sesiones from pid=2375, uid=10064 requires android.permission.permRead, or grantUriPermission()

但是,我的 "sender" 应用程序(带有数据库的应用程序)已经具有所需的权限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.carlos.gymlog" >

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/MiTema" >
        <activity
            android:name=".Principal"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider android:name="MiContentProvider"
            android:authorities="mi.uri.porquesi"
            android:readPermission="android.permission.permRead"
            android:exported="true"
            android:grantUriPermissions="true"> </provider>

    </application>

</manifest>

这是导致 "receiver" 应用程序(试图访问另一个应用程序)中的错误的代码:

ArrayList<Sesion> sacarDatos(Context c){

        Uri cUri = Uri.parse("content://mi.uri.porquesi/sesiones");
        ContentProviderClient miCP = c.getContentResolver().acquireContentProviderClient(cUri);

        ArrayList<Sesion> sesiones = null;
        try {
            Cursor cur  = miCP.query(cUri, null, null, null, null);
            sesiones = new ArrayList<Sesion>();
            cur.moveToFirst();
            Sesion sesion = null;
            do {
                sesion = new Sesion(cur.getInt(0),cur.getInt(1),cur.getInt(2),cur.getInt(3));
                sesiones.add(sesion);
            } while (cur.moveToNext());

        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return sesiones;
    }

最后,这是我的自定义内容提供商:

public class MiContentProvider extends android.content.ContentProvider {

    private static final String uri = "content://mi.uri.porquesi";

    public static final Uri CONTENT_URI = Uri.parse(uri);


    @Override
    public boolean onCreate() {

        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

        BaseDatosHelper miBD = new BaseDatosHelper(getContext(), "SESIONES", null, 1);
        SQLiteDatabase db = miBD.getWritableDatabase();
        SQLiteQueryBuilder qb  = new SQLiteQueryBuilder();
        qb.setTables("SESIONES");

        Cursor cur = qb.query(db,projection,selection,selectionArgs,"","",sortOrder);
        cur.setNotificationUri(getContext().getContentResolver(),uri);
        return cur;
    }

(其余方法如 insert() 未实现,它们只是 return null 或其他任何内容,我只想 select 数据不插入它)。

编辑:

我的应用 A 有

 <provider android:name="MiContentProvider"
        android:authorities="mi.uri.porquesi"
        android:exported="true"
        android:permission="mi.permision"
        android:grantUriPermissions="true"> </provider>
    <permission
        android:name="mi.permision"
        />

(只是一个随机的临时名称)

在应用程序 B 中,我添加了

<uses-permission android:name="mi.permision"/>

但是,现在我得到:

java.lang.SecurityException: Permission Denial: opening provider com.example.carlos.gymlog.MiContentProvider from ProcessRecord{335efe6e 3116:com.example.carlos.sample/u0a67} (pid=3116, uid=10067) requires mi.permision or mi.permision

所以它识别出我需要我的自定义权限,但它没有识别出我的应用程序 B 正在使用它。为什么??

假设我们有应用程序 A 和应用程序 B。应用程序 A 有 ContentProvider;应用程序 B 想要使用来自应用程序 A 的 ContentProvider。并且,您想要使用自定义权限保护 ContentProvider

应用程序 A 需要在其清单中使用 a <permission> element,并在 android:name 属性中使用您的自定义权限名称。 不要 在该自定义权限名称上使用 android.permission 前缀,因为您不是 Android 开源项目的开发人员。为您的应用使用命名空间,例如 com.kace91.permission.AND_REMEMBER_THAT_CUSTOM_PERMISSIONS_HAVE_SECURITY_ISSUES.

App A 然后需要 the <provider> manifest element 上的一个属性,该属性的值与 <permission> 元素的 android:name 属性的名称相匹配。要么使用android:permission防御所有操作,要么拥有两个自定义权限并使用android:readPermissionandroid:writePermission不要 简单地使用android:readPermission,因为这意味着任何应用程序都可以在未经许可的情况下修改ContentProvider,而且这不太可能是用户想要的。

应用程序 A 还需要 <provider> 元素上的 android:exported="true" 属性,表示第三方应用程序可以启动与该 ContentProvider 的通信。

App B 可以拥有 a <uses-permission> manifest element,其 android:name 属性值与 App A 的 <permission> 元素的 android:name 属性相匹配。如果您使用了两个权限,对于读写,App B 需要两个 <uses-permission> 元素。

那么,如果App A先于App B安装,并且用户同意授予App B持有自定义权限,那么App B就可以对App A的ContentProvider执行指定的操作。

而且,正如我在评论中指出的那样,there are security issues with custom permissions