Android Browser UI与chromium核心的混搭

近期一直在参照chromium android的ContentShell做移植,当然做浏览器,ContentShell肯定是不够的。有时为了试验chromium android版本的功能,就会在ContentShell上添加一些界面元素。随着功能越来越多,ContentShell上摆放的button也越来越多,界面越来越难看,代码也越来越乱。由此想重新规划一下Browser的UI,但是一来对Android的UI研究不多,二来在UI上花费过多的精力,重心就会有所偏离,毕竟我的研究方向是移植与内核优化。于是就寻求现成的浏览器代码,找了一圈开源浏览器,发现Android自带的浏览器最适合。Android Browser由Google出品,质量自然是没的说,代码结构清晰,功能完备,就是其UI对国人来说不太友好。下面就分析一下将chromium核心挂接到Android Browser上。

一、Android4.0 Browser架构分析

Android 4.0的浏览器引入了很多新特性,如隐私浏览、预加载、离线阅读、google帐号同步等。Android 4.0也是手机和平板系统融合的一个版本,自然的Android 4.0 Browser也提供了两套界面,分别适应手机和平板系统。为此,Android 4.0 Browser采用了视图/控制器分离的架构,可以灵活的支持多套界面,总体的类图如下:

AndroidBrowserUI_ClassDiagram

Android Browser采用了经典的MVC设计模式,可以很方便的支持手机和平板两套UI,这也为改造UI提供了便利。Browser的UI分为三个层次,分别是总体UI、Tab和WebView,对应的控制器为UiController、TabController和WebViewController。总体UI对应着主界面,抽象出一个接口UI,派生子类XLargeUi对应于平板的UI,PhoneUi对应于手机的UI。在BrowserActivity类,有一个方法isTablet用于判断平板还是手机。实例化UI子类的代码如下:

boolean xlarge = isTablet(this);
if (xlarge) {
    mUi = new XLargeUi(this, mController);
} else {
    mUi = new PhoneUi(this, mController);
}
mController.setUi(mUi);

Browser UI的复用技巧

为了达到UI的复用,Browser的界面被划分为多个区域,然后组合起来形成一个完整的用户界面。这是通过两种方式实现的:

1. 使用代码动态加载

比如主界面的xml定义如下:

<merge
     xmlns:android="https://schemas.android.com/apk/res/android">
     <FrameLayout android:id="@+id/fullscreen_custom_content" 
         android:visibility="gone" 
         android:background="@color/black" 
         android:layout_width="match_parent" 
         android:layout_height="match_parent" 
     />
     <LinearLayout android:orientation="vertical" 
        android:id="@+id/vertical_layout" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent">
        <LinearLayout android:id="@+id/error_console" 
            android:layout_width="match_parent" 
            android:layout_height="wrap_content" 
        />
        <FrameLayout android:id="@+id/main_content" 
            android:layout_width="match_parent" 
            android:layout_height="match_parent" 
        />
    </LinearLayout>
</merge>

然后在代码中动态添加到界面,这是通过LayoutInflater的inflate方法实现的:

        FrameLayout frameLayout = (FrameLayout) mActivity.getWindow()
                .getDecorView().findViewById(android.R.id.content);
        LayoutInflater.from(mActivity)
                .inflate(R.layout.custom_screen, frameLayout);
        mContentView = (FrameLayout) frameLayout.findViewById(
                R.id.main_content);

Tab内容则是在attachTabToContentView(Tab tab)方法中动态附着到mContentView上的。

2. xml包含

android提供了一个很好的特性,就是xml layout文件可以包含另外一个xml layout文件,这样将共用的一些UI分离出来,放到单独的xml文件,可以最大程度的达到复用的目的。例如title_bar.xml文件就包含了对title_bar_nav的引用:

 <RelativeLayout
     xmlns:android="https://schemas.android.com/apk/res/android" 
     android:id="@+id/titlebar" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content">
     <include
         layout="@layout/title_bar_nav" 
         android:id="@+id/taburlbar" 
         android:layout_width="match_parent" 
        android:layout_height="@dimen/toolbar_height" />
    ...
</RelativeLayout>

二、Chromium android分析

关于chromium的分析,可以参考<<Chromium源码分析:Content API>>。chromium在三个层次上提供了API,分别是:WebKit API/Content API/Chrome API。我们之前是在Content API层面做浏览器,不过最新的chromium代码在chrome层面上进行了分层,将一些浏览器的UI剥离出来,这样既可以利用chrome的一些实现(比如多Tab、密码保存,扩展),又可以有自己独立的UI。Android版本提供了一个简单的参考实现ChromiumTestShell,非常具有参考价值,类结构图如下:

ChromiumTestShell_ClassDiagram

从类图中可以大致推断出和Android Browser的对应关系:

TestShell_Browser_Contrast

当然,上图只是一个大致的对应关系,并非严格的一一对应。

三、捏合Android Browser和Chromium TestShell

为了让Chromium的代码挂接到Browser上,设计了一个glue层,就是按照WebView API封装chromium的接口,这样Browser的代码只需稍作修改。设计的类图如下:

MogoBrowser_Glu_ClassDiagram

其中TabManager的代码合并到TabControl(也可以使用包含或者代理模式),修改TabControl原来的创建/显示/隐藏/关闭Tab的代码,改用TabManager的相应代码。

四、后续

Android Browser的代码使用了很多SDK未公开的API,可以采用一些方法避免这一问题,后面考虑去掉这些私有API调用,也考虑使用Android2.3 SDK,使之支持更多的手机。另外chromium android的移植代码不完善,后续会花主要精力做这一块的完善工作。

补充:

2013-05

工作重点转向在chromium之上提供Android WebView兼容API的工作,请关注github上的项目:https://github.com/mogoweb/chromium_webview

致力于为WebApp/hybrid APP提供强大的引擎。

Android Browser UI与chromium核心的混搭》上有 6 条评论

  1. 饭饭风

    我在最新的的content_shell项目中的文件并没有看到类是于TabBase,TabManager的对象,只能找到ContentView对象。不过源码里面的注释默认一个ContentVeiw对象就是一个Tab样的。

    回复
  2. 匿名

    饭饭风 :
    我在最新的的content_shell项目中的文件并没有看到类是于TabBase,TabManager的对象,只能找到ContentView对象。不过源码里面的注释默认一个ContentVeiw对象就是一个Tab样的。

    在chrome/android/testshell下,考虑到chrome中实现了一些浏览器的特性,所以基于chromium_testshell移植更容易

    回复

发表评论

电子邮件地址不会被公开。

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>