程序员iOS Developer

WKWebView的使用、优化和封装(VDWebView)

2018-12-22  本文已影响63人  volientDuan

VDWebView的源码和使用示例

VDWebView带来的便捷

CocoaPods

pod 'VDWebView', '~> 1.0.0'

基本描述

为什么使用WKWebView

提供了哪些更加熟悉和更加便捷的属性和方法

VDWebViewDelegate

/// 类UIWebView代理方法
- (void)webViewDidStartLoad:(VDWebView *)webView;
- (void)webViewDidFinishLoad:(VDWebView *)webView;
- (void)webView:(VDWebView *)webView didFailLoadWithError:(NSError *)error;
- (BOOL)webView:(VDWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
/**
 JS调原生代理方法(注册了过的方法将全部通过此方法回调)

 @param webView VDWebView
 @param message 回调消息
 */
- (void)webView:(VDWebView *)webView didReceiveScriptMessage:(WKScriptMessage *)message;

/**
 JS弹框拦截方法--如果需要自定义弹框建议声明此方法

 @param webView VDWebView
 @param type 弹框类型
 @param title 标题
 @param content 内容
 @param completionHandler 结果处理必须执行completionHandler(data)
 */
- (void)webView:(VDWebView *)webView showAlertWithType:(VDJSAlertType)type title:(NSString *)title content:(NSString *)content completionHandler:(void (^)(id))completionHandler;

新增了哪些属性和方法

///预估网页加载进度
@property (nonatomic, readonly) CGFloat estimatedProgress;
// 是否显示进度条 默认不显示
@property (nonatomic, assign) BOOL isShowProgressBar;
///进度条
@property (nonatomic, strong) UIView *progressBar;
/**
 web页面加载完毕后的内容高度(在页面加载完成后获取)
 */
@property (nonatomic, readonly) CGFloat *contentHeight;
/// 是否启用js调用原生弹框 默认为NO 禁止(默认加载弹框在根试图)
@property (nonatomic, assign) BOOL enableAllAlert;
@property (nonatomic, assign) BOOL enableAlert;
@property (nonatomic, assign) BOOL enableConfirm;
@property (nonatomic, assign) BOOL enablePrompt;

///back 层数
- (NSInteger)countOfHistory;
- (void)gobackWithStep:(NSInteger)step;

JS调用OC方法的绑定

在使用WKWebView时我们需要调用WKWebViewconfiguration中的userContentController所属类WKUserContentController提供的实例方法进行注册,具体方法如下:

- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;

对应的注销方法为:

- (void)removeScriptMessageHandlerForName:(NSString *)name;

已知的循环引用问题

在使用addScriptMessageHandler:name:方法注册时传入的这个handler被循环引用,如果不调用对应的注销方法就会导致handler这个对象无法被释放,如果你这个handler传入是webView所在的控制器,那么你就要在销毁这个控制器前注销掉你注册的方法.

tip: 如何知道控制器有没有被释放,重写dealloc(),没走此方法说明未被释放

VDWebView是如何解决循环引用问题

简要分析可分为下面三步

这些做的好处在于你在使用VDWebView时无需自己去一个个手动注销了(如果你注册的方法多的话那就是噩梦了)

VDWebView是如何进行方法的注册和回调的

- (void)addScriptMessageHandler:(id)scriptMessageHandler name:(NSString *)name;
// 没效果可使用try-catch
window.webkit.messageHandlers.#OC方法名#.postMessage(#参数#)

回调方式分两种:delegate和target-action; 两种方式只能存一,优先delegate

- (void)webView:(VDWebView *)webView didReceiveScriptMessage:(WKScriptMessage *)message;

为什么要增加target-action的方式

target-action:目标-动作模式,拜C语言所赐,更是灵活很多,编译期没有任何检查,都是运行时的绑定

JS的调用和注入

可通过两种方式进行JS方法的调用,推荐第一种

- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler;

- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)javaScriptString;

脚本的注入和移除

/**
 注入脚本(js...)

 @param source 注入的内容
 @param injectionTime 注入时间
 @param mainFrameOnly 只作用主框架
 */
- (void)addUserScriptWithSource:(NSString *)source injectionTime:(WKUserScriptInjectionTime)injectionTime forMainFrameOnly:(BOOL)mainFrameOnly;

/**
 移除所有注入的脚本
 */
- (void)removeAllUserScripts;

后续版本思考和设计中

尾声

愿意了解或者有任何疑问的欢迎指教,有何不足多多担待!

上一篇 下一篇

猜你喜欢

热点阅读