Android:如何构造传递给Intent.CreateChooser的* full *路径

时间:2017-06-01 18:45:24

标签: c# android xamarin.android xamarin.forms

尝试让Android选择器显示可用的操作,以便用户启动存储在我的本地文件夹中的PDF文件。 当我传递像 /data/user/0/myappappname/files/output.pdf 这样的文件名时(当然,它存在),我得到了一个很好的选择,包含了所有可以接受的应用程序pdf文件。但当我选择其中任何一个时,我收到错误(来自外部应用程序)文档路径无效。不会抛出任何异常。

然后我尝试(出于测试目的)将 fname 设置为 /storage/emulated/0/Download/TLCL.pdf (文件也存在),以及一切正常。

起初,我认为这与文件权限有关(因为第一个路径是我的应用程序的私有路径),但后来我发现标志 ActivityFlags.GrantReadUriPermission 正是为了暂时授予的目的而构建的文件访问其他应用程序。结果仍然相同。

由于这是一个Xamarin.forms项目,我选择文件创建位置是有限的(我使用PCLStorage,它总是写入app-private,本地文件夹),所以我没有选择生成文件/文件,/下载等。

我显然做错了什么。任何想法都赞赏。

是否有从系统获取完整路径的选项,包括 / storage / emulated / 0 部分(或其他设备上的任何内容)?也许这会有所帮助吗?

一段代码:

(mimeType早先定义为“application / pdf”)

SqlPrompt

2 个答案:

答案 0 :(得分:1)

我的解决方案可能不是您想要的,是生成一个文件(在我的情况下是一个zip文件),将其导出到公共文件夹,并将该文件用于选择器。

使用这些:

private readonly string PublicDocsPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/AppName";
private readonly string PrivateDocsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);

和一些基本功能:

    public Stream GetOutputStream(string destFilePath)
    {
        string destFolderPath = Path.GetDirectoryName(destFilePath);
        if (!Directory.Exists(destFolderPath))
            Directory.CreateDirectory(destFolderPath);
        return new FileStream(destFilePath, FileMode.Create, FileAccess.Write, FileShare.None);
    }
    public Stream GetInputStream(string sourceFilePath)
    {
        if (!File.Exists(sourceFilePath)) throw new FileNotFoundException();
        string sourceFolderPath = Path.GetDirectoryName(sourceFilePath);
        return new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
    }

您可以将文件复制到公用文件夹(或子文件夹,只需组装路径)并将该文件用于选择器:

    public void SendEmail(string subject, string body, string recipient, string mimeType, string attachmentFilePath, string activityTitle)
    {
        var emailIntent = new Intent(Intent.ActionSendMultiple);
        if (string.IsNullOrEmpty(subject)) throw new ArgumentException();
        emailIntent.PutExtra(Intent.ExtraSubject, subject);
        if (!string.IsNullOrEmpty(recipient))
            emailIntent.PutExtra(Intent.ExtraEmail, new[] { recipient });
        if (!string.IsNullOrEmpty(body))
            emailIntent.PutExtra(Intent.ExtraText, body);
        if (!string.IsNullOrEmpty(attachmentFilePath))
        {
            var file = new Java.IO.File(attachmentFilePath);
            file.SetReadable(true, true);
            var uri = Android.Net.Uri.FromFile(file);
            emailIntent.PutParcelableArrayListExtra(Intent.ExtraStream, new List<IParcelable>(){uri});                              
        }
        emailIntent.SetType(mimeType);
        _activity.StartActivity(Intent.CreateChooser(emailIntent, activityTitle));
    }

此选择器专门允许用户通过电子邮件或谷歌驱动器发送文件,但您可以随意组装它。此函数的attachmentFilePath与传递给上面的GetOutputStream函数的字符串相同。

答案 1 :(得分:0)

我们正在使用Acr.IO而不是PCLStorage,我记得有一个属性可以为您返回完整路径。 我们正在使用的代码如下,但我想知道您是否只是缺少&#34; file://&#34;在你的路径的开头,我注意到在我们的代码中,以及之前的stackoverflow回答了与此问题类似的问题,open a PDF in Xamarin.Forms (Android) 我们在Android上使用依赖FileService并使用此代码打开PDF:

updateDataset = function(target, chart, label, color, data) {
    var store = chart.data.datasets[0].label;
    var bgcolor = chart.data.datasets[0].backgroundColor;
    var dataSets = chart.data.datasets[0].data;
    var exists = false;
    for (var i = 0; i < chart.data.datasets[0].label.length; i++) {
        if (chart.data.datasets[0].label[i] === label) {
            chart.data.datasets[0].label
            exists = true;
            chart.data.datasets[0].label.push(store.splice(i, 1)[0][1]);
            chart.data.datasets[0].backgroundColor.push(bgcolor.splice(i, 1)[0][1]);
            chart.data.datasets[0].data.push(dataSets.splice(i, 1)[0][1]);      
        }
    }
    if (!exists) {
        chart.data.datasets[0].label.push(label);
        chart.data.datasets[0].backgroundColor.push(color);
        chart.data.datasets[0].data.push(data);
        exists = false;
    }
    chart.update();  
};