iOS 解决 [NSURL fileURLWithPath:] 对 # 的编码问题

avatar
奇舞团移动端团队 @奇舞团

级别:★☆☆☆☆
标签:「iOS URL编码」「URL # 变 %23」「URL # 无法访问」
作者: Xs·H
审校: QiShare团队


和读者们分享一个作者在项目中遇到的 URL 编码 # 号变 %23,无法加载的问题。

在某项目中,需要用 WKWebView 加载本地一个 html 文件,路径为:

Printing description of pagePath: /var/mobile/Containers/Data/Application/02EA4A1C-D15D-4B03-A12C-46F097F655E8/Documents/corp/7723038392975868/MiniApp/7723038392986376/page.html#/pages/home/index

加载代码如下:

NSURL *url = [NSURL fileURLWithPath:pagePath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];

运行代码后,发现 webView 并无法加载此文件。难道是路径本身有问题?于是作者将 page.html 依赖的资源在 Mac上准备好,然后在 Chrome 中实验了下,发现是可以访问的。

那难道是 webView 最终 loadURL 出了问题?于是作者开始断点调试。

  • 打印 pagepath 的结果:

Printing description of pagePath: /var/mobile/Containers/Data/Application/23A57DC2-7BAD-40C3-BDF8-AA8355284706/Documents/corp/7723038392975868/MiniApp/7723038392986376/page.html#/pages/home/index

  • 打印 url 的结果:

Printing description of url: file:///var/mobile/Containers/Data/Application/23A57DC2-7BAD-40C3-BDF8-AA8355284706/Documents/corp/7723038392975868/MiniApp/7723038392986376/page.html%23/pages/home/index

url 粘贴到 Chrome 中发现的确无法访问。经过仔细对比,发现 pagePath 中的 # 经过 [NSURL fileURLWithPath:] 后变成了 %23。猜测是 URL 编码的问题,于是使用以下代码尝试解决问题:

pagePath = [pagePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

然而,运行后发现并没有效果,# 依然被编码成了 %23。作者猜测是不是对 pagePath 使用的编码配置不对,于是又尝试了多种编码配置(包括从网上搜到的一些),但最终都是无效果。

作者开始怀疑是 webView 本身有问题,于是将 pagePathpage.html 后面的 #/pages/home/index 去掉后在 webView 中加载,发现能够加载。并且发现,在- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation 回调方法中 po 出的 URL 竟然是带有 #/pages/home/index 后缀的。如下:

Printing description of webView.URL: file:///var/mobile/Containers/Data/Application/23A57DC2-7BAD-40C3-BDF8-AA8355284706/Documents/corp/7723038392975868/MiniApp/7723038392986376/page.html#/pages/home/index

发现 page.html 内部逻辑使得自己在被访问后重定向了 page.html#/pages/home/index。这不是重点,但这却表明了 webView 本身没有问题,是支持 # 号字符的。那么问题还是出在了 # 变成 %23 的地方。

经过反复测试,作者发现 [NSURL fileURLWithPath:] 方法会把 pagePath 中的 # 变成 %23,而 [NSURL URLWithString:] 并不会。仔细测试和观察,后者的结果恒定比前者少了个 file:// 的前缀。这下好了,临时解决方案有了:

pagePath = [@"file://" stringByAppendingString:pagePath];
NSURL *url = [NSURL URLWithString:pagePath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];

运行代码,pagePath 可以被正常加载访问了。 作者总感觉这个解决方案有点“野”,但经过查阅资料,最终还是没有找到其他解决方案,就暂且如此吧。

关注我们的途径有:
QiShare(简书)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公众号)

Xcode 调整导航目录字体大小b
Swift 5.1 (21) - 泛型
Swift 5.1 (20) - 协议
Swift 5.1 (19) - 扩展
Swift 5.1 (18) - 嵌套类型
Swift 5.1 (17) - 类型转换与模式匹配
浅谈编译过程
深入理解HTTPS
浅谈 GPU 及 “App渲染流程”
iOS 查看及导出项目运行日志
Flutter Platform Channel 使用与源码分析
奇舞团安卓团队——aTaller
奇舞周刊