【问题标题】:Share file to another app (whatsapp, telegram, gmail)将文件共享到另一个应用程序(whatsapp、电报、gmail)
【发布时间】:2017-10-03 11:04:16
【问题描述】:

我正在使用 Xamarin.Forms 开发一个 android 应用程序。

到目前为止,我在开发过程中没有发现太多困难,但现在我觉得我错过了一些东西。

我想:

  1. 将自定义文件 (*.sl) 从我的应用程序共享到任何可以处理附件的应用程序(如 whatsapp、电报、gmail.. 等)
  2. 用我的应用打开我的自定义文件 (*.sl)

所以,我在网上搜索了一下,最终得到了这个;

在我的 AndroidManifest.xml 中处理我的自定义文件

   <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>

还有这个类,用作我的 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;
    }
}

这里我调用了我的共享服务的 Show 方法

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);
}

当我在任何设备(非模拟)上测试应用程序时,我得到相同的结果。

  • Gmail 提示“附件的权限被拒绝”
  • WhatsApp 和 Telegram 显示“不支持附件”

Resources.ShareViaMessage(这是一个小描述)可以毫无问题地打印到目标应用程序中。

自定义文件实际上是一个带有自定义扩展名 (.sl) 的 .txt 文件。

有人可以帮忙吗?

【问题讨论】:

  • GmailWhatsApp 必须有一定的安全检查,这在您的应用程序方面是无法更改的。
  • 我想必须有办法绕过这些检查(甚至一些'如果'我可以硬编码以避免这些检查)。例如,从电报我可以将任何类型的文件共享给whatsApp,反之亦然(与gmail相同)......
  • 所以,我尝试使用 .txt 而不是我的 .sl 文件(文件的内容相同),它可以正常工作。那么,关于如何将我的 .sl 注册为 text/plain mimetype 文件有什么建议吗?

标签: c# android xamarin android-intent xamarin.android


【解决方案1】:

最后我想出了一个解决方案。 我从清单中删除了意图,并将它们编码在主要活动中,如下所示:

[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"
})]

还更改了 Share.Show 方法以使用来自文件提供程序的 uri:

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);
    }

在清单中,在我添加的 application 标记内

  <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>

这是我的 file_paths.xml

的内容
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <files-path name="exports" path="exports/"/>
</paths>

现在我的应用程序导出 .sl 文件,whatsapp、telegram、gmail 和任何其他支持 text/plain 文件的应用程序都接受附件。

此外,当打开/发送 .sl 文件时,我的应用程序会被列出并可用作此类文件的默认设置。

希望这对将来的其他人有所帮助:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多