UIWebView探秘

这篇文章是我三年前在腾讯的时候做的一个组内分享,当时iOS7刚发布,JavaScriptCore第一次进入开发者眼中,WKWebView也还没有出来(尽管webkit框架已经有了),很多东西都是未知的,研究这个只能通过WebKit的一些开源代码和仅有的一些文档(还是Mac的WebView文档)来进行,所以有些地方可能有错误。另外由于年代久远,有些内容可能过时了,仅作参考吧。

话不多说,回到正题。

首先,UIWebView是什么?

UIWebView是iOS开发中最常使用的控件之一,主要用于加载web页面,可通过一些函数来将javascript脚本嵌入页面中,并与其中的页面元素进行交互。

UIWebView的能力很丰富,可以将其理解为一个内置的webkit,具有页面解析、排版布局、执行javascript脚本等功能。WebKit是由Apple公司开发的开源浏览器内核,应用于Apple Safari浏览器。

此外,UIWebView还支持浏览word/excel/ppt/pdf/page/number等多种文档格式。

UIWebView的内核是WebKit(部分功能阉割过的)

WebKit主要分为三个模块:WebCore、JavaScriptCore、平台应用相关Port,如图1所示。

§1.WebCore是最核心的部分,负责HTML、CSS的解析和页面布局渲染;

§2.JavaScriptCore负责JavaScript脚本的解析执行,通过bindings技术和WebCore进行交互;

§3.Port部分的代码结合上层应用,封装WebCore的行为为上层应用提供API来使用。


UIWebview属于UIKit,封装了webkit.framework的WebView。

WebView组合管理了WebCore.framework的Page,并提供了各种Clients


关于WebView的结构就简单的介绍到这了,说实在的,研究不多,想深入了解的话,可以看看这篇文章:http://blog.csdn.net/hursing/article/details/8771847


再说下使用UIWebView的优缺点吧(这也是老生常谈了)

优点:


§1.修改、部署方便。由于web天然的特性,在部署方式上比原生应用更灵活。原生的App在发布后只能等苹果审批再次上传,用户也必须下载应用才能更新,而web可绕开苹果的审批,随时修改和部署。

§2.web具有跨平台性。有不少应用是将UIWebView作为一个主要容器,将原本UIKit的内容,搬到web上来,通过一些js的页面框架,实现跨平台开发,这一类应用统称为web app。这种方式可以实现一套代码,多个平台使用,节省了开发工作量。

缺点:

§1.由于web页面需要经过网络下载资源并解析,所以相对于原生应用比较费时,也消耗用户的流量。

§2.webkit实现动画和3D绘图的能力远不及原生的SDK,对HTML5的支持也还不够。

§3.javascript是单线程,会阻塞UI。

§4.原生的SDK具有特殊的能力,比如获取设备的位置、重力感应、摄像头捕获图像等等。

5.由于代码在页面端,与终端有交互时调试困难。

当然,现在还有React Native、Weex这一类介于Web和原生之间的技术方案,综合了两者的优势,但是使用起来也满复杂的,之后会单独写一篇文章介绍这种技术。


下面再谈谈JS与OC之间的交互吧。

我们常说,JS与原生之间需要伪协议,那么伪协议是什么?

就是类似这样的一串字符,跟http协议有点像是吧

qqapi://qqwallet/pay/…

为什么要用伪协议呢?

因为UIWebView没有接口让js直接调用,唯一能办到的就是在其委托方法去捕获页面跳转的请求,所以为了让页面端具有与本地SDK交互的能力,就必须人为制造一种“假”的页面跳转请求,来让UIWebView感知到页面的意图,从而执行相关代码。

§伪协议是怎么起作用的?

-(BOOL)webView:(UIWebView*)webViewshouldStartLoadWithRequest:(NSURLRequest*)requestnavigationType:(UIWebViewNavigationType)navigationType;

这个委托方法能捕捉到请求。

如果返回的是YES,则继续页面跳转,如果返回NO,则不跳转,一般执行程序内部的代码逻辑都会返回NO。

