Reputation: 415
I’m trying to display a PDF file using a file provider. However when the PDF reader opens it does not contain the content of the file. The file is stored in the internal storage of the application within the files folder.
Manifest:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.mycom.myapp.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
File_paths:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="export" />
</paths>
pdfViewRenderer.cs:
string libraryPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
var path = Path.Combine(libraryPath, fileName);
string application = "application/pdf";
Java.IO.File javaFile = new Java.IO.File(fileName);//externalPath
Android.Net.Uri androidURI = FileProvider.GetUriForFile(Forms.Context.ApplicationContext, "com.mycom.myapp.fileprovider", javaFile);
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(androidURI, Filetype);
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
intent.SetFlags(ActivityFlags.NoHistory);
intent.SetFlags(ActivityFlags.ClearWhenTaskReset);
Forms.Context.StartActivity(Intent.CreateChooser(intent, "Open PDF"));
Upvotes: 1
Views: 3741
Reputation: 74094
You can not directly access a file within the application's .apk
, the `.apk' does not present itself as a filesystem.
You can copy an AndroidAsset
to your application cache directory and then grant FileProvider
permission to a file-based Uri
to allowed external applications to access that file within your app's sandbox.
Add a provider
within your AndroidManifest
's application
element:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.sushihangover.artificialgravitycalc"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/cache_path" />
Then add an xml file whose filename matches the provider's android:resource:
to your Resources/xml
that contains the path that you are granting access to:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="appcache" path="." />
</paths>
Note: You might have to add the xml
directory to your Resources
folder as by default it is not added via the basic Xamarin.Android
project template. (and it must be named xml
, lowercase)
Add your .pdf
to the Assets
directory and make sure that it is flagged as a AndroidAsset
build type:
Now you can copy that Asset
to your app's cache directory, create a FileProvider
-based Uri
, grant read access to it, and try to open it. In this case you need at least one installed application that publishes that it handles the application/pdf
mime-type:
var pdfAssetName = "PlayScriptLanguageSpecification.pdf";
var savePath = Path.GetTempFileName();
using (var assetStream = Application.Context.Assets.Open(pdfAssetName))
using (var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write))
{
byte[] buffer = new byte[1024];
int readCount = 0;
do
{
readCount = assetStream.Read(buffer, 0, buffer.Length);
fileStream.Write(buffer, 0, readCount);
} while (readCount > 0);
}
var targetIntent = new Intent(Intent.ActionView);
var file = new Java.IO.File(savePath);
var uri = FileProvider.GetUriForFile(this, PackageName, file);
targetIntent.SetDataAndType(uri, "application/pdf");
targetIntent.SetFlags(ActivityFlags.NoHistory);
targetIntent.SetFlags(ActivityFlags.GrantReadUriPermission);
Intent intent = Intent.CreateChooser(targetIntent, "Open File");
StartActivity(intent);
Upvotes: 1