iOS WebView使用Ajax與iOS的互動

來源:互聯網
上載者:User

標籤:orm   ict   vpd   hello   直接   proc   catch   自己   json   

iOS 使用Ajax實現與Javascript同步非同步互動
實現原理:

1.Ajax可以實現同步與非同步請求2.UIWebView可以實現Ajax跨域請求3.NSURLProtocol可以攔截Ajax請求4.NSURLProtocol可以實現類比響應結果

需要解決的問題:

2.1.實現NSURLProtocol攔截Ajax請求2.實現Ajax跨域,解決Ajax預檢請求問題3.實現NSURLProtocol返迴響應

對於上述問題,我們定義自己的NSURLProtocol

#import <Foundation/Foundation.h>@interface MyURLProtocol : NSURLProtocol@end

代碼實現
我們這裡指定schema為 oschina://
對於其中可能遇到預檢請求問題,請參閱(Ajax跨域(CROS)請求中的Preflighted Requests)

@interface MyURLProtocol() @property(nomatic,strong) NSMutableDictionary * reponseHeader;@end@implementation MyURLProtocol//複寫canInitWithRequest,決定是否攔截請求+(BOOL)canInitWithRequest:(NSURLRequest *)request{   //這裡實現對  oschina://syncHttpRequest和oschina://asyncHttpRequest攔截    if(request.URL.scheme!=nil && [[request.URL.scheme lowercaseString] isEqualToString:@"oschina"])    {        if([request.URL.host isEqualToString:@"syncHttpRequest"] || [request.URL.host isEqualToString:@"asyncHttpRequest"])        {            if(_reponseHeader==nil)             {                 _reponseHeader = @{                                  @"Access-Control-Allow-Credentials":@"true",                                  @"Access-Control-Allow-Origin":@"*",                                  @"Access-Control-Expose-Headers":@"jsStr",                                  @"Access-Control-Allow-Methods":@"GET,POST,PUT,OPTIONS,HEAD",                                  @"Access-Control-Allow-Headers":@"Origin,jsStr,Content-Type,X-Request-Width",                                  @"Access-Control-Max-Age":@"10",                                  @"Cache-Control":@"no-cache,private",                                  @"Pragma":@"no-cache,no-store",                                  @"Expires":@"0",                                  @"Connection":@"Close"                                  };            }            return YES;        }   }    //如果不攔截,則返回NO    return NO;}//複寫 canonicalRequestForRequest ,加工請求,這裡我們可以不加工,直接使用req+ (NSURLRequest*) canonicalRequestForRequest:(NSURLRequest *)req{    return req;}//複寫startLoading,並處理預檢請求- (void) startLoading{    //處理跨網域作業,如果是options操作。如果是跨域訪問會發送一個options請求,需要response一個許可權才會繼續走head請求  //此外,ajax發送的資料無法被接收,需要一個自訂要求標頭X-Javascript-Header,用來javascript->iOS傳遞資料  if ([self.request.HTTPMethod isEqualToString:@"OPTIONS"])    {        NSDictionary * fields_resp = _reponseHeader;        //響應ajax預檢請求        NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[self.request URL] statusCode:200 HTTPVersion:@"1.1" headerFields:fields_resp];        [[self client] URLProtocol: self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];        [[self client] URLProtocol:self didLoadData:[NSData data]];        [[self client] URLProtocolDidFinishLoading:self];    }else{        //實現對ajax正式請求的解析與響應        [self doRequestToResponse];    }}-(void) doRequestToResponse{    NSDictionary *dic = [self.request.allHTTPHeaderFields copy];    NSString *jsStr = dic[@"X-Javascript-Header"];  //擷取回應標頭資料    NSString * userAgentInStorage   = [[NSUserDefaults standardUserDefaults] stringForKey:@"UserAgent"];    NSString * userAgent =  dic[@"User-Agent"];//必要時儲存user-Agent    if([NSString isEmptyOrNil:userAgentInStorage] && ![NSString isEmptyOrNil:userAgent])    {        [[NSUserDefaults standardUserDefaults] setObject:userAgent forKey:@"UserAgent"];        [[NSUserDefaults standardUserDefaults] synchronize];    }   if([NSString isEmptyOrNil:jsStr])    {        [self sendRequestErrorToClient];        return;    }  if([jsStr hasPrefix:@"@"])    {        jsStr = [jsStr stringByReplacingOccurrencesOfString:@"@" withString:@""];    }    NSData *data = [GTMBase64 decodeString:jsStr];    jsStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];    // 轉換    jsStr = [jsStr stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];    jsStr = [jsStr stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];    jsStr = [jsStr stringByReplacingOccurrencesOfString:@"\t" withString:@"\\t"];    jsStr = [jsStr stringByReplacingOccurrencesOfString:@"\0" withString:@"\\0"];    NSMutableDictionary *jsDic = [jsStr mutableObjectFromJSONString];    if(jsDic==nil)    {        NSString * tempJsStr = [jsStr stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];        jsDic = [tempJsStr mutableObjectFromJSONString];    }    if(jsDic==nil)    {        [UMJS showToast:@"參數解析失敗!"];        return;    }    NSString *serviceName= jsDic[@"service"];    NSString *methodName = jsDic[@"method"];    id params = jsDic["params"];   [------------------處理響應的請結果------------------------]     //1.開始處理,略    //發送相應資料到Ajax端,假定結果為result   NSString * response = [@{@"result":result,@"msg":@"Hello World",@"code":@1} JSONString];  [self sendResponseToClient:response];   [------------------處理響應的請結果------------------------]}-(void) sendResponseToClient:(NSString *) str{     NSData *repData = [str dataUsingEncoding:NSUTF8StringEncoding];    NSMutableDictionary *respHeader = [NSMutableDictionary dictionaryWithDictionary:fields_resp];    respHeader[@"Content-Length"] = [NSString stringWithFormat:@"%ld",repData.length];    NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[self.request URL] statusCode:200 HTTPVersion:@"1.1" headerFields:respHeader];    [[self client] URLProtocol: self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];    [[self client] URLProtocol:self didLoadData:repData];    [[self client] URLProtocolDidFinishLoading:self]; }//發送錯誤請求資訊-(void) sendRequestErrorToClient{    NSData *data = [@"" dataUsingEncoding:NSUTF8StringEncoding];    NSDictionary * fields_resp =_reponseHeader;    NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[self.request URL] statusCode:400 HTTPVersion:@"1.1" headerFields:fields_resp];    [[self client] URLProtocol: self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];    [[self client] URLProtocol:self didLoadData:data];    [[self client] URLProtocolDidFinishLoading:self];}- (void) stopLoading{//    NSLog(@"stopLoading");}//處理跳轉(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response { if ([response isKindOfClass:[NSHTTPURLResponse class]]) { NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response; if ([HTTPResponse statusCode] == 301 || [HTTPResponse statusCode] == 302) { NSMutableURLRequest *mutableRequest = [request mutableCopy]; [mutableRequest setURL:[NSURL URLWithString:[[HTTPResponse allHeaderFields] objectForKey:@”Location”]]]; request = [mutableRequest copy]; [[self client] URLProtocol:self wasRedirectedToRequest:request redirectResponse:response]; } } return request; }

