<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="16" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:label="$safeprojectname$" android:icon="@drawable/icon"></application>
</manifest> |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.DocIOSample" android:installLocation="auto"> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="27"/> <application android:label="DocIOSample.Android"></application> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> </manifest> |
Java.Lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
The code I'm using is as follows:
The AndroidManifest.xml contains:
android:name="android.support.v4.content.FileProvider"
android:authorities="com.ESFJP.ESFAtas.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/>
The provider_paths.xml, which lies in the folder Resources/xml, is:
xmlns:android="http://schemas.android.com/apk/res/android">
name="external_files" path="/Atas"/>
name="files" path="/Atas"/>
The async method to save the file and open:
public async Task Save(string fileName, string contentType, MemoryStream stream)
{
string exception = string.Empty;
string root = null;
if (Android.OS.Environment.IsExternalStorageEmulated)
{
root = Android.OS.Environment.ExternalStorageDirectory.ToString();
}
else
root = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
Java.IO.File myDir = new Java.IO.File(root + "/Atas");
myDir.Mkdir();
Java.IO.File file = new Java.IO.File(myDir, fileName);
if (file.Exists()) file.Delete();
try
{
//The permission failure happens in this line when the target version is set to API Level 27 Nougat
FileOutputStream outs = new FileOutputStream(file);
stream.Position = 0;
outs.Write(stream.ToArray());
outs.Flush();
outs.Close();
}
catch (Exception e)
{
//The permission failure can be seen here if the target version is set to API level 27 Nougat
exception = e.ToString();
}
finally
{
stream.Dispose();
}
if (file.Exists())
{
string auth = "com.ESFJP.ESFAtas.fileprovider";
string extension = Android.Webkit.MimeTypeMap.GetFileExtensionFromUrl(Uri.FromFile(file).ToString());
string mimeType = Android.Webkit.MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension);
if (mimeType == null)
mimeType = "*/*";
//The Java.Lang.NullPointerException is thrown from this line \/\/\/
Uri uri = FileProvider.GetUriForFile(Forms.Context, auth, file);
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(uri, mimeType);
intent.AddFlags(ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission);
intent.AddFlags(ActivityFlags.NewTask | ActivityFlags.NoHistory);
var resInfoList = Forms.Context.PackageManager.QueryIntentActivities(intent, PackageInfoFlags.MatchDefaultOnly);
foreach (var resolveInfo in resInfoList)
{
var packageName = resolveInfo.ActivityInfo.PackageName;
Forms.Context.GrantUriPermission(packageName, uri, ActivityFlags.GrantWriteUriPermission | ActivityFlags.GrantPrefixUriPermission | ActivityFlags.GrantReadUriPermission);
}
Forms.Context.StartActivity(intent);
}
}
If you set the Targed Android version
to Use Compile using SDK version
the app manages to at least create the file, but it won't open, giving the Java.Lang.NullPointerException mentioned above. IF you set it to Android 8.1 (API Level 27 - Oreo), it won't manage to create the file. It says that the permission has not been granted at this line exception = e.ToString();
. I've marked the line where that happens, it's on the public async Task Save(string fileName, string contentType, MemoryStream stream)
.
So, is there any chance we might solve that? I've seen some libraries that follows this kind of solution to create and open files, like this one:
https://github.com/jamesmontemagno/MediaPlugin
I've uploaded a sample on my github to reproduce this issue, which's as follows:
https://github.com/RaelsonCraftz/XamarinFileProviderSample
This is the only thing that restricts my app to going live, since I cannot publish to play store applications lesser than API level 27. Any help on this issue is appreciated!
Screenshot of modified file |
Details |
AndroidManifest.xml
|
In the given sample, we have found that you showed two application tag (AdroidManifest.xml). We suspect that the issue might be due that application tags, we have modified the codes and also done the configuration changes to provide access to android file provider in AndroidManifest.xml file. |
SaveAndroid.cs
|
We have modified the SaveAndroid.cs file to save and open the file from the device. |
provider_paths.xml
|
Also, we have changed the file provider options in provider_paths.xml to resolve the issue in application |
MainActivity.cs
|
To resolve the permission exception when deploying application in Android 8.1 (API Level 27 - Oreo) target, it is need to grant permission for the application to access storage. We have done the changes in MainActivity.cs to grant permission when opening the application. |
This latest sample provided by you worked for me after replacing following deprecated line:
Android.OS.Environment.ExternalStorageDirectory.ToString();
with
Android.App.Application.Context.GetExternalFilesDir(null).AbsolutePath;
Just posting, in case anybody interested in future.
Zeeshan, Thanks for
sharing.