C# Android:如何构造传递给Intent.CreateChooser的*完整*路径

C# Android:如何构造传递给Intent.CreateChooser的*完整*路径,c#,android,xamarin.android,xamarin.forms,C#,Android,Xamarin.android,Xamarin.forms,试图使Android chooser显示可用操作,以便用户启动存储在我的本地文件夹中的PDF文件。 当我传递文件名时,比如/data/user/0/myappappname/files/output.pdf(当然存在),我会得到一个很好的选择器,其中包含所有可以接受pdf文件的应用程序。但是当我选择其中任何一个时,我会收到一个错误(来自外部应用)文档路径无效。不会引发异常 然后我尝试(出于测试目的)将fname设置为类似/storage/emulated/0/Download/TLCL.pdf(

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

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

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

由于这是一个Xamarin.forms项目,我在文件创建位置的选择上受到限制(我使用PCLStorage,它总是写入应用程序私有的本地文件夹),因此我没有在/Documents、/Downloads等中生成文件的选项

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

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


一段代码:

(mimeType在前面定义为“application/pdf”)

公共异步任务启动文件(字符串fname,字符串mimeType)
{
var uri=Android.Net.uri.Parse(“文件:/”+fname);
var intent=新的intent(intent.ActionView);
SetDataAndType(uri,mimeType);
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask | ActivityFlags.grantradeuripermission);
尝试
{
Forms.Context.StartActivity(Intent.CreateChooser(Intent,“ChooseApp”);
返回true;
}
捕获(例外情况除外)
{
Debug.WriteLine(“启动文件:+ex.Message”);
返回false;
}

我的解决方案可能不是您想要的,就是生成一个文件(在我的例子中是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));
    }
public void sendmail(字符串主题、字符串正文、字符串收件人、字符串mimeType、字符串attachmentFilePath、字符串activityTitle)
{
var emailIntent=新意图(Intent.ActionSendMultiple);
if(string.IsNullOrEmpty(subject))抛出新的ArgumentException();
emailIntent.PutExtra(Intent.ExtraSubject,subject);
如果(!string.IsNullOrEmpty(收件人))
emailIntent.PutExtra(Intent.ExtraEmail,新[]{recipient});
如果(!string.IsNullOrEmpty(body))
emailIntent.PutExtra(Intent.extextext,body);
如果(!string.IsNullOrEmpty(attachmentFilePath))
{
var file=newjava.IO.file(attachmentFilePath);
SetReadable(true,true);
var uri=Android.Net.uri.FromFile(文件);
emailIntent.PutParcelableArrayListExtra(Intent.ExtraStream,new List(){uri});
}
emailIntent.SetType(mimeType);
_activity.StartActivity(Intent.CreateChooser(emailIntent,activityTitle));
}

此选择器特别允许用户通过电子邮件或google drive发送他们的文件,但您可以根据需要组装它。此函数的attachmentFilePath与上面传递到GetOutputStream函数中的字符串相同。

我们使用的是Acr.IO而不是PCLStorage,我记得它有一个返回fullpa的属性这是给你的。 下面是我们正在使用的代码,但我想知道您是否只是在路径的开头缺少了“file://”,因为我注意到这在我们的代码中,以及前面对类似问题的stackoverflow回答, 我们在Android上使用依赖项文件服务,并使用以下代码打开PDF:

 public void OpenNatively(string filePath) {
        Android.Net.Uri uri;
        if (filePath.StartsWithHTTP()) {
            uri = Android.Net.Uri.Parse(filePath);
        }
        else {
             uri = Android.Net.Uri.Parse("file:///" + filePath);
        }
        Intent intent = new Intent(Intent.ActionView);
        var extension = filePath.Substring(filePath.LastIndexOf(".")+1);
        if (extension == "ppt" || extension == "pptx") {
            extension = "vnd.ms-powerpoint";
        }
        var docType = "application/" + extension;
        intent.SetDataAndType(uri, docType);
        intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);

        try {
            Xamarin.Forms.Forms.Context.StartActivity(intent);
        }
        catch (Exception e) {
            Toast.MakeText(Xamarin.Forms.Forms.Context, "No Application found to view " + extension.ToUpperInvariant() + " files.", ToastLength.Short).Show();
        }
    }

嘿,这看起来是一个很好的解决方法。我明天第一件事就是试用。感谢您花费时间和精力。我将等待一段时间,看看是否有人可以解决我原来的问题(不导出到公用文件夹),如果没有-这就是我将要做的。谢谢。这与我以前做的基本相同。问题肯定是在app private folder中创建的文件的访问权限。不过,Acr.IO乍一看似乎不错,谢谢你提供的信息。
 public void OpenNatively(string filePath) {
        Android.Net.Uri uri;
        if (filePath.StartsWithHTTP()) {
            uri = Android.Net.Uri.Parse(filePath);
        }
        else {
             uri = Android.Net.Uri.Parse("file:///" + filePath);
        }
        Intent intent = new Intent(Intent.ActionView);
        var extension = filePath.Substring(filePath.LastIndexOf(".")+1);
        if (extension == "ppt" || extension == "pptx") {
            extension = "vnd.ms-powerpoint";
        }
        var docType = "application/" + extension;
        intent.SetDataAndType(uri, docType);
        intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);

        try {
            Xamarin.Forms.Forms.Context.StartActivity(intent);
        }
        catch (Exception e) {
            Toast.MakeText(Xamarin.Forms.Forms.Context, "No Application found to view " + extension.ToUpperInvariant() + " files.", ToastLength.Short).Show();
        }
    }