前言
最近有朋友問我OC和JS交互的問題迷帜,我又翻開看了一下之前的代碼迹鹅,發(fā)現(xiàn)了一個(gè)對jscore理解非常方便的方法,分享給大家。這篇文章我主要講js調(diào)用OC贯溅,OC調(diào)用js不在該范圍內(nèi)
JavaScriptCore做OC交互的方法
主要分為兩種:
- 使用block在js代碼里注入方法
- 使用JSExport協(xié)議在js代碼里注入一個(gè)對象
方法一
使用Block
OC代碼:
controller.m
- (void)webViewDidFinishLoad:(UIWebView *)webView {
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"testClick"] = ^(NSString * p1, NSString * p2) {
NSLog(@"p1:%@, p2:%@", p1, p2);
};
}
- 這里我在
- (void)webViewDidFinishLoad:(UIWebView *)webView
webview的加載結(jié)束代理方法中調(diào)用了JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
拿到上下文。 - 然后給JSContext上下文添加了
testClick
block啄育,這個(gè)block有兩個(gè)參數(shù)。
JS代碼:
<html>
<head>
<script>
function func3Click() {
testClick("參數(shù)一", "參數(shù)二");
}
</script>
</head>
<body>
<button onclick="func3Click()">button3</button>
</body>
</html>
- 在js代碼中大家可以注意到testClick
("參數(shù)一", "參數(shù)二");
對應(yīng)的是OC中的context[@"
testClick"] = ^(NSStri ...
拌消。這樣就完成了js和OC的交互挑豌。
方法二
使用JSExport協(xié)議
OC代碼:
JSHandler.h
@import JavaScriptCore;
@protocol JSHandlerDelegate <JSExport>
- (void)twoparamWithOne:(NSString *)p1 two:(NSString *)p2;
@end
@interface JSHandler : NSObject<JSHandlerDelegate>
@end
JSHandler.m
@implementation JSHandler
- (void)twoparamWithOne:(NSString *)p1 two:(NSString *)p2 {
NSLog(@"p1:%@, p2:%@", p1, p2);
}
@end
controller.m
- (void)webViewDidFinishLoad:(UIWebView *)webView {
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
JSHandler * handler = [[JSHandler alloc] init];
context[@"abchaha"] = handler;
}
我將關(guān)鍵代碼抽離了出來
- 我創(chuàng)建了一個(gè)
JSHandler
類,該類有一個(gè)- (void)twoparamWithOne:(NSString *)p1 two:(NSString *)p2
的方法墩崩,用來供js調(diào)用氓英。 - 在我的controller中有一個(gè)webview,
- (void)webViewDidFinishLoad:(UIWebView *)webView
是webview的加載結(jié)束代理方法泰鸡。我該方法中通過[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
拿到方法拿到j(luò)score的上下文變量(用來操作js)债蓝。 - 用
contextp[@"abchaha"] = handler
壳鹤,來將我創(chuàng)建的JSContext
對象傳給jscore盛龄,這樣在js里就可以使用abchaha
這個(gè)變量來調(diào)用JSHandler的協(xié)議里聲明的方法了。下面我們來看看JS部分的代碼。
JS代碼:
<html>
<head>
<script>
function func3Click() {
abchaha.twoparamWithOneTwo("參數(shù)一", "參數(shù)二");
}
</script>
</head>
<body>
<button onclick="func3Click()">button3</button>
</body>
</html>
注意這里abchaha.twoparamWithOneTwo("參數(shù)一", "參數(shù)二");
這行是關(guān)鍵代碼余舶。
- 大家可以看到啊鸭,OC中
contextp[@"
abchaha"] = handler
的key對應(yīng)了js中abchaha.twoparamWithOneTwo("參數(shù)一", "參數(shù)二");
- OC協(xié)議中的方法
- (void)
twoparamWithOne:(NSString *)p1
two:(NSString *)p2;
,對應(yīng)了js中的twoparamWithOne Two("參數(shù)一", "參數(shù)二");
匿值,在js中使用駝峰原則就可以調(diào)用到OC協(xié)議中的方法赠制。
JavaScriptCore在干什么
上述兩個(gè)方法方法一明顯比方法二要簡單的多,但其實(shí)不知道大家有沒有發(fā)現(xiàn)一個(gè)規(guī)律挟憔。那就是他們都是使用documentView.webView.mainFrame.javaScriptContext
拿到了JSContext
上下文钟些,我們可以用這個(gè)JSContext
使用[]
給他設(shè)置字段。
其實(shí)可以這樣理解绊谭。下面我用js和oc對應(yīng)的代碼來做一下我的理解政恍。
方法一
- 當(dāng)我們的webview代理里什么都沒寫的時(shí)候,是這樣的达传。
JS
OC
- 當(dāng)我們在webview代理里使用
context[@"abchaha"] = handler;
設(shè)置實(shí)現(xiàn)JSExport
協(xié)議的類的對象時(shí)篙耗,是這樣的。
JS
var abchaha = 實(shí)現(xiàn)JSExport的對象;
OC
id <繼承JSExport的協(xié)議> abchaha = 實(shí)現(xiàn)JSExport的對象;
- 當(dāng)我們在JS里調(diào)用
abchaha.twoparamWithOneTwo("參數(shù)一", "參數(shù)二");
的時(shí)候宪赶,是這樣的宗弯。
JS
var abchaha = 實(shí)現(xiàn)JSExport的對象;
abchaha.twoparamWithOneTwo("參數(shù)一", "參數(shù)二");
OC
id <繼承JSExport的協(xié)議> abchaha = 實(shí)現(xiàn)JSExport的對象;
[abchaha twoparamWithOne:@"參數(shù)一" two:@"參數(shù)二"];
方法二
什么都沒寫的時(shí)候就不展示了,就是NoCode搂妻。
當(dāng)我們在webview代理里使用
context[@"testClick"] = ^(NSStri ...
設(shè)置Block的時(shí)候蒙保,是這樣的。
JS
var testClick = (var p1){
...
}
OC
void(^ testClick)(NSString * p1, NSString * p2) = ^() {
...
};
- 當(dāng)我們在JS里調(diào)用
abchaha.twoparamWithOneTwo("參數(shù)一", "參數(shù)二");
的時(shí)候欲主,是這樣的追他。
JS
var testClick = (var p1) {
...
}
testClick("參數(shù)一", "參數(shù)二");
OC
void(^ testClick)(NSString * p1, NSString * p2) = ^() {
...
};
testClick(@"參數(shù)一", @"參數(shù)二");
總結(jié)
其實(shí)方法一和方法二都是拿到JSContext對象以后,給它設(shè)置變量岛蚤,你可以理解為在往js里寫代碼邑狸。
方法一是給了js一個(gè)我們聲明好協(xié)議的對象,讓js可以直接調(diào)用對象協(xié)議中的方法涤妒。而方法二是給js設(shè)置了一個(gè)閉包(block)讓js可以回調(diào)我們的方法单雾。
我甚至可以使用context[@"
aStr"] = @"哈哈哈";
直接給js設(shè)置一個(gè)字符串,然后在js中使用alert(
aStr);
來彈出它她紫。
至此硅堆,我建議大家可以把JSContext
按它的本意來理解,這個(gè)JSContext就是拿到js上下文贿讹,然后給js代碼通過[]
來設(shè)置變量渐逃。