下载PDF并打开触发FileUriExposedException问题求助
android.os.FileUriExposedException When Opening Downloaded PDFs on Android Hey there! I get that you're new to Android Studio and Java, even with your programming background—Android has its own quirks, so let's work through this step by step. That FileUriExposedException pops up because Android 7.0 (API level 24) and later block apps from sharing file:// URIs directly with other apps (like your PDF reader). Instead, we need to use FileProvider to generate a secure content:// URI. Here's exactly what to do:
1. Configure FileProvider in Your AndroidManifest.xml
Open your AndroidManifest.xml file (under app/src/main/) and add this <provider> tag inside the <application> section. This tells Android your app can safely share files with other apps:
<application ...> <!-- Your existing app code here --> <provider android:name="androidx.core.content.FileProvider" android:authorities="com.yourpackage.name.fileprovider" <!-- Replace with your app's package name + .fileprovider --> android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
Make sure to replace com.yourpackage.name with your actual app package name (you can find this at the top of your AndroidManifest.xml).
2. Create the File Paths Configuration File
Next, we need to define which directories your app is allowed to share.
- Right-click the
resfolder in your project → New → Android Resource Directory. - Set "Resource type" to
xml, name the directoryxml, and click OK. - Inside the new
xmlfolder, create a file namedfile_paths.xmland paste this code:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Share files from your app's private external storage Download folder --> <external-files-path name="shared_pdfs" path="Download" /> <!-- Points to /Android/data/your_package_name/files/Download --> </paths>
This lets FileProvider access the Download folder inside your app's private external storage—no extra permissions needed for Android 10+, which simplifies things a lot.
3. Download the PDF to Your App's Private Storage
Let's use Android's built-in DownloadManager to handle the download (it's more reliable than writing your own network code). Here's a code snippet you can add to your Activity:
import android.app.DownloadManager; import android.content.Context; import android.net.Uri; import android.os.Environment; import android.widget.Toast; public void startPdfDownload(String pdfUrl) { DownloadManager.Request request = new DownloadManager.Request(Uri.parse(pdfUrl)); request.setTitle("Downloading PDF"); request.setDescription("Please wait..."); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); // Save the PDF to your app's private Download folder request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, "my_document.pdf"); // Enqueue the download request DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); manager.enqueue(request); Toast.makeText(this, "Download started!", Toast.LENGTH_SHORT).show(); }
Call this method with your target PDF URL (e.g., startPdfDownload("https://example.com/your-file.pdf")).
4. Open the Downloaded PDF with a PDF Reader
Once the download finishes, we need to get the file's secure URI via FileProvider and launch the PDF reader. First, let's set up a listener to detect when the download completes (add this to your Activity's onCreate):
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import java.io.File; public class MainActivity extends AppCompatActivity { private BroadcastReceiver downloadCompleteReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Register a receiver to listen for download completion downloadCompleteReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { openDownloadedPdf(); } }; registerReceiver(downloadCompleteReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); } private void openDownloadedPdf() { // Locate the downloaded PDF file File pdfFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "my_document.pdf"); if (pdfFile.exists()) { // Generate a secure content URI using FileProvider Uri pdfUri = androidx.core.content.FileProvider.getUriForFile( this, "com.yourpackage.name.fileprovider", // Same authority as in your manifest pdfFile ); // Create intent to open the PDF with a reader app Intent openPdfIntent = new Intent(Intent.ACTION_VIEW); openPdfIntent.setDataAndType(pdfUri, "application/pdf"); openPdfIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // Grant read access to the PDF reader // Check if there's an app that can handle this intent if (openPdfIntent.resolveActivity(getPackageManager()) != null) { startActivity(openPdfIntent); } else { Toast.makeText(this, "No PDF reader installed on your device", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(this, "PDF file not found", Toast.LENGTH_SHORT).show(); } } @Override protected void onDestroy() { super.onDestroy(); // Unregister the receiver to avoid memory leaks unregisterReceiver(downloadCompleteReceiver); } }
Don't forget to replace com.yourpackage.name.fileprovider with the same authority you used in the manifest.
Quick Notes
- Permissions: Since we're using the app's private external storage, you don't need to request
WRITE_EXTERNAL_STORAGEpermission for Android 10 (API 29) and above. For older versions, you might need to add the permission to your manifest and request it at runtime—but most devices are on Android 10+ now. - File Names: Make sure the file name in
setDestinationInExternalFilesDirmatches the one inopenDownloadedPdf.
That should fix the FileUriExposedException and let you open the downloaded PDF smoothly. Let me know if you hit any snags!
内容的提问来源于stack exchange,提问作者thugzook

