How to Share PDF from Assets Folder

Viewed 22

I am developing a book application. A professional application which I later publish on play store. It would be nice if it had a share button which shares pdf to different apps. I spent hours searching for that but I couldn't found the way to share pdf that is in Assets folder. Most of them are sharing images and those who are sharing pdf are using URL. It would be nice if anyone tells me. Thanks in advance.

2 Answers

Here is the code I wrote a code in java language. I translated it from a fellow member who have written in Kotlin language.

In AndroidManifest.xml add the following lines just before

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
    android:name="android.support.FILE_PROVIDER_PATHS"
    android:resource="@xml/file_path" />
</provider>

After that create an xml resource file name file_path. Then copy the below code there.

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<root-path
    name="root"
    path="/"/>
</paths>

Then go in that java class where you are doing sharing. There we create new functions. These actually create an empty file in files directory, then copy the content of asset to file and create a share intent then.

private File createFileInFilesDir(String filename) throws IOException {
    File file = new File(getFilesDir().getPath()+"/"+filename);
    if (file.exists()) {
        if (!file.delete()) {
            throw new IOException();
        }
    }
    if (!file.createNewFile()) {
        throw new IOException();
    }
    return file;
}
private void copyAssetToFile(String assetName, File file) throws IOException {
    byte[] buffer = new byte[1024];
    InputStream inputStream = getAssets().open(assetName);
    OutputStream outputStream = new FileOutputStream(file);
    while (inputStream.read(buffer) > 0) {
        outputStream.write(buffer);
    }
}
private Intent createIntentForFile(File file, String intentAction) {
    Uri uri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", file);
    Intent intent = new Intent(intentAction);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.setDataAndType(uri, "application/pdf");
    intent.putExtra(Intent.EXTRA_STREAM,uri);
    return intent;
}
private void sharePdfAsset(String assetName, String intentAction) throws IOException {
    try {
        File file = createFileInFilesDir(assetName);
        copyAssetToFile(assetName, file);
        Intent intent = createIntentForFile(file, intentAction);

        startActivity(Intent.createChooser(intent, "Sharing PDF"));
    } catch (IOException e) {
        e.printStackTrace();
        new AlertDialog.Builder(this)
                .setTitle(R.string.error)
                .setMessage(R.string.share_error)
                .show();
    }
}

Actually I am using a proper share button to share pdf on action bar so I used onoptionsItemselected method.

 public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    // We are using switch case because multiple icons can be kept
    switch (item.getItemId()) {
        case R.id.shareButton:
            try {
                sharePdfAsset("your_file_name.pdf", Intent.ACTION_SEND);
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
    return super.onOptionsItemSelected(item);

If anyone else had done this in easier way please share.

The short answer is: copy the file from assets to storage

Then use FileProvider and ACTION_SEND to share the file from storage.

But more elegant would be to not copy and use an assets provider.

Related