iOS中远程JavaScript获取本地资源的解决方案咨询
iOS端实现远程网页加载本地资源方案
核心思路
iOS的WKWebView默认限制远程页面直接访问本地file://协议资源,我们可以通过自定义URL Scheme + WKURLSchemeHandler的方式,拦截自定义Scheme的请求,读取本地资源并返回给WebView,实现和Android WebViewAssetLoader类似的功能。
具体实现步骤
1. 修改网页JS代码,替换资源路径
将原代码中的file:///IOSLOCALASSET替换为自定义Scheme(例如ios-local-asset),修改后的JS代码如下:
<script type="text/javascript"> let gbvar = new Object(); //globalVariable gbvar.device = "ios"; //device 정보 if(gbvar.device == "ios"){ document.write("<script type='text/javascript' src='ios-local-asset://resources/js/jquery-3.4.1.min.js' ></script>"); document.write("<script type='text/javascript' src='ios-local-asset://resources/js/jquery-ui.js' ></script>"); } </script>
2. 实现WKURLSchemeHandler协议,处理自定义Scheme请求
创建一个类实现WKURLSchemeHandler协议,负责拦截自定义Scheme的请求,读取本地资源并响应WebView:
import WebKit class LocalAssetSchemeHandler: NSObject, WKURLSchemeHandler { func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { guard let url = urlSchemeTask.request.url, url.scheme == "ios-local-asset" else { urlSchemeTask.didFailWithError(NSError(domain: "LocalAssetError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的Scheme"])) return } // 拼接本地资源路径(假设资源放在主Bundle的Resources目录下) let pathComponents = url.pathComponents.dropFirst() // 移除路径开头的/ let resourcePath = pathComponents.joined(separator: "/") guard let localFilePath = Bundle.main.path(forResource: resourcePath, ofType: nil) else { urlSchemeTask.didFailWithError(NSError(domain: "LocalAssetError", code: -2, userInfo: [NSLocalizedDescriptionKey: "未找到指定资源"])) return } do { let data = try Data(contentsOf: URL(fileURLWithPath: localFilePath)) // 根据文件类型设置对应的Content-Type let mimeType = getMimeType(for: localFilePath) let response = URLResponse(url: url, mimeType: mimeType, expectedContentLength: data.count, textEncodingName: nil) urlSchemeTask.didReceive(response) urlSchemeTask.didReceive(data) urlSchemeTask.didFinish() } catch { urlSchemeTask.didFailWithError(error) } } func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) { // 按需处理任务取消逻辑 } // 根据文件路径获取对应MIME类型的辅助方法 private func getMimeType(for path: String) -> String { let ext = (path as NSString).pathExtension.lowercased() switch ext { case "js": return "application/javascript" case "css": return "text/css" case "ttf", "otf", "woff", "woff2": return "font/truetype" case "png": return "image/png" case "jpg", "jpeg": return "image/jpeg" default: return "application/octet-stream" } } }
3. 配置WKWebView并注册Scheme Handler
在初始化WKWebView时,将自定义Scheme的处理器注册到配置中:
import WebKit class ViewController: UIViewController, WKNavigationDelegate { private var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() let configuration = WKWebViewConfiguration() // 注册自定义Scheme的处理器 let schemeHandler = LocalAssetSchemeHandler() configuration.setURLSchemeHandler(schemeHandler, forURLScheme: "ios-local-asset") // 创建并添加WKWebView到视图 webView = WKWebView(frame: view.bounds, configuration: configuration) webView.navigationDelegate = self view.addSubview(webView) // 加载目标远程网页 if let targetURL = URL(string: "https://your-remote-page-url.com") { webView.load(URLRequest(url: targetURL)) } } }
4. 本地资源放置注意事项
- 将需要加载的本地资源(如JS、字体文件)添加到Xcode项目中,确保勾选对应的Target,并在
Build Phases的Copy Bundle Resources列表中能看到这些文件。 - 保持本地资源的文件夹层级和网页中指定的路径一致(比如网页中是
resources/js/xxx.js,本地就要对应创建resources/js文件夹并放入文件)。
关键说明
- 自定义Scheme方案可以规避WKWebView对远程页面访问
file://资源的跨域限制,是iOS 11及以上版本的推荐方案。 - 若需兼容iOS 10及以下版本,可考虑通过
WKUserScript将本地资源内容直接注入到页面中,但灵活性不如Scheme Handler方案。
内容的提问来源于stack exchange,提问作者user9281840
相关产品推荐
相关产品推荐

