crossWalk替换webView集成

crossWalk替换webView集成
最近遇到一个盒子,性能有点差,设计出来的PSD效果那是史无前例的美。先说说我们的app架构吧,我们现在的搞法都是没有用androidTV原生写的。因为我们做的是电视端的APP,与电视交互的只有遥控,所以焦点标示很重要。我们的搞法就是webView浏览器加载我们的页面,有视频播放的就加个MediaPlay,这个自带播放器目前我们还是够用的,但是也有坑,后面说。
前端UI把这些切出来后,我们实现基本上是看盒子性能来写我们的页面的。差点的盒子,我们现在连jQuery都不敢引入。因为之前的经历说出来都是泪,所以目前我们都是最原始的写法,更加不谈什么ES6、ES7,css3的样式UI都不敢瞎写,总之就是大家都是内心把它当传统盒子看,在这个前提下小心谨慎的加样式,验效果,就是这样也发现还是入坑了。
当我们实现完了,在浏览器跑完后,我们app壳加载页面验,出来的效果惨不忍睹,页面就是想僵尸验,卡,卡,卡的感觉。最后找来一个专门人士,刻苦攻关,一个晚上集成crosswalk,这里先说集成步骤,然后我们再来说那些坑。
1、项目环境下的build.gradle引入
在repositories里加入
maven {
url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'
}
crossWalk替换webView集成_第1张图片
2、app下的build.gradle引入依赖
在dependencies里加入
compile 'org.xwalk:xwalk_core_library:23.53.589.4'
这个compile 需要说明一下,AS3.0之前是这样引入的,如果使用的AS3.0,那么引入可以改为
api 'org.xwalk:xwalk_core_library:23.53.589.4'
implementation 'org.xwalk:xwalk_core_library:23.53.589.4'
注意他们是有区别的
api完全等价于compile ,在编译性能上implementation 会有所提高的。但是模块之间有依赖还是用api,下面来看看官方解释:
在3.0版本中,compile 指令被标注为过时方法,而新增了两个依赖指令,一个是implement 和api,这两个都可以进行依赖添加,但是有什么区别呢? 
api 指令
完全等同于compile指令,没区别,你将所有的compile改成api,完全没有错。 
implement指令
这个指令的特点就是,对于使用了该命令编译的依赖,对该项目有依赖的项目将无法访问到使用该命令编译的依赖中的任何程序,也就是将该依赖隐藏在内部,而不对外部公开。 
文不如图
这里写图片描述 
crossWalk替换webView集成_第2张图片

用api指令编译,Glide依赖对app Module 是可见的,app Module也可以使用Glide依赖 
crossWalk替换webView集成_第3张图片

用implement指令编译依赖对app Module 是不可见的,app Module不可以直接使用Glide 
建议
在Google IO 相关话题的中提到了一个建议,就是依赖首先应该设置为implement的,如果没有错,那就用implement,如果有错,那么使用api指令,这样会使编译速度有所增快。
Ps:关于引入依赖的版本号怎么找最新的,在浏览器打开maven引入的地址,依次进入目录
org/xwalk/xwalk_shared_library/ ,最终url地址:
https://download.01.org/crosswalk/releases/crosswalk/android/maven2/org/xwalk/xwalk_shared_library/
crossWalk替换webView集成_第4张图片
最下面的就是最新版了,至少国内是最新版,如果,可能有新版,但是国外的maven地址速度不一定靠谱,国内最新版应该够用了。从上面看来,从intel在iWeb大会上吹过牛后,到现在对版本的维护貌似有所延期,最近一次已经是10个月之前的了。用第三方的玩意就怕版本变更。。。扯远了。
3、 AndroidManifest.xml引入权限
application节点里加入android:hardwareAccelerated="true"
这个是硬件加速,也就是如果盒子有GPU,设置这个会有更好的表现,同时分担CPU的压力,下面是官方解释:
从Android3.0 (API level11)开始,Android的2D显示管道被被设计得更加支持硬加速了.硬加速使用GPU承担了所有在View的canvas上执行的绘制操作.
  启用硬加速最简单的的方法是对整个应用启用硬件速.如果你的应用只使用标准的view和Drawable,全局启用硬加速将不会带来任何负面影响.然而,因为硬加速不是被所有的2D绘制所支持,所以启用它时可能对你的自定义绘制产生影响.出现的问题经常是不可见的,也可能是异常,或错误地显示了像素.为了避免这些问题,Android提供了在以下各级别上启用或禁止硬加速的能力:
