360浏览器(Android)是国内做的比较出彩的"壳浏览器"。用Android自带的原生API来实现自己的功能。避免了在内核上的体力消耗。当然这种做法褒贬不一,我们不作评论。我本身并不用360的浏览器,我个人还是偏好QQ的浏览器,个人觉得做的比较好。当然不单纯指的产品形态上,当你用性能软件测试的时候,作为开发的人心中自然对一款好的软件充满好感。
我这篇文章将讨论关于360浏览器的页面生成机制,当然一切都基于猜想。我不想深究大多数人更加关心的UI控件,因为我对它的UI写法真的没有多大的兴趣。如果你熟悉自定义控件的话,相信对你来说,写这些控件对你来说也不是难事。
我假设你已经是对Android的sdk有所了解,尤其是对WebView有所了解的。兴许你也看过源码。我们知道WebView的跳转是只能在单个WebView内部完成的。而WebView的前进后退是调用api goBack()或者goForward()完成的。WebView这个控件里面的数据被Android的sdk封装的非常死,你很难通过接口来获得里面的重要数据。当然你兴许会想到反射。我并不认为反射是不值得用的方案,因为360的浏览器在代码中也用到了反射。如果你了解一点破解,不妨看一下360浏览器apk里面的代码。发现它也用反射来获得一部分数据。
其实最让我疑惑的就是360浏览器多页面的问题,我试图在这上面找答案。我们知道,我们可以复写WebViewClient的
shouldOverrideUrlLoading 方法来避免WebView 跳转,然后可以通过参数的URL来做一些特殊的事情。但是带来的问题也非常的明显。我如何处理“跳转”和“返回”的问题?
也就是说我们从WebView A生成了WebView B,假如B上有一个按钮返回,我如何再回到A呢?360浏览器实现的原理很简单,就是在WebView生成的时候事先load一下 about:blank, B在回退的时候发现是blank页面,就回到了A页面。现在回头想想似乎所有的浏览器实现都是采用这种步骤。不过作为新人,对我来说确实个不错的经验。
上面我们完成了返回,接下来就是跳转。如果网站下发了重定向信息,那么本地又如何做区分呢?这个逻辑我并没有破解出来,因为这段代码360隐藏的N个层次,如果你已经对360的代码进行了破解,你会发现,它也抽象出了和webview一模一样的接口用来管理,甚至webviewClient也一样。然后通过各种强转来进行传递。我实在是没有精力看下去了。下面是我实验过比较好的两个方案:
1.点击:
非重定向的信息一定是由点击事件产生的,因此加入点击检测可以用来判断那些跳转是由点击产生的。
2.绘制:
这是我认为比较好的方法,对于跳转页面,或者是中间页面,是很少有页面绘制的,你需要复写一个监听:
webview.setPictureListener(new PictureListener() {
public void onNewPicture(WebView view, Picture picture) {
// TODO Auto-generated method stub
System.out.println("draw picture");
}
});
来标记是否有绘制,如果没有绘制的链接变化就是跳转。当然你如果有更好的方案也请跟我沟通,我将进行修正。。