Android WebView跳转触发ActivityNotFoundException部分机型无法复现问题咨询
问题根因
- 崩溃直接由
shouldOverrideUrlLoading方法的不严谨逻辑触发:代码中对所有WebView跳转URL都直接构造ACTION_VIEW意图启动外部Activity,未做有效性校验和异常兜底。当WebView内嵌广告触发的跳转URL没有对应的系统应用可处理时,就会抛出ActivityNotFoundException导致崩溃 - 日志中
act参数显示为空属于系统日志打印的格式化问题,代码中实际已传入Intent.ACTION_VIEW,无需纠结该显示异常
修复方案
1. 增加Intent有效性预校验
跳转前调用resolveActivity方法查询系统是否存在可处理当前意图的Activity,仅当查询结果非空时再执行跳转
2. 增加跳转异常捕获兜底
即使做了预校验,仍存在系统组件匹配的边缘 case,用try-catch包裹startActivity逻辑,彻底避免崩溃
3. 可选:限制跳转协议范围
如果业务不需要支持自定义scheme跳转,可以过滤仅允许http/https协议的URL跳转到外部,其余协议直接在WebView内部加载,减少异常触发概率
修改后的代码示例
@SuppressLint("SetJavaScriptEnabled") private void initSetting() { addJavascriptInterface(new AdJavascriptInterface(), "AdJavascriptInterface"); setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView webView, String s) { webView.loadUrl("javascript:(" + jsimg + ")()"); EventBus.getDefault().postSticky(new CloseSplashEvent()); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // 过滤非http/https协议,直接在WebView内加载 if (!url.startsWith("http://") && !url.startsWith("https://")) { view.loadUrl(url); return true; } Uri uri = Uri.parse(url); Intent intent = new Intent(Intent.ACTION_VIEW, uri); // 预校验是否有可处理的应用 if (intent.resolveActivity(getContext().getPackageManager()) != null) { try { getContext().startActivity(intent); } catch (ActivityNotFoundException e) { // 异常兜底,可根据业务需要添加日志上报或用户提示 e.printStackTrace(); } } else { // 无对应处理应用时,直接在WebView内加载 view.loadUrl(url); } return true; } }); WebSettings webSettings = getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setUseWideViewPort(true); webSettings.setLoadWithOverviewMode(true); webSettings.setLoadsImagesAutomatically(true); }
稳定复现方法
构造包含自定义scheme(如test://test.com)的测试网页,加载到该WebView中触发跳转,即可复现原崩溃问题,修复后再次测试验证异常是否被拦截。
内容的提问来源于stack exchange,提问作者Saint Mafia
相关产品推荐
相关产品推荐