Application
Activity
Window
View
我们这里简单粗鲁的对整个APP使用了硬件加速,也就是在Application节点里加的这个设置。
Activity级
与Application一样,也是在Activity节点设置即可。
Window级
   如果你需要更高颗粒度的控制,你可以使用以下代码为一个window启用硬加速:
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); 
注:现在你还不能在window级别禁止硬加速.
这个在写文档之前我们的app里是没有设置这个的,后来在代码中加入这几行代码,验证没有产生任何异常,但是貌似肉眼也没感觉出啥效果。
View级
你可以在运行时使用以下代码禁止个别的View的硬加速:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
注:当前你不能在View级别启用硬加速.View层有除禁止硬加速之外的其它功能.
判定一个View是否能被硬加速
  有时一个应用了解是否启用了硬件速是很有用的,对那些自定义View之类的东西尤其重要.在你的应用做了一些不被最新的管线所支持的自定义绘制时这更加重要.
  有两种方法可以检查应用是否被硬加速:
View.isHardwareAccelerated():如果View附加到一个硬加速的window上就返回true.
Canvas.isHardwareAccelerated():如果Canvas被硬加速了就返回true.
  如果你必须在你的绘制代码中做这个,应使用Canvas.isHardwareAccelerated()而不是View.isHardwareAccelerated().当一个view附加到一个硬加速的window上,它仍可以使用非硬件速的Canvas进行绘制操作.比如当为了高速缓存而把一个view画到一个bitmap中.
以上代码在onCreated里验证,没看出明显效果。不过我想现在的盒子应该都有GPU,打开硬件加速也没有什么影响吧。这些不是因为引入crossWalk才有的,这里只是顺便科普下,我自己也没有用过除了Application的硬件加速,今天写文档顺便也学习了。
4、布局引入使用
android:id="@+id/xwalkWebView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" />
到此,crossWalk的webView引入就完成了,它的API与webView惊人的相似,只是在有些处理上做了细化,感觉intel就是来研究google开源的android的,说不定intel以后也要出手机盒子智能系统了,YY下,大佬们的世界我反正不懂。
做完这些你就可以编译了,让这个apk打开个网页看看效果吧。如果你在编译中遇到

专门人士应该一看,就应该知道这是SDK的版本低了,设置修改下
crossWalk替换webView集成_第5张图片
crossWalk目前要求的SDK最低版本是16,也就是对应Android 4.1、4.1.1 (JELLY_BEAN)

5、下面就来说说我跟同事在哪个晚上遇到的坑吧(我目前对这个坑依然无解,第二天同事找到一个方法规避,我也找到一个猥琐的方法规避,但是目前都依然还有坑,主要是因为我们的壳只有一个Activity(盒子apk的常规搞法),视频播放使用的是MediaPlayer,有全屏和小屏播放切换)
网上描述的说:返回按钮, 它是会不用你写逻辑,而自己去执行网页的跳转的。
在webView里,你可能在dispatchKeyEvent方法里判断按钮键值,如果是返回,我们就调用webView.goBack(),执行页面返回。但是在crossWalk里,你按返回按键,还没有进dispatchKeyEvent页面就已经执行返回,跳到上一个历史页面了。对于这一点网上还有开发者叫好,我。。。。。
我们这里的返回做的不一定是返回上一个页面啊,我们还肩负MediaPlayer的全屏退出。当我在页面上小屏播放时,获得焦点按OK键是全屏播放并显示进度条时长,进入播控逻辑的,比如快进快退暂停。当我在全屏播放怎么退出呢?操作惯性肯定是会下意识的按返回,那问题就来了,这时候按返回。我希望的是像在webView里一样,我可以判断播放是否全屏的状态,然后决定是加载上一个页面还是退出全屏。事实上是页面先加载上一个页面了,我调用页面的js方法居然是调用的上一个页面的方法。。。。
也许有人会说那你全屏播放怎么不跳页面,在新页面做啊?
那我现在说下为什么,首先跳新页面是不是有加载时间?直接当前MediaPlayer调整配合它的SurfaceView大小全屏,播放不用中断,是不是给人一种很“快”的感觉?如果你跳页面,在再页面的js方法里写请求,获取播放串,调用MediaPlayer,那播放位置怎么做到跟原来小窗口连贯一致?(写到这我突然想到,如果我全屏播放页面是加载一个新页面(空页面或随便什么页面,反正被SurfaceView遮住在),但是播放的MediaPlayer我如果还是原先的逻辑直接调整当前SurfaceView的大小,我再按返回键是不是我页面返回也正确了,窗口我也可以调整了?需要验证,过后找专门同事讨论下)
同事的做法是参考网上的做法,自己在包一层,写个MyXwalkView继承XWalkView,重写父类的几个方法:
public MyXWalkView(Context context) {
super(context);
}

