2013-01-16 9 views
6

Stworzyłem niestandardowego dostawcę treści, do którego będzie mieć dostęp jeszcze kilka aplikacji. Załączam TAG uprawnień w pliku dostawcy usługi AndroidManifest.xml, aw drugiej aplikacji dodałem tagu use-permissions, ale bez powodzenia. Logcat pokazuje mi:Odmowa zezwolenia: operator otwierający

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

Szukałem podobnych pytań, ale wygląda na to, że wszystko jest w porządku. Jakieś pomysły ? Dzięki!

Oto mój dostawca plik 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> 

I to jest mój drugi plik AndroidManifest.xml zastosowanie:

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

Odpowiedz

14

ale wydaje się, że wszystko jest poprawne

Niezupełnie.

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

Po pierwsze, naprawdę, naprawdę, naprawdę, naprawdę powinno się umieścić przestrzeń nazw na tych nazwach uprawnień. Ustaw je jako com.company.contentprovider.READ_DATABASE i 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" 
    /> 

drugie, swoje wartości android:readPermission i android:writePermission trzeba użyć wartości android:name z <permission>, nie android:label. android:label to tylko nazwa wyświetlana. Więc, powyższy fragment powinien być:

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

(choć punkty za wyraźnie oddanie android:exported="true", co jest dobrym pomysłem)

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

trzecie, Twój inny oczywisty nie używać starego android:name, ani moje sugerowane zmienione android:name, ani android:label, ale coś zupełnie innego, gdzie zdecydowałeś się powiedzieć, że są one w przestrzeni nazw , a nie są. To powinno być:

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

(choć możliwe jest, że com.company.contentprovider.WRITE_DATABASE będzie wystarczająca - Nie wiem, czy android:writePermission automatycznie oznaczać android:readPermission lub nie)

wprowadzić te zmiany, i myślę, że będzie mieć więcej szczęścia.

+0

Dziękujemy! Jak tylko dojadę do pracy jutro, wprowadzę te modyfikacje i poinformuję o wynikach! –

+0

Zadziałało, tak jak powiedziałeś, ale jest jeszcze jedna wątpliwość. Mam, powiedzmy, 20 innych aplikacji, które uzyskają dostęp do mojego dostawcy treści. Chcę, aby każda z moich aplikacji sprawdzała, czy dostawca zawartości istnieje. Jeśli tak, to po prostu używa uprawnień do rejestrowania danych. W przeciwnym razie zarejestruj dostawcę, a następnie zapisz dane. więc pomyślałem, że w pliku AndroidManifest.xml każdej aplikacji można umieścić zarówno tagi pozwolenia, jak i pozwolenia na użycie. Czy to zadziała? youtube downloader

+0

@MauricioAlencar: „Chcę każdemu z moich aplikacji, aby sprawdzić, czy dostawca treści istnieje, jeżeli tak, to po prostu. używa uprawnień do rejestrowania danych, w przeciwnym razie zarejestruj dostawcę, a następnie zapisz dane za." - to bardzo zły plan. Wszystkie 20 aplikacji należy całkowicie uniezależnić od siebie. W obecnej wersji Twój plan mówi, że jeśli użytkownik odinstaluje 1 z 20 - i 1 stanie się tym, który zdecydował się być "Dostawcą Treści" - stracą dane dla wszystkich 20 aplikacji. – CommonsWare

13

Powyższa odpowiedź była trochę myląca dla mnie. Ale mam to teraz. Chcę również opublikować moje rozwiązanie. Może dla kogoś lepiej jest zrozumieć.

Pierwsza aplikacja A to aplikacja z bazą danych SQLite i "dostawcą niestandardowych treści". Aplikacja B używa z ContentResolver databse z App A.

To jest Android Mechanizm.pliku XML z 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 i to jest AndroidManifest.xml Plik z App B. Ważna jest część z "używa-gość":

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

A Kod ContentProvider dla App A wygląda to tak:

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

a kod do ContentResolver z 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(); 
} 
} 

Mam nadzieję, że może to komuś pomóc zrozumieć to lepiej.

+0

O wiele bardziej przejrzyste! –

+0

Bardzo pomocne dziękuję! – rufism

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

Powstaje pytanie, czy powinien on być

android:authorities="de.test.ContentProvider" 
<--- 
Powiązane problemy