SoFunction
Updated on 2025-04-27

Implement file sharing function based on Android

1. Project introduction

1.1 Background and Meaning

In Android applications, "sharing" is one of the most common cross-app interaction modes. Whether users transfer documents, pictures, audio, video or any type of files through social, email, cloud disk and other third-party applications, they need to rely on system-levelIntentMechanism and content provider (ContentProvider) to complete seamless docking. Implementing the "Share File" function can not only improve the user experience of the application, but also make the application easier to be disseminated and promoted.

This project is aimed at mainstream versions of Android 5.0 and above, and demonstrates how to:

  • Create and manage files in internal storage or external private directories;

  • Use the official recommendedFileProviderSafely expose files to other applications;

  • Build and send a share intent to share a single or multiple files with any target application;

  • Processing Android 7.0+Strict document URI restrictionsFileUriExposedException);

  • Compatible with Android 10+Scoped Storage(range storage);

  • UtilizeSimplify development;

  • Handle runtime permissions and exceptions gracefully.

And on this basis, it provides best practices and extended ideas to help readers integrate the "Share File" function into real projects.

1.2 Project Objectives

  • File creation and management: Read and write files (text, pictures, PDF, any binary) in the application storage space, and retain sharing paths.

  • FileProvider Configuration:existandres/xml/file_paths.xmlRegisterFileProviderand set a shareable directory structure.

  • Share Intent Build:based onIntent.ACTION_SENDandIntent.ACTION_SEND_MULTIPLE, supports single file and multiple file sharing, and sets appropriate MIME type and URI permissions.

  • Runtime permissions: Dynamically apply for necessary storage or media permissions to ensure normal function in Android 6.0+ environment.

  • Compatibility processing: Handle URI exposure restrictions over Android 7.0, and Scoped Storage (SAF) differences for Android 10+.

  • Example complete: Concentrated display of all key files and codes, including comment partitions, for easy copying and use;

  • Extension and optimization: Summarize common pitfalls, performance suggestions, and advanced features that can be considered in the next step (such as cloud sharing, WorkManager background sharing, Compose version, etc.).

2. Explanation of related knowledge

2.1 Overview of Intent Sharing Mechanism

Android sharing mechanism is based onImplicit Intent, core steps:

  1. Construct an Intent containing the operation type, such asACTION_SEND(Single file/single data) orACTION_SEND_MULTIPLE(Multiple files).

  2. Call()Specify the MIME type, such as"text/plain""image/jpeg""*/*"

  3. use(Intent.EXTRA_STREAM, uri)orIntent.EXTRA_STREAMList, attach the file URI to share.

  4. Grant read permissions to the target application, usually through(Intent.FLAG_GRANT_READ_URI_PERMISSION).

  5. CallstartActivity((intent, "Share to")), adjust the system sharing panel.

2.2 FileProvider Principle

Because Android 7.0+ is prohibitedfile://URI shares files across processes and will throwFileUriExposedException. Recommended practices:

  • existStatement in the<provider android:name="" ...>, and point to an XML resource@xml/file_paths

  • existfile_paths.xmlDefine a shareable directory in  for example<external-files-path name="shared" path="shared_files/"/>

  • use(context, authority, file)WillConvert tocontent:// URI。

  • authorityUsually it is"${applicationId}.fileprovider", it must be consistent with Manifest.

2.3 Scoped Storage and External Storage

  • Android 9 and below: External storage (()) can be read and written freely, but it is requiredWRITE_EXTERNAL_STORAGEPermissions;

  • Android 10: Introduce Scoped Storage, apply sandboxing, and directly accessing external public directories is restricted; it can be passedrequestLegacyExternalStorage=trueTemporary compatibility;

  • Android 11+: More stringent, recommendedStorage Access Framework(SAF) or access only your own private directory.

  • For sharing, as long as the file is in the application private directory (getFilesDir()orgetExternalFilesDir()) and exposed through FileProvider to access across applications without additional storage permissions.

2.4 Simplification

Provided by AndroidX, simplify the sharing process:

(activity)
    .setType(mimeType)
    .setStream(uri)
    .setChooserTitle("Share File")
    .startChooser();

Automatically handle read permission tags and Intent wrappers internally.

