WKWebView 与 Vue 桥接

809 阅读4分钟

笔者刚开始学习 Vue,为了熟悉 Vue 和 iOS 的桥接及回调的交互,写了以下文章来了解一下 Vue 如何和 iOS 进行桥接交互传参

iOS 项目

一. 初始化创建 WKWebView 容器

目前iOS给前端提供的容器,均依赖于 WKWebView,以下实现方式是根据 WKWebView 自身的 handerMessage 来和前端建立通信。

浅解 WKWebView 的系统API

1. WKWebViewConfiguration

/*! 
@abstract A copy of the configuration with which the web view was

initialized. 
*/

@property (nonatomic, readonly, copy) WKWebViewConfiguration *configuration;

WKWebViewConfiguration 主要为了添加 WKWebview 配置信息

2. WKUserScript 用于进行JavaScript注入

/*! 
A @link WKUserScript @/link object represents a script that can be injected into webpages.

 */

WKUserScript:用于进行 JavaScript 注入

3. WKUserContentController

/*! 
A WKUserContentController object provides a way for JavaScript to post

messages to a web view.

The user content controller associated with a web view is specified by its

web view configuration.
 */

WKUserContentController:这个类主要用来做 native 与 JavaScript 的交互管理, 用来处理 iOS 和前端的桥接方法触发响应

// 这个类主要用来做native与JavaScript的交互管理

WKUserContentController * userController = [[WKUserContentController alloc] init];

// 注册一个name为jsToOcNoPrams的js方法 设置处理接收JS方法的对象
// 此方法 webViewApp 即和前端约定好的,handerMessage 方法名
[userController addScriptMessageHandler:scriptMessageDelegate  name:@"webViewApp"];

4. WKScriptMessageHandler

WKScriptMessageHandler:这个协议类专门用来处理监听 JavaScript 方法从而调用原生 OC 方法,和 WKUserContentController 搭配使用。

/*! A class conforming to the WKScriptMessageHandler protocol provides a

 method for receiving messages from JavaScript running in a webpage.

 */

二. WKWebView 的 WKNavigationDelegate 及 WKUIDelegate 代理方法

1. WKNavigationDelegate 主要处理一些跳转、加载处理操作

// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
}

// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
} 

// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
}

// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
}

//提交发生错误时调用
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    [self.progressView setProgress:0.0f animated:NO];
}  

// 接收到服务器跳转请求即服务重定向时之后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
}
    
// 根据WebView对于即将跳转的HTTP请求头信息和相关信息来决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
}
    
// 根据客户端受到的服务器响应头以及response相关信息来决定是否可以跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
}

//进程被终止时调用
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{
}

2. WKUIDelegate :主要处理JS脚本,确认框,警告框等

/**
 *  web界面中有弹出警告框时调用
 *  @param webView           实现该代理的webview
 *  @param message           警告框中的内容
 *  @param completionHandler 警告框消失调用
 */

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {}

// 确认框
// JavaScript调用confirm方法后回调的方法 confirm是js中的确定框,需要在block中把用户选择的情况传递进去
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{}

// 输入框
// JavaScript调用prompt方法后回调的方法 prompt是js中的输入框 需要在block中把用户输入的信息传入
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{}

// 页面是弹出窗口 _blank 处理
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {}

3. 监听网页加载进度progress 及网页的 title

estimatedProgress 用来监听网页加载进度,自定义 progress 来显示网页的加载进度条,提升使用体验。

添加

// 监听加载进度
[_mainWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];

// 添加监测网页标题title的观察者
[_mainWebView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];

移除

- (void)dealloc {
    // 移除观察者
    [self.mainWebView removeObserver:self forKeyPath:@"estimatedProgress"];
    [self.mainWebView removeObserver:self forKeyPath:@"title"];
}

至此,一个默认的 WKWebView 容器创建好了。

Vue 项目

一. 使用 Vue CLI 初始化创建一个 vue2 版本的默认项目

启动终端

cd Desktop 

vue create vue_demo

-- -- -- 
创建成功后,npm run serve,启动服务,加载本地服务的 ip 地址,http://--.---.--.---:8080/ 在 刚创建的 iOS 容器内 已经可以显示 Vue 页面了

二. 前端 与 iOS 交互

1. 建立通信桥接通道, iOS 调用实现 Vue 的方法

iOS 端代码

// 注册一个 name 为 webViewApp 的 JS 方法 处理接收 JS 方法的对象
[userController addScriptMessageHandler:scriptMessageDelegate  name:@"webViewApp"];

image.png

Vue 端代码

// 直接调用 window 方法即可,webViewApp 为前端和原生那边统一定义的 方法名
window.webkit.messageHandlers.webViewApp.postMessage

image.png

2. iOS 传值给前端

统一定义了一个回调接收的方法 iosCallback,可实现 iOS 传值给前端,客户端可以拿到前端body传参JSON里面的方法名,去实现对应的功能

原生代码实现看下面截图

image.png


前端给客户端传参可以为字符串、对象、JSON.stringify字符串

Vue 代码实现看下面截图, 一般我们会在 body 里面传 action:方法名,iOS那边拿到这个方法名,去实现对应的功能。

image.png


iOS 传值给前端有个需要注意的点

如果直接传值字符串的话,使用以下方式
// js 接收
直接输出 value即可。

如果iOS传值的是UTF8JSON字符串的话
NSString *ocDataStr = [NSString 
console.log("得到原生传值结果:" + JSON.stringify(value));