iOS HTML加载本地资源

0.0 需求:如标题.

这个其实是cordova远程加载html.各种插件js放在本地的一个需求.

问题分析:
    1. 社区开源的意思是啥(我也不懂)
    2. read error , search Google , ask help
以下非原创.

昨天,一个朋友让我帮他在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];
    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];
}

到这里为止远程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];
}

0. 值得学习的博主
1. stackoverflow 链接 关键词 iOS WebView remote html with local image files
2. 安卓版的相关知识

1. 容易忽略点.
1. 上面需要加载的本地链接.是遵守协议规范格式的
2. Cordova项目 直接引入cordova.js就可以. cordova_plugin.js 会自定加载.但是如果1.你不注意是不会正确加载的(当加载不出来的时候去看cordova的源码吧.会有收获的)
3. 心细一点,什么错误都不会有的
4. 不修改cordova的源码,注册自定义的协议类, 也可以实现相同的效果我注册是放在appdelegate中的
5. 只是为了提醒第4点, 不修改cordova的源码暂时没有发现有什么问题.有的话我会更新说明
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354