Xamarin.iOS适配iOS17时Word文档打开为只读的问题求助
iOS 17下UIDocumentInteractionController打开Word文档只读问题解决
问题背景
- 应用将文档存储在
Documents子目录(对应Environment.SpecialFolder.MyDocuments),示例路径:/var/mobile/Containers/Data/Application/8A3B2B40-100C-45EF-B9F1-6FBB01D27247/Documents/Notes/4324518a-2f04-4a67-b160-0fb7523ce0ba.docx - 通过
UIDocumentInteractionController.PresentOpenInMenu调用Word应用编辑文档,iOS 16及以下版本可直接编辑并自动保存回原路径 - iOS 17中Word打开文档后显示只读,提示“保存副本以编辑”,已启用
LSSupportsOpeningDocumentsInPlace,测试项目可复现该问题
问题原因
iOS 17对文件交互的权限机制做了调整:
- 仅依赖
LSSupportsOpeningDocumentsInPlace已不足以保证外部应用获得原文件的编辑权限 NSUrl.FromFilename生成的URL缺少必要的权限标记,导致Word无法获取原文件的写入权限- 文档交互控制器的Delegate未正确设置,影响权限传递流程
解决方案
1. 修正文件URL生成方式
使用NSUrl.CreateFileUrl替代NSUrl.FromFilename,确保生成包含权限信息的文件URL。
2. 正确设置UIDocumentInteractionController的Delegate
实现UIDocumentInteractionControllerDelegate,确保预览和交互的视图控制器正确返回。
3. 匹配正确的文档UTI
docx格式对应的UTI是com.microsoft.word.docx,原代码使用的com.microsoft.word.doc仅对应doc格式,会导致类型识别错误。
4. 补充Info.plist配置
确保Info.plist中同时启用以下配置:
<key>UIFileSharingEnabled</key> <true/> <key>LSSupportsOpeningDocumentsInPlace</key> <true/>
修改后的代码
public async Task SaveAndView(string filename, string contentType, MemoryStream stream) { string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); string filePath = Path.Combine(path, filename); // 将MemoryStream内容写入目标文件 using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write)) { stream.Position = 0; await stream.CopyToAsync(fileStream); } // 生成带权限的文件URL var fileUrl = NSUrl.CreateFileUrl(filePath, null); var uIDocumentInteractionController = UIDocumentInteractionController.FromUrl(fileUrl); // 设置正确的UTI(匹配docx格式) uIDocumentInteractionController.Uti = "com.microsoft.word.docx"; // 设置Delegate uIDocumentInteractionController.Delegate = new DocumentInteractionDelegate(); var presentingViewController = UIApplication.SharedApplication.KeyWindow.RootViewController; uIDocumentInteractionController.PresentOpenInMenu(CGRect.Empty, presentingViewController.View, true); } // 实现UIDocumentInteractionControllerDelegate public class DocumentInteractionDelegate : UIDocumentInteractionControllerDelegate { public override UIViewController ViewControllerForPreview(UIDocumentInteractionController controller) { return UIApplication.SharedApplication.KeyWindow.RootViewController; } public override UIView ViewForPreview(UIDocumentInteractionController controller) { return UIApplication.SharedApplication.KeyWindow.RootViewController.View; } }
内容的提问来源于stack exchange,提问作者Deon
相关产品推荐
相关产品推荐

