Android 11 (API 30) ContentProvider开发及碰到的问题 (Unknown URL content)

参考:

《疯狂Android讲义》第四版,第九章

问题解决,参考:

https://stackoverflow.com/questions/63563995/failed-to-find-content-provider-in-api-30

https://www.sohu.com/a/448764139_611601

测试包含两个应用程序:FirstContentProviderFirstContentResolver,下面分别对两者进行说明

注意:本次开发在Android 11 (API 30)下完成

build.gradle关于版本的内容:

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.0"

    defaultConfig {
        applicationId "com.example.contentprovidertest"
        minSdkVersion 16
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

FirstContentProvider

新建应用程序项目后(创建时可以选择Empty Activity),修改AndroidManifest.xml,增加如下内容:

        <provider
            android:authorities="com.example.provider"
            android:name=".FirstProvider"
            android:exported="true" />
image-20210730195012670.png

android:authorities="com.example.provider"字段可以自定义

android:name=".FirstProvider"中的FirstProvider就是需要创建的类,在MainActivity所在的包下新建该类:

package com.example.firstcontentprovider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class FirstProvider extends ContentProvider {
  @Override
  public boolean onCreate() {
    Log.d("--oncreate--", "--onCreate--方法被调用");
    return false;
  }

  @Nullable
  @Override
  public Cursor query(
      @NonNull Uri uri,
      @Nullable String[] strings,
      @Nullable String s,
      @Nullable String[] strings1,
      @Nullable String s1) {
    Log.d("--query--", "--query--方法被调用" + "," + " where参数为:" + s);
    return null;
  }

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

  @Nullable
  @Override
  public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
    Log.d("--insert--", "--insert--方法被调用" + "," + " value参数为:" + contentValues);
    return null;
  }

  @Override
  public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
    Log.d("--delete--", "--delete--方法被调用" + "," + " where参数为:" + s);
    return 0;
  }

  @Override
  public int update(
      @NonNull Uri uri,
      @Nullable ContentValues contentValues,
      @Nullable String s,
      @Nullable String[] strings) {
    Log.d(
        "--update--",
        "--update--方法被调用" + "," + " where参数为:" + s + ", " + "value参数为: " + contentValues);
    return 0;
  }
}

修改activity_main.xml,只是修改TextView的文本内容(不影响程序功能,这一步可做可不做):

image-20210730194644472.png

FirstContentResolver

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    tools:context=".MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="query"
        android:id="@+id/btn_query" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="insert"
        android:id="@+id/btn_insert" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="update"
        android:id="@+id/btn_update" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="delete"
        android:id="@+id/btn_delete" />

</LinearLayout>

MainActivity.java

package com.example.firstcontentresolver;

import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

  private Uri uri = Uri.parse("content://com.example.provider");
  private Button mBtnQuery, mBtnInsert, mBtnUpdate, mBtnDelete;

  @Override
  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mBtnQuery = findViewById(R.id.btn_query);
    mBtnInsert = findViewById(R.id.btn_insert);
    mBtnUpdate = findViewById(R.id.btn_update);
    mBtnDelete = findViewById(R.id.btn_delete);

    mBtnQuery.setOnClickListener(
        view -> {
          Cursor cursor = getContentResolver().query(uri, null, "query where", null, null);
          Toast.makeText(this, "远程ContentProvider返回的Cursor为:" + cursor, Toast.LENGTH_SHORT).show();
        });

    mBtnInsert.setOnClickListener(
        view -> {
          ContentValues values = new ContentValues();
          values.put("name", "android_insert");
          Uri newUri = getContentResolver().insert(uri, values);
          Toast.makeText(this, "远程ContentProvider新插入记录的Uri为:" + newUri, Toast.LENGTH_SHORT).show();
        });

    mBtnUpdate.setOnClickListener(
        view -> {
          ContentValues values = new ContentValues();
          values.put("name", "android_update");
          int count = getContentResolver().update(uri, values, "update_where", null);
          Toast.makeText(this, "远程ContentProvider更新记录数为:" + count, Toast.LENGTH_SHORT).show();
        });

    mBtnDelete.setOnClickListener(
        view -> {
          int count = getContentResolver().delete(uri, "delete_where", null);
          Toast.makeText(this, "远程ContentProvider删除记录数为:" + count, Toast.LENGTH_SHORT).show();
        });
  }
}

碰到的问题:Unknown URL content

如果编写完上述两个源文件,就运行两个程序,那么FristContentResolvert在点击主界面的按钮后,程序会崩溃,查看日志得到如下错误:

image-20210730195430019.png

经过一番搜索,这是在 Android 11 下才会出现的问题,简单来说,就是出于安全考虑,Android 11 要求应用事先说明需要访问的其他软件包

可以使用:adb shell dumpsys package queries查看哪些软件包是可以访问的,使用grep可以过滤出我们想要看的软件包,例如:

image-20210730200147582.png

解决的方法:使用<queries>标签说明需要访问的其他软件包

AndroidManifest.xml中添加<queries>

    <queries>
        <package android:name="com.example.firstcontentprovider" />
    </queries>
image-20210730200414162.png

运行程序进行测试

启动两个程序,打开FirstContentProviderLogCat

image-20210730200750156.png

按图中箭头标注的条件进行过滤

依次点击FirstContentResolver的四个按钮,可以看到:

image-20210730200955269.png

至此,测试完成

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容