2013-01-16 12 views
6

Ho creato un fornitore di contenuti personalizzato, a cui si accederà da qualche altra applicazione. Ho incluso il permesso TAG nel file del fornitore AndroidManifest.xml e nella seconda applicazione ho incluso il tag uses-permissions, ma non ci sono riuscito. Logcat mi mostra:Rifiuto dell'autorizzazione: fornitore di apertura

java.lang.SecurityException: Permission Denial: opening provider com.company.contentprovider.AplicacaoContentProvider requires READ_DATABASE or WRITE_DATABASE. 

Ho cercato domande simili, ma sembra che tutto sia corretto. Qualche idea ? Grazie !!!

Ecco il mio provider di file AndroidManifest.xml:

<?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> 

E questo è il mio secondo file dell'applicazione AndroidManifest.xml:

<?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> 

risposta

14

ma sembra che tutto sia corretto

Non esattamente.

<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> 

In primo luogo, in realtà si dovrebbe davvero mettere uno spazio dei nomi su questi nomi di autorizzazioni. Rendili com.company.contentprovider.READ_DATABASE e 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" 
    /> 

In secondo luogo, i tuoi android:readPermission e android:writePermission valori bisogno di usare il valore android:name da <permission>, non android:label. android:label è solo un nome visualizzato. Così, il pezzo di codice sopra dovrebbe essere:

<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" 
    /> 

(anche se, i punti bonus per mettere esplicitamente android:exported="true", che è una buona idea)

<uses-permission android:name="android.permissions.READ_DATABASE"/> 
<uses-permission android:name="android.permissioms.WRITE_DATABASE"/> 

In terzo luogo, l'altro manifesto non utilizzare il vecchio android:name, né la mia proposta suggerita android:name, né android:label, ma qualcos'altro interamente, in cui hai scelto di dire che questi sono nello spazio dei nomi android.permission, e non lo sono. Questo dovrebbe essere:

<uses-permission android:name="com.company.contentprovider.READ_DATABASE"/> 
<uses-permission android:name="com.company.contentprovider.WRITE_DATABASE"/> 

(anche se è possibile che com.company.contentprovider.WRITE_DATABASE sarà sufficiente - non so se android:writePermission implicherà automaticamente android:readPermission o no)

fare quei cambiamenti, e penso che sarà avere migliore fortuna

+0

Grazie! Appena riuscirò a lavorare domani, farò queste modifiche e ti farò sapere i risultati! –

+0

Ha funzionato, proprio come hai detto tu, ma c'è un altro dubbio. Ho, diciamo, altre 20 app che accederanno al mio fornitore di contenuti. Voglio ciascuna delle mie app per verificare se il content provider esiste. Se lo fa, quindi usa solo il permesso per registrare i dati. Altrimenti, registrare il provider e quindi registrare i dati. quindi, ho pensato di includere sia i permessi che i permessi di utilizzo-tag nel file AndroidManifest.xml di ogni app. Funzionerà? youtube downloader

+0

@MauricioAlencar: "Voglio che ogni una delle mie applicazioni per verificare se esiste il fornitore di contenuti Se lo fa, poi basta. usa il permesso per registrare i dati, altrimenti registra il provider e quindi registra i dati un." - Questo è un piano estremamente cattivo. Si prega di rendere tutte le 20 applicazioni completamente indipendenti l'una dall'altra. Così com'è, il tuo piano dice che se l'utente dovesse disinstallare 1 dei 20 - e quello 1 è stato il 1 che ha deciso di essere il "ContentProvider" - perdono i loro dati per tutte e 20 le app. – CommonsWare

13

La risposta sopra è stata un po 'confusa per me. Ma l'ho capito ora. Voglio pubblicare anche la mia soluzione. Forse per qualcuno è meglio capire.

La prima app A è l'app con il database SQLite e il "provider di contenuti personalizzato". L'App B utilizza con un ContentResolver il databse dell'App A.

Questo è l'AndroidManifest.xml-File da 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 e questo è l'AndroidManifest.xml-File da App B. Importante è la parte con "usa-autorizzazione":

<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> 

E Codice della ContentProvider per App a si presenta così:

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; 
} 
} 

E il Codice in materia di ContentResolver da 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(); 
} 
} 

Spero che questo possa aiutare qualcuno a capire meglio.

+0

Molto più chiaro! –

+0

Molto utile grazie! – rufism

-2
public static final String AUTHORITY = "de.test.TestContentProvider"; 
//...... 

C'è una domanda se debba essere

android:authorities="de.test.ContentProvider" 
<---