在iOS應用的開發(fā)過程中,我們經(jīng)常會使用到WebView,當我們對WebView進行操作的時候,有時會需要進行源生的操作.那么我記下來就與大家分享一下OC與JS交互.
首先先說第一種方法,并沒有牽扯OC與JS交互,只是做攔截和跳轉(zhuǎn).
攔截跳轉(zhuǎn)的URL,跳轉(zhuǎn)源生界面(用起來感覺怪怪的,萬一URL更換了怎么辦.)
UIWebView
//UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *url = request.URL.absoluteString;
if ([url rangeOfString:@"需要跳轉(zhuǎn)源生界面的URL判斷"].location != NSNotFound) {
//跳轉(zhuǎn)原生界面
return NO;
}
return YES;
}
WKWebView
//使用WKWebview需要導入WebKit
#import <WebKit/WebKit.h>
//WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSString *url = navigationAction.request.URL.absoluteString;
if ([url rangeOfString:@"需要跳轉(zhuǎn)源生界面的URL判斷"].location != NSNotFound) {
//跳轉(zhuǎn)原生界面
//Cancel the navigation
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
----------?↓↓↓↓↓↓?----------
OC與JS交互(WebView監(jiān)聽事件)
正入主題.
一.OC調(diào)用JS
1.UIWebView
①直接運行
NSString *jsStr = @"執(zhí)行的JS代碼";
[webView stringByEvaluatingJavaScriptFromString:jsStr];
②使用JavaScriptCore框架
#import <JavaScriptCore/JavaScriptCore.h>
- (void)webViewDidFinishLoad:(UIWebView *)webView {
//獲取webview中的JS內(nèi)容
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
NSString *runJS = @"執(zhí)行的JS代碼";
//準備執(zhí)行的JS代碼
[context evaluateScript:runJS];
}
2.WKWebView
[webView evaluateJavaScript:@"執(zhí)行的JS代碼" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
}];
二.JS調(diào)用OC ??????
當網(wǎng)頁觸發(fā)某種操作,可以給App傳遞消息.比如WebView中購買某樣東西,點擊購買,需要獲取這件商品的訂單信息,并且需要App進行源生的支付.
這種方法需要你和后臺或者前端協(xié)商好一下,讓他們在執(zhí)行JS方法的時候,將你需要的數(shù)據(jù)放到你能拿到的位置.
下面簡單貼一個HTML文件.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>App與WebView交互</title>
</head>
<body>
<button style="width: 100%; height: 100px;" onclick="buttonClick()">點擊購買</button>
</body>
<script>
//按鈕點擊事件
function buttonClick() {
//傳遞的信息
var jsonStr = '{"id":"666", "message":"我是傳遞的數(shù)據(jù)"}';
//UIWebView使用
getMessage(jsonStr);
//WKWebView使用
//使用下方方法,會報錯,為使界面執(zhí)行邏輯通暢,因此使用try-catch
try {
window.webkit.messageHandlers.getMessage.postMessage(jsonStr)
} catch(error) {
console.log(error)
}
}
function getMessage(json){
//空方法
}
</script>
</html>
window.webkit.messageHandlers.<方法名>.postMessage(<數(shù)據(jù)>)
JS端寫此方法的盆友可能會報錯,導致界面邏輯無法進行,因此使用try-catch就好了.
我在網(wǎng)頁上只寫了一個按鈕.點擊按鈕,會觸發(fā)buttonClick()
方法.
UIWebView
在網(wǎng)頁加載完成的時候檢測JS方法執(zhí)行.
- (void)webViewDidFinishLoad:(UIWebView *)webView {
//核心方法如下
JSContext *content = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//此處的getMessage和JS方法中的getMessage名稱一致.
content[@"getMessage"] = ^() {
NSArray *arguments = [JSContext currentArguments];
for (JSValue *jsValue in arguments) {
NSLog(@"=======%@",jsValue);
}
};
}
由上方方法,當JS方法getMessage()
執(zhí)行的時候,此方法回調(diào)的jsValue內(nèi)容就是我們需要的內(nèi)容.(HTML中JS傳遞的數(shù)據(jù))
WebView中的getMessage與HTML文件JS方法的getMessage名稱需保持一致.
WKWebView
實現(xiàn)WKScriptMessageHandler
的代理方法.
//設置addScriptMessageHandler與JS對應方法名.并且設置<WKScriptMessageHandler>協(xié)議與協(xié)議方法
[[_webView configuration].userContentController addScriptMessageHandler:self name:@"getMessage"];
//WKScriptMessageHandler協(xié)議方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
//code
NSLog(@"name = %@, body = %@", message.name, message.body);
}
上方
-addScriptMessageHandler:name:
方法中name
填寫的方法名必須與window.webkit.messageHandlers.<方法名>.postMessage(<數(shù)據(jù)>)
中的方法名一致.
當JS端執(zhí)行window.webkit.messageHandlers.<方法名>.postMessage(<數(shù)據(jù)>)
.
此協(xié)議方法就會被執(zhí)行.,根據(jù)message.name
判斷一下自己需要執(zhí)行哪步操作.message.body
即是傳輸?shù)膮?shù)信息.(HTML中JS傳遞的數(shù)據(jù))
WKWebView 內(nèi)存泄露
但是這樣WebView所在的ViewController的- (void)dealloc{}
不執(zhí)行.那么內(nèi)存又有問提了.
可以另外創(chuàng)建一個代理對象,然后通過代理對象回調(diào)指定的self.
//.h
@interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>
@property (nonatomic, assign) id<WKScriptMessageHandler> scriptDelegate;
- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;
@end
//.m
@implementation WeakScriptMessageDelegate
- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
self = [super init];
if (self) {
_scriptDelegate = scriptDelegate;
}
return self;
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
[self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}
@end
設置代理
[[_webView configuration].userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"方法名"];
WebView的ViewController的- (void)dealloc{}
方法中進行銷毀.
- (void)dealloc {
...
[[_webView configuration].userContentController removeScriptMessageHandlerForName:@"方法名"];
...
}
----------END
當然,安卓開發(fā)的盆友也是可以通過這種方式從中獲取網(wǎng)頁的數(shù)據(jù)的.安卓注入的接口名稱在JS中也是會報錯的.因此也需要try-catch.
好了.以上就是與大家分享的OC與JS交互(WebView監(jiān)聽事件).有不足之處還請各位大佬指出.萬分感激~