Search code examples
androidipcprovider

Android 11+ Content provider not working when the app is not running?


I have created two apps, let's call them app A and app B. I want app A to provide data to app B via a custom provider. I wrote the code and it works fine under Android 11. However, when running on a real device with Android 11 +, if app A is not running, it will give a "Failed to find provider info for xxx" error. If you open app A, it works fine.

My question is, does the provider after Android 11 require the app is running? Is there a way to make files in your sandbox available to other apps without running the app?

I've searched all over the Internet to find the answer. I did add the <queries> Node, try to add various permissions, it still won't work without app A enabled (not required under Android 11). Who can help me?

Supplemnet:

My compileSdk version is 34, targetSdk version is 33, and gradle plugin version is 8.1.2

This is AndroidManifest.xml of app A:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <queries>
        <package android:name="com.test.projectb" />
    </queries>
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/Theme.ProjectA"
        tools:targetApi="31">
        <provider android:name=".CustomDataProvider"
            android:authorities="com.test.projecta.provider"
            android:exported="true"
            android:enabled="true"
            android:grantUriPermissions="true"
            >

        </provider>

        <activity
            android:name=".MainActivity"
            android:exported="true"

            android:label="@string/app_name"
            android:theme="@style/Theme.ProjectA">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>


</manifest>

App A CustomDataProvider code:

public class CustomDataProvider extends ContentProvider {

   @Override
   public boolean onCreate() {
      Log.i("projectA","onCreate");
      return true;
   }

   @Override
   public Cursor query(Uri uri, String[] projection, String selection,
                       String[] selectionArgs, String sortOrder) {
      Log.i("projectA","query");
      String fileName = "data";
      String fileContent = FileUtil.readFromFile(getContext(), fileName);
      MatrixCursor cursor = new MatrixCursor(new String[]{"content"});
      cursor.addRow(new Object[]{fileContent});
      return cursor;
   }

   @Nullable
   @Override
   public String getType(@NonNull Uri uri) {
      Log.i("projectA","getType");
      return "vnd.android.cursor.item/vnd.com.test.projecta.provider.data";
   }

   @Nullable
   @Override
   public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
      Log.i("projectA","insert");
      return null;
   }

   @Override
   public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
      Log.i("projectA","delete");
      return 0;
   }

   @Override
   public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s,
                     @Nullable String[] strings) {
      Log.i("projectA","update");
      return 0;
   }

}

AndroidManifest.xml of app B:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    >

    <queries>
        <package android:name="com.test.projecta" />
        <provider android:authorities="com.test.projecta.provider"/>
    </queries>
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ProjectB"


        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.ProjectB">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

        </activity>

    </application>


</manifest>

App B get content code:

public String readDataFromProvider(Context context, Uri contentUri) {
        Cursor cursor = null;
        String data = "";

        try {
            ContentResolver resolver =  getContentResolver();
            cursor = resolver.query(contentUri, null, null, null, null);
            if (cursor != null && cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndexOrThrow("content");
                data = cursor.getString(columnIndex);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }

        return data;
    }

@Override
public void onClick(View view) {
    Uri dataUri = Uri.parse("content://com.test.projecta.provider/data");
    String content = readDataFromProvider(context,dataUri);
    }

Solution

  • I have found the cause of the problem. Some brands of Adnroid phones (in my case, VIVO) have a switch in the App's Settings that indicates whether the app allows to "connect and launch" other apps. Also, this switch is off by default, and when it's on, everything works. I found that many brands of mobile phone manufacturers have this function, mainly to prevent apps from having permission to open other apps silently in the background, resulting in excessive consumption of system resources.