Xamarin.ios Xamarin IOS文件选择器:无法从icloud驱动器获取所选文件
我已经从Nuget安装了filepicker控件,并尝试从MonoTouch10文件夹添加引用,后来从github添加到我的xamarin.ios项目中Xamarin.ios Xamarin IOS文件选择器:无法从icloud驱动器获取所选文件,xamarin.ios,xamarin.forms,icloud-drive,icloud-documents,Xamarin.ios,Xamarin.forms,Icloud Drive,Icloud Documents,我已经从Nuget安装了filepicker控件,并尝试从MonoTouch10文件夹添加引用,后来从github添加到我的xamarin.ios项目中 FileData file = await CrossFilePicker.Current.PickFile(); if (file != null) { } 这是我添加到浏览按钮的代码,在从iCloud驱动器中选择一个文件后,控制永远不会出现“如果条件” 再次,当我第二次点击浏览按钮时,应用程序崩溃,说“一次只能激活一个操作”。为了回答我
FileData file = await CrossFilePicker.Current.PickFile();
if (file != null) { }
这是我添加到浏览按钮的代码,在从iCloud驱动器中选择一个文件后,控制永远不会出现“如果条件”
再次,当我第二次点击浏览按钮时,应用程序崩溃,说“一次只能激活一个操作”。为了回答我自己的问题,我在插件中自定义了,比如
DocumentPicker\u didpickdocumentturls
事件,而不是DocumentPicker\u DidPickDocument
new FileData(e.FilePath, e.FileName, () =>
{
var url = new Foundation.NSUrl(e.FilePath);
return new FileStream(url.Path, FileMode.Open, FileAccess.Read);
})
这解决了我的问题。谢谢。修改iOS平台的FilePickerImplementation插件的源代码可以这样工作:
using Foundation;
using MobileCoreServices;
using Plugin.FilePicker.Abstractions;
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using UIKit;
using System.Diagnostics;
namespace Plugin.FilePicker
{
/// <summary>
/// Implementation for FilePicker
/// </summary>
public class FilePickerImplementation : NSObject, IUIDocumentMenuDelegate, IFilePicker
{
private int _requestId;
private TaskCompletionSource<FileData> _completionSource;
/// <summary>
/// Event which is invoked when a file was picked
/// </summary>
public EventHandler<FilePickerEventArgs> Handler
{
get;
set;
}
private void OnFilePicked(FilePickerEventArgs e)
{
Handler?.Invoke(null, e);
}
public void DidPickDocumentPicker(UIDocumentMenuViewController documentMenu, UIDocumentPickerViewController documentPicker)
{
documentPicker.DidPickDocument += DocumentPicker_DidPickDocument;
documentPicker.WasCancelled += DocumentPicker_WasCancelled;
documentPicker.DidPickDocumentAtUrls += DocumentPicker_DidPickDocumentAtUrls;
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(documentPicker, true, null);
}
private void DocumentPicker_DidPickDocumentAtUrls(object sender, UIDocumentPickedAtUrlsEventArgs e)
{
var control = (UIDocumentPickerViewController)sender;
foreach (var url in e.Urls)
DocumentPicker_DidPickDocument(control, new UIDocumentPickedEventArgs(url));
control.Dispose();
}
private void DocumentPicker_DidPickDocument(object sender, UIDocumentPickedEventArgs e)
{
var securityEnabled = e.Url.StartAccessingSecurityScopedResource();
var doc = new UIDocument(e.Url);
var data = NSData.FromUrl(e.Url);
var dataBytes = new byte[data.Length];
System.Runtime.InteropServices.Marshal.Copy(data.Bytes, dataBytes, 0, Convert.ToInt32(data.Length));
string filename = doc.LocalizedName;
string pathname = doc.FileUrl?.ToString();
// iCloud drive can return null for LocalizedName.
if (filename == null)
{
// Retrieve actual filename by taking the last entry after / in FileURL.
// e.g. /path/to/file.ext -> file.ext
// filesplit is either:
// 0 (pathname is null, or last / is at position 0)
// -1 (no / in pathname)
// positive int (last occurence of / in string)
var filesplit = pathname?.LastIndexOf('/') ?? 0;
filename = pathname?.Substring(filesplit + 1);
}
OnFilePicked(new FilePickerEventArgs(dataBytes, filename, pathname));
}
/// <summary>
/// Handles when the file picker was cancelled. Either in the
/// popup menu or later on.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void DocumentPicker_WasCancelled(object sender, EventArgs e)
{
{
var tcs = Interlocked.Exchange(ref _completionSource, null);
tcs.SetResult(null);
}
}
/// <summary>
/// Lets the user pick a file with the systems default file picker
/// For iOS iCloud drive needs to be configured
/// </summary>
/// <returns></returns>
public async Task<FileData> PickFile()
{
var media = await TakeMediaAsync();
return media;
}
private Task<FileData> TakeMediaAsync()
{
var id = GetRequestId();
var ntcs = new TaskCompletionSource<FileData>(id);
if (Interlocked.CompareExchange(ref _completionSource, ntcs, null) != null)
throw new InvalidOperationException("Only one operation can be active at a time");
var allowedUtis = new string[] {
UTType.UTF8PlainText,
UTType.PlainText,
UTType.RTF,
UTType.PNG,
UTType.Text,
UTType.PDF,
UTType.Image,
UTType.UTF16PlainText,
UTType.FileURL
};
var importMenu =
new UIDocumentMenuViewController(allowedUtis, UIDocumentPickerMode.Import)
{
Delegate = this,
ModalPresentationStyle = UIModalPresentationStyle.Popover
};
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(importMenu, true, null);
var presPopover = importMenu.PopoverPresentationController;
if (presPopover != null)
{
presPopover.SourceView = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
presPopover.PermittedArrowDirections = UIPopoverArrowDirection.Down;
}
Handler = null;
Handler = (s, e) => {
var tcs = Interlocked.Exchange(ref _completionSource, null);
tcs?.SetResult(new FileData(e.FilePath, e.FileName, () => { var url = new Foundation.NSUrl(e.FilePath); return new FileStream(url.Path, FileMode.Open, FileAccess.Read); }));
};
return _completionSource.Task;
}
public void WasCancelled(UIDocumentMenuViewController documentMenu)
{
var tcs = Interlocked.Exchange(ref _completionSource, null);
tcs?.SetResult(null);
}
private int GetRequestId()
{
var id = _requestId;
if (_requestId == int.MaxValue)
_requestId = 0;
else
_requestId++;
return id;
}
public async Task<bool> SaveFile(FileData fileToSave)
{
try
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var fileName = Path.Combine(documents, fileToSave.FileName);
File.WriteAllBytes(fileName, fileToSave.DataArray);
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return false;
}
}
public void OpenFile(NSUrl fileUrl)
{
var docControl = UIDocumentInteractionController.FromUrl(fileUrl);
var window = UIApplication.SharedApplication.KeyWindow;
var subViews = window.Subviews;
var lastView = subViews.Last();
var frame = lastView.Frame;
docControl.PresentOpenInMenu(frame, lastView, true);
}
public void OpenFile(string fileToOpen)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var fileName = Path.Combine(documents, fileToOpen);
if (NSFileManager.DefaultManager.FileExists(fileName))
{
var url = new NSUrl(fileName, true);
OpenFile(url);
}
}
public async void OpenFile(FileData fileToOpen)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var fileName = Path.Combine(documents, fileToOpen.FileName);
if (NSFileManager.DefaultManager.FileExists(fileName))
{
var url = new NSUrl(fileName, true);
OpenFile(url);
}
else
{
await SaveFile(fileToOpen);
OpenFile(fileToOpen);
}
}
}
}
<代码>使用基础;
使用流动储备;
使用Plugin.FilePicker.Abstractions;
使用制度;
使用System.IO;
使用System.Linq;
使用系统线程;
使用System.Threading.Tasks;
使用UIKit;
使用系统诊断;
名称空间插件.FilePicker
{
///
///文件选择器的实现
///
公共类文件选择器实现:NSObject、IUIDocumentMenuDelegate、IFilePicker
{
私有int_requestId;
私有TaskCompletionSource\u completionSource;
///
///在拾取文件时调用的事件
///
公共事件处理程序
{
得到;
设置
}
私有void onficked(FilePickerEventArgs e)
{
Handler?.Invoke(null,e);
}
public void DidPickDocumentPicker(UIDocumentMenuViewController文档菜单,UIDocumentPickServiceController文档选择器)
{
documentPicker.DidPickDocument+=documentPicker\u DidPickDocument;
documentPicker.WasCancelled+=documentPicker\u已取消;
documentPicker.didpickdocumentturls+=documentPicker\u didpickdocumentturls;
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(documentPicker,true,null);
}
私有无效文档选择器(对象发送方,UIDocumentPickedAtUrlsEventArgs e)
{
变量控制=(UIDocumentPickerViewController)发送方;
foreach(e.url中的var url)
DocumentPicker_DidPickDocument(控件,新UIDocumentPickedEventArgs(url));
control.Dispose();
}
私有无效文档选取器\u DidPickDocument(对象发送者,UIDocumentPickedEventArgs e)
{
var securityEnabled=e.Url.StartAccessingSecurityScopedResource();
var doc=新的UIDocument(e.Url);
var data=NSData.FromUrl(e.Url);
var-dataBytes=新字节[data.Length];
System.Runtime.InteropServices.Marshal.Copy(data.Bytes,dataBytes,0,Convert.ToInt32(data.Length));
字符串文件名=doc.LocalizedName;
字符串路径名=doc.FileUrl?.ToString();
//iCloud驱动器可以为LocalizedName返回null。
如果(文件名==null)
{
//通过获取FileURL中/之后的最后一个条目来检索实际文件名。
//例如/path/to/file.ext->file.ext
//filesplit是:
//0(路径名为null,或last/位于位置0)
//-1(路径名中的否)
//正整数(字符串中/的最后一次出现)
var filesplit=pathname?.LastIndexOf('/')?0;
filename=路径名?.Substring(filesplit+1);
}
onFilePickerEventArgs(数据字节、文件名、路径名));
}
///
///在取消文件选取器时处理。在
///弹出菜单或更高版本。
///
///
///
public void DocumentPicker_已取消(对象发送者,事件参数e)
{
{
var tcs=Interlocked.Exchange(ref\u completionSource,null);
tcs.SetResult(空);
}
}
///
///允许用户使用系统默认文件选择器拾取文件
///对于iOS,需要配置iCloud驱动器
///
///
公共异步任务PickFile()
{
var media=await takemediasync();
返回媒体;
}
私有任务TakeMediaAsync()
{
var id=GetRequestId();
var ntcs=新任务完成源(id);
if(联锁的比较交换(参考完成源,ntcs,null)!=null)
抛出新的InvalidOperationException(“一次只能激活一个操作”);
var allowedUtis=新字符串[]{
UTType.UTF8纯文本,
UTType.PlainText,
UTType.RTF,
UTType.PNG,
UTType.Text,
UTType.PDF,
UTType.Image,
UTType.UTF16纯文本,
UTType.FileURL
};
变量导入菜单=
新的UIDocumentMenuViewController(allowedUtis,UIDocumentPickerMode.Import)
{
委托=此,
ModalPresentationStyle=UIModalPresentationStyle.Popover
};
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(importMenu,true,null);
var presPopover=importMenu.PopoverPresentationController;
如果(预跳!=null)
{
Prespover.SourceView=UIApplication.SharedApplication.KeyWindow.RootViewController.View;
PrePopOver.PermittedArrowDirections=UIPopoverArrowDirection.Down;
}
Handler=null;
处理程序=(s,e)=>{
var tcs=互锁。交换(