安全异常:在Android 8.0上的ActiveAndroid中未能找到用户0的提供程序null。

40

我有一个使用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]

还有其他人经历过这种情况吗?我们需要在 AndroidManifest.xml 文件中指定 Content Provider 吗?

很抱歉,我目前没有相关的独立示例。我会努力整理一些资料。

提前致谢。


2
“Failed to find provider null” 表示 Uri 格式不正确,其权限字符串可能缺失或字面上为 "null" - CommonsWare
我遇到了相同的崩溃,但堆栈跟踪中提供程序不是“null”。不知道为什么会发生这种情况,但它只在Android 8上发生... - Otziii
2
这个问题让我疯了。针对SDK 25的定位工作正常,针对26+的定位会崩溃并出现这个错误。我已经正确设置了提供程序中的权限。仍然会崩溃。我不知道这是怎么回事。当然,在调用时我的Uri不为空!你有什么新的消息吗? - Zordid
@Velval的下面的回答可能是正确的:https://dev59.com/MFcO5IYBdhLWcg3wXgfh#47664761 - ThomasW
10个回答

54

正如@GeigerGeek所指出的,在Android 26及以上版本中的安全性更改要求您在清单文件中指定内容提供程序。

对于ActiveAndroid,您可以在清单文件中添加以下内容并更改包名称。

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

如果在您的构建过程中使用了“flavours”,则可以改为使用以下内容:

android:authorities="${applicationId}"

使用${applicationId}将有助于基于口味的项目结构,其中每个口味的应用程序包可能不同。

有关更多解决方案或信息,请参见此处


请注意:权限可能是其他字符串,而不仅仅是您的包名。 - Kirill Karmazin

6

对于热修复,请设置您的

compileSdkVersion 25
targetSDKVersion 25

你需要忽略Android O的功能,这将节省你的时间!

对于热修复很重要:

但是这种解决方案将会失效。

2018年8月:新应用程序需要针对API级别26(Android 8.0)或更高版本进行定位。 2018年11月:现有应用程序的更新需要针对API级别26或更高版本进行定位。 2019年及以后:每年targetSdkVersion的要求都会提高。在每个Android甜点发布后的一年内,新应用程序和应用程序更新将需要定位到相应的API级别或更高级别。

另外,你可以使用ActiveAndroid进行修复,但它现在已被弃用。你可以尝试或者你可以尝试ReActiveAndroid

使用ActiveAndroid,请访问https://github.com/pardom/ActiveAndroid/issues/536#issuecomment-344470558

如果项目通过addModelClasses配置方法在java源代码中定义了模型类,但应用程序仍会崩溃,因为模型类不会通过该配置加载。在这种情况下,您需要将模型定义移动到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));

我不认为ReActiveAndroid来自同一个团队。 "不幸的是,[ActiveAndroid]的作者停止了对其进行维护,所以我决定代替他继续维护这个库。" - nasch

3

据说Android O需要使用自定义ContentProvider来使用数据库,即使您不打算与其他应用程序共享数据。

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

您的自定义类必须在AndroidManifest.xml文件中的应用程序标签内的provider标签中定义。如果适用,请将exported设置为false以保护数据免受外部使用。

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

对我来说,问题出现在我从contentResolver中调用notifyChange。最终我发现并不需要这个功能,因此我避免了实现ContentProvider。

2
如果你的包名与应用程序ID不同,那么你应该使用应用程序ID。最初的回答中已经给出了这个提示。
<provider
            android:name="com.activeandroid.content.ContentProvider"
            android:authorities="${applicationId}"
            android:exported="false" />

0
当我在搜索同样的问题时,我被重定向到了这个问题。然而,这个具体的问题涉及到一个特定的库实现。为了克服由于Android O中新引入的更改而导致的错误,我们必须通过在AndroidManifest.xml文件的application标签下添加以下内容来为ContentProvider提供特定的权限。
<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;
    }
}

0

0
有两个简单的步骤。
  1. 您需要在AndroidManifest.xml文件中的application标签下指定提供程序,如下所示。

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

就是这样了。你已经准备好了。

这里是Github上SQLite读/写/更新操作的完整工作代码。希望能对你有所帮助!


-1

-1

编辑清单并在应用程序节点内添加此提供程序标签节点。

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

我使用了这个方法,成功解决了错误。点击此处查看演示


-1

我在Android O上使用Active Android时遇到了完全相同的问题。原来是我自定义的ContentProvider中的某个方法返回了Uri,有时会返回null,这就导致了问题。所以我在下面的方法中添加了@Nullable注释,解决了该问题。

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

This doesn't fix the problem. - Katerina A.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接