PhoneGap学习笔记三:PhoneGap底层原理(中)

来源:互联网 发布:专业屏幕录制软件 编辑:程序博客网 时间:2024/05/24 03:23

昨天讲解了DroidGap类,DroidGap继承Activity,在DroidGap的init()初始化方法中设置了WebView,今天主要讲解CordovaWebView类以及CordovaWebviewClient类和CordovaChromeClient类。

CordovaWebView类

public class CordovaWebView extends WebView {...}

CordovaWebView类继承WebView类,在上一篇博文中已经对WebView类做了简要的介绍。PhoneGap针对不同平台的WebView做了扩展和封装,使WebView这个组件变成可访问设备本地API的强大浏览器,所以开发人员在PhoneGap框架下可通过JavaScript访问设备本地API。

可以说,CordovaWebView是整个PhoneGap的核心组件

复制代码
 1   /** 2      * Constructor. 3      * 4      * @param context 5      */ 6     public CordovaWebView(Context context) { 7         super(context); 8         if (CordovaInterface.class.isInstance(context)) 9         {10             this.cordova = (CordovaInterface) context;11         }12         else13         {14             Log.d(TAG, "Your activity must implement CordovaInterface to work");15         }16         this.loadConfiguration();17         this.setup();18     }
复制代码

CordovaWebView类的构造函数中,需要传入Context,并且Context必须是CordovaInterface的实现类(这里需要特别注意)。构造函数里调用loadConfiguration()和Setup()方法。在CordovaWebView类的构造函数重载方法中,还有setWebChromeClient和setWebViewClient对CordovaWebView的设置,原因在上篇最后也有讲到,这两个类的具体讲解在下面。

loadConfiguration

loadConfiguration()的作用是从res/xml/cordova.xml文件中加载Cordova配置信息,包括允许加载本地网页等,xml文件没几行,不细说。

setup

setup()方法初始化WebView配置,包括设置WebView初始化视图大小、是否允许垂直滚动条、触摸焦点信息。

因为PhoneGap的强大之处在于可以在Web端直接调用底层API,包括照相机、指南针、GPS等设备,其实现这些功能是通过JavaScript与底层交互实现的,所以在接下来设置settings.setJavaScriptEnabled(true)也就理所当然的事情了。

然后设置了数据库database、DOM storage和地理位置应用geolocation等信息,这里也不细讲。

需要着重提到的一点是最后PhoneGap插件的初始化。没错,PhoneGap插件的初始化是在这里进行的。PhoneGap插件管理机制是PhoneGap实现跨平台的基础。pluginManager类在后面也会讲到。

 

在上篇中讲到了DroidGap类loadUrl()方法,我们可以把它看成是整个PhoneGap应用的入口函数。实际DroidGap类的loadUrl()方法调用了CordovaWebView类的loadUrl()方法:

loadUrl

代码不多,也比较好理解,自己看吧,不细讲了。O(∩_∩)O~

loadUrlIntoView

这里需要细讲一下。Android WebView里并没有对加载超时的处理,PhoneGap自己实现了加载超时处理的方法。虽然看不看这里并不会影响对PhoneGap整个机制的理解,但拿出来讲一下对以后可能也会很有用处。

从代码的第26行注释看起,CordovaWebViewClient类有一个属性LoadUrlTimeout,这里不要被其定义为int类型迷惑,实际这个变量完全可以是boolean布尔值,因为它只有两个值:0和1。在页面开始加载时currentLoadUrlTimeout初始化为me.loadUrlTimeout(这个值初始化为0),在页面加载完成(注意:这里CordovaWebViewClient派上用场了),即CordovaWebViewClient类里OnpageFinished()方法中appView.LoadUrlTimeout被置成1。定义了loadError和runOnUiThread两个线程。然后起了一个在Timeout之后执行的线程,具体执行那个线程就看页面是否加载完成,即OnpageFinished()方法中appView.LoadUrlTimeout是否被置成了1。

 

CordovaWebViewClient类

CordovaWebViewClient类主要处理各种通知、请求事件的,重写了WebView类的一些方法,这里主要讲解其中onPageStarted()和onPageFinished()两个方法。

onPageStarted

从文档注释我们可以看出,onPageStarted方法用于通知主应用程序Web页面开始加载了。其中在页面加载时比较重要的一步是创建CallbackServer对象并初始化。(CallbackServer类可是实现插件异步执行的重头戏啊,好紧张啊,写了这么久CallbackServer终于出现了啊o(╯□╰)o)

onPageFinished

上文已经提到在onPageFinished方法中会执行this.appView.loadUrlTimeout++,定时器loadUrlTimeout的值被置为1,表明页面加载完成。如果没有执行到此,说明加载超时,在CordovaWebView类的loadUrlIntoView()方法中判断if(currentLoadUrlTimeout ==me.loadUrlTimeout),则执行loadError线程。

CordovaChromeClient类

WebChromeClient是辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等,一般的WebView可以不设置ChromeClient,比如你的WebView不需要处理JavaScript脚本。前面已经提到为什么PhoneGap要设置ChromeClient,不再多说。

引用某位大侠的话说,关于Java/JS互调,在android sdk文档中,也有用JsInterfaceloadUrl做到交互的示例。PhoneGap并没有选择用JsInterface,而是使用拦截prompt这种hack做法。

对JavaScript消息的拦截是在onJsPrompt()方法中实现并处理的。

onJsPrompt

onJsPrompt到底拦截了哪些信息呢?

从传入参数来说,比较重要的有两个:message和defaultValue。

message字符串存放了插件的应用信息,如Camera插件的图片质量、图片是否可编辑,图片返回类型等。

defaultValue字符串存放了插件信息:service(如Camera)、action(如getPicture())、callbackId、async等。

拦截到这些信息后就会调用this.appView.pluginManager.exec(service, action, callbackId, message, async)去执行。

当然onJsPrompt不只实现插件调用信息,还有JavaScript polling轮询信息、CallbackServer调用信息等处理。