JavaScriptCoreSafari的一個JavaScript引擎,後在iOS7.0中被變成了iOS的一個框架,用作OC與JS之間的橋接,使得OC與JS交互更加方便簡單。 JavaScriptCoreDemo 咱們在
JavaScriptCore.h
中能夠看到以下五個類javascript
//提供OC與JS交互的上下文環境
#import "JSContext.h"
//JS的數據,通常是變量、對象和函數
#import "JSValue.h"
//管理JSValue的內存
#import "JSManagedValue.h"
//一個虛擬資源空間,裏面有着JSContext對象,各個JSContext對象可相互傳值
#import "JSVirtualMachine.h"
//這是一個協議,能夠經過這個協議實現用js調用OC的對象達到JS調用OC的效果
#import "JSExport.h"
複製代碼
先寫JS,直接看代碼。css
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<title>UIWebView中OC與JS交互</title>
</head>
<style type="text/css">
.button {
background: #f5be14;
margin: 10px;
text-align: center;
width: 300px;
height: 44px;
line-height: 44px;
margin: 10px auto;
border-radius: 5px;
}
#setImage {
width: 200px;
height: 200px;
margin: 0 auto;
}
#setText {
width: 200px;
height: 200px;
margin: 0 auto;
}
</style>
<body>
<div class="button" onclick="firstClick()">今晚打老虎</div>
<div class="button" onclick="secondClick()">請用力的點我</div>
<div class="button" onclick="thirdClick()">彈我彈我</div>
<div class="button" onclick="forthClick()">選擇圖片</div>
<div class="button" onclick="callOCToCallJSClick()">調用OC執行JS來鏈接兩個字符串</div>
<div id="setImage"></div>
<div id="setText"></div>
</body>
<script type="text/javascript">
var prefixStandard = "LFJSToOC://";
function getText(index) {
return document.getElementsByClassName("button")[index].innerText;
}
function firstClick() {
var action = "firstClick";
var token = getText(0);
alert(jsToOC_Object.getConnectText("我是唐伯虎", token));
}
function secondClick() {
var action = "secondClick";
var token = getText(1);
setUrl(action, token);
}
function thirdClick() {
var action = "thirdClick";
var token = getText(2);
setUrl(action, token);
}
function forthClick() {
var action = "forthClick";
var token = getText(3);
jsToOC_Object.getSystemImage();
}
function callOCToCallJSClick() {
var action = "callOCToCallJSClick";
var token = getText(4);
setUrl(action, token);
}
function setUrl(action, token) {
var url = prefixStandard + "/" + action + "/" + token;
//這個loadUrl就是調用OC的執行函數
loadUrl(url, action, token);
}
function showImageOnDiv(imageStr) {
var imgDiv = document.getElementById("setImage");
imgDiv.innerHTML = "<image style='width:200px;' src='data:image/png;base64,"+imageStr+"'>";
}
//OC調用JS的函數
function ocToJS(str1, str2) {
var str = str1 + " OCTOJS " + str2;
var textDiv = document.getElementById("setText");
textDiv.innerHTML = str;
}
</script>
</html>
複製代碼
實現的效果以下 html
咱們在webViewDidFinishLoad
代理方法中獲取JS的上下文JSContext。前端
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
self.title = title;
NSLog(@"webView加載完成");
//攔截JS的回調
JSContext *jsContext = self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
}
複製代碼
在JavaScriptCore中,JS調用OC能夠有兩種方式java
//js
loadUrl(url, action, token);
複製代碼
對應的OC代碼以下git
//注意:這裏面是子線程
jsContext[@"loadUrl"] = ^(JSValue *value, NSString *action, NSString *token) {
NSLog(@"value = %@", value);
NSLog(@"action = %@", action);
NSLog(@"token = %@", token);
dispatch_async(dispatch_get_main_queue(), ^{
SEL sel = NSSelectorFromString([NSString stringWithFormat:@"%@:", action]);
objc_msgSend(self, sel, token);
});
};
複製代碼
注意
:由於JSValue
對JSContext
是強引用的關係,因此咱們這裏要注意不能在block內使用外部的JSValue
對象,會形成循環引用。 JSValue
就是js的數據類型,咱們能夠根據本身的須要轉換成OC類型,JSValue
提供了相應的方法,github
- (BOOL)toBool;
- (double)toDouble;
- (int32_t)toInt32;
- (uint32_t)toUInt32;
- (NSNumber *)toNumber;
- (NSString *)toString;
- (NSDate *)toDate;
- (NSArray *)toArray;
- (NSDictionary *)toDictionary;
···
複製代碼
OC的數據類型也能夠傳喚成JSValue
web
+ (JSValue *)valueWithObject:(id)value inContext:(JSContext *)context;
+ (JSValue *)valueWithBool:(BOOL)value inContext:(JSContext *)context;
+ (JSValue *)valueWithDouble:(double)value inContext:(JSContext *)context;
+ (JSValue *)valueWithInt32:(int32_t)value inContext:(JSContext *)context;
+ (JSValue *)valueWithUInt32:(uint32_t)value inContext:(JSContext *)context;
···
複製代碼
js
jsToOC_Object.getConnectText("我是唐伯虎", token)
複製代碼
這個jsToOC_Object
是咱們在OC中建立的對象,getConnectText
是咱們在OC中實現的方法,上代碼數組
@protocol JSToOC_Protocol <JSExport, NSObject>
//打開系統相冊獲取圖片
- (void)getSystemImage;
//鏈接兩個字符串
JSExportAs(getConnectText,
- (NSString *)connetText1:(NSString *)str1 withText2:(NSString *)str2);
@end
@interface JSToOC_Object : NSObject <JSToOC_Protocol>
@property (nonatomic, weak) id<JSToOC_Protocol> delegate;
@end
@implementation JSToOC_Object
- (void)getSystemImage {
NSLog(@"JS調用了打開系統相冊, 這裏走的是子線程,若是對UI操做須要回到主線程");
dispatch_async(dispatch_get_main_queue(), ^{
if (self.delegate && [self.delegate respondsToSelector:@selector(getSystemImage)]) {
[self.delegate getSystemImage];
}
});
}
//鏈接字符串1和字符串2
- (NSString *)connetText1:(NSString *)str1 withText2:(NSString *)str2 {
NSString *connectText = [NSString stringWithFormat:@"%@,我選擇%@", str1, str2];
return connectText;
}
@end
複製代碼
如代碼所示,須要定義一個遵照JSExport
的協議,這個協議裏面實現的方法就是能夠供js直接調用的方法,這裏面能夠不用JSExportAs
也能直接使用。 而後咱們須要在webViewDidFinishLoad
代理裏面告訴JSContext咱們有這麼一個對象專門供js調用OC方法的。bash
JSToOC_Object *jsToOC_Object = [JSToOC_Object new];
//把OC的JSToOC_Object對象傳遞給JS,供JS調用OC方法
jsContext[@"jsToOC_Object"] = jsToOC_Object;
複製代碼
JS調用OC後,OC的響應也相對應的有block和JSExport兩種方式,他們有個共同點須要注意,回調都是在子線程裏。 作完這些,之後只要和前端定義方法名和參數,就能隨時調用了。
stringByEvaluatingJavaScriptFromString
evaluateScript
[self.jsContext evaluateScript:@"showMessage()"];
複製代碼
callWithArguments:(NSArray *)arguments;
方法,數組裏面是按順序傳的參數NSString *str1 = @"OC調用JS鏈接兩個字符串";
NSString *str2 = @"試試好很差用";
[self.jsContext[@"ocToJS"] callWithArguments:@[str1, str2]];
複製代碼
效果以下
綜上就是JavaScriptCore的基本使用,由於iOS12之後蘋果就大力推WKWebView了,因此重心仍是要放在WK上,共勉。