public MyXWalkView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public MyXWalkView(Context context, Activity activity) {
super(context, activity);
}

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK){
return false; //这里很关键说是要return true
}
return super.dispatchKeyEvent(event);
}
按照android的思维是我返回true就是告诉你我已经处理了,后面不用你再处理,同事的想法是在这里return true。然后我的Activity上的 dispatchKeyEvent就不再处理了,我们再在onKeyDown里处理,结果是无论我们返回true,false效果是一样的,页面确实按照我们的思路跳了,但是页面实际还是没有交由交由我们页面上的js自己控制(我们的url是用cookie的存储,类似栈先进后出,地址是否加到栈里也是我们自己控制,我可以请求多个地址但是这个地址不加到栈里,我返回就不用一级级返回。我们在页面的返回按钮上写我们自己的逻辑,也就是浏览器正常了,那就是我们就可以开始加apk壳了,壳里值针对上下左右返回,调用我们页面的js方法就行)。
我们项目里有一个场景是看完一条图文信息,点击下一条,页面加载下一个,下一个下下个。。。。这样进入的页面,我们都不加到url栈里,大家可以想象,我们用栈控制的肯定是正常的,但是APK壳实际是页面一个个叠起来了的,那么我按“返回”,差异就显而易见了。
就应为发现这个,我的想法就是在壳里还是根据键值调用对应的js方法,我没加载一个页面我就把apk加载的记录清理掉,这样就保证它自己没有页面可以返回,从而调用我的js方法执行我们url栈的逻辑。具体做法:
@Override
public void onPageLoadStopped(XWalkView view, String url, LoadStatus status) {
super.onPageLoadStopped(view, url, status);
xWalkWebView.getNavigationHistory().clear(); //清理历史记录
mHandler.sendEmptyMessageDelayed(HIDE_UI_LOADING_IMG, 500);
}
但是还是事与愿违,如果操作过快,不知道是不是清理历史记录需要时间还是怎么的,操作过快的返回还是偶现不正常的现象。这里清理历史记录我在shouldOverrideUrlLoading、onLoadFinished、onPageLoadStarted也都做了,不知道是不是还有什么地方没有做到位,导致返回还是偶现不正常,看来这个方法不靠谱。
上面是返回的坑,下面在说说布局的坑。
对于android布局,是写在xml下面的会在页面上面一点,越下面页面层级越靠上。这次我们是页面上有播放的,所以是webView在最上面,下面是MediaPlayer的SurfaceView,进度条SeekBar、时间TextView等。这样布局后发现播放窗口不出来,但是有声音,所以我们怀疑是webView挡住了,于是我们调整顺序结果还是不行,最后现场的同事发现如果按下“禁音”键,视频是一致可以展示,而按音量加减当音量的条条消失,视频就有被遮住了。说到这里不得不佩服同事的专业敏感度,他敏锐的想到这个调声音展示的条条、禁音时的图标展示不就是跟Toast一样吗?于是,他想到自己造一个在页面上,设置它透明,这样就。。。。不过不知道别人有没有遇到这样的问题,目前我这水枪反正是没整明白的。
综上所述,对于crossWalk的坑规避方法
1、返回采用包一层重写几个方法实现比较靠谱
2、布局一般不会有问题,如果有视频布局那就造个透明的Toast吧,期待更好的解决办法。
另外,这个开源的2017年前的版本更新基本是1-2月一个,今年最近的版本是1.20号的,现在11月21了,还没有更新,不知道后面intel的规划是怎么样的。用开源第三方的就这点不好,有些不可控,之前公司用的金山云的播放器,现在金山云要收费了。。。感觉我们应该还是让公司的专门人事开始常用组件的开发。比如webView、MediaPlayer,之前同事也提到过播放器要自己写,就目前看貌似已经全民RN了。安卓原生都转RN了,原生写的越来越少了,我觉得吧RN应该让我们这种非专门人士上手,曾经环境都搭了没有机会。。。。
扯远了,以上就是all。还有很多不明白的地方,这里可能没有遇到,期待crossWalk的第二阶段分享。




你可能感兴趣的:(android盒子,crossWalk)