js里面只需要 修改一下window.location.href = qqapi://qqwallet/pay/…  就可以了

这里面如果要传参数怎么办呢?

参数的传递一般是 将相关参数以json的形式附加在请求后面,为了避免非法字符,一般还会进行base64编码。封装更彻底的可以将参数放在应用程序的一个全局数组中,js只需一个索引就能找到需要的参数。

iOS执行代码后回调js的函数一般是在js调native时就已经通过参数传过来了,ios端只需要按特定的格式组织起来,就可以回调。

有几点需要注意的:

1.Native调用JS是同步    stringByEvaluatingJavaScriptFromString

而JS调用Native是异步    UIWebView delegate

2.由于web跳转请求本身会导致页面处理流程中断,并且javascript不具有多线程的能力,所以一般会通过一个隐藏的iframe来加载这个请求。

由此带来的线程阻塞问题在native调用js时通过deferiframe来解决


关于JavaScriptCore框架

1.从iOS7.0开始支持

2.JavaScriptCore.framework是开源webkit的一部分。该框架提供了用Objective-C封装的大量标准JavaScript对象。通过该framework可以对JavaScript代码进行评估(evaluate),以及解析JSON。实际也就是开放一个JavaScript的运行环境,供执行js代码。一些数据处理和运算不必再转成Objective-C来写,Apple帮忙搞定,每个JavaScript的对象都可以用C和Objective-C的类来访问。

另外,js也可以直接调用OC代码了,有望在不久的将来替代JSBridge成为交互的新方式。

1.Objective C->Javascript

JSContext:An instance ofJSContextrepresents a

JavaScript execution environment.(一个Context就是一个JavaScript代码执行的环境,也叫作用域。)

JSValue:Conversion

between Objective-C and JavaScript types.(JS是弱类型的,ObjectiveC是强类型的,JSValue被引入处理这种类型差异,在Objective-C对象和JavaScript对象之间起转换作用)

2.Javascript->ObjectiveC

Blocks:JS functions(对应JS函数)

JSExportprotocol:JS objects(对应JS对象)


关于调试JS代码

§在ios6之前 在UIWebView中调试js代码是一件非常困难的事情,不像PC上有那么多工具,通过传统的alert的方式效率低而且容易出错。

§从ios6开始,苹果已经支持用safari来连接iPhone模拟器里面的UIWebView进行调试了,所以调试上已经方便了很多。

§方法一:

§1.首先创建一个UIWebView的子类

§2.重载方法:

- (void)webView:(id)webViewwindowScriptObjectAvailable:(id)newWindowScriptObject

§3.定义并实现YourScriptDebugDelegate

然后就能通过ScriptDebugDelegate来定位js的错误了

§- (void)webView:(WebView*)webView

didParseSource:(NSString*)source

baseLineNumber:(unsigned)lineNumber

fromURL:(NSURL *)url

sourceId:(int)sid

forWebFrame:(WebFrame*)webFrame;

可以处理解析成功、解析失败、以及解析中抛出异常等各种情况

§方法二:Weinre

§Weinre这种框架,可以做一些基本的调试工作,但是它现在功能还没有象pc上的js调试器那么强大,例如它不能下断点,另外如果有js执行错误,它也无法正确的将错误信息报出。它还有一些bug,例如在mac机下,如果你同时连接了有线网和无线网,那么weinre将无法正确地连接到调试页面。

苹果自带的safari也是类似的框架。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 前言 关于UIWebView的介绍,相信看过上文的小伙伴们,已经大概清楚了吧,如果有问题,欢迎提问。 本文是本系列...
    CoderLF阅读 8,943评论 2 12
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,418评论 25 707
  • 总结: 最近放假,执行力度与安排事物上做的不好。每天过的有点混乱。明天是最后一天假期,期望上班后一切回归正轨。
    轩宁妈阅读 157评论 0 0
  • 缘起 先是在网络浏览过程中发现了简书,然后被 Markdown 所吸引,因为,居然还不知道有这样的标记语言,更为...
    何必阅读 4,505评论 9 16