Reputation: 1642
Edited to fine the question
In Android, I need to download a pdf file to "Documents" folder and open it with the default program. I downloaded the document and stored it in a Byte array. Then I call this method:
/// <summary>
/// Save data bytes on "My documents" folder and open
/// </summary>
/// <param name="fileName">Filename, for example: "Test.pdf"</param>
/// <param name="data">Array of bytes to save</param>
/// <returns>True if success or false if error</returns>
public bool SaveAndOpen(string fileName, byte[] data)
{
try
{
// Get my documents path
string filePath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads);
// Combine with filename
string fullName = Path.Combine(filePath, fileName);
// If the file exist on device delete it
if (File.Exists(fullName))
{
// Note: In the second run of this method, the file exists
File.Delete(fullName);
}
// Write bytes on "My documents"
File.WriteAllBytes(fullName, data);
// Launch file as process
Process.Start(fullName);
return true;
}
catch (Exception ex)
{
Console.WriteLine("ERROR: " + ex.Message + ex.StackTrace);
return false;
}
}
The problem is to open the pdf document with the default pdf reader.
The line "Process.Start(fullName);" throws an exception
System.ComponentModel.Win32Exception (0x80004005): Access denied
Thanks for your time!
Upvotes: 1
Views: 7245
Reputation: 2372
I will extend @duefectu answer with class for reading file for more extensions Where MainActivity.MainActivityInstance is stored MainActivityContext
public void Open(string path)
{
try
{
var url = new Java.IO.File(path);
var uri = FileProvider.GetUriForFile(MainActivity.MainActivityInstance,
MainActivity.MainActivityInstance.PackageName + ".fileprovider", url);
var intent = new Intent(Intent.ActionView);
if (url.ToString().Contains(".doc") || url.ToString().Contains(".docx"))
{
// Word document
intent.SetDataAndType(uri, "application/msword");
}
else if (url.ToString().Contains(".pdf"))
{
// PDF file
intent.SetDataAndType(uri, "application/pdf");
}
else if (url.ToString().Contains(".ppt") || url.ToString().Contains(".pptx"))
{
// Powerpoint file
intent.SetDataAndType(uri, "application/vnd.ms-powerpoint");
}
else if (url.ToString().Contains(".xls") || url.ToString().Contains(".xlsx"))
{
// Excel file
intent.SetDataAndType(uri, "application/vnd.ms-excel");
}
else if (url.ToString().Contains(".zip"))
{
// ZIP file
intent.SetDataAndType(uri, "application/zip");
}
else if (url.ToString().Contains(".rar"))
{
// RAR file
intent.SetDataAndType(uri, "application/x-rar-compressed");
}
else if (url.ToString().Contains(".rtf"))
{
// RTF file
intent.SetDataAndType(uri, "application/rtf");
}
else if (url.ToString().Contains(".wav") || url.ToString().Contains(".mp3"))
{
// WAV audio file
intent.SetDataAndType(uri, "audio/x-wav");
}
else if (url.ToString().Contains(".gif"))
{
// GIF file
intent.SetDataAndType(uri, "image/gif");
}
else if (url.ToString().Contains(".jpg") || url.ToString().Contains(".jpeg") ||
url.ToString().Contains(".png"))
{
// JPG file
intent.SetDataAndType(uri, "image/jpeg");
}
else if (url.ToString().Contains(".txt"))
{
// Text file
intent.SetDataAndType(uri, "text/plain");
}
else if (url.ToString().Contains(".3gp") || url.ToString().Contains(".mpg") ||
url.ToString().Contains(".mpeg") || url.ToString().Contains(".mpe") ||
url.ToString().Contains(".mp4") || url.ToString().Contains(".avi"))
{
// Video files
intent.SetDataAndType(uri, "video/*");
}
else
{
intent.SetDataAndType(uri, "*/*");
}
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask | ActivityFlags.GrantReadUriPermission | ActivityFlags.NewTask);
MainActivity.MainActivityInstance.StartActivity(intent);
}
catch (Exception exception)
{
}
}
Upvotes: 1
Reputation: 1642
I found a way to save and open the file:
/// <summary>
/// Save data bytes on "My documents" folder and open
/// </summary>
/// <param name="fileName">Filename, for example: "Test.pdf"</param>
/// <param name="data">Array of bytes to save</param>
/// <returns>True if success or false if error</returns>
public bool SaveAndOpen(string fileName, byte[] data)
{
try
{
// Get my downloads path
string filePath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads);
// Combine with filename
string fullName = Path.Combine(filePath, fileName);
// If the file exist on device delete it
if (File.Exists(fullName))
{
// Note: In the second run of this method, the file exists
File.Delete(fullName);
}
// Write bytes on "My documents"
File.WriteAllBytes(fullName, data);
// Get the uri for the saved file
Android.Net.Uri file = Android.Support.V4.Content.FileProvider.GetUriForFile(
this,
this.PackageName + ".fileprovider",
new Java.IO.File(fileName));
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(file, "application/pdf");
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask | ActivityFlags.GrantReadUriPermission | ActivityFlags.NewTask);
this.ApplicationContext.StartActivity(intent);
return true;
}
catch (Exception ex)
{
Console.WriteLine("ERROR: " + ex.Message + ex.StackTrace);
return false;
}
}
It's needed to request the permissions at runtime. I used Plugin.Permisions available on Nuget:
Plugin.Permissions.PermissionsImplementation.Current.RequestPermissionsAsync(
new Plugin.Permissions.Abstractions.Permission[]
{
Plugin.Permissions.Abstractions.Permission.Storage,
Plugin.Permissions.Abstractions.Permission.MediaLibrary
});
Also add a provider in the AndroidManifest.xml file:
<application android:label="My app" android:icon="@mipmap/icon">
<provider android:name="android.support.v4.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"></meta-data>
</provider>
</application>
In the same AndroidManifest add permisions for:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
And add an external path in Resources/xml/file_paths.xml
<external-path name="external_files" path="."/>
Don't know if I have not needed permissions, but with this way works.
Upvotes: 3