Android 2.3 Webkit

Android 2.3 Webkit

1.前言

    大家对WebView应该不陌生, 它是Android里面用来显示网页的控件, 用它显示网页只需要几行代码, 如下:

public class WebViewDemoActivity extendsActivity {

   @Override

   public void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.main);  

       mWebView = (WebView) findViewById(R.id.webview);

       mWebView.loadUrl("http://www.2cto.com");   

    }

}

       这样在WebViewDemoActivity启动时就会显示出google的主页, 我们还可以在里面输入关键字进行搜索。究竟WebView的loadUrl函数里面究竟做了哪些事情呢?我们带着好奇心走进android的Webkit世界。

2.加载网页过程的UML序列图

       这里先给出loadUrl整个过程的uml序列图, 然后再慢慢分析。 。

3.WebKit介绍 

       前面提到了Webkit,那究竟Webkit是什么呢?它和我们所熟悉的WebView是什么关系呢?这里引用网上的解释:“WebKit是一个开源的浏览器网页排版引擎,包含WebCore排版引擎和JSCore引擎。WebCore和JSCore引擎来自于KDE项目的KHTML和KJS开源项目。Android平台的Web引擎框架采用了WebKit项目中的WebCore和JSCore部分,上层由Java语言封装,并且作为API提供给Android应用开发者,而底层使用WebKit核心库(WebCore和JSCore)进行网页排版。”可见,WebView就属于Android的Webkit提供给应用开发者用的上层API部分。
        很多伟大的软件都是可移植的,Webkit也不例外。目前Webkit支持Qt,Gtk,Android等等。大家都知道移植是有条件的,比如要将linux系统移植到某个硬件平台,那么这个硬件平台至少要有个硬件定时器来进行进程调度,要有mmu来支持虚拟内存管理,另外对系统ram和flash的空间也是有一定底线要求的。移植Webkit所要求的条件是什么呢?先分析Webkit加载网页的这样一个过程:
l        从网络上把url地址上的html文件下载到本地
l        词法分析和语法分析
l        绘制
       很明显,Webkit需要依赖平台相关的网络接口和图形接口,如下图所示:

    可移植的软件都可以分为两部分:平台相关代码和平台无关代码。这两部分之间的交互是通过固定接口来完成的,当然Webkit也不例外。对于Android Webkit,我们把它简单看为两部分:Android和WebCore。 Android到Webcore方向当然是直接调用的关系, 而WebCore有时也需要回调Android部分的代码, 这就需要通过WebCore定义的一套固定的接口来完成。如下图所示, ResourceHandle是WebCore获取网络资源的接口, Android平台对这个接口的实现是调用了Android API中的android.net.*包里面的类实现的。 GraphicContext是WebCore绘制页面的接口, Android平台对这个接口的实现是通过调用Android平台的2D绘图引擎Skia实现的。
 
 
 

4.加载网页过程分析

    有一个很重要的概念需要解释一下,Frame,翻译成中文是“帧”,一个html页面构成如下图,即一个html页面包含一个MainFrame,MainFrame中又可以包含0到n个子Frame。一个Frame对应一个Url,在MainFrame里包含子Frame就意味着把子Frame的内容嵌入到MainFrame的一块空间里面。
      
        在WebKit里面有个结构体WebCore::Frame,这个数据结构就包含了,一个网页解析后的全部数据。下面就是从一个Url到生成一个MainFrame的过程。

       接下来就是要将Main frame里面的数据显示出来,这部分代码是每个平台的实现都是不同的,我们以Android为例。首先需要说明的是,Android Webkit加载网页是通过三个线程协作完成的:
l        UI线程:Android图形系统派发事件的线程,WebView的onDraw函数和onTouchEvent函数就是运行在这个线程。UI线程只做一些轻量级的工作,会将耗时的工作转给Webcore线程进行处理。
l        WebCore线程:在andriod.webkit.WebViewCore类中创建,负责html文件解析等任务。
l        下载线程:在android.webkit.WebViewWorker中创建,负责下载从指定url下载html。
      
       当调用WebView.loadUrl时线程协作图如下,UI线程向WebCore线程发送消息,WebCore线程接到消息会把下载任务交给下载线程,下载线程下载完毕后通知WebCore线程进行html的解析,WebCore线程解析完html后通知UI线程刷新界面。

       回顾一下这个图:

       Webcore线程就是通过ResourceHandleAndroid来启动下载线程下载html的,然后WebCore线程进行html解析,最后生成能够描述整个html页面的Main  frame,再通知UI线程绘制页面。假设UI线程在onDraw函数里需要通过分析Mainframe来绘图,那么很可能给人不流畅的感觉。所以WebCore线程在生成Frame结构体之后,又做了一个工作,就是解析Main frame并绘制到一块内存上面,而UI线程在onDraw时只需把这块内存上的内容绘制到屏幕上即可,这块内存叫PictureSet。Picture是一个图片集合,Main frame是Frame的集合,PictureSet里面的Picture和Main frame里面得Frame都是一一对应的关系。    
       还记得以前提到的代码层次吗?PictureSet是属于Webkit的Andriod移植层的,而Frame是属于WebCore层的,也就是说WebCore生成Frame后任务就完成了,然后会通过固定的接口通知Android移植层,Android移植层随后分析Frame来生成PictureSet。在PictureSet生成后才会通知UI线程更新界面,WebView.onDraw中便会将PictureSet绘制到画布上。
       最后需要补充说明的是,Android的Webkit移植层比其它平台相比多了jni部分,通过阅读代码你会发现WebView,WebViewCore等类在Java和C++部分都存在,它们是通过Java和c++一起实现的。
 
 

