一、前言
这个代码又问题,还是会让原生错误页面闪现下,所以借鉴意义不大
很早前遇到了一个需求,就是自定义错误页面,在该页面还可以进行重新加载。当时搜集了网上的一些资料。只能满足第一步,进行重试时候系统的错误页总会闪一下,一直解决不了。最近解决了这个问题,经过简单测试觉得还可以。但是对立面的兼容和细节问题没有处理,这里只是简单记录下实现的大致思路。
二、实现思路
最初时候定义错误页面时候下意识想使用android的布局文件进行定义。其实这种方式是比较困难的,首先一个web页面在加载过程中结束时候不知道是成功和失败,所以需要在错误时候先进行标记,最后结束时候再进行判断错误还是成功,说着简单,实际处理起来会有很多细小的问题。所以这是用html进行自定义错误页,是用js与本地代码进行交互。因为重新加载了自定义的错误页。所以如果页面进行重新加载的话就不能调用WebView::reload()
函数了,而是需要调用上一次的历史记录,也就是回退一步。这个代码是根据github上的一份代码改的,但是这份代码也只是能完成第一步,在此基础上将后续逻辑进行了完善
三、简单的代码演示
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
>
<data>
</data>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</layout>
package io.github.hugehoge.sample
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.webkit.*
import androidx.databinding.DataBindingUtil
import io.github.hugehoge.sample.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private val binding: ActivityMainBinding by lazy {
DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
}
// TODO: Move to companion object
private val displayErrorContentCode by lazy {
val html = assets.open("error.html")
.bufferedReader()
.readText()
"""document.documentElement.innerHTML = `$html`"""
}
private var backSteps = -1;//默认回退一步,倘若自定义加载错误页则回退两步
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// for debug
WebView.setWebContentsDebuggingEnabled(true)
setupWebView()
if (savedInstanceState == null) {
binding.webView.loadUrl(INITIAL_PAGE_URL)
}
}
override fun onResume() {
super.onResume()
binding.webView.onResume()
}
override fun onPause() {
super.onPause()
binding.webView.onPause()
}
private fun setupWebView() {
// This setting is required
binding.webView.settings.javaScriptEnabled = true
binding.webView.addJavascriptInterface(JSBridge(),"test")
// for debug
binding.webView.settings.cacheMode = WebSettings.LOAD_NO_CACHE
binding.webView.webViewClient =
if (Build.VERSION.SDK_INT < 23) {
object : WebViewClient() {
override fun onReceivedError(
view: WebView?,
errorCode: Int,
description: String?,
failingUrl: String?
) {
super.onReceivedError(view, errorCode, description, failingUrl)
backSteps = -2
view?.loadDataWithBaseURL(null,displayErrorContentCode, "text/html", "UTF-8",null);
view?.invalidate();
}
}
} else {
object : WebViewClient() {
override fun onReceivedError(
view: WebView?,
request: WebResourceRequest?,
error: WebResourceError?
) {
super.onReceivedError(view, request, error)
Log.e("YM->","加载错误")
backSteps = -2
view?.loadDataWithBaseURL(null,displayErrorContentCode, "text/html", "UTF-8",null);
view?.invalidate();
}
}
}
binding.webView.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
binding.swipeRefreshLayout.isRefreshing = newProgress in 1..99
}
override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean {
Log.e("Ym-->","------->:${consoleMessage?.message()}")
return super.onConsoleMessage(consoleMessage)
}
}
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.keyCode === KeyEvent.KEYCODE_BACK) {
if (binding.webView.canGoBack()) {
// binding.webView.loadUrl("javascript:history.go(-1)");
//获取webView的浏览记录
val mWebBackForwardList: WebBackForwardList = binding.webView.copyBackForwardList()
//这里的判断是为了让页面在有上一个页面的情况下,跳转到上一个html页面,而不是退出当前activity
if (mWebBackForwardList.currentIndex > 0) {
val historyUrl =
mWebBackForwardList.getItemAtIndex(mWebBackForwardList.currentIndex - 1).url
if (historyUrl != INITIAL_PAGE_URL) {
// binding.webView.goBack()
Log.e("YM-->","--->错误页返回步数:$backSteps")
binding.webView.goBackOrForward(backSteps)
backSteps = -1
// binding.webView.goForward()
// binding.webView.loadUrl("javascript:history.go(-2)");
return true
}
}
} else {
return super.onKeyDown(keyCode, event)
}
}
return super.onKeyDown(keyCode, event)
}
companion object {
private const val INITIAL_PAGE_URL = "https://www.baidu.com/"
}
inner class JSBridge {
// 定义JS需要调用的方法
// 被JS调用的方法必须加入@JavascriptInterface注解
@JavascriptInterface
fun hello(msg: String) {
// System.out.println("JS调用了Android的hello方法");
Log.e("YM","--->js函数调用:$msg")
backSteps = -1
binding.webView.post {
binding.webView.goBackOrForward(backSteps)
}
}
}
}
在../app/src/main/assets
下面将编写相关html代码
p.external { color: blue; }
<html>
<head>
<title>Custom Error Page</title>
<style>
p.internal { color: green; }
</style>
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript">
function callAndroid(){
// 由于对象映射,所以调用test对象等于调用Android映射的对象
test.hello("js调用了android中的hello方法");
}
</script>
</head>
<body>
<h1>Custom Error Page</h1>
<h2>Description</h2>
<p>This is a custom error page.</p>
<h2>Image</h2>
<p>SVG format available.</p>
<svg width="64" height="64" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" fill="red"/>
</svg>
<h2>CSS</h2>
<p class="internal">Internal CSS available.</p>
<p class="external">External CSS not available.</p>
<button type="button" onclick="callAndroid()">点击刷新页面</button>
</body>
</html>
四、参考链接
- 全面总结 Android WebView与 JS 的交互方式
- Android webview custom error page
- WebView加载自定义error页面,解决自定义error页面但是原始error页面一闪而过的问题
原文地址:https://blog.csdn.net/Mr_Tony/article/details/122685102
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_21424.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。