.NET MAUI iOS端使用PDF.js加载AppData目录PDF文件失败
.NET MAUI iOS中PDF.js加载AppData目录PDF失败的解决方案
问题场景
在.NET MAUI iOS应用中,使用PDF.js的viewer.html加载AppData目录中的PDF文件时,仅显示工具栏但文档内容为空。直接用WebView加载PDF绝对路径可正常显示,Android端加载也正常,仅iOS端出现问题;加载应用包内的测试PDF则能正常显示。
核心原因
iOS的WKWebView对file://协议的跨源访问有严格限制:应用包内的资源(路径前缀为file:///var/containers/Bundle/...)和AppData目录的资源(路径前缀为file:///private/var/mobile/Containers/Data/...)属于不同的文件域,默认禁止跨域访问,导致PDF.js无法加载跨域的本地PDF文件。
解决方案1:调整WKWebView配置+路径编码
步骤1:完善WKWebView权限配置
修改WebViewHandler的映射代码,添加跨域访问本地文件的权限:
Microsoft.Maui.Handlers.WebViewHandler.Mapper.AppendToMapping("newPdfView", (handler, view) => { #if ANDROID handler.PlatformView.Settings.JavaScriptEnabled = true; handler.PlatformView.Settings.AllowFileAccess = true; handler.PlatformView.Settings.AllowFileAccessFromFileURLs = true; handler.PlatformView.Settings.AllowUniversalAccessFromFileURLs = true; #else if (handler.PlatformView is WebKit.WKWebView wkWebView) { wkWebView.Configuration.Preferences.SetValueForKey(Foundation.NSObject.FromObject(true), new Foundation.NSString("allowFileAccessFromFileURLs")); // 添加允许跨域访问本地文件的配置 wkWebView.Configuration.Preferences.SetValueForKey(Foundation.NSObject.FromObject(true), new Foundation.NSString("allowUniversalAccessFromFileURLs")); } #endif });
步骤2:对PDF路径进行合法URL编码
避免路径中的特殊字符(如空格、中文)导致URL解析失败,通过Uri对象生成标准的file://链接:
#if IOS var pdfFilePath = Foundation.NSBundle.MainBundle.PathForResource("pdfjs/web/viewer", "html"); // 获取AppData中PDF的完整路径 string pdfFullPath = Path.Combine(FileSystem.Current.AppDataDirectory, "Cataloghi", pdf.Descrizione + ".pdf"); // 生成合法的file://格式URL Uri pdfUri = new Uri(pdfFullPath); string encodedPdfUrl = pdfUri.AbsoluteUri; // 拼接viewer.html的访问路径 string path = $"file://{pdfFilePath}?file={encodedPdfUrl}"; newPdfView.Source = new UrlWebViewSource{ Url = path}; #elif ANDROID newPdfView.Source = $"file:///android_asset/pdfjs/web/viewer.html?file=file:{WebUtility.UrlEncode(Path.Combine(FileSystem.AppDataDirectory, "Cataloghi", pdf.Descrizione + ".pdf"))}"; #endif
解决方案2:将PDF.js资源复制到AppData目录
把应用包内的PDF.js相关文件(viewer.html、viewer.js、viewer.css及依赖资源)复制到AppData目录,让viewer和PDF处于同一文件域,彻底解决跨域问题:
#if IOS // 定义PDF.js资源的源目录和目标目录 string viewerAssetDir = Path.Combine(Foundation.NSBundle.MainBundle.BundlePath, "pdfjs", "web"); string viewerTargetDir = Path.Combine(FileSystem.Current.AppDataDirectory, "pdfjs", "web"); // 复制整个web目录(包含所有PDF.js依赖资源) if (!Directory.Exists(viewerTargetDir)) { Directory.CreateDirectory(viewerTargetDir); // 复制文件 foreach (var file in Directory.GetFiles(viewerAssetDir)) { string destFile = Path.Combine(viewerTargetDir, Path.GetFileName(file)); if (!File.Exists(destFile)) File.Copy(file, destFile); } // 复制子目录(如images、locale等) foreach (var dir in Directory.GetDirectories(viewerAssetDir)) { string destDir = Path.Combine(viewerTargetDir, Path.GetFileName(dir)); if (!Directory.Exists(destDir)) { Directory.CreateDirectory(destDir); foreach (var file in Directory.GetFiles(dir)) { string destFile = Path.Combine(destDir, Path.GetFileName(file)); if (!File.Exists(destFile)) File.Copy(file, destFile); } } } } // 加载AppData目录下的viewer.html string viewerTargetPath = Path.Combine(viewerTargetDir, "viewer.html"); string pdfFullPath = Path.Combine(FileSystem.Current.AppDataDirectory, "Cataloghi", pdf.Descrizione + ".pdf"); Uri pdfUri = new Uri(pdfFullPath); string path = $"file://{viewerTargetPath}?file={pdfUri.AbsoluteUri}"; newPdfView.Source = new UrlWebViewSource{ Url = path}; #endif
解决方案3:修改PDF.js的viewer.js(可选)
如果不想移动PDF.js资源,可以修改viewer.js中的跨域检查逻辑:
打开pdfjs/web/viewer.js,找到以下代码块(通常在文件开头):
if (origin !== viewerOrigin && protocol !== "blob:") { throw new Error("file origin does not match viewer's"); }
注释或删除这段代码,允许PDF.js加载不同域的本地文件。注意:这种方式可能存在安全风险,仅在信任本地文件来源的场景使用。
内容的提问来源于stack exchange,提问作者Davide Zonta
相关产品推荐
相关产品推荐

