C# Android:如何构造传递给Intent.CreateChooser的*完整*路径
试图使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部分(或其他设备上的任何部分)?也许那会有帮助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(
一段代码: (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();
}
}