Android语言基础教程(255)Android使用WebView显示网页经典范例之打造功能实用的网页浏览器:别翻了!你的App里就差这个“万能口袋”:用WebView手搓一个让妹子惊呼的浏览器

引言:为什么你的App需要这个“万能口袋”?

想象一下这个场景:你正在刷一个购物App,看到一篇超棒的穿搭攻略,你一点击,App居然“嗖”地一下跳转到了手机自带的浏览器!这种感觉,就像你正吃着火锅唱着歌,突然被麻匪劫了道,体验感瞬间清零。

这时候,WebView就该闪亮登场了!它不是什么黑科技,你可以把它理解成 “镶嵌在你自己App里的一个迷你浏览器内核” 。有了它,用户不用离开你的App,就能无缝浏览网页内容。无论是展示用户协议、新闻资讯,还是内嵌一个H5小游戏,WebView都是你的不二之选。

今天,咱不整那些虚头巴脑的概念,就跟我一起,手把手把这个“万能口袋”打造得既实用又酷炫。系好安全带,老司机要发车了!

第一章:WebView初体验——从“Hello, World”级别开始

万事开头难?不,开头很简单。

1.1 权限,咱得先“上牌”

想在App里畅游网络世界,首先得在AndroidManifest.xml文件里拿到“上网许可证”:

<uses-permission android:name="android.permission.INTERNET" />

这条权限就像是给你的App办了张“宽带套餐”,没它?WebView就只能在家玩单机游戏了。

1.2 布局里,给它个“家”

在布局文件activity_main.xml里,给WebView划块地儿:

<WebView
    android:id="@+id/myWebView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

简单粗暴,全屏都是它的地盘。

1.3 代码里,让它“动起来”

在MainActivity中,几行代码就能让它显示网页:

class MainActivity : AppCompatActivity() {

    private lateinit var myWebView: WebView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        myWebView = findViewById(R.id.myWebView)
        
        // 基本设置
        val webSettings = myWebView.settings
        webSettings.javaScriptEnabled = true // 让WebView能执行JS,很重要!

        // 加载网页
        myWebView.loadUrl("https://www.baidu.com")
    }
}

搞定!运行一下,你的App里已经能显示百度了。是不是简单得有点不敢相信?但先别高兴太早,这只是一个“毛坯房”,用户体验堪比“战地记者”——只能看,不能互动,遇到问题就卡死。

第二章:高级装修——把“毛坯房”升级成“智能精装”

一个合格的浏览器,怎么能没有前进、后退、刷新?怎么能任由网页跳转到系统浏览器?下面,我们就开始精装修。

2.1 拦截“不速之客”——自定义WebViewClient

默认情况下,你点击网页里的链接,它会问系统:“嘿,哪个App能处理这个链接?”然后可能就打开了Chrome。这不行!我们必须拦截它,告诉它:“在我这一亩三分地,就得听我的!”

这就需要请出我们的“门神”——WebViewClient

myWebView.webViewClient = object : WebViewClient() {
    // 这个方法是关键!当有新的链接需要加载时,它会问我们:“老板,这个货咱自己吞了吗?”
    override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
        val url = request?.url.toString()
        // 如果这个URL不是我们信任的基域,可以选择用外部浏览器打开
        // 但这里,我们选择所有链接都在WebView内部打开
        view?.loadUrl(url)
        return true // 返回true表示:我处理了,你别管了。
    }

    // 网页开始加载
    override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
        super.onPageStarted(view, url, favicon)
        // 这里可以显示一个加载中的进度条
        showLoadingProgress()
    }

    // 网页加载结束
    override fun onPageFinished(view: WebView?, url: String?) {
        super.onPageFinished(view, url)
        // 隐藏加载进度条
        hideLoadingProgress()
        // 更新一下工具栏的标题,显示网页自己的标题
        supportActionBar?.title = view?.title
    }

    // 遇到错误(比如没网)
    override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
        super.onReceivedError(view, request, error)
        // 可以显示一个友好的错误页面,比如一个“网络开小差了”的提示和重试按钮
        showErrorPage()
    }
}

看,有了WebViewClient,我们就完全掌控了网页的加载过程,用户体验直接提升一个档次。

2.2 记录“来时路”——实现前进后退

用户逛网页,就像在逛超市,得有购物车(历史记录)才能前进后退。WebView自带了这个“购物车”,我们只需要提供几个按钮来操作它。

首先,在布局里加个简单的底部工具栏:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:background="#f0f0f0">

    <Button
        android:id="@+id/btnBack"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="后退" />

    <Button
        android:id="@+id/btnForward"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="前进" />

    <Button
        android:id="@+id/btnReload"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="刷新" />

</LinearLayout>

然后在Activity里给这些按钮赋予灵魂:

private fun setupNavigation() {
    findViewById<Button>(R.id.btnBack).setOnClickListener {
        if (myWebView.canGoBack()) {
            myWebView.goBack() // 回到上一页
        } else {
            // 如果不能后退了,可能是退出App,或者给个提示
            finish()
        }
    }

    findViewById<Button>(R.id.btnForward).setOnClickListener {
        if (myWebView.canGoForward()) {
            myWebView.goForward() // 前进到下一页
        }
    }

    findViewById<Button>(R.id.btnReload).setOnClickListener {
        myWebView.reload() // 刷新
    }
}

2.3 给加载加个“进度条”——让等待不再焦虑

网页加载像等外卖,有个进度条心里就踏实多了。WebView提供了一个好伙伴WebChromeClient来帮我们获取加载进度。

