Android 11 had enforce some rules for storage, link refer : Storage updates in Android 11
Use Case : I have 2 applications, application A will write file (.txt) into external storage, application B will read the file from external storage without user interaction. But exception was thrown when read / write on Android 11, stated that permission was denied.
So I did some research and found that only MediaStore API and Storage Access Framework allow access files that created by other application, link refer : Data and file storage overview
But both methods are not suitable for my use case:
So is there any other way that I can access non-media files on external storage that created by different apps on Android 11?
Despite all my researches, I didn't find a solution to my problem.
Thank you for your help.
Updates
I tried FileProvider but when I tried start activity, it always show error
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.testapp, PID: 20141 android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.example.app2.action.RECEIVE dat=content://com.example.testapp.fileprovider/myfiles/default_user.txt flg=0x1 } at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2067) at android.app.Instrumentation.execStartActivity(Instrumentation.java:1727) at android.app.Activity.startActivityForResult(Activity.java:5320)
This is how I start App 2 activity from App 1
File filePath = new File(getFilesDir(), "files");
File newFile = new File(filePath, "default_user.txt");
Intent intent = new Intent();
intent.setAction("com.example.app2.action.RECEIVE");
intent.setData(FileProvider.getUriForFile(this, "com.example.testapp.fileprovider", newFile));
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
App 1 Manifest
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:requestLegacyExternalStorage="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.TestApp">
<activity android:name=".StorageActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity">
</activity>
<service
android:name=".service.TestService"
android:enabled="true"
android:exported="true" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.testapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>
App 2 Manifest
<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:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.TestApp">
<activity android:name=".ReceiverActivity">
<intent-filter>
<action android:name="com.example.app2.action.RECEIVE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="content"
android:host="com.example.testapp" />
</intent-filter>
</activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
You should directly start app2 using a launch intent for it.
try {
File file = new File( .... );
Uri uri = FileProvider.getUriForFile(context, getPackageName() + ".fileprovider", file);
String apkPackage = "com.example.app2";
Intent intent = context.getPackageManager().getLaunchIntentForPackage(apkPackage);
if ( intent==null )
{
Toast.makeText(context, "Sorry, could not get launch intent for: " + apkPackage, Toast.LENGTH_LONG).show();
return;
}
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(uri, mimeType);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
context.startActivity(intent);
}
catch ( IllegalArgumentException e)
{
e.printStackTrace();
Toast.makeText(context, "IllegalArgumentException: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
catch ( Exception e)
{
e.printStackTrace();
Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
}
You do not need intent-filters in manifest of app2.
The receiving side can get the uri with:
Uri uri = getIntent().getData();