完全抄錄:
iOS中UIWebView與WKWebView、JavaScript與OC交互榨汤、Cookie管理看我就夠(上)
深入淺出 JavaScriptCore
JavaScriptCore框架詳解
UIWebView OC調(diào)用JS
1蠕搜、stringByEvaluatingJavaScriptFromString
/*缺點
1、所以無法判斷是否調(diào)用成功收壕,失敗返回nil讥脐,js本身方法返回是nil
2、返回值是NSString啼器,其他類型數(shù)據(jù)需要轉換解析
*/
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
self.navigationItem.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
- JavaScriptCore(iOS 7.0 +)
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
//更新標題旬渠,這是上面的講過的方法
//self.navigationItem.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
//獲取該UIWebView的javascript上下文
JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//這也是一種獲取標題的方法。
JSValue *value = [self.jsContext evaluateScript:@"document.title"];
//更新標題
self.navigationItem.title = value.toString;
}
//在調(diào)用前端壳,設置異掣娑回調(diào)
[self.jsContext setExceptionHandler:^(JSContext *context, JSValue *exception){
NSLog(@"%@", exception);
}];
//執(zhí)行方法
JSValue *value = [self.jsContext evaluateScript:@"document.titlexxxx"];
UIWebView JS調(diào)用OC
- Custom URL Scheme(攔截URL)
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//標準的URL包含scheme、host损谦、port岖免、path、query照捡、fragment等
NSURL *URL = request.URL;
if ([URL.scheme isEqualToString:@"darkangel"]) {
if ([URL.host isEqualToString:@"smsLogin"]) {
NSLog(@"短信驗證碼登錄颅湘,參數(shù)為 %@", URL.query);
return NO;// NO(阻止本次跳轉)
}
}
return YES;
}
優(yōu)點:泛用性強,可以配合h5實現(xiàn)頁面動態(tài)化栗精。比如頁面中一個活動鏈接到活動詳情頁闯参,當native尚未開發(fā)完畢時,鏈接可以是一個h5鏈接悲立,等到native開發(fā)完畢時鹿寨,可以通過該方法跳轉到native頁面,實現(xiàn)頁面動態(tài)化薪夕。且該方案適用于Android和iOS脚草,泛用性很強。
缺點:無法直接獲取本次交互的返回值原献,比較適合單向傳參馏慨,且不關心回調(diào)的情景埂淮,比如h5頁面跳轉到native頁面等。
- JavaScriptCore(iOS 7.0 +)
OC現(xiàn)實JS的方法
JS代碼
function share(title, imgUrl, link) {
//這里需要OC實現(xiàn)
}
OC代碼
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
//將js的function映射到OC的方法
[self convertJSFunctionsToOCMethods];
}
- (void)convertJSFunctionsToOCMethods
{
//獲取該UIWebview的javascript上下文
//self持有jsContext
self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//js調(diào)用oc
//其中share就是js的方法名稱写隶,賦給是一個block 里面是oc代碼
//此方法最終將打印出所有接收到的參數(shù)倔撞,js參數(shù)是不固定的
// ja的"share",有則替換樟澜,無則添加。
self.jsContext[@"share"] = ^() {
NSArray *args = [JSContext currentArguments];//獲取到share里的所有參數(shù)
//args中的元素是JSValue叮盘,需要轉成OC的對象
NSMutableArray *messages = [NSMutableArray array];
for (JSValue *obj in args) {
[messages addObject:[obj toObject]];
}
NSLog(@"點擊分享js傳回的參數(shù):\n%@", messages);
};
}
一個有兩個參數(shù)秩贰,一個返回值的js方法
JS
//該方法傳入兩個整數(shù),求和柔吼,并返回結果
function testAddMethod(a, b) {
//需要OC實現(xiàn)a+b毒费,并返回
return a + b;
}
console.log(testAddMethod(1, 5)); //output 6
OC直接替換該方法
self.jsContext[@"testAddMethod"] = ^NSInteger(NSInteger a, NSInteger b) {
return a + b;
};
JS調(diào)用
console.log(testAddMethod(1, 5)); //output 6, 方法為 a + b
OC替換該方法為兩數(shù)相乘
self.jsContext[@"testAddMethod"] = ^NSInteger(NSInteger a, NSInteger b) {
return a * b;
};
JS調(diào)用
console.log(testAddMethod(1, 5)); //output 5愈魏,該方法變?yōu)榱?a * b觅玻。
OC調(diào)用方法原實現(xiàn),并且在原結果上乘以10
//調(diào)用方法的本來實現(xiàn)培漏,給原結果乘以10
JSValue *value = self.jsContext[@"testAddMethod"];
self.jsContext[@"testAddMethod"] = ^NSInteger(NSInteger a, NSInteger b) {
JSValue *resultValue = [value callWithArguments:[JSContext currentArguments]];
return resultValue.toInt32 * 10;
};
JS調(diào)用
console.log(testAddMethod(1, 5)); //output 60溪厘,該方法變?yōu)榱?a + b) * 10
回調(diào):
比如h5中有一個分享按鈕,用戶點擊之后牌柄,調(diào)用native分享(微信分享畸悬、微博分享等),在native分享成功或者失敗時珊佣,回調(diào)h5頁面蹋宦,告訴其分享結果,h5頁面刷新對應的UI咒锻,顯示分享成功或者失敗
JS代碼
//聲明(其實不需要聲明冷冗,因為原生注入代碼方法是:有則替換,無則添加)
function share(shareData) {
}
//調(diào)用的時候需要這么寫
share({
title: "title",
imgUrl: "http://img.dd.com/xxx.png",
link: location.href,
result: function(res) { //函數(shù)作為參數(shù)
console.log(res ? "success" : "failure");
}
});
OC代碼
//異步回調(diào)
self.jsContext[@"share"] = ^(JSValue *shareData) { //首先這里要注意惑艇,回調(diào)的參數(shù)不能直接寫NSDictionary類型取试,為何呢?
//仔細看疤估,打印出的確實是一個NSDictionary榛鼎,但是result字段對應的不是block而是一個NSDictionary
NSLog(@"%@", [shareData toObject]);
//獲取shareData對象的result屬性,這個JSValue對應的其實是一個javascript的function兢卵。
JSValue *resultFunction = [shareData valueForProperty:@"result"];
//回調(diào)block习瑰,將js的function轉換為OC的block
void (^result)(BOOL) = ^(BOOL isSuccess) {
[resultFunction callWithArguments:@[@(isSuccess)]];
};
//模擬異步回調(diào)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"回調(diào)分享成功");
result(YES);
});
};
UIWebView的Cookie管理
UIWebView的Cookie管理很簡單,一般不需要我們手動操作Cookie秽荤,因為所有Cookie都會被[NSHTTPCookieStorage sharedHTTPCookieStorage]這個單例管理甜奄,而且UIWebView會自動同步CookieStorage中的Cookie柠横,所以只要我們在Native端,正常登陸退出课兄,h5在適當時候刷新牍氛,就可以正確的維持登錄狀態(tài),不需要做多余的操作烟阐。
可能有一些情況下搬俊,我們需要在訪問某個鏈接時,添加一個固定Cookie用來做區(qū)分蜒茄,那么就可以通過header來實現(xiàn)
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
[request addValue:@"customCookieName=1314521;" forHTTPHeaderField:@"Set-Cookie"];
[self.webView loadRequest:request];
也可以主動操作NSHTTPCookieStorage唉擂,添加一個自定義Cookie
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:@{
NSHTTPCookieName: @"customCookieName",
NSHTTPCookieValue: @"1314521",
NSHTTPCookieDomain: @".baidu.com",
NSHTTPCookiePath: @"/"
}];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie]; //Cookie存在則覆蓋,不存在添加
還有一些常用的方法檀葛,如讀取所有Cookie轉換成HTTPHeaderFields玩祟,并添加到request的header中
NSArray *cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies;
//Cookies數(shù)組轉換為requestHeaderFields
NSDictionary *requestHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
//設置請求頭
request.allHTTPHeaderFields = requestHeaderFields;