1
votes

I am having some issues with Android share intents. I am able to succesfully share image files (jpg, png, gifs), but when I try to share any other files (doc, docx, xlsx, ppt), I get errors from the apps saying that there were errors opening the files, but when I try to open them from the file manager, they work fine.

var uri = Android.Net.Uri.Parse(System.IO.Path.Combine(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDownloads).AbsolutePath, fileName));

string auth = "xamarintestapp.xamarintestapp.fileprovider";
string mimeType = Android.Webkit.MimeTypeMap.Singleton.GetMimeTypeFromExtension(Android.Webkit.MimeTypeMap.GetFileExtensionFromUrl(fileName.ToLower()));
if (mimeType == null)
mimeType = "*/*";
var file = new Java.IO.File(System.IO.Path.Combine(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDownloads).AbsolutePath, fileName));
Android.Net.Uri intentUri = null;


Intent intent = new Intent(Intent.ActionView);

intent.SetDataAndType(uri, mimeType);

intent.SetFlags(ActivityFlags.GrantReadUriPermission);


Forms.Context.StartActivity(Intent.CreateChooser(intent, "Choose an App"));

I have tried checking the MIME type, and they seem to be correct (application/vnd.openxmlformats-officedocument.wordprocessingml.document for doc and docx files). Any help would be greatly appreciated.

1

1 Answers

0
votes

You need to use a file scheme-based based uri instead of just passing a filesystem-based path.

Note: The Downloads directory is a publicly accessible file location on Android so no granting of rights, nor content provider, is needed, but if these files, doc|x or not, are coming from within your app's sandbox, then you would need to implement a content provider and share a content://-based provider uri to Word, Excel and other apps...

Example:

var fileName = "demo.docx";
var mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(MimeTypeMap.GetFileExtensionFromUrl(fileName)) ?? "*/*";
var downloads = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDownloads);
using (var intent = new Intent(Intent.ActionView))
using (var uri = new Uri.Builder()
                     .Scheme("file")
                     .Authority("localhost")
                     .AppendEncodedPath(downloads.CanonicalPath)
                     .AppendEncodedPath(fileName)
                     .Build())
{
    intent.SetDataAndType(uri, mimeType);
    StartActivity(Intent.CreateChooser(intent, "Choose an App"));
}

Update:

....exposed beyond app through ClipData.Item.getUri()

Compiling against, say Android P/API-28, and using a minSDKVersion but no targetSDKVersion in the manifest (Xamarin calls it "automatic") and this code will work (I have Android P apps using the latest APIs running using the above code but they do not "target" a specific API level at runtime.)

But you are targeting a specific API >= Nougat thus you will have to implement a file provider to "share" even public files and thus provide content://-based uris to the app you are sharing to.