SecurityException: Не удалось найти нулевой провайдер для пользователя 0; на ActiveAndroid на Android 8.0

У меня есть приложение, использующее ActiveAndroid, и оно работает нормально. Однако; теперь, когда я пытаюсь сохранить модель в базе данных, я получаю SecurityException.

Стек:

Error saving model java.lang.SecurityException: Failed to find provider null for user 0; expected to find a valid ContentProvider for this authority 
at android.os.Parcel.readException(Parcel.java:1942) 
at android.os.Parcel.readException(Parcel.java:1888) 
at android.content.IContentService$Stub$Proxy.notifyChange(IContentService.java:801) 
at android.content.ContentResolver.notifyChange(ContentResolver.java:2046) 
at android.content.ContentResolver.notifyChange(ContentResolver.java:1997) 
at android.content.ContentResolver.notifyChange(ContentResolver.java:1967) 
at com.activeandroid.Model.save(Model.java:162)
[.... local stack removed]

Кто-нибудь еще испытал это? Нужно ли указывать Content Provider в AndroidManifest.xml?

Извините, но у меня пока нет отдельного примера. Я буду работать над тем, чтобы что-то собрать.

Заранее спасибо

Ответ 1

Как указано в @GeigerGeek, изменения безопасности в Android 26 и выше требуют, чтобы вы указали поставщика контента в своем манифесте.

Для ActiveAndroid вы можете добавить ниже в свой манифест и изменить имя вашего пакета.

<provider
  android:name="com.activeandroid.content.ContentProvider"
  android:authorities="<your.package.name>"
  android:enabled="true"
  android:exported="false">
</provider>

Если вы используете ароматизаторы в процессе сборки, вы можете использовать ниже:

android:authorities="${applicationId}"

Использование ${applicationId} поможет в структуре проекта, основанной на ароматах, где пакет приложения может быть различным для каждого варианта.

Для большего количества решений или информации это было взято отсюда.

Ответ 2

Для исправления установите ваш

compileSdkVersion 25
targetSDKVersion 25

и вы будете игнорировать особенности Android. Это спасет ваш день!

важно для оперативного исправления:

Но это решение будет недействительным.

Август 2018 года. Требуются новые приложения для определения уровня API 26 (Android 8.0) или выше. Ноябрь 2018 г.: обновление существующих приложений требуется для целевого уровня API 26 или выше. 2019 года: каждый год будет увеличиваться требование targetSdkVersion. В течение одного года после каждого выпуска Android-десерта новые приложения и обновления приложений должны будут ориентироваться на соответствующий уровень API или выше.

Другие способы, вы можете исправить с ActiveAndroid, но это устарело. Вы можете попробовать или вы можете попробовать ReActiveAndroid

с ActiveAndroid, посетите https://github.com/pardom/ActiveAndroid/issues/536#issuecomment-344470558

Когда в проекте определены классы моделей в исходном коде java с помощью метода конфигурации addModelClasses, приложение все равно будет аварийно завершать работу, поскольку классы моделей не будут загружаться через эту конфигурацию. В этом случае вам нужно переместить определение модели в файл AndroidManifest.xml.

AndroidManifest.xml

<provider
    android:name=".content.DatabaseContentProvider"
    android:authorities="your package name"
    android:exported="false" />

DatabaseContentProvider.java

...
import com.activeandroid.content.ContentProvider;
...

public class DatabaseContentProvider extends ContentProvider {

@Override
protected Configuration getConfiguration() {
    Configuration.Builder builder = new Configuration.Builder(getContext());
    builder.addModelClass(SomeModel.class);
    builder.addModelClass(OtherModel.class);
    return builder.create();
 }}

Если вы что-то делаете с FileProvider, не забудьте изменить имя пакета

 Uri contentUri = FileProvider.getUriForFile(mContext,
            "your package name", new File(mImageFilePath));

Ответ 3

Android O, по-видимому, требует использования специального ContentProvider для использования базы данных, даже если вы не собираетесь делиться своими данными с другими приложениями.

https://developer.android.com/about/versions/oreo/android-8.0-changes.html

Пользовательский класс должен быть определен в теге поставщика в теге приложения в AndroidManifest.xml. Если применимо, установите exported = false, чтобы защитить ваши данные от внешнего использования.

