iOS webView 遠程html加載本地資源

   昨天,一個朋友讓我幫他在IOS上弄這樣一件事情:html

    webView 調用遠程URL,而且讓遠程的web 經過自定義標籤能實現內嵌本地的圖片、js 或音頻等。ios

    好比:在服務器端 的html文件中 這樣寫到web

<html>服務器

    <body>網絡

        <h1>we are loading a custom protocl</h1>app

        <b>image?</b><br/>框架

        <img src="myapp://image1.png" />函數

        <body>性能

</html>測試

那麼當這個頁面被iOS 中webView 顯示的時,當渲染到 myapp://image1.png 的自定義標籤的時候能將本地的圖片資源 替換進去。這樣的好處就是在網絡上無需傳輸圖片,性能比較高。

    我朋友的項目是基於cordova 框架,一開始我還不是很理解他爲何說要遠程web 調用本地資源,在個人腦海裏面就是:「這個框架js 不都是本地的嗎????」

,而後他告訴我是他在cordova 框架中導航到 本身的web 服務器。   我聽了以後就只能用「呵呵」 表示了,好吧...也就無論了。

     那麼我就想到其實cordova框架就是基於webView 的一個事件攔截和封裝的。 其實它是對NSURLProtocol 的自定義累進行註冊,那麼全部的webview 對http請求都會被他攔截到;

這裏咱們能夠作不少事情;

接下來咱們本身作本身的 NSURLProtocol 累吧

#import <Foundation/Foundation.h>

#import <CoreFoundation/CoreFoundation.h>

#import <MobileCoreServices/MobileCoreServices.h>

@interface NSURLProtocolCustom : NSURLProtocol  //在項目中添加自定義NSURLProtocolCustom 而且繼承NSURLProtocol

{

}

//實現中重現以下幾個方法

@implementation NSURLProtocolCustom

//重寫方法 1

 +(BOOL)canInitWithRequest:(NSURLRequest *)request

{

    NSLog(@"canInitWithRequest");

   // 這裏是html 渲染時候入口,來處理自定義標籤 如 "myapp",若return YES 則會執行接下來的 -startLoading方法 

    if ([request.URL.scheme caseInsensitiveCompare:@"myapp"] == NSOrderedSame||

        [request.URL.scheme caseInsensitiveCompare:@"app"] == NSOrderedSame) {

           return YES;

    }

     return NO;

}

//重寫方法

+(NSURLRequest*)canonicalRequestForRequest:(NSURLRequest *)request

{

    NSLog(@"canInitWithRequest");

    return request;

}

//重寫方法

-(void)startLoading

{

  //處理自定義標籤 ,並實現內嵌本地資源

    NSLog(@"startLoading");

    NSLog(@"%@", super.request.URL);

    NSString *url=super.request.URL.resourceSpecifier;// 獲得//image1.png"

  //去掉 //前綴()

    url=[url substringFromIndex:2];//image1.png

 

    //如果app 協議 須要添加www (這裏是咱們本身業務上的吹)

    if ([super.request.URL.scheme caseInsensitiveCompare:@"app"]) {

        url=[[NSString alloc] initWithFormat:@"www/%@",url];

    }

    

//  NSString *path=  [[NSBundle mainBundle] pathForResource:@"www/image1.png" ofType:nil];

      NSString *path=  [[NSBundle mainBundle] pathForResource:url ofType:nil];//這裏是獲取本地資源路徑 如 :png,js 等

 

    if (!path) {

        return;

    }

    //根據路徑獲取MIMEType   (如下函數方法須要添加.h文件的引用,)

       // Get the UTI from the file's extension:

    CFStringRef pathExtension = (__bridge_retained CFStringRef)[path pathExtension];

    CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, NULL);

    CFRelease(pathExtension);

    

    // The UTI can be converted to a mime type:

    NSString *mimeType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType);

    if (type != NULL)

        CFRelease(type);

  // 這裏須要用到MIMEType

    NSURLResponse *response = [[NSURLResponse alloc] initWithURL:super.request.URL

                                                        MIMEType:mimeType

                                           expectedContentLength:-1

                                                textEncodingName:nil];

//    NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"廣告iOS" ofType:@"png"];

    NSData *data = [NSData dataWithContentsOfFile:path];//加載本地資源

    //硬編碼 開始嵌入本地資源到web中

    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];

    [[self client] URLProtocol:self didLoadData:data];

    [[self client] URLProtocolDidFinishLoading:self];

}

-(void)stopLoading

{

    NSLog(@"something went wrong!");

}

 @end

//類已經實現好了 那麼怎樣調用呢???

//其餘代碼都已經省略了,核心以下:

- (void)viewDidLoad {

    [super viewDidLoad];

   // 這裏能夠看出 只要註冊一次就夠了。。。咱們能夠將它寫在delegate 入口就能夠實現全部的請求攔截

     [NSURLProtocol registerClass:[NSURLProtocolCustom class]];

     

   //測試: 這裏webView 我是直接從interface build 中引用過來的因此沒有自定義實例化。

    self.myWebView.backgroundColor = [UIColor  redColor];

    self.myWebView.scalesPageToFit =YES;

    self.myWebView.delegate =self;

    NSURL *url =[[NSURL alloc] initWithString:@"http://192.168.199.197/soqik/test.html"];//地址能夠是遠程地址也能夠是本地的html 方法

    

    NSURLRequest *request =  [[NSURLRequest alloc] initWithURL:url];

    [self.myWebView loadRequest:request];

    // Do any additional setup after loading the view, typically from a nib.

}

  到這裏爲止遠程web調用本地的js 或者圖片資源已經完成了,接下來就是怎樣在cordova 中進行改造。。。。本來覺得在cordova中這樣弄進去就能夠了,可是發現這樣是不行的,緣由很簡單:它們已經對 這個封裝過,因此必須改造它們的對象。通過必定時間的研究 最終發現改造須要到:

CDVURLProtocol.h類中實現

那麼這裏須要注意的是:若資源找不到則須要調用Cordova封裝的方法

//錯誤處理,而不是直接返回nil  不進行任何處理,這樣會致使js 沒法正常加載、運行

-(void)startLoading{

 

....//省略

if (!path) {

[self sendResponseWithResponseCode:401 data:nil mimeType:nil];//重要
return;
}

...//省略

//不然

NSData *data = [NSData dataWithContentsOfFile:path];

[self sendResponseWithResponseCode:200 data:data mimeType:mimeType];

}

 

好吧,表示完美解決。。。。cordova中能夠幹任何本身想弄的事情了

   (參考資料:http://stackoverflow.com/questions/5572258/ios-webview-remote-html-with-local-image-files)

相關文章
相關標籤/搜索