现在很多项目中都有嵌套H5,但有些功能让H5来做用户体验不是很好,那么这部分功能就需要使用js和客户端交互来完成 。最近开发了图片选择器提供给前端使用,在用户选择完图片后客户端将沙盒路径传给js,用于展示选中的图片。
/private/var/mobile/Containers/Data/Application/3861D884-D098-4F33-BA90-22BDF9D84F9B/Documents/chooseImages/5731BBA0-C6A2-48A4-94F7-A29A2A97F3DA.png
很显然前端不能加载沙盒路径的图片
那么如何让前端支持加载沙盒图片呢?
解决方法就是自定义协议,然后拦截实现协议以达到前端加载客户端本地图片的目的。
1、自定义CustomURLProtocol继承NSURLProtocol
#import "CustomURLProtocol.h"
@interface CustomURLProtocol(){
NSURLRequest *request;
}
@end
// 协议名
static NSString *const hasInitKey = @"webImage";
@implementation IRCCustomURLProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([request.URL.scheme caseInsensitiveCompare:hasInitKey] == NSOrderedSame) {
return YES;
}
return NO;
}
- (void)startLoading {
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil];
NSString *imgPath = [NSString stringWithFormat:@"%@%@", self.request.URL.host, self.request.URL.path];
NSData *data = [NSData dataWithContentsOfFile:imgPath];
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
NSLog(@"start loading !");
}
2、在AppDelegate中注册协议
[NSURLProtocol registerClass:[CustomURLProtocol class]];
3、前端加载图片
<img style="width: 100px;height:100px;" id="image" src="webImage://private/var/mobile/Containers/Data/Application/3861D884-D098-4F33-BA90-22BDF9D84F9B/Documents/chooseImages/5731BBA0-C6A2-48A4-94F7-A29A2A97F3DA.png" />
这种解决方法只在UIWebView中起作用,WKWebView在iOS 11之前是没有办法加载本地资源的。
WKWebView不支持NSURLProtocol如何解决?
通过查看WebKit源码发现在源码中存在注册自定义的方法只是没有开放,使用WKBrowsingContextController
类中的registerSchemeForCustomProtocol:
方法可以注册自定义协议,那么我们可以自定义一个Category来实现自定义协议注册,核心代码:
+ (void)wk_registerScheme:(NSString *)scheme {
Class cls = NSClassFromString(@"browsingContextController")
SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");
if ([(id)cls respondsToSelector:sel]) {
[(id)cls performSelector:sel withObject:scheme];
}
}
具体使用参考大牛的解决方法,传送门:WKURLSchemeHandler,有人反映使用私有API会APP Store被拒,项目中使用此方法目前成功上线。
iOS 11 新增WKURLSchemeHandler实现 (Swift)
import UIKit
import WebKit
class CustomWKURLSchemeHandler: NSObject, WKURLSchemeHandler, UINavigationControllerDelegate,UIImagePickerControllerDelegate {
var task: WKURLSchemeTask?
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
task = urlSchemeTask
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
let viewController = webView.next as! ViewController
viewController.present(picker, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
task = nil
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
guard let task = task else { return }
let image = info[.originalImage] as! UIImage
let data = image.pngData()
let response = URLResponse(url: task.request.url!, mimeType: "image/png", expectedContentLength: -1, textEncodingName: nil)
task.didReceive(response)
task.didReceive(data!)
task.didFinish()
}
}
let configuration = WKWebViewConfiguration()
configuration.setURLSchemeHandler(CustomWKURLSchemeHandler(), forURLScheme: "webImage")
let webView = WKWebView(frame: .zero, configuration: configuration)
let request = URLRequest(url: URL(string: "http://localhost:8080/b/file.html")!)
webView.load(request)
view = webView
<h2>这是一张图片</h2>
<img style="width: 200px;height:200px;" id="image1" src="" /><br/>
<button style="width: 200px;height:40px;" onclick="btnAction()">加载路径</button>
<script>
function btnAction() {
var imagePathStr = "webImage://imagePath.png";
document.getElementById("image1").src = imagePathStr;
alert(imagePathStr);
}
</script>
总结
- 相同路径的资源,代理或自定义协议只会执行一次,再次加载不会触发代理或自定义协议方法
网友评论