Xamarin.ios Xamarin IOS文件选择器:无法从icloud驱动器获取所选文件

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驱动器中选择一个文件后,控制永远不会出现“如果条件” 再次,当我第二次点击浏览按钮时,应用程序崩溃,说“一次只能激活一个操作”。为了回答我

我已经从Nuget安装了filepicker控件,并尝试从MonoTouch10文件夹添加引用,后来从github添加到我的xamarin.ios项目中

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=互锁。交换(