Ideas for realization

  1. Create a demo file

    • When the application starts,getExternalFilesDir("shared")orgetFilesDir()Write a test text file in

  2. Configure FileProvider

    • existRegister in  ;

    • existres/xml/file_paths.xmlDefinition in<external-files-path name="shared" path="shared/"/>

  3. UI layout

    • existactivity_main.xmlPlace two buttons: "Share a single file" and "Share multiple files"; put another oneTextViewShow sharing results;

  4. MainActivity Implementation

    • Dynamic application CAMERA permission is not required, but it is requiredREAD_EXTERNAL_STORAGEorWRITE_EXTERNAL_STORAGEonly on Android ≤9;

    • In the callback of the button click, callshareSingleFile()andshareMultipleFiles()method;

  5. shareSingleFile()

    • GetFile, tocontent://URI, by()

    • StructureIntent.ACTION_SENDsetType()putExtra(EXTRA_STREAM, uri)addFlags(FLAG_GRANT_READ_URI_PERMISSION)

    • CallstartActivity((...))

  6. shareMultipleFiles()

    • StructureArrayList<Uri>, add the URIs of multiple files respectively;

    • useACTION_SEND_MULTIPLEputParcelableArrayListExtra(EXTRA_STREAM, urisList)

  7. Result processing

    • After the sharing is completed, if you want to capture and return, you must use it.startActivityForResult(), but most third-party applications do not return results.

4. Complete code integration

&lt;!-- ==================== File:  ==================== --&gt;
&lt;manifest xmlns:andro
    package=""&gt;
 
    &lt;!-- Android 9 If you operate external storage, you need to declare this permission.,But the examples are only in private directories,No storage permission required --&gt;
    &lt;uses-permission android:name=".WRITE_EXTERNAL_STORAGE"
                     android:maxSdkVersion="28"/&gt;
 
    &lt;application
        android:allowBackup="true"
        android:label="File Sharing Example"
        android:theme="@style/"&gt;
        
        &lt;activity android:name=".MainActivity"&gt;
            &lt;intent-filter&gt;
                &lt;action android:name=""/&gt;
                &lt;category android:name=""/&gt;
            &lt;/intent-filter&gt;
        &lt;/activity&gt;
 
        &lt;!-- FileProvider register --&gt;
        &lt;provider
            android:name=""
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true"&gt;
            &lt;meta-data
                android:name=".FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/&gt;
        &lt;/provider&gt;
    &lt;/application&gt;
&lt;/manifest&gt;
&lt;!-- ==================== File: res/xml/file_paths.xml ==================== --&gt;
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;paths xmlns:andro&gt;
    &lt;!-- Allow sharing app Private external directory:.../Android/data/.../files/shared/ --&gt;
    &lt;external-files-path
        name="shared"
        path="shared/"/&gt;
    &lt;!-- If you need to share private internal storage,Can be added:
    &lt;files-path
        name="internal"
        path="shared/"/&gt;
    --&gt;
&lt;/paths&gt;
&lt;!-- ==================== File: res/layout/activity_main.xml ==================== --&gt;
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;LinearLayout xmlns:andro
    android:orientation="vertical"
    android:padding="24dp"
    android:gravity="center_horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"&gt;
 
    &lt;Button
        android:
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Share a single file"/&gt;
 
    &lt;Button
        android:
        android:layout_width="match_parent"
        android:layout_marginTop="16dp"
        android:layout_height="wrap_content"
        android:text="Share multiple files"/&gt;
 
    &lt;TextView
        android:
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Share status: Not operated"
        android:textSize="16sp"/&gt;
&lt;/LinearLayout&gt;
// ==================== File:  ====================
package ;
 
import ;
import ;
import ;
import ;
import .*;
import ;
import ;
import ;
import .*;
import ;
import ;
 
/**
  * MainActivity: Demonstrate Android file sharing function
  */
public class MainActivity extends AppCompatActivity {
 
    private Button btnShareSingle, btnShareMultiple;
    private TextView tvStatus;
    private File sharedDir;
 
