OC--UIWebView的JS與OC交互、Cookie管理

完全抄錄:
iOS中UIWebView與WKWebView、JavaScript與OC交互、Cookie管理看我就夠(上)
深入淺出 JavaScriptCore
JavaScriptCore框架詳解

UIWebView OC調(diào)用JS

1、stringByEvaluatingJavaScriptFromString

/*缺點(diǎn)
1、所以無法判斷是否調(diào)用成功,失敗返回nil,js本身方法返回是nil
2、返回值是NSString,其他類型數(shù)據(jù)需要轉(zhuǎn)換解析
*/
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;

self.navigationItem.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
  1. JavaScriptCore(iOS 7.0 +)
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    //更新標(biāo)題,這是上面的講過的方法
    //self.navigationItem.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];

    //獲取該UIWebView的javascript上下文
    JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

    //這也是一種獲取標(biāo)題的方法。
    JSValue *value = [self.jsContext evaluateScript:@"document.title"];
    //更新標(biāo)題
    self.navigationItem.title = value.toString;
}
//在調(diào)用前,設(shè)置異常回調(diào)
[self.jsContext setExceptionHandler:^(JSContext *context, JSValue *exception){
        NSLog(@"%@", exception);
}];
//執(zhí)行方法
JSValue *value = [self.jsContext evaluateScript:@"document.titlexxxx"];
UIWebView JS調(diào)用OC
  1. Custom URL Scheme(攔截URL)
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    //標(biāo)準(zhǔn)的URL包含scheme、host、port、path、query、fragment等
    NSURL *URL = request.URL;    
    if ([URL.scheme isEqualToString:@"darkangel"]) {
        if ([URL.host isEqualToString:@"smsLogin"]) {
            NSLog(@"短信驗(yàn)證碼登錄,參數(shù)為 %@", URL.query);
            return NO;// NO(阻止本次跳轉(zhuǎn))
        }
    }
    return YES;
}

優(yōu)點(diǎn):泛用性強(qiáng),可以配合h5實(shí)現(xiàn)頁(yè)面動(dòng)態(tài)化。比如頁(yè)面中一個(gè)活動(dòng)鏈接到活動(dòng)詳情頁(yè),當(dāng)native尚未開發(fā)完畢時(shí),鏈接可以是一個(gè)h5鏈接,等到native開發(fā)完畢時(shí),可以通過該方法跳轉(zhuǎn)到native頁(yè)面,實(shí)現(xiàn)頁(yè)面動(dòng)態(tài)化。且該方案適用于Android和iOS,泛用性很強(qiáng)。

缺點(diǎn):無法直接獲取本次交互的返回值,比較適合單向傳參,且不關(guān)心回調(diào)的情景,比如h5頁(yè)面跳轉(zhuǎn)到native頁(yè)面等。

  1. JavaScriptCore(iOS 7.0 +)

OC現(xiàn)實(shí)JS的方法
JS代碼

function share(title, imgUrl, link) {
     //這里需要OC實(shí)現(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的方法名稱,賦給是一個(gè)block 里面是oc代碼
    //此方法最終將打印出所有接收到的參數(shù),js參數(shù)是不固定的
    // ja的"share",有則替換,無則添加。
    self.jsContext[@"share"] = ^() {
        NSArray *args = [JSContext currentArguments];//獲取到share里的所有參數(shù)
        //args中的元素是JSValue,需要轉(zhuǎn)成OC的對(duì)象
        NSMutableArray *messages = [NSMutableArray array];
        for (JSValue *obj in args) {
            [messages addObject:[obj toObject]];
        }
        NSLog(@"點(diǎn)擊分享js傳回的參數(shù):\n%@", messages);
    };
}

一個(gè)有兩個(gè)參數(shù),一個(gè)返回值的js方法
JS

//該方法傳入兩個(gè)整數(shù),求和,并返回結(jié)果
function testAddMethod(a, b) {
     //需要OC實(shí)現(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)用方法原實(shí)現(xiàn),并且在原結(jié)果上乘以10

//調(diào)用方法的本來實(shí)現(xiàn),給原結(jié)果乘以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中有一個(gè)分享按鈕,用戶點(diǎn)擊之后,調(diào)用native分享(微信分享、微博分享等),在native分享成功或者失敗時(shí),回調(diào)h5頁(yè)面,告訴其分享結(jié)果,h5頁(yè)面刷新對(duì)應(yīng)的UI,顯示分享成功或者失敗
JS代碼

//聲明(其實(shí)不需要聲明,因?yàn)樵⑷氪a方法是:有則替換,無則添加)
function share(shareData) {

}

//調(diào)用的時(shí)候需要這么寫
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類型,為何呢?
    //仔細(xì)看,打印出的確實(shí)是一個(gè)NSDictionary,但是result字段對(duì)應(yīng)的不是block而是一個(gè)NSDictionary  
      NSLog(@"%@", [shareData toObject]);     
    //獲取shareData對(duì)象的result屬性,這個(gè)JSValue對(duì)應(yīng)的其實(shí)是一個(gè)javascript的function。
    JSValue *resultFunction = [shareData valueForProperty:@"result"];
    //回調(diào)block,將js的function轉(zhuǎn)換為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管理很簡(jiǎn)單,一般不需要我們手動(dòng)操作Cookie,因?yàn)樗蠧ookie都會(huì)被[NSHTTPCookieStorage sharedHTTPCookieStorage]這個(gè)單例管理,而且UIWebView會(huì)自動(dòng)同步CookieStorage中的Cookie,所以只要我們?cè)贜ative端,正常登陸退出,h5在適當(dāng)時(shí)候刷新,就可以正確的維持登錄狀態(tài),不需要做多余的操作。

可能有一些情況下,我們需要在訪問某個(gè)鏈接時(shí),添加一個(gè)固定Cookie用來做區(qū)分,那么就可以通過header來實(shí)現(xiàn)

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
[request addValue:@"customCookieName=1314521;" forHTTPHeaderField:@"Set-Cookie"];
[self.webView loadRequest:request];

也可以主動(dòng)操作NSHTTPCookieStorage,添加一個(gè)自定義Cookie

NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:@{
    NSHTTPCookieName: @"customCookieName", 
    NSHTTPCookieValue: @"1314521", 
    NSHTTPCookieDomain: @".baidu.com",
    NSHTTPCookiePath: @"/"
}];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];    //Cookie存在則覆蓋,不存在添加

還有一些常用的方法,如讀取所有Cookie轉(zhuǎn)換成HTTPHeaderFields,并添加到request的header中

NSArray *cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies;
//Cookies數(shù)組轉(zhuǎn)換為requestHeaderFields
NSDictionary *requestHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
//設(shè)置請(qǐng)求頭
request.allHTTPHeaderFields = requestHeaderFields;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容