5.Android Webkit插件

5.1.本章的目的

       引导读者理解Android Webkit的插件框架, 通过介绍本人研究过程阅读过并认为有价值的文章,并对Android Framework源码中的SampleBrowserPlugin里难懂的地方进行解释, 希望能够清除读者对怎样写Android Webkit插件的疑惑。 SampleBrowserPlugin 是Android Webkit插件的例程, 位于源码中的development/samples/BrowserPlugin目录下, 先看一下里面的README文件吧。

5.2.推荐先看几篇文章

l        https://developer.mozilla.org/en/Gecko_Plugin_API_Reference:虽然firefox是gecko的引擎,但是gecko和webkit的插件同样遵循NPAPI的标准, 这篇看完后就会弄如下几个问题:
(1)什么是Webkit插件, 有什么作用
(2)NPAPI一些函数和结构的作用。

l        http://www.2cto.com/kf/201203/123782.html:这篇文章会帮助你对Android Webkit插件有个简单的了解。

l       http://www.2cto.com/kf/201203/123783.html:这篇文章提到了Android Webkit插件的两种模式。

5.3.架构

插件是用来扩展webkit的, 是webkit的智囊团。 例如有一种新类型的数据嵌在网页里,如下图所示, webkit不知如何处理, 此时webkit就会问他的插件们如何处理"application/x-shockwave-flash”类型的数据。


 
<embed src="http://player.youku.com/player.php/Type/Folder/Fid/13005645/Ob/1/Pt/0/sid/XMzAxNDEwMTY4/v.swf"
quality="high"
width="480"
height="400"
align="middle"
allowScriptAccess="always"
allowFullScreen="true"
mode="transparent"
type="application/x-shockwave-flash">
</embed>
 
webkit写在先,插件产生再后。Webkit的设计者写基类,插件编写者写子类来实现基类的虚函数。同时,webkit也提供api供插件的子类调用。这样解释来看,架构和Android Framework的思想一致,插件系统的控制点在webkit (framework)。

上图的NPPluginFuncs是插件必须要实现的接口,而如果你的插件要扩展浏览器规定的接口,向通过网页中的javascript脚本调用到插件的函数,就需要继承NPClass来做扩展。下面代码示范如何在网页中调用插件的扩展接口:
1.                 <embed type="application/plugin-mimetype">  
2.                 <script>  
3.                   var embed = document.embeds[0];   
4.                   embed.nativeMethod();   
5.                   alert(embed.nativeProperty);   
6.                   embed.nativeProperty.anotherNativeMethod();   
7.                 </script>
 

5.4.编译安装SampleBrowserPlugin

l        进入android源码顶层目录运行:make SampleBrowserPlugin

       会生成out/target/product/generic/data/app/SampleBrowserPlugin.apk

l        开启模拟器(模拟器创建时需要添加sdcard支持)

l        运行adb install “path to SampleBrowserPlugin.apk”

5.5.运行例程

l        写个s.html文件内容如下:

<objecttype="application/x-testbrowserplugin" height=50 width=250>

    <param name="DrawingModel"value="Surface" />

    <param name="PluginType"value="Background" />

</object>

l        运行adb push “path to s.html” /mnt/sdcard

l        在模拟器中启动Browser程序, 在地址栏输入:file:///mnt/sdcard/s.htmlfile:///sdcard/s.html,结果如下图说明浏览器正确加载运行了插件。\



5.6.SampleBrowserPlugin.apk里面包含了什么

l        libsampleplugin.so: NPAPI中plugin方的实现, 会安装到/data/data/com.android.sampleplugin/lib目录下。

l        一些配合libsampleplugin.so工作的java class。

l        一个“莫名其妙”的Service。

              为什么说它“莫名其妙”?让我们看看SamplePlugin.java的内容:

public class SamplePluginextends Service {

    @Override

    public IBinder onBind(Intentintent) {

        // TODO Auto-generated method stub

        return null;

    }

}

 

    初看觉得写代码的人是在开玩笑吧, 这样的Service能有什么用呢? 再看这个Service在AndroidManifest.xml里的描述:

       <service android:name=".SamplePlugin">

            <intent-filter>

                <action android:name="android.webkit.PLUGIN" />

            </intent-filter>

            <meta-data android:name="type" android:value="native"/>

        </service>

    不过没有这个Service, 现在有点启发了吗?试想一下Webkit是怎样知道这个插件的存在的呢?

Webkit是通过PackageManager查询系统中能够响应android.webkit.PLUGIN的Service来得到插件安装的路径的。

5.7.对Surface模式和Bitmap模式的理解

l        Surface模式:如果plugin要绘制的内容是动态的就需要在单独的surface上绘图。

l        Bitmap模式:Webkit为Plugin提供绘图的Bitmap, Plugin在上面绘图后Webkit再把Bitmap 的内容绘制到WebView所在的Surface上面。

5.8.具体分析

百闻不如一见, 去看SampleBrowserPlugin的代码吧, 结合上面提到的文档, 条理就会很清楚。

原文链接:http://www.2cto.com/kf/201203/123786.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值