0x00. 为何不直接使用内置的WebView组件?
Android中的WebView组件,在4.4以前的版本是WebKit的内核,4.4以后才换成chromium的内核。而且不同版本之间运行的效率也参差不齐,适配问题很让人头疼。因此考虑用第三方webview是个不错的选择。
0x01、有哪些第三方WebView可供选择呢?
方案1:Crosswalk
Home · crosswalk-project/crosswalk-website Wiki · GitHub
优点:各种流畅、强大,静态集成
缺点:体积过大,打包后的APK要48M左右,这个问题有点致命
解决思路:使用Crosswalk的精简版 crosswalk-lite(此版本不是官方主推,更新也不频繁)
Crosswalk Lite
可以看到,体积确实小了很多,但是,请注意这段话:
Lite仅支持x86和ARM的32位版本。 尚不支持x86_64和ARM64。所以,如果想适配64位的Android机,此方案只能舍弃。
接下来我们再看看方案2
方案2:腾讯TBS X5内核webview
优点:体积小,可以动态集成,静态集成,而且APP接入TBS后可以共享使用微信,或者手机QQ,QQ浏览器的X5内核
缺点:首次安装APP后第一次启动时X5内核总是加载失败(手机中已经安装了微信和QQ也不行,直接运行官网的demo也是首次加载失败),kill掉程序后再次启动就好了(这个问题有人已经在官网反馈了,但是官方没有给出解决方案)
集成可以动态集成(启动APP后再开始下载X5内核)和静态集成(X5内核一起打包进APK,不需再次下载)
0x02. 动态集成TBS(studio)
A. 获取TBS
去官网下载TBS的SDK文件,选择第一个(完整版)即可,目前是v3.6.0.1315版本,下载后解压文件如下:
其中,studio版的demo是module, 不能直接运行,如果想跑起来,需要以module添加进某个项目中再运行这个module
B. 新建项目
新建一个studio的空项目,把解压SDK后的jar包文件放在libs目录下,并导入,如图:
C. 集成TBS
把 SDK接入示例-Android Studio.zip 解压,把main目录下的jniLibs文件夹整个复制到自己的项目的main目录下,如图:
x5暂时不提供64位so文件,为了保证64位手机能正常加载x5内核,需如下配置:
1)打开app的build.gradle,在defaultConfig标签内加入
ndk{abiFilters"armeabi","armeabi-v7a","x86","mips"}
完整如下:
defaultConfig {
applicationId "your applicationId"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk{abiFilters "armeabi", "armeabi-v7a", "x86", "mips"}
}
2)如果配置后编译报错,打开项目的gradle.properties文件,在最后加上
android.useDeprecatedNdk=true
至此,动态集成TBS X5内核webview介绍完毕,总结一下动态集成的特点,就是先集成,后加载(当手机中没有X5内核时TBS底层会自动下载X5内核)。可是,如果用户第一次安装就没有网络,手机中也没有X5内核,这种场景怎么办呢?总不能用系统的webview吧,如果那样,很多功能将不可使用。所以,接下来介绍一下静态集成,集成完成后不需任何网络就可以使用
0x03. 静态集成TBS(studio)
动态集成和静态集成大同小异,具体步骤:
1:打开连接后,下载压缩包,解压后,是如下文件:
2:和动态集成一样,把jar包放在项目的libs目录下面,导入
3:把apk文件的后缀改为zip, 然后解压,得到多个so包,像动态集成一样,把jniLibs文件夹粘贴到main目录下, 把jniLibs里面的armeabi文件夹清空,把刚才解压APK文件得到的所有so包放在armeabi文件夹中。其实整个过程就是把动态集成中缺少的so包添加到项目中,这样就不需要再下载了。
至此,静态集成TBS完毕。下面我们再来介绍一下用法(两种集成方式使用基本相同,只有预加载X5内核的代码不同)
0x04. 使用WebView(studio)
A. 添加权限
打开app的清单文件AndroidManifest.xml,添加权限(从官方demo中复制即可) 如下:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 硬件加速对X5视频播放非常重要,建议开启 -->
<uses-permission android:name="android.permission.GET_TASKS"/>
B. 加载X5内核
这一步骤静态集成和动态集成代码不同,咱们分开介绍
1)动态集成的X5内核加载代码:
因为在打开webview之前要加载X5内核,此过程比较耗时,虽然是异步的,但是如果没有加载完成或者没有加载成功,打开的webview将是Android原生的控件,而不是X5内核的WebView,所以这个动作越早做越好,因此官方建议自定义application, 在onCreate方法中调用QbSdk.initX5Environment()来预加载X5内核,该方法需要传递2个参数,第一个参数是context,第二个参数是实现QbSdk.PreInitCallback接口的实例,此接口是X5内核初始化的回调接口,有两个抽象方法,onCoreInitFinished()和 onViewInitFinished(boolean var1),其中,onCoreInitFinished()回调方法表示X5内核初始化完成(注意,不保证一定成功),onViewInitFinished(boolean var1) 回调方法回传的参数如果为true,表示X5内核加载成功,否则X5内核加载失败。如下:
public class APPAplication extends Application {
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
@Override
public void onViewInitFinished(boolean arg0) {
// TODO Auto-generated method stub
//x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
Log.d("app", " onViewInitFinished is " + arg0);
}
@Override
public void onCoreInitFinished() {
// TODO Auto-generated method stub
}
};
//x5内核初始化接口
QbSdk.initX5Environment(getApplicationContext(), cb);
}
}
2)静态集成的X5内核加载代码:
在加载X5内核时(即application的onCreate方法里),不再调用QbSdk.initX5Environment()方法,而是调用QbSdk.preinstallStaticTbs(getApplicationContext());方法,而且要在异步线程中执行。
public class LemageApplication extends Application {
public static boolean x5Init;
@Override
public void onCreate() {
super.onCreate();
new Thread(new Runnable() {
@Override
public void run() {
QbSdk.preinstallStaticTbs(getApplicationContext());
}
}).start();
}
}
最后,无论是动态集成还是静态集成,只要自定义了application, 别忘了在AndroidManifest.xml文件中更改名字 ,同时,如果需要硬件加速的话,也要加上
android:hardwareAccelerated="true"
如下代码:
<application
android:name="your applicationId"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:hardwareAccelerated="true"
android:theme="@style/AppTheme">
至此,就可以在项目中使用x5内核的webview了。如果是想通过x5来播放视频,那么请继续往下看:
0x05. 播放视频(studio)
如果需要webview播放视频,那么有两种方式,第一种,参考官方demo的FullScreenActivity类,此类中有一个webview加载的是本地的html,在html中通过标签来播放网络视频,可以调节屏幕大小,可以根据自己的需求灵活控制。第二种先要在AndroidManifest.xml中声明一个VideoActivity类,如下:
<!--视频播放界面-->
<activity
android:name="com.tencent.smtt.sdk.VideoActivity"
android:alwaysRetainTaskState="true"
android:configChanges="orientation|screenSize|keyboardHidden"
android:exported="false"
android:launchMode="singleTask">
<intent-filter>
<action android:name="com.tencent.smtt.tbs.video.PLAY"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
然后想播放视频时,可以在自己的activity中直接调用TbsVideo.openVideo()方法,该方法需要传递两个参数,第一个是context, 第二个是播放视频的路径. 需要注意的是,在调用TbsVideo.openVideo()方法前,需要判断一下视频播放器是否初始化完成,代码如下:
private void startVideo() {
if ((TbsVideo.canUseTbsPlayer(this))) {
//可以播放视频
TbsVideo.openVideo(this, urlTest);
} else {
Toast.makeText(this, "视频播放器没有准备好", Toast.LENGTH_SHORT).show();
}
}
0x06. 使用office(studio)
X5内核的一大特色就是可以在手机不安装office的情况下,可以只需下载插件即可浏览office文档(下载插件的过程由TBS内部控制),应用层只需调用API即可。下面以浏览PDF文件举例:(注:X5内核不能浏览远程office,只能先下载到本地再浏览)
A. TbsReaderView
显示浏览PDF效果的控件不是webview,而是TbsReaderView,而且,TbsReaderView不能在XML中布局,必须要代码动态布局,否则报错。通过查看TbsReaderView的源代码发现,它只有一个构造方法,需要两个参数,第一个参数是context, 第二个参数是TbsReaderView.ReaderCallback,也就是说,如果在xml中布局,那么构造方法不会读取XML中的属性,所以只能代码生成实例后添加进父控件中显示。
B. 调用
private void displayFile() {
Bundle bundle = new Bundle();
//传递文件路径
bundle.putString("filePath", url);
//加载插件保存的路径
bundle.putString("tempPath", Environment.getExternalStorageDirectory().getPath());
boolean result = mTbsReaderView.preOpen(parseFormat("测试XLSX.xlsx"), false);
if (result) {
mTbsReaderView.openFile(bundle);
}
}
首先,创建一个Bundle对象,然后,分别put目标office文件的本地路径,和pdf插件保存的路径,然后把bundle对象作为参数传递给TbsReaderView就可以了。
至此,TBS X5内核webview集成和基础使用全部介绍完毕,对比如下:
动态集成:体积小,所以启动程序后如果没有X5内核会自动下载
静态集成:体积大,但是不需要下载,使用户在没有网的情况下也可以使用
*** ******注意:
网上有很多文章说是无论是静态还是动态集成,有的机型首次安装APP时加载X5内核都失败,必须要kill掉程序后再次启动才能加载成功。这个问题我自己也遇到过。其实产生这个问题的原因是X5内核还没有加载完成就加载WebView,此时的WebView是原生的WebView,而不是X5内核的,此时如果不kill掉程序,哪怕X5内核加载完成也改变不了这个WebView的内核了。所以会造成这个问题。解决的办法就是想办法在X5内核加载完成之前不加载com.tencent.smtt.sdk.WebView就可以了,等X5内核加载成功后再加载com.tencent.smtt.sdk.WebView。如果在X5内核加载成功之前一定要用WebView,可以先用原生的代替。这样哪怕是首次安装APP也可以不用kill掉程序就可以用X5内核了。
但是,还有一个问题,官网说是X5内核共享,但是手机中明明安装了微信,QQ,可是首次安装为什么还需要加载X5内核?如果有知道的同仁请告知一下,感谢。