Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
907 views
in Technique[技术] by (71.8m points)

storage - Android 11 sharing file between apps

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:

  • MediaStore API can only access Media files(images, audio files, videos)
  • Storage Access Framework need user interaction

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>
question from:https://stackoverflow.com/questions/65878479/android-11-sharing-file-between-apps

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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();

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...