CordovaActivity加载Web页源码分析

来源:互联网 发布:java获取图片绝对路径 编辑:程序博客网 时间:2024/06/11 14:55

之前做项目直接用WebView加载url显示Web页,感觉简单无比。最近接触项目,采用的是Cordova框架实现,其中Activity继承自CordovaActivity然后在onCreate代码中就直接调用loadUrl(url)就加载网页了,当时我的小心脏扑通跳啊,因为当时知道Cordova框架还是基于WebView来实现的混合开发框架,所以为了一探究竟,决定研究研究源码看看到底是在什么地方通过WebView来加载的页面,这也就是本文的主要内容。

1、涉及到的主要类介绍

本小节主要是介绍分析代码过程中,揪出来的一些类,当然其中还有一些接口,但由于接口没有实现方法,所以在分析中略过,就直接列出涉及到的类了。

CordovaActivity:实例化CordovaWebViewImpl类型成员变量CordovaWebViewImpl:实例化SystemWebViewEngine类型成员变量SystemWebViewEngine:实例化SystemWebView类型成员变量SystemWebView:WebView子类loadUrl操作最中在这个类中完成

2、初始化流程梳理

首先,CordovaActivity通过loadUrl方法开始加载页面

public void loadUrl(String url) {    if (appView == null) {       init();    }    // If keepRunning    this.keepRunning = preferences.getBoolean("KeepRunning", true);    appView.loadUrlIntoView(url, true);}

通过代码可以看到其中有一个init()的初始化方法,它都干了啥呢?贴出它的代码看看吧

protected void init() {    appView = makeWebView();    createViews();    if (!appView.isInitialized()) {        appView.init(cordovaInterface, pluginEntries, preferences);    }    cordovaInterface.onCordovaInit(appView.getPluginManager());    // Wire the hardware volume controls to control media if desired.    String volumePref = preferences.getString("DefaultVolumeStream", "");    if ("media".equals(volumePref.toLowerCase(Locale.ENGLISH))) {        setVolumeControlStream(AudioManager.STREAM_MUSIC);    }}

其中有一个appView是一个CordovaWebViewImpl类型的变量,它通过makeWebView方法来完成实例化

protected CordovaWebView makeWebView() {    return new CordovaWebViewImpl(makeWebViewEngine());}

从makeWebView方法实现可以看到,在实例化CordovaWebViewImpl时,还在CordovaWebViewImpl构造函数中通过makeWebViewEngine方法返回了SystemWebViewEngine类型参数,也就是在实例化CordovaWebViewImpl类的时候,实例化了它的SystemWebViewEngine成员变量。
再来看看makeWebViewEngine方法

protected CordovaWebViewEngine makeWebViewEngine() {    return CordovaWebViewImpl.createEngine(this, preferences);}/********************/public static CordovaWebViewEngine createEngine(Context context, CordovaPreferences preferences) {   String className = preferences.getString("webview", SystemWebViewEngine.class.getCanonicalName());   try {        Class<?> webViewClass = Class.forName(className);        Constructor<?> constructor = webViewClass.getConstructor(Context.class, CordovaPreferences.class);        return (CordovaWebViewEngine) constructor.newInstance(context, preferences);    } catch (Exception e) {        throw new RuntimeException("Failed to create webview. ", e);    }}

通过makeWebViewEngine方法实例化CordovaWebViewImpl,同时在CordovaWebViewImpl中实例化SystemWebViewEngine变量,这里实例化SystemWebViewEngine变量用到了反射构建实例的方法,以前我没有用这种用法,通过阅读源码也算是学到东西了。从构造函数的参数可以看出是通过SystemWebViewEngine的如下构造函数来实例化SystemWebViewEngine成员的。

/** Used when created via reflection. */public SystemWebViewEngine(Context context, CordovaPreferences preferences) {    this(new SystemWebView(context), preferences);}public SystemWebViewEngine(SystemWebView webView, CordovaPreferences preferences) {    this.preferences = preferences;    this.webView = webView;    cookieManager = new SystemCookieManager(webView);}

从以上代码可以看出,在实例化SystemWebViewEngine的过程中,又实例化了SystemWebViewEngine的SystemWebView成员变量。

到现在,CordovaActivity中的loadUrl中的init()初始化方法,算是完成了它干的事情,即初始化CordovaActivity的CordovaWebViewImpl成员变量,初始化CordovaWebViewImpl的SystemWebEngine成员变量,初始化SystemWebEngine的SystemWebView成员变量,这样梳理了一遍初始化流程后,几个类之间的关系也就理清楚了。

3、加载Url流程梳理

再看CordovaActivity的loadUrl方法,在完成初始化后执行了appView.loadUrlIntoView(url,true)方法,它调用了CordovaWebViewImpl中的loadUrlIntoView方法,其中有一段关键代码如下

cordova.getActivity().runOnUiThread(new Runnable() {   public void run() {         if (loadUrlTimeoutValue > 0) {             cordova.getThreadPool().execute(timeoutCheck);         }         engine.loadUrl(url, _recreatePlugins);    }});

其中在UI线程中调用了engine.loadUrl这个方法,对应到SystemWebViewEngine中去找对应方法有:

@Overridepublic void loadUrl(final String url, boolean clearNavigationStack) {     webView.loadUrl(url);}

这里的webView就是SystemWebView了,那么整个加载到这里就基本结束了。第一次尝试着讲解阅读源码的东西,发现自己能讲出来的才是真的理解了的,当然这里讲的不好,也可能是自己理解的还不透彻,有疑问的欢迎留言咨询。