I've created a custom content provider, which will be accessed by a few more applications. I've included the permission TAG in my provider AndroidManifest.xml file, and in the second application, I included the uses-permissions tag, but no success. Logcat shows me:
java.lang.SecurityException: Permission Denial: opening provider com.company.contentprovider.AplicacaoContentProvider requires READ_DATABASE or WRITE_DATABASE.
I've search on similar questions, but it seems like everything is correct. Any ideas ? Thanks !!!
Here is my provider AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.company.contentprovider"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<permission android:name="READ_DATABASE" android:label="@string/app_read" android:protectionLevel="normal"></permission>
<permission android:name="WRITE_DATABASE" android:label="@string/app_write" android:protectionLevel="normal"></permission>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".CompanyProvider"
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="AplicacaoContentProvider"
android:authorities="com.company.contentprovider"
android:exported="true"
android:readPermission="@string/app_read"
android:writePermission="@string/app_write"
/>
</application>
And this is my second application AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testeprovider"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permissions.READ_DATABASE"/>
<uses-permission android:name="android.permissioms.WRITE_DATABASE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.testeprovider.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
The answer above was a litle confusing for me. But I got it now. I want to post my solution as well. Maybe for someone it's more better to understand.
First App A is the App that has the SQLite-Database and the "Custom Content Provider". App B uses with a ContentResolver the databse from App A.
This is the AndroidManifest.xml-File from App A:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.test"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<permission android:name="de.test.READ_DATABASE" android:protectionLevel="normal" />
<permission android:name="de.test.WRITE_DATABASE" android:protectionLevel="normal" />
<application
android:debuggable="true"
... >
...
...
<provider
android:name="de.test.TestContentProvider"
android:authorities="de.test.ContentProvider"
android:exported="true"
android:readPermission="de.test.READ_DATABASE"
android:writePermission="de.test.WRITE_DATABASE" />
...
...
</application>
Ok and this is the AndroidManifest.xml-File from App B. Important is the part with "uses-permission":
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.test.testercontentprovider"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="17" />
<uses-permission android:name="de.test.READ_DATABASE" />
<uses-permission android:name="de.test.WRITE_DATABASE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="de.test.testercontentprovider.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
And the Code of the ContentProvider for App A looks like this:
public class TestContentProvider extends ContentProvider {
public static final String AUTHORITY = "de.test.TestContentProvider";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/" + "nameoftable");
@Override
public boolean onCreate() {
...
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
return null;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}
And the Code for the ContentResolver from App B:
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
public static final String AUTHORITY = "de.test.TestContentProvider";
public static final String TABLE_NAME = "nameoftable";
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ContentResolver cr = getContentResolver();
// show entries of db
listEntries(cr);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void listEntries(ContentResolver cr) {
Uri uri = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
Cursor c = cr.query(uri, null, null, null, null);
if (c == null) {
Log.d(TAG, "Cursor c == null.");
return;
}
while (c.moveToNext()) {
String column1 = c.getString(0);
String column2 = c.getString(1);
String column3 = c.getString(2);
Log.d(TAG, "column1=" + column1 + " column2=" + column2 + " column3=" + column3);
}
c.close();
}
}
I hope this can help someone to understand it better.
but it seems like everything is correct
Not exactly.
<permission android:name="READ_DATABASE" android:label="@string/app_read" android:protectionLevel="normal"></permission>
<permission android:name="WRITE_DATABASE" android:label="@string/app_write" android:protectionLevel="normal"></permission>
First, you really really really really really really should put a namespace on those permission names. Make them com.company.contentprovider.READ_DATABASE
and com.company.contentprovider.WRITE_DATABASE
.
<provider android:name="AplicacaoContentProvider"
android:authorities="com.company.contentprovider"
android:exported="true"
android:readPermission="@string/app_read"
android:writePermission="@string/app_write"
/>
Second, your android:readPermission
and android:writePermission
values need to use the android:name
value from <permission>
, not android:label
. android:label
is a display name only. So, the above snippet should be:
<provider android:name="AplicacaoContentProvider"
android:authorities="com.company.contentprovider"
android:exported="true"
android:readPermission="com.company.contentprovider.READ_DATABASE"
android:writePermission="com.company.contentprovider.WRITE_DATABASE"
/>
(though, bonus points for explicitly putting android:exported="true"
, which is a good idea)
<uses-permission android:name="android.permissions.READ_DATABASE"/>
<uses-permission android:name="android.permissioms.WRITE_DATABASE"/>
Third, your other manifest does not use your old android:name
, nor my suggested revised android:name
, nor android:label
, but something else entirely, where you elected to say that these are in the android.permission
namespace, and they are not. This should be:
<uses-permission android:name="com.company.contentprovider.READ_DATABASE"/>
<uses-permission android:name="com.company.contentprovider.WRITE_DATABASE"/>
(though it is possible that com.company.contentprovider.WRITE_DATABASE
will be sufficient -- I don't know if android:writePermission
will automatically imply android:readPermission
or not)
Make those changes, and I think you will have better luck.
I was facing the same problem, then I remember I forgot to
add export tag for provider in the Manifest
<provider
android:name=".UsersProvider"
android:authorities="com.xyz.demoapplication"
android:exported="true">
</provider>
To access in another app you need to export true this allows other application to access Content Provider from this host application
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With