可以有三種方法
一、 setLocation
通過重新設(shè)置 url现横,標(biāo)記一種特殊的 url scheme阁最,在 UIWebView delegate中進(jìn)行攔截,也是最 low 的方法速种。
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if ([request.URL.scheme isEqualToString:@"jscallnative"]) {
// do something
}
return YES;
}
二、設(shè)置 iframe.source
可以給 UIWebView 添加一個(gè)不可見的 iframe馏颂,通過設(shè)置 iframe.source 棋傍,也可以回調(diào)到 UIWebView 的 shouldLoadRequest 方法,這個(gè)是異步調(diào)用的亿絮。 這個(gè)可以參考 WebViewJavascriptBridge麸拄。
JS 端
function _doSend(message, responseCallback) {
if (responseCallback) {
var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime()
responseCallbacks[callbackId] = responseCallback
message['callbackId'] = callbackId
}
sendMessageQueue.push(message)
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE
}
native:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (webView != _webView) { return YES; }
NSURL *url = [request URL];
__strong UIWebView* strongDelegate = _webViewDelegate;
if ([request.URL.scheme isEqualToString:@"jscallnative"]) {
// do something
return NO;
} else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
} else {
return YES;
}
}
三拢切、通過 XMLHTTPRequest
1、native 首先創(chuàng)建一個(gè)繼承 N?S?U?RLProtocol的類(比如 JNURLProtocol
),并通過[NSURLProtocol registerClass:self]
;把自己注冊淮椰。
2、JS 創(chuàng)建一個(gè) XMLHttpRequest 對(duì)象,然后可以設(shè)置攜帶的參數(shù),設(shè)置同步或者異步,然后通過 send 發(fā)送請求豺撑。
function iOSExec(){
var execXhr = new XMLHttpRequest();
execXhr.open('HEAD', "/!test_exec?" + (+new Date()), true); //設(shè)置scheme
var vcHeaderValue = /.*\((.*)\)/.exec(navigator.userAgent)[1];
execXhr.setRequestHeader('vc', vcHeaderValue);//設(shè)置參數(shù)等
execXhr.setRequestHeader('rc', "{\"userName\":\"walawala\"}");
// 發(fā)起請求
execXhr.send(null);
}
3黔牵、native 的 JSURLProtocol 實(shí)現(xiàn) +(BOOL)canInitWithRequest:(NSURLRequest *)request
來截取收到的 request猾浦。
+(BOOL)canInitWithRequest:(NSURLRequest *)request{
NSString *url = request.URL.absoluteString;
if([url containsString:@"!test_exec"]){
//do something
NSLog(@" receieve something from js \n header: %@ ;\n body: %@ ; \n request:%@ ",request.allHTTPHeaderFields,request.HTTPBody,request);
// 這里因?yàn)閯偛旁?js 端,發(fā)送的是異步請求音瓷,所以這里是在后頭線程。
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"HA HA" message:@"receieve something from js" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Sure", nil];
[alert show];
});
}
/*
// 這個(gè)類不處理任何請求绳慎,所以返回 NO,如果返回 YES靡砌,則代表這個(gè)類要處理這個(gè)request珊楼,則要實(shí)現(xiàn)下面的幾個(gè)方法。
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a
toRequest:(NSURLRequest *)b
- (void)startLoading
- (void)stopLoading
等等
*/
return NO;
}
目前 cordova 首先選擇這種方式画舌,備用 iframe已慢。
附 XMLHTTPRequest 參數(shù)說明
/*
創(chuàng)建一個(gè)新的http請求,并指定此請求的方法佑惠、URL以及驗(yàn)證信
規(guī)定請求的類型、URL 以及是否異步處理請求乍丈。
method:請求的類型把将;GET 或 POST,大小寫不敏感
url:文件在服務(wù)器上的位置
async:true(異步)或 false(同步),可選请垛,默認(rèn) true
*/
execXhr.open('POST', "/!test_exec?" + (+new Date()), true);
/**
設(shè)置 header
*/
execXhr.setRequestHeader('vc', vcHeaderValue);//設(shè)置參數(shù)等
/*
將請求發(fā)送到服務(wù)器洽议。
string:僅用于 POST 請求
*/
execXhr.send(string);
關(guān)于 NSURLProtocol
可以參考這里
1、NSURLProtocol也是蘋果眾多黑魔法中的一種混稽,使用它可以輕松地重定義整個(gè)URL Loading System审胚。當(dāng)你注冊自定義NSURLProtocol后,就有機(jī)會(huì)對(duì)所有的請求進(jìn)行統(tǒng)一的處理膳叨。
2、NSURLProtocol是NSURLConnection的handler饿自。NSURLConnection的每個(gè)請求都會(huì)去便利所有的Protocols,并詢問你能處理這個(gè)請求么(canInitWithRequest: )昭雌。如果這個(gè)Protocol返回YES城豁,則第一個(gè)返回YES的Protocol會(huì)來處理這個(gè)connection抄课。Protocols的遍歷是反向的,也就是最后注冊的Protocol會(huì)被優(yōu)先判斷跟磨。
經(jīng)過測試,NSURLSessionDataTask 也會(huì)走到(canInitWithRequest:)哎榴,但是使用 AFNetworking 卻沒有走到僵蛛。
- (void)loadNormalRequest {
// AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//
// [manager GET:@"https://www.baidu.com" parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
//
// } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// NSLog(@" success %@ ",responseObject);
// } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// NSLog(@" failed %@ ",error);
// }];
NSURL *URL = [NSURL URLWithString:@"https://www.baidu.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
// ...
}];
[task resume];
// NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
// NSURLRequest *request = [NSURLRequest requestWithURL:url];
// NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
// [connection start];
}
3充尉、 當(dāng)你的handler被選中了,connection就會(huì)調(diào)用–> initWithRequest:cachedResponse:client:姿鸿,緊接著會(huì)調(diào)用–>startLoading倒源。然后你需要負(fù)責(zé)回調(diào):–>URLProtocol:didReceiveResponse:cacheStoragePolicy:,有些則會(huì)調(diào)用:–>URLProtocol:didLoadData:, 并且最終會(huì)調(diào)用–>URLProtocolDidFinishLoading:笋熬。你有沒有發(fā)現(xiàn)這些方法和NSURLConnection delegate的方法非常類似——這絕非偶然!