这一章说的是网页浏览器。
app时常会使用到自定义WebView。但是想做成一个高可用性的WebView配置其实很有技巧。这节就给一个完整自定义WebView的配置。这里包括对浏览器的适配,还有一些浏览器的地址验证。
```
/**
* 初始化WebView
*/
fun initWeb() {
mProgress = findViewById(R.id.web_progress)
mProgress!!.setColorSchemeResources(R.color.common_pink_5,
R.color.common_light_green_2, R.color.common_blue_3)
web = findViewById(R.id.web)
web!!.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY
val webSettings = web!!.settings
webSettings.javaScriptEnabled = true
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
//设置自适应屏幕,两者合用
webSettings.useWideViewPort = true //将图片调整到适合webview的大小
webSettings.loadWithOverviewMode = true // 缩放至屏幕的大小
webSettings.displayZoomControls = false //隐藏原生的缩放控件
webSettings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN //支持内容重新布局
webSettings.supportMultipleWindows() //多窗口
// webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
webSettings.allowFileAccess = true //设置可以访问文件
webSettings.setNeedInitialFocus(true) //当webview调用requestFocus时为webview设置节点
webSettings.javaScriptCanOpenWindowsAutomatically = true //支持通过JS打开新窗口
webSettings.loadsImagesAutomatically = true //支持自动加载图片
webSettings.defaultTextEncodingName = "UTF-8"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
webSettings.allowFileAccessFromFileURLs = false
webSettings.allowUniversalAccessFromFileURLs = false
}
// 设置可以支持缩放
webSettings.setSupportZoom(true)
// // 设置出现缩放工具
webSettings.builtInZoomControls = true
// 自适应屏幕
webSettings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL
//缓存相关
webSettings.setAppCacheEnabled(true)
webSettings.domStorageEnabled = true
//开启定位
webSettings.setGeolocationEnabled(true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE
}
web!!.webViewClient = object : BridgeWebViewClient(web!!) {
override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) {
Logger.e("网页链接加载失败:" + description + "->" + failingUrl + ",当前网页:" + view.url)
try {
// String host = Uri.parse(failingUrl).getHost();
val scheme = Uri.parse(failingUrl).scheme
if (scheme.equals("http", ignoreCase = true) || scheme.equals("https", ignoreCase = true)) {
if (TextUtils.equals(failingUrl, view.url)) {
}
}
} catch (ex: Exception) {
Logger.e("", ex)
}
// showError();
}
@RequiresApi(api = Build.VERSION_CODES.M)
override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceError) {
Logger.e("网页链接加载失败:" + error.errorCode + "->" + request.url + ",当前网页:" + view.url)
try {
// String host = request.getUrl().getHost();
val scheme = request.url.scheme
if (scheme.equals("http", ignoreCase = true) || scheme.equals("https", ignoreCase = true)) {
if (TextUtils.equals(request.url.toString(), view.url)) {
}
}
} catch (ex: Exception) {
Logger.e("", ex)
}
// showError();
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
mProgress?.visibility = View.GONE
mTextSwitcher?.setText(view?.title)
}
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
mProgress?.visibility = View.VISIBLE
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
Logger.d("网页重写地址:" + request?.url)
try {
request ?: return super.shouldOverrideUrlLoading(view, request)
val host = request.url.host
val scheme = request.url.scheme
if (scheme.equals("http", ignoreCase = true) || scheme.equals("https", ignoreCase = true)) {
return checkInvalidAddressV4(host)
}
} catch (ex: Exception) {
Logger.e("网页重加载失败", ex)
}
return super.shouldOverrideUrlLoading(view, request)
}
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
Logger.d("网页重写地址:" + url)
if (TextUtils.isEmpty(url)) {
return true
}
val uri = Uri.parse(url)
try {
val host = uri.host
val scheme = uri.scheme
if (scheme.equals("http", ignoreCase = true) || scheme.equals("https", ignoreCase = true)) {
if (checkInvalidAddressV4(host)) {
return false
} else {
return false
}
}
} catch (ex: Exception) {
Logger.e("网页重加载失败", ex)
}
return super.shouldOverrideUrlLoading(view, url)
}
override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) {
try {
handler.proceed()
} catch (ex: Exception) {
Logger.e("处理网页SSL证书失败", ex)
}
}
}
web!!.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView, newProgress: Int) {
super.onProgressChanged(view, newProgress)
}
}
val url = baseIntent!!.getStringExtra(ARouterConstants.PARAM.WEB_URL)
JavaScriptInterface.inject(this, url, web!!) //添加jsbridge框架
web!!.loadUrl(url) //加载网页
}
/**
* 检测是否不可用地址
* @param addressString(ipv4)
* @return
*/
fun checkInvalidAddressV4(addressString: String): Boolean {
try
{
val addressStrings = addressString.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val address = ByteArray(addressStrings.size)
for (i in address.indices) {
address[i] = java.lang.Byte.valueOf(addressStrings[i])!!
}
if (address.size == 4) {
val b0 = address[0]
val b1 = address[1]
//127.x.x.x
val SECTION_0 = 0x7F.toByte()
//10.x.x.x/8
val SECTION_1 = 0x0A.toByte()
//172.16.x.x/12--172.31.x.x
val SECTION_2 = 0xAC.toByte()
val SECTION_3 = 0x10.toByte()
val SECTION_4 = 0x1F.toByte()
//192.168.x.x/16
val SECTION_5 = 0xC0.toByte()
val SECTION_6 = 0xA8.toByte()
when (b0) {
SECTION_0 -> return true
SECTION_1 -> return true
SECTION_2 -> if (b1 >= SECTION_3 && b1 <= SECTION_4) {
return true
}
SECTION_5 -> if (b1 == SECTION_6) {
return true
}
else -> return false
}