我试图制作一个应用程序,通过自定义内容提供程序从另一个应用程序访问SQLite表。我收到以下错误:
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()
然而,我的"发件人" app(具有数据库的应用程序)已具有所需权限:
<?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>
这是导致&#34;接收器&#34;中错误的代码。应用程序(试图访问另一个的应用程序):
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()没有实现,它们只返回null或者它是什么,我只是想选择不插入的数据)。
编辑:
我的应用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正在使用它。为什么?
答案 0 :(得分:5)
假设我们有App A和App B. App 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上的属性,该属性的值与android:name
元素的<permission>
属性的名称相匹配。使用android:permission
来保护所有操作,或使用两个自定义权限并使用android:readPermission
和android:writePermission
。 不要只使用android:readPermission
,因为这意味着任何应用都可以在未经许可的情况下修改ContentProvider
,而且这不太可能是用户想要的。
应用A还需要android:exported="true"
元素上的<provider>
属性,表示第三方应用可以发起与ContentProvider
的通信。
然后,应用B可以拥有a <uses-permission>
manifest element,android:name
属性值与应用A中android:name
元素的<permission>
属性相匹配。如果您使用了两个权限,读取和写入,App B将需要两个<uses-permission>
元素。
然后,如果在App B之前安装App A,并且用户同意授予App B保留自定义权限的权限,则App B将能够在App A的ContentProvider
上执行指定的操作。
并且,如我的评论中所述,there are security issues with custom permissions。