自訂結束之後,我們需要在AppDetegate或者UIViewController註冊一下才行,注意:多次註冊也是可以的,不會造成多次攔截。

[NSURLProtocol registerClass:[UyURLProtocol class]];

通過這種方式,我們可以實現iOS端資料處理,在Javascript端我們需要實現2類調用,同步和非同步

//非同步請求function sendAsyncAjax(xJavascript, onload, onerror) {     var xhr, results, url;     url = ‘oschina://asyncHttpRequest?rnd=‘+Math.random();     xhr = new XMLHttpRequest();   try{     xhr.open(‘POST‘, url, true);     xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");     xhr.setRequestHeader("Cache-Control", "no-cache,private");     xhr.setRequestHeader("Pragma", "no-cache,no-store");     xhr.setRequestHeader("User-Agent", navigator.userAgent);    //通過X-Javascript-Header發送資料到iOS,注意,使用第三方Base64 encode    xhr.setRequestHeader("X-Javascript-Header", Base64Util.encode(xJavascript));     xhr.onload = function (e) {         if (this.status === 200) {             results = JSON.parse(xhr.responseText);             onload(results);         }else{             onload({‘e‘:e});         }     };     xhr.onerror = function (e) {         onerror({‘e‘:e});     };     }catch(exception){       console.error(exception);   }finally{    try{    xhr.send(null);    }catch(exception2){}  }}//同步請求function sendSyncAjax(xJavascript) {     var xhr, results, url;     url = ‘oschina://syncHttpRequest?rnd=‘+Math.random();     xhr = new XMLHttpRequest();   try{     xhr.open(‘POST‘, url, true);     xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");     xhr.setRequestHeader("Cache-Control", "no-cache,private");     xhr.setRequestHeader("Pragma", "no-cache,no-store");     xhr.setRequestHeader("User-Agent", navigator.userAgent);     //通過X-Javascript-Header發送資料到iOS,注意,使用第三方Base64 encode    xhr.setRequestHeader("X-Javascript-Header", Base64Util.encode(xJavascript));     }catch(exception){       console.error(exception);     }finally{    try{      xhr.send(null);    }catch(exception2){}  } if (xhr.readyState == 4) {        if (xhr.status == 200) {           return  xhr.execXhr.responseText;        } else {            return xhr.execXhr.responseText;        }    } return {};}

然後我們通過javascript調用

var script = JSON.stringify({service:"NetworkUtil",method:"getNetworkInfo",params:{}};sendAsyncAjax(script ,function(result){}, function(error){});或者var script = JSON.stringify({service:"NetworkUtil",method:"getNetworkInfo",params:{}};var result = sendSyncAjax(script);

一般來說NetworkUtil可以調用的方法必須是類方法

@implementation NetworkUtil+(NSString * )getNetworkInfo{  NSString * result = [略];  return result;}@end

我們這裡實現了iOS平台上同步非同步方法,Android平台有系統提供的javascriptInterface介面,當然,我們想要實現和本篇iOS類似的方式,我們可以使用ServerSocket方式來實現,具體過程可能使用到訊號量的概念,這裡不再贅述.

大家可以加我的或者QQ:1499732272 ,我會提供關於iOS開發相關的各種資料!

iOS WebView使用Ajax與iOS的互動

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.