    @Override
    protected void onCreate(@Nullable Bundle saved) {
        (saved);
        setContentView(.activity_main);
 
        // 1. Bind the control        btnShareSingle   = findViewById(.btn_share_single);
        btnShareMultiple = findViewById(.btn_share_multiple);
        tvStatus         = findViewById(.tv_status);
 
        // 2. Create a sample file directory        sharedDir = new File(getExternalFilesDir("shared"), "");
        if (!()) ();
 
        // 3. Create sample files in the directory        createExampleFile("", "This is the sample file 1 Contents。");
        createExampleFile("", "This is the sample file 2 Contents。");
        createExampleFile("", "This is the sample file 3 Contents。");
 
        // 4. Single file sharing        (v -&gt; {
            File file = new File(sharedDir, "");
            if (()) shareSingleFile(file, "text/plain");
            else ("The file does not exist: ");
        });
 
        // 5. Multi-file sharing        (v -&gt; {
            List&lt;File&gt; files = new ArrayList&lt;&gt;();
            (new File(sharedDir, ""));
            (new File(sharedDir, ""));
            (new File(sharedDir, ""));
            shareMultipleFiles(files, "text/plain");
        });
    }
 
    /**
      * Create a sample text file
      */
    private void createExampleFile(String name, String content) {
        File out = new File(sharedDir, name);
        try (FileWriter fw = new FileWriter(out)) {
            (content);
        } catch (IOException e) {
            ();
            ("File creation failed:" + name);
        }
    }
 
    /**
      * Share a single file
      */
    private void shareSingleFile(File file, String mimeType) {
        Uri uri = getUriForFile(file);
        if (uri == null) return;
        Intent intent = new Intent(Intent.ACTION_SEND);
        (mimeType);
        (Intent.EXTRA_STREAM, uri);
        (Intent.FLAG_GRANT_READ_URI_PERMISSION);
        startActivity((intent, "Share File"));
    }
 
    /**
      * Share multiple files
      */
    private void shareMultipleFiles(List&lt;File&gt; files, String mimeType) {
        ArrayList&lt;Uri&gt; uris = new ArrayList&lt;&gt;();
        for (File f : files) {
            Uri uri = getUriForFile(f);
            if (uri != null) (uri);
        }
        if (()) {
            ("No file to share");
            return;
        }
        Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
        (mimeType);
        (Intent.EXTRA_STREAM, uris);
        (Intent.FLAG_GRANT_READ_URI_PERMISSION);
        startActivity((intent, "Share multiple files"));
    }
 
    /**
      * Get content:// URI, compatible with each version
      */
    private Uri getUriForFile(File file) {
        try {
            // Use FileProvider to generate URI            String authority = getPackageName() + ".fileprovider";
            return (this, authority, file);
        } catch (IllegalArgumentException e) {
            ();
            ("URI cannot be obtained:" + ());
            return null;
        }
    }
}

5. Code interpretation

  1. FileProvider Configuration

    • existStatement in the<provider>authorities="${applicationId}.fileprovider"Must be with()InauthorityUnconsistent;

    • file_paths.xmlDefined<external-files-path name="shared" path="shared/"/>Share allowedgetExternalFilesDir("shared")all files under;

  2. Sample file creation

    • createExampleFile()Write text files to private external storage directories without external storage permissions;

    • The document is written inAndroid/data/<pkg>/files/shared/, automatically clean up after uninstalling the application;

  3. Share a single file

    • Intent.ACTION_SEND: used for single file sharing;

    • setType("text/plain"): Tell the system file type;

    • EXTRA_STREAM: Attachment URI;

    • addFlags(FLAG_GRANT_READ_URI_PERMISSION): Grant temporary read permissions to the target application.

  4. Share multiple files

    • ACTION_SEND_MULTIPLE: Supports multiple files;

    • Similar to single file, but mostly passedputParcelableArrayListExtra(EXTRA_STREAM, uris)Add multiple URIs;

  5. Runtime compatibility

    • Android 7.0+ Forced usecontent:// URI;

    • FileProvider will issue permissions to each URI internally, and the target application isonActivityResultCan be used in  ;

    • Android 6.0+ If you need to apply for public external storage operationRead/writePermissions, but the example only uses a private directory and no application is required.

6. Project summary and expansion

6.1 Effect review

  • Successfully realize sharing with multiple files in single form, overwriting any text, pictures, and binary files.

  • Adopt the officially recommended FileProvider solution, compatible with Android 7.0+ strict file URI restrictions.

  • Private directories do not require storage permissions, are safe and reliable, and do not require additional storage applications.

6.2 Common pitfalls and attention

  1. URI permission invalid: Must be for eachIntentjoin inFLAG_GRANT_READ_URI_PERMISSION

  2. Authority inconsistentgetUriForFile()ofauthorityRequired with ManifestproviderConsistent, otherwise throw exceptions;

  3. Scoped Storage: Android 10+ If you need to access a public directory or SD card, you need to use SAF instead (Intent.ACTION_OPEN_DOCUMENT / MediaStore), FileProvider is only available for private directories;

  4. Big file sharing: When sharing large files, do not read, write or copy files in the UI thread;

6.3 Extensible direction

  1. Customize

    • useSimplify Intent construction and permission processing;

  2. Cloud sharing

    • Upload the file to the cloud before sharing, generate a publicly accessible URL, and then passACTION_SENDShare link;

  3. Timely sharing in the background

    • CombinedWorkManagerGenerate reports regularly and share them automatically;

  4. Jetpack Compose implementation

    • useIntentandrememberLauncherForActivityResultIntegrated share button;

  5. Native CameraX and MediaStore

    • Before sharing pictures or videos, take photos/record and save them to MediaStore via CameraX before sharing;

  6. Advanced MIME Negotiation

    • Adjust MIME for different target applications, such as sharing Office documents (application/msword) or compressed package (application/zip);

  7. Share progress feedback

    • For large files or network sharing, you can display the status of "Preparing", "Shared", and "Failed" in the UI;

  8. Secure encryption sharing

    • Use AES encryption before sharing files and decrypt them on the receiver or in the target application.

The above is the detailed content of the file sharing function based on Android. For more information about Android file sharing, please follow my other related articles!