myWebView.webChromeClient = object : WebChromeClient() {
    // 当网页加载进度发生变化时,这个方法会被调用
    override fun onProgressChanged(view: WebView?, newProgress: Int) {
        super.onProgressChanged(view, newProgress)
        // newProgress 是一个0-100的整数
        if (newProgress < 100) {
            // 更新你的进度条UI,比如一个横向的ProgressBar
            updateProgressBar(newProgress)
        } else {
            // 加载完成,隐藏进度条
            hideProgressBar()
        }
    }
}
第三章:应对“江湖险恶”——处理各种疑难杂症

现实世界是残酷的,你的WebView会遇到各种“坑”。

3.1 权限申请——当网页想“用你的麦克风”

如果网页里要使用摄像头、麦克风、定位等,你需要重写WebChromeClient的相关方法,并自己在Activity中处理权限申请。这是个细活儿,但套路固定:

myWebView.webChromeClient = object : WebChromeClient() {
    // 处理网页请求权限(如摄像头、麦克风)
    override fun onPermissionRequest(request: PermissionRequest?) {
        // 1. 先检查我们自己有没有这个权限(比如RECORD_AUDIO, CAMERA)
        // 2. 如果没有,向用户申请
        // 3. 用户授权后,调用 request.grant(request.resources) 把权限“转交”给网页
        // 4. 用户拒绝,调用 request.deny()
        // 注意:这里涉及到Android的动态权限申请,代码略长,但逻辑清晰
    }
}

3.2 与JavaScript“勾肩搭背”——原生与网页的通信

这是WebView最强大的功能之一!你可以让网页里的JavaScript调用你App里的原生方法。

比如,网页里有个按钮,一点击,就能在你的App里弹出一个原生Toast。

首先,在Kotlin端,创建一个充当“桥梁”的对象:

class WebAppInterface(private val context: Context) {
    
    // 这个方法将被JavaScript调用
    @JavascriptInterface
    fun showToast(toast: String) {
        Toast.makeText(context, toast, Toast.LENGTH_SHORT).show()
    }
}

然后,把这个桥梁对象“安装”到WebView上:

myWebView.addJavascriptInterface(WebAppInterface(this), "Android")
// "Android" 是给JavaScript端调用的对象名

最后,在网页的JavaScript里,就可以这么玩了:

// 当按钮被点击时
function onButtonClick() {
    // 调用原生Android方法
    Android.showToast("Hello from Web!");
}

这样一来,你的App和H5页面就成了亲密无间的战友,可以实现无比灵活的功能。

第四章:完整代码示例——“开箱即用”的终极武器

理论说了这么多,是时候上硬菜了!下面是一个整合了以上所有功能的、相对完整的Activity代码。

(注意:为了简洁,此处代码省略了部分细节,如动态权限申请的完整代码,但核心逻辑俱全)

class MainActivity : AppCompatActivity() {

    private lateinit var myWebView: WebView
    private lateinit var progressBar: ProgressBar

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        initViews()
        setupWebView()
        setupNavigation()
        
        // 加载初始页面
        myWebView.loadUrl("https://www.baidu.com")
    }

    private fun initViews() {
        myWebView = findViewById(R.id.myWebView)
        progressBar = findViewById(R.id.progressBar) // 假设布局里有个横向ProgressBar
    }

    private fun setupWebView() {
        val webSettings = myWebView.settings
        webSettings.javaScriptEnabled = true
        webSettings.domStorageEnabled = true // 开启DOM存储,对复杂H5应用很重要
        webSettings.loadWithOverviewMode = true
        webSettings.useWideViewPort = true

        // 设置WebViewClient
        myWebView.webViewClient = MyWebViewClient()
        // 设置WebChromeClient
        myWebView.webChromeClient = MyChromeClient()

        // 添加JS接口
        myWebView.addJavascriptInterface(WebAppInterface(this), "Android")
    }

    private fun setupNavigation() {
        // ... 同上文,设置后退、前进、刷新按钮的点击事件
    }

    // 处理返回键
    override fun onBackPressed() {
        if (myWebView.canGoBack()) {
            myWebView.goBack()
        } else {
            super.onBackPressed()
        }
    }

    // 自定义WebViewClient
    inner class MyWebViewClient : WebViewClient() {
        override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
            view.loadUrl(request.url.toString())
            return true
        }

        override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
            progressBar.visibility = View.VISIBLE
        }

        override fun onPageFinished(view: WebView?, url: String?) {
            progressBar.visibility = View.GONE
        }
    }

    // 自定义WebChromeClient
    inner class MyChromeClient : WebChromeClient() {
        override fun onProgressChanged(view: WebView?, newProgress: Int) {
            progressBar.progress = newProgress
        }
    }
}

// JS桥梁类
class WebAppInterface(private val context: Context) {
    @JavascriptInterface
    fun showToast(message: String) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
    }
}
结语:你的“万能口袋”,远不止于此

恭喜你!走到这一步,你已经不是一个WebView小白了。你亲手打造了一个不仅能用,而且好用的内嵌浏览器。它具备了:

  • 内部加载:不让用户“跳戏”。
  • 导航功能:前进后退刷新,随心所欲。
  • 视觉反馈:进度条让等待不再枯燥。
  • 深度交互:能与JavaScript互通有无。

但这仅仅是开始。WebView的潜力远不止于此,你还可以探索:

  • 文件上传:处理<input type="file">
  • 下载管理:拦截下载链接,用系统的DownloadManager处理。
  • 自定义错误页面:设计得比原生提示好看一百倍。
  • 缓存策略:让二次加载快如闪电。

希望这篇“有网感”的深度教程,能真正帮你把WebView这个“万能口袋”玩出花来。代码就在这里,大胆地复制、粘贴、修改、折腾吧!遇到问题就去搜,就去问,这才是程序员成长的正确姿势。

祝你编码愉快,我们下次再见!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值