Unity3d NativeShare在Android8.0+设备报错FileUriExposedException求助
Hey there, that FileUriExposedException is a super common gotcha for Android 7.0 (API 24) and newer—Google tightened security to block apps from exposing local file paths directly via file:// URIs. Let's get your NativeShare script working on Oreo and above with these straightforward steps:
Step 1: Add FileProvider Configuration to AndroidManifest.xml
First, we need to declare a FileProvider in your Android manifest to safely share file URIs. Open your project's Plugins/Android/AndroidManifest.xml (create the file if it doesn't exist) and add this inside the <application> tag:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
Next, create a new folder Plugins/Android/res/xml and add a file named file_paths.xml with this content (this tells FileProvider which directories we're allowed to share):
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path name="shared_files" path="." /> </paths>
The <files-path> tag maps directly to Unity's Application.persistentDataPath (which corresponds to the files directory on Android), so this covers your screenshot storage path perfectly.
Step 2: Update the NativeShare.cs Android Code
Now modify the Android section of your Share method to use FileProvider instead of direct file:// URIs. Here's the revised code block:
#if UNITY_ANDROID AndroidJavaClass intentClass = new AndroidJavaClass("android.content.Intent"); AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent"); intentObject.Call<AndroidJavaObject>("setAction", intentClass.GetStatic<string>("ACTION_SEND")); // Replace old Uri.parse logic with FileProvider AndroidJavaObject fileObject = new AndroidJavaObject("java.io.File", imagePath); AndroidJavaClass fileProviderClass = new AndroidJavaClass("androidx.core.content.FileProvider"); AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); string packageName = currentActivity.Call<string>("getPackageName"); AndroidJavaObject uriObject = fileProviderClass.CallStatic<AndroidJavaObject>( "getUriForFile", currentActivity, packageName + ".fileprovider", // Matches authority from AndroidManifest fileObject ); // Grant temporary read permission to the receiving app intentObject.Call<AndroidJavaObject>("addFlags", intentClass.GetStatic<int>("FLAG_GRANT_READ_URI_PERMISSION")); intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_STREAM"), uriObject); intentObject.Call<AndroidJavaObject>("setType", "image/png"); intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), shareText); AndroidJavaObject jChooser = intentClass.CallStatic<AndroidJavaObject>("createChooser", intentObject, subject); currentActivity.Call("startActivity", jChooser); #endif
Key Changes Breakdown:
- FileProvider.getUriForFile: Generates a secure
content://URI instead of the blockedfile://scheme, which is required for Android 7.0+. - FLAG_GRANT_READ_URI_PERMISSION: Gives the receiving app temporary access to the screenshot file, so it can load and display it.
- Package Name Authority: Uses your app's unique package name to ensure the FileProvider authority matches what's declared in the manifest (avoids mismatches).
Step 3: Double-Check Unity Android Settings
Make sure your Unity project is set up to use AndroidX (since we're using androidx.core.content.FileProvider):
- Go to Edit > Project Settings > Player > Android > Publishing Settings
- Enable Custom Main Gradle Template
- Open the generated
mainTemplate.gradleand confirm it includes AndroidX dependencies (Unity usually adds this by default in recent versions, look for something likeimplementation 'androidx.core:core:1.+').
That's it! This should resolve the FileUriExposedException and get your share feature working smoothly on Android 8.0+ devices while keeping compatibility with older versions.
内容的提问来源于stack exchange,提问作者Ahmad Zafar

