昨天,一个朋友让我帮他在IOS上弄这样一件事情:

webView 调用远程URL,并且让远程的web 通过自定义标签能实现内嵌本地的图片、js 或音频等。

比如:在服务器端 的html文件中 这样写到

<html>

<body>

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

<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)

iOS webView 远程html加载本地资源的更多相关文章

  1. [IOS]UIWebView 请求网络页面或者加载本地资源页面

    UIWebView是一个能够显示网页的IOS视图控件,我们可以用它来访问一个网站.下面是具体的实例: 操作步骤: 1.首先在xib文件中拖放一个UIWebView控件到view中 2.将下载的页面以及 ...

  2. iOS WebView 加载本地资源(图片,文件等)

    https://www.cnblogs.com/dhui69/p/5596917.html iOS WebView 加载本地资源(图片,文件等) NSString *path = [[NSBundle ...

  3. 填补Resources和WWW加载本地资源的坑

    总的来说Resources和WWW加载本地资源坑比较多,大多与路径有关. 下面代码构成了一个路径的预读模块: 此模块主要解决的坑是:Resources或WWW加载本地的文件夹中的多个文件时,无法获取文 ...

  4. 引入外部 CDN失效时--怎么加载本地资源文件(本文以jquery为例)

    相信大家都使用过CDN静态资源库,比如下面 CDN官方静态资源库:https://cdnjs.com/ 七牛前端公开库:http://staticfile.org   (vue,react,nl都有) ...

  5. MFC CDHtmlDialog 加载本地资源

    步骤:1.资源视图 项目右击选择资源添加,自定义添加新类型 如:JS(会增加JS文件夹)2. 选择1新建的文件夹右击 添加资源 导入 选择js文件引入3. 在资源文件Resource.h文件夹能找到资 ...

  6. qt webengineview 加载本地资源方式

    一.如果把资源添加到本地资源qrc库里了,请使用 ui->preview->setUrl(QUrl("qrc:/HelloWorld2.html")): 二.如果没有现 ...

  7. ios中UIWebview中加载本地文件

    [super viewDidLoad]; webview=[[UIWebView alloc] initWithFrame:self.view.bounds]; [self.view addSubvi ...

  8. 转:Android Webview 加载外部html时选择加载本地的js,css等资源文件

    原文地址:http://m.blog.csdn.net/blog/qduningning/43196819 在使用WebView加载网页的时候,有一些固定的资源文件如js的jquery包,css,图片 ...

  9. 控件WebView网页的加载

    Android:控件WebView网页的加载 WebView可以使得网页轻松的内嵌到app里,还可以直接跟js相互调用. webview有两个方法:setWebChromeClient 和 setWe ...

随机推荐

  1. IIS 服务没有及时响应启动或控制请求

    微软刚发布的补丁的原因,据说补丁KB939373.KB942831都会影响iis的正常运行,但是我在“添加或删除程序里”(要勾选:显示更新,才能会显示所打的补丁)没有发现以上两个补丁.最后,我发现把K ...

  2. [linux系统]--Sed

    删除:d命令 $ sed ‘2d’ example—–删除example文件的第二行. $ sed ‘2,$d’ example—–删除example文件的第二行到末尾所有行. $ sed ‘$d’ ...

  3. google 提供webrtc 的实例使用 turnserver的方式

    google的turnserver 下载方式:svn checkout http://rfc5766-turn-server.googlecode.com/svn/branches/v3.2/ rfc ...

  4. [ASM C/C++] C makefile:2: *** missing separator. Stop. 问题

    在利用make编译代码时,makefile文件的目标代码前面要用tab而不能用空格来代替. 要不然就会提示: makefile:2: *** missing separator.  Stop. 要注意 ...

  5. Auty自动化测试框架第二篇——读取与执行脚本列表

    [本文出自天外归云的博客园] 在Auty中的文件结构,lib目录下的read_selection.py和execute_selection.py文件:

  6. Hadoop安装指引

    pre.ctl { font-family: "Liberation Mono", monospace } p { margin-bottom: 0.25cm; line-heig ...

  7. VB6中的引用传递 与 VB.NET中的引用传递的区别

    首先注意一点,在VB6中缺省参数传递的方式是:引用传递,而在VB.NET中缺省参数传递的方式是:值传递. 然后我们看下面VB6中的引用传递与VB.NET中的引用传递的对比. VB6中的引用传递 Pri ...

  8. [Prodinner项目]学习分享_第四部分(完结篇)_Controller层(控制器)

    Controller作用: 数据从数据库查询出来后,通过一定的业务逻辑,筛选出来一个结果集,我们最终的目的是要将这个结果集在页面中显示的. Controller就是起到这个作用,将业务逻辑层的结果集调 ...

  9. [Prodinner项目]学习分享_第一部分_Model层

    事先声明一下,小弟我是菜鸟一个,在研究大半天之后,基本会开发一些简单的功能了,特此分享一下,也为自己做一个笔记. 项目简介: MVC4 , EF5 , Code First , 多层架构 开发工具:V ...

  10. 开启curl扩展(转)

    一.win7系统32位, apache2.2, php5.2升级到5.4. 这个比较容易: 1. phpinfo发现没有加载curl; 2. 在php.ini中设置extension_dir 指向e: ...