LZ-Says:想和你喝酒是假,想醉你怀里是真。
前言
最近一段时间,都是在被前端虐了,还好,谈不上游刃有余,至少可以实现所需功能,调试起来也不会太过于懵逼。
当然,和大佬相比,还是差距很多。前段时间,因为个人原因,暂时停滞了前行之路,而今,慢慢拾起,希望努力实现自己想要的。
好久没碰 Android,今天拿 TBS X5 作为练手~
TBS X5 了解
曾经,在 Android 的世界里,加载网页,WebView 首当其冲,但是,当理想遇到显示,又出现如下情况 (节选自 TBS X5 官方) :
- 传统系统内核 ( Webview ) 存在适配成本高、不安全、不稳定、耗流量、速度慢、视频播放差、文件能力差等问题
那么针对以上提出的问题,我们该怎么办呢?
- 优化?Enmmm,Sorry,打扰了。
- 第三方开源方案,Enmmm,似乎还是有些问题,应用率以及使用率相对来说有待期待。
- TBS X5?试试?
那么 TBS X5 是个什么鬼?它又是拥有着何样的才能呢?一起来看~
腾讯浏览服务(TBS,Tencent Browsing Service)整合腾讯底层浏览技术和腾讯平台资源及能力,提供整体浏览服务解决方案。
而 ta 又具有何方风采呢?为了省事儿,直接官方盗图~
- 速度快:相比系统 webview 的网页打开速度有 30+% 的提升;
- 省流量:使用云端优化技术使流量节省 20+%;
- 更安全:安全问题可以在 24 小时内修复;
- 更稳定:经过亿级用户的使用考验,CRASH 率低于 0.15%;
- 兼容好:无系统内核的碎片化问题,更少的兼容性问题;
- 体验优:支持夜间模式、适屏排版、字体设置等浏览增强功能;
- 功能全:在 Html5、ES6 上有更完整支持;
- 更强大:集成强大的视频播放器,支持视频格式远多于系统 webview;
- 视频和文件格式的支持 x5 内核多于系统内核;
- 防劫持是 x5 内核的一大亮点
简单了解之后,我们开始准备玩转操作~
TBS X5 实践
TBS X5 SDK 下载地址:https://x5.tencent.com/tbs/sdk.html
针对官方提供 SDK,这里我们选择 Android SDK(完整版),最新的更新日期为:2019-02-13。首先创建项目,将下载下来的 So 库文件以及 Jar 包倒入工程,如下所示:
设置支持的 CPU 架构以及开启 DataBinding 支持:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
defaultConfig {
...
// 支持 CPU 架构
ndk {
abiFilters "armeabi"
}
...
}
...
dataBinding {
enabled = true
}
}
dependencies {
...
implementation files('libs/tbs_sdk_thirdapp_v4.3.0.1020_43633_sharewithdownload_withoutGame_obfs_20190111_105200.jar')
}
定义常量工具类:
package com.tbs.tbsdemo.app
/**
* @author: heliquan
* @data: 2019/3/28
* @desc: 生活不易 且行且珍惜
*/
/**
* 传递状态标志
*/
const val S_STATE_CODE = "stateCode"
/**
* 加载网页
*/
const val S_LOAD_URL = "loadUrl"
/**
* 加载视频
*/
const val S_LOAD_VIDEO = "loadVideo"
/**
* URL 地址
*/
const val U_URL = "https://heliquan.blog.csdn.net/"
/**
* 在线视频地址
*/
const val U_VIDEO = "https://img-cdn-qiniu.dcloud.net.cn/uniapp/doc/uni-app20190127.mp4"
随后嘛,添加对应的权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
<!-- 硬件加速对X5视频播放非常重要,建议开启 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
定义 BaseApplication,初始化 TBS X5:
package com.tbs.tbsdemo.app.base
import android.app.Application
import android.util.Log
import com.tencent.smtt.sdk.QbSdk
/**
* @author: heliquan
* @data: 2019/3/28
* @desc:
*/
class BaseApplication : Application() {
override fun onCreate() {
super.onCreate()
initTencentX5()
}
private fun initTencentX5() {
val cb = object : QbSdk.PreInitCallback {
override fun onViewInitFinished(arg0: Boolean) {
Log.e("HLQ_Struggle", "x5 內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核:$arg0")
}
override fun onCoreInitFinished() {
Log.e("HLQ_Struggle", "x5 內核初始化 onCoreInitFinished")
}
}
QbSdk.initX5Environment(applicationContext, cb)
}
}
当然,不要忘记在 AndroidManifest 中指明,如下:
<application
android:name=".app.base.BaseApplication"
...
android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning">
...
</application>
接下来,搭建一个类似下面的门户:
并在首页设置跳转,这里默认已经创建了 Web 加载页:
package com.tbs.tbsdemo
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import com.tbs.tbsdemo.app.S_LOAD_URL
import com.tbs.tbsdemo.app.S_LOAD_VIDEO
import com.tbs.tbsdemo.app.S_STATE_CODE
/**
* @author HLQ_Struggle
* @date 2019年3月24日
* @desc
*/
class MainActivity : AppCompatActivity() {
private val mSelfActivity = MainActivity@ this
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
/**
* Activity 跳转
* @param stateCode
*/
private fun startActivity(stateCode: String) {
var intent = Intent(mSelfActivity, X5WebActivity::class.java)
intent.putExtra(S_STATE_CODE, stateCode)
startActivity(intent)
}
fun loadUrl(view: View) {
startActivity(S_LOAD_URL)
}
fun loadVideo(view: View) {
startActivity(S_LOAD_VIDEO)
}
}
而最后则是开始着手编写我们 Web 加载页,简单说下想法:
- Web 页根据上页传递标志符进行动态设置加载 URL;
- Web 页加载时,顶部需要有进度条;
- 剩下则是 Web 常规设置,例如 WebSettings 等。
哦可,首先着手编辑 Web 页的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".X5WebActivity">
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
style="?android:attr/progressBarStyleHorizontal"
android:indeterminateDrawable="@color/colorBar"
android:progress="0"
android:max="100"
android:layout_height="3dp"/>
<com.tencent.smtt.sdk.WebView
android:id="@+id/x5_web"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</layout>
下面,则是我们的 Web 加载页,很 easy,直接附上源码吧~
package com.tbs.tbsdemo
import android.databinding.DataBindingUtil
import android.graphics.Bitmap
import android.graphics.PixelFormat
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.KeyEvent
import android.view.View
import android.widget.Toast
import com.tbs.tbsdemo.app.*
import com.tbs.tbsdemo.databinding.ActivityX5WebBinding
import com.tencent.smtt.export.external.interfaces.SslError
import com.tencent.smtt.export.external.interfaces.SslErrorHandler
import com.tencent.smtt.sdk.WebChromeClient
import com.tencent.smtt.sdk.WebSettings
import com.tencent.smtt.sdk.WebView
import com.tencent.smtt.sdk.WebViewClient
/**
* @author HLQ_Struggle
* @date 2019年3月24日
* @desc 重新感受下 Android 之美 重新领略 Kotlin 优雅
* */
class X5WebActivity : AppCompatActivity() {
private val mSelfActivity = X5WebActivity@ this
var mDataBind: ActivityX5WebBinding? = null
var mLoadUrl = ""
override fun onCreate(savedInstanceState: Bundle?) {
window.setFormat(PixelFormat.TRANSLUCENT)
super.onCreate(savedInstanceState)
mDataBind = DataBindingUtil.setContentView(mSelfActivity, R.layout.activity_x5_web)
initLoadUrl()
initX5WebViewSettings()
}
private fun initLoadUrl() {
var stateCode = intent.getStringExtra(S_STATE_CODE)
when (stateCode) {
S_LOAD_URL -> {
mLoadUrl = U_URL
}
S_LOAD_VIDEO -> {
mLoadUrl = U_VIDEO
}
else -> {
Toast.makeText(mSelfActivity, "传了个鸟啊这是???", Toast.LENGTH_SHORT).show()
}
}
}
private fun initX5WebViewSettings() {
// 支持获取手势焦点
mDataBind?.x5Web?.requestFocusFromTouch()
initWebSettings()
initChromeClient()
mDataBind?.x5Web?.loadUrl(mLoadUrl)
}
private fun initWebSettings() {
val webSetting = mDataBind?.x5Web?.settings
// 开启 JS
webSetting?.javaScriptEnabled = true
// 开启支持插件
webSetting?.pluginsEnabled = true
// 将图片调整适合 WebView 大小(响应式)
webSetting?.useWideViewPort = true
// 缩放至屏幕大小
webSetting?.loadWithOverviewMode = true
// 支持缩放
webSetting?.setSupportZoom(true)
webSetting?.builtInZoomControls = true
// 隐藏默认缩放控件
webSetting?.displayZoomControls = false
// 支持重新布局
webSetting?.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN
// 开启多窗口
webSetting?.supportMultipleWindows()
// 不使用缓存
webSetting?.cacheMode = WebSettings.LOAD_NO_CACHE
// 允许访问文件
webSetting?.allowFileAccess
// 允许通过 JS 打开新窗口
webSetting?.javaScriptCanOpenWindowsAutomatically
// 允许自动加载图片
webSetting?.loadsImagesAutomatically = true
// 允许定位
webSetting?.setGeolocationEnabled(true)
// 设置默认编码格式
webSetting?.defaultTextEncodingName = "UTF-8"
// 不显示水平滚动条
mDataBind?.x5Web?.isHorizontalScrollBarEnabled = false
// 不显示垂直滚动条
mDataBind?.x5Web?.isVerticalScrollBarEnabled = false
}
private fun initChromeClient() {
// 使用内置浏览器打开
mDataBind?.x5Web?.webViewClient = object : WebViewClient() {
/**
* 开始加载网页
*/
override fun onPageStarted(webView: WebView?, url: String?, bitmap: Bitmap?) {
super.onPageStarted(webView, url, bitmap)
}
/**
* 网页加载完成
*/
override fun onPageFinished(webView: WebView?, url: String?) {
super.onPageFinished(webView, url)
}
/**
* 网页加载失败处理
*/
override fun onReceivedError(webView: WebView?, errorCode: Int, desc: String?, faileUrl: String?) {
super.onReceivedError(webView, errorCode, desc, faileUrl)
}
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
view.loadUrl(url)
return true
}
/**
* Https 处理
*/
override fun onReceivedSslError(webView: WebView?, handler: SslErrorHandler?, sslError: SslError?) {
// 信任所有网址证书
handler!!.proceed()
}
}
mDataBind?.x5Web?.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
mDataBind?.progressBar?.progress = newProgress
if (newProgress == 100) {
// newProgress 代表网页加载进度,到达 100 完成加载
mDataBind?.progressBar?.visibility = View.GONE
}
}
}
}
/**
* 重写返回 使其在网页中点击返回键可以依次返回上级
*/
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (keyCode == KeyEvent.KEYCODE_BACK && mDataBind?.x5Web?.canGoBack()!!) {
mDataBind?.x5Web?.goBack()
} else {
finish()
}
return false
}
}
一起来看效果演示图:
有的小伙伴说了,如何确保集成 TBS X5 成功呢?很 easy,随便打开网页,复制显示小水滴即说明成功,如下所示:
后记
当然,TBS X5 也存在一些问题,例如不支持在线浏览 PDF 文件、不支持 64 位,不过暂时还没有遇到其他的。
iOS 提供的 WebView 相比 Android 可谓良心发现呐,简直爽的一批~
好了,简单回顾下 Android 以及 Kotlin,果不其然,好多忘记了,尴尬 ???
这里顿时想到鸡大大黑黑大脸又要说还是不熟悉,???
好吧,好吧,我也要认认真真啦~
朝着鸡大大,冲鸭~
经历 Error
Q 1:net::ERR_CLEARTEXT_NOT_PERMITTED
如下图所示:
解决方案:
Mainifest 中的 application 添加如下:
android:usesCleartextTraffic="true"
参考地址:
个人公众号
不定期发布博文,最近有点忙,感谢老铁理解,欢迎关注~
参考资料
- TBS X5 官方地址:https://x5.tencent.com/tbs/index.html