一、前言

这个代码问题,还是会让原生错误页面闪现下,所以借鉴意义不大
​ 很早前遇到了一个需求,就是自定义错误页面,在该页面可以进行重新加载。当时搜集了网上的一些资料。只能满足第一步,进行重试时候系统的错误页总会闪一下,一直解决不了。最近解决了这个问题,经过简单测试觉得还可以。但是对立面的兼容细节问题没有处理这里只是简单记录实现的大致思路。

二、实现思路

​ 最初时候定义错误页面时候下意识想使用android布局文件进行定义。其实这种方式比较困难的,首先一个web页面加载过程结束时候不知道是成功和失败,所以需要在错误时候先进行标记最后结束时候再进行判断错误还是成功,说着简单,实际处理起来会有很多细小的问题。所以这是用html进行自定义错误页,是用js本地代码进行交互。因为重新加载了自定义的错误页。所以如果页面进行重新加载的话就不能调用WebView::reload()函数了,而是需要调用一次的历史记录,也就是回退一步。这个代码是根据github上的一份代码改的,但是这份代码也只是能完成第一步,在此基础上将后续逻辑进行了完善

三、简单的代码演示

​ 整个代码分为两部分,本地代码和html代码,如下:

activity_main.xml

<?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"
            /&gt;
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout&gt;
</layout&gt;

MainActivity.kt

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代码

style.css

p.external { color: blue; }

error.html

<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>

四、参考链接

  1. 全面总结 Android WebView与 JS 的交互方式
  2. Android webview custom error page
  3. WebView加载自定义error页面,解决自定义error页面但是原始error页面一闪而过的问题

原文地址:https://blog.csdn.net/Mr_Tony/article/details/122685102

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_21424.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注