You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android TV应用WebView场景下,遥控器DPad操作或鼠标移动触发NullPointerException崩溃求助

Android TV应用WebView场景下,遥控器DPad操作或鼠标移动触发NullPointerException崩溃求助

问题描述

我最近在开发基于Kotlin的Android TV应用,用Jetpack Compose嵌入WebView加载网页,网页本身加载完全正常,但一旦按下电视遥控器的DPad导航键或者移动鼠标,应用就会直接崩溃,抛出NullPointerException。卡了好几天没搞定,求各位大佬帮忙分析下!

我的代码

package com.example.tvapp

import android.annotation.SuppressLint
import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier

class MainActivity : ComponentActivity() {
    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            WebViewScreen(url = "https://portal.centralstage.io")
        }
    }
}

@Composable
fun WebViewScreen(url: String) {
    AndroidView(
        factory = { context ->
            WebView(context).apply {
                settings.javaScriptEnabled = true
                webViewClient = WebViewClient()
                loadUrl(url)
            }
        },
        modifier = Modifier.fillMaxSize()
    )
}

崩溃日志

FATAL EXCEPTION: main
Process: com.example.tvapp, PID: 2811
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.InputDevice.getVendorId()' on a null object reference
    at android.view.View.onResolvePointerIcon(View.java:29569)
    at android.view.ViewGroup.onResolvePointerIcon(ViewGroup.java:2078)
    at android.view.ViewGroup.dispatchResolvePointerIcon(ViewGroup.java:2092)
    at android.view.ViewGroup.onResolvePointerIcon(ViewGroup.java:2067)
    at android.view.ViewGroup.dispatchResolvePointerIcon(ViewGroup.java:2092)
    at android.view.ViewGroup.onResolvePointerIcon(ViewGroup.java:2067)
    at android.view.ViewGroup.dispatchResolvePointerIcon(ViewGroup.java:2092)
    at android.view.ViewGroup.onResolvePointerIcon(ViewGroup.java:2067)
    at android.view.ViewGroup.dispatchResolvePointerIcon(ViewGroup.java:2092)
    at android.view.ViewGroup.onResolvePointerIcon(ViewGroup.java:2067)
    at android.view.ViewGroup.dispatchResolvePointerIcon(ViewGroup.java:2092)
    at android.view.ViewGroup.onResolvePointerIcon(ViewGroup.java:2067)
    at android.view.ViewGroup.dispatchResolvePointerIcon(ViewGroup.java:2092)
    at android.view.ViewGroup.onResolvePointerIcon(ViewGroup.java:2067)
    at android.view.ViewGroup.dispatchResolvePointerIcon(ViewGroup.java:2092)
    at android.view.ViewGroup.onResolvePointerIcon(ViewGroup.java:2067)
    at android.view.ViewRootImpl.updatePointerIcon(ViewRootImpl.java:7116)
    at android.view.ViewRootImpl.resetPointerIcon(ViewRootImpl.java:7092)
    at android.view.ViewRootImpl.-$$Nest$mresetPointerIcon(Unknown Source:0)
    at android.view.ViewRootImpl$ViewRootHandler.handleMessageImpl(ViewRootImpl.java:6046)
    at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:5862)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8177)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)

问题分析

从崩溃栈能明确看到,异常出在系统的View.onResolvePointerIcon方法里:当调用InputDevice.getVendorId()时,InputDevice对象是null,直接触发了空指针。这是Android TV平台上Compose和WebView交互的一个兼容性bug——处理遥控器DPad或鼠标输入时,系统尝试解析指针图标,但输入设备对象没被正确初始化或传递,最终导致崩溃。

解决方案

最直接有效的办法是自定义WebView子类,重写onResolvePointerIcon方法,捕获并处理空指针异常,绕过系统层面的崩溃:

步骤1:创建自定义TVWebView类

import android.content.Context
import android.view.MotionEvent
import android.view.PointerIcon
import android.webkit.WebView

class TVWebView(context: Context) : WebView(context) {
    override fun onResolvePointerIcon(event: MotionEvent?, pointerIndex: Int): PointerIcon? {
        return try {
            // 正常情况调用父类方法处理
            super.onResolvePointerIcon(event, pointerIndex)
        } catch (e: NullPointerException) {
            // 捕获空指针,返回默认指针图标避免崩溃
            PointerIcon.getSystemIcon(context, PointerIcon.TYPE_DEFAULT)
        }
    }
}

步骤2:在Composable中替换为自定义WebView

修改WebViewScreen里的WebView创建逻辑,用我们自定义的TVWebView替代原生WebView:

@Composable
fun WebViewScreen(url: String) {
    AndroidView(
        factory = { context ->
            TVWebView(context).apply {
                settings.javaScriptEnabled = true
                webViewClient = WebViewClient()
                loadUrl(url)
            }
        },
        modifier = Modifier.fillMaxSize()
    )
}

可选补充优化

如果还想更稳妥,可以在WebView初始化时直接设置默认指针图标,提前避免系统触发异常解析:

TVWebView(context).apply {
    // 其他原有设置...
    pointerIcon = PointerIcon.getSystemIcon(context, PointerIcon.TYPE_DEFAULT)
}

验证效果

替换完成后重新运行应用,测试遥控器DPad导航和鼠标移动操作,应该不会再出现空指针崩溃了。这个方案通过在WebView层拦截异常,绕过了系统层面的输入设备空指针问题,是目前解决该兼容性bug的常用手段。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 11:00:27