<provider android:name=".MyContentProvider"
    android:exported="false"
    android:authorities="com.your_app_path.MyContentProvider"/>

Для меня проблема возникла из-за того, что я вызывал notifyChange из contentResolver. Я не нуждался в этом, поэтому мне удалось избежать реализации ContentProvider.

Ответ 4

Возможно, из-за вашего uri null, когда вы используете notifyChange, https://developer.android.com/about/versions/oreo/android-8.0-changes.html#ccn

Android O добавит чек для провайдера:

311 .checkContentProviderAccess(uri.getAuthority(), userHandle);
312 if (msg != null) {
313 if (targetSdkVersion >= Build.VERSION_CODES.O) {
314 throw new **SecurityException**(msg);
315 } else {

Ответ 5

Я был перенаправлен на этот вопрос, когда искал ту же проблему. Однако этот конкретный вопрос относится к конкретной реализации библиотеки. Чтобы преодолеть эту ошибку из-за изменений, недавно представленных в Android O, мы должны предоставить определенные полномочия ContentProvider, добавив следующее в файл AndroidManifest.xml под тегом application.

<provider
    android:name=".DatabaseContentProvider"
    android:authorities="com.yourpackage.name"
    android:exported="false" /> 

И вам нужен класс ContentProvider подобный следующему.

public class DatabaseContentProvider extends ContentProvider {

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        return null;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri,
                        @Nullable String[] projection,
                        @Nullable String selection,
                        @Nullable String[] selectionArgs,
                        @Nullable String sortOrder) {
        return null;
    }

    @Override
    public boolean onCreate() {
        return true;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values,
                      @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }
}

Ответ 6

Есть два простых шага.

  1. Вам необходимо указать провайдера в вашем AndroidManifest.xml под тегом application как AndroidManifest.xml ниже.

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/AppTheme">
        <activity
            android:name=".activity.MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
    
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    
        <provider
            android:name=".util.DatabaseContentProvider"
            android:authorities="com.your.application.package.name"
            android:exported="false" />
    </application>
    

  2. И вам нужно иметь класс java, который определяет провайдера, указанного в манифесте. В моем случае у меня был файл провайдера в пакете util.

    package com.your.application.package.name.util;
    
    import android.content.ContentProvider;
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.net.Uri;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    
    public class DatabaseContentProvider extends ContentProvider {
    
        @Nullable
        @Override
        public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
            return null;
        }
    
        @Nullable
        @Override
        public Cursor query(@NonNull Uri uri,
                        @Nullable String[] projection,
                        @Nullable String selection,
                        @Nullable String[] selectionArgs,
                        @Nullable String sortOrder) {
            return null;
        }
    
        @Override
        public boolean onCreate() {
            return true;
        }
    
        @Override
        public int update(@NonNull Uri uri, @Nullable ContentValues values,
                      @Nullable String selection, @Nullable String[] selectionArgs) {
            return 0;
        }
    
        @Override
        public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
            return 0;
        }
    
        @Nullable
        @Override
        public String getType(@NonNull Uri uri) {
            return null;
        }
    }
    

Это. Тебе хорошо идти.

Вот полный рабочий код для операции чтения/записи/обновления SQLite в Github. Надеюсь, это поможет!

Ответ 7

если ваш пакет отличается от applicationId, вам следует использовать applicationId

<provider
            android:name="com.activeandroid.content.ContentProvider"
            android:authorities="${applicationId}"
            android:exported="false" />

Ответ 8

У меня была такая же проблема с активным Android на Android O. Оказывается, что один из методов в моем пользовательском ContentProvider возвратил Uri, иногда он возвращает null, и это вызывало проблему. Поэтому я добавил аннотацию @Nullable к методу, как показано ниже, в котором исправлена ​​проблема.

@Nullable
@Override
public Uri insert(Uri uri, ContentValues contentValues) {..}

Ответ 9

Измените манифест и добавьте тег провайдера node в боковое приложение node.

<application ....>
    <provider android:name="com.activeandroid.content.ContentProvider"
        android:exported="false"
        android:enabled="true"
        android:authorities="here will be package name of your app"/>
.....
</application>

Я использую это, и он исправил мою ошибку. Нажмите здесь для демонстрации.