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)

相关文章
相关标签/搜索