I'm developing an android app using Xamarin.Forms.
So far i did not found too much difficulties during the development, but now i think i'm missing something.
I would like to:
So, i digged a bit around the web and ended up with this;
In my AndroidManifest.xml to handle my custom file
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:host="*" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\.sl" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="application/octet-stream" />
<data android:mimeType="application/sl" />
</intent-filter>
And this class, used as a Service from my Xamarin.Forms pcl
public class ShareDroid : IShare
{
private Context _context;
private FileSystemExDroid _fsDroid;
public ShareDroid()
{
_context = Android.App.Application.Context;
_fsDroid = new FileSystemExDroid();
}
public void Show(string title, string message, string filePath)
{
if(!_fsDroid.FileExists(filePath))
return;
var extension = filePath.Substring(filePath.LastIndexOf(".", StringComparison.Ordinal) + 1).ToLower();
var contentType = GetContentType(extension);
var intent = new Intent(Intent.ActionSend);
intent.SetType(contentType);
intent.PutExtra(Intent.ExtraStream, Uri.Parse("file://" + filePath));
intent.PutExtra(Intent.ExtraText, string.Empty);
intent.PutExtra(Intent.ExtraSubject, message ?? string.Empty);
var chooserIntent = Intent.CreateChooser(intent, title ?? string.Empty);
chooserIntent.SetFlags(ActivityFlags.ClearTop);
chooserIntent.SetFlags(ActivityFlags.NewTask);
_context.StartActivity(chooserIntent);
}
private static string GetContentType(string extension)
{
string contentType;
switch (extension)
{
case "pdf":
contentType = "application/pdf";
break;
case "png":
contentType = "image/png";
break;
case "sl":
contentType = "application/sl";
break;
default:
contentType = "application/octet-stream";
break;
}
return contentType;
}
}
And here i call the Show method of my share service
private void OnShare()
{
var fileSystem = DependencyService.Get<IFileSystemEx>();
var serializer = DependencyService.Get<ISerializer>();
var share = DependencyService.Get<IShare>();
var fileName = $"{Name}_{Id}.sl";
var path = fileSystem.CreateFilePath(fileName, SpecialFolder.Personal);
serializer.Save(path, Model);
share.Show(Resources.ShareViaLabel, Resources.ShareViaMessage, path);
}
When i test the app on any device (not emulated) i get the same result.
The Resources.ShareViaMessage (which is a little description) gets printed in the target app without problem.
The custom file is actually a .txt file with a custom extension (.sl).
Anyone can help?
In the end i came up with a solution. I removed the intents from the manifest, and coded them in the main activity like this:
[IntentFilter(
new[] { Intent.ActionView },
Categories = new [] { Intent.CategoryBrowsable, Intent.CategoryDefault },
DataMimeType = "text/plain",
DataPathPatterns = new []
{
@".*\\.sl",
@".*\\..*\\.sl",
@".*\\..*\\..*\\.sl",
@".*\\..*\\..*\\..*\\.sl"
})]
[IntentFilter(
new[] { Intent.ActionSend },
Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault },
DataMimeType = "text/plain",
DataPathPatterns = new []
{
@".*\\.sl",
@".*\\..*\\.sl",
@".*\\..*\\..*\\.sl",
@".*\\..*\\..*\\..*\\.sl"
})]
also changed the Share.Show method to use the uri from the fileprovider:
public void Show(string title, string filePath)
{
if(!_fsDroid.FileExists(filePath))
return;
var fileUri = FileProvider.GetUriForFile(_context, "com.***********.******.fileprovider", new File(filePath));
var intent = new Intent(Intent.ActionSend);
intent.SetType("text/plain");
intent.PutExtra(Intent.ExtraText, string.Empty);
intent.PutExtra(Intent.ExtraStream, fileUri);
intent.SetData(fileUri);
intent.SetFlags(ActivityFlags.GrantReadUriPermission);
intent.SetFlags(ActivityFlags.ClearTop);
intent.SetFlags(ActivityFlags.NewTask);
var chooserIntent = Intent.CreateChooser(intent, title ?? string.Empty);
_context.StartActivity(chooserIntent);
}
In the manifest, inside the application tag i added
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.***********.******.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
and this is the content of my file_paths.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="exports" path="exports/"/>
</paths>
And now my application exports .sl file, and whatsapp, telegram, gmail and any other app that support text/plain file accepts the attachments.
Also, when opening/sending the .sl file my app is listed and usable as default for this kind of file.
Hope this helps out someone else in the future :)