Cordova InAppBrowser 使用 _blank 加载 URL 时白屏
结论
_blank 白屏通常不是 loadstart 或 loadstop 失效,而是支付页面没有在 InAppBrowser 创建的独立原生 WebView 中正常渲染。loadstop 只表示顶层导航已经结束,不代表 TLS、重定向资源、JavaScript 和页面渲染都没有问题。
_self 使用 Cordova 主 WebView,_blank 则使用 InAppBrowser 的独立 WebView。两者的 WebView 内核、Cookie、会话、TLS 能力和配置可能不同,所以 _self 能打开页面,不等于 _blank 也能正常打开。
先修正错误事件名,获取实际报错,再依次检查服务器证书链、TLS 兼容性、重定向、Cookie 和 WebView 版本。不要通过忽略 SSL 错误来接入支付页面。确认页面能在 _blank 中渲染后,可以用 hidden=yes 预加载,等 loadstop 触发后再显示,避免用户看到加载期间的白屏或黑屏。
先修正错误监听
示例把事件名称写成了 loadloaderror,正确名称是 loaderror。这个拼写错误会让真正的加载错误无法被记录:
var target = '_blank';
var options = [
'location=yes',
'hidden=yes',
'clearcache=yes',
'clearsessioncache=yes'
].join(',');
var ref = cordova.InAppBrowser.open(
'https://certepayments.omannet.cbo.gov.om/',
target,
options
);
ref.addEventListener('loadstart', function (event) {
console.log('Loading started:', event.url);
});
ref.addEventListener('loadstop', function (event) {
console.log('Loading finished:', event.url);
ref.show();
});
ref.addEventListener('loaderror', function (event) {
console.error(
'Loading error:',
'code=' + event.code,
'message=' + event.message,
'url=' + event.url
);
ref.close();
});
ref.addEventListener('exit', function () {
console.log('Browser is closed...');
});
调试时应记录 code、message 和 url。只输出 error.message,通常不足以定位问题。
为什么 _blank 和 _self 表现不同
使用 _self 时,URL 会在 Cordova 应用当前的主 WebView 中打开。原有应用页面会被替换,因此在远程页面完成初始化前,用户可能会看到主 WebView 的黑色背景。
使用 _blank 时,InAppBrowser 会创建新的浏览器窗口和 WebView。这个 WebView 有自己的加载环境,可能与主 WebView 存在以下差异:
- Cookie 和登录会话尚未准备好;
- Android System WebView 或 iOS WebKit 的版本、TLS 能力不同;
- 某些 WebView 无法验证服务器证书链;
- 页面重定向后加载的脚本、样式或接口失败;
- 支付页面依赖第三方 Cookie、弹窗或特定的 JavaScript 行为;
- JavaScript 或 CSS 与旧版 WebView 不兼容;
- 页面或网关根据 User-Agent 返回不同内容。
因此,即使已经触发 loadstop,页面仍然可能白屏。例如,服务器返回了 HTML 外壳,但关键 JavaScript 加载失败。此时顶层导航依然会结束并触发 loadstop。
建议的排查顺序
1. 检查服务器的 HTTPS 配置
支付网关必须提供完整、可信的证书链,并支持目标设备可用的 TLS 协议和加密套件。需要检查:
- 证书是否过期;
- 域名是否与证书匹配;
- 中间证书是否完整;
- 页面重定向涉及的所有域名是否都有有效证书;
- 页面中的脚本、样式和接口是否都使用有效的 HTTPS 地址。
如果问题出在证书或 TLS,应在支付网关服务器端修复。不要修改 InAppBrowser 来忽略证书错误。这种做法不安全,也不适合支付场景。
2. 更新 WebView 和插件
在 Android 上,_blank 页面通常依赖设备的 Android System WebView。应在出现问题的设备上确认:
- Android System WebView 或 Chrome 已更新;
- 项目使用的
cordova-plugin-inappbrowser与当前 Cordova 平台兼容; - 问题是否只发生在特定 Android 版本或厂商设备上。
如果应用主 WebView 使用了额外的 WebView 引擎,而 InAppBrowser 仍然使用系统 WebView,两者更容易出现不同的加载结果。
3. 使用 WebView 远程调试
仅靠 Cordova 的加载事件,无法判断问题来自网络还是页面渲染。在 Android 上连接设备后,可以使用 Chrome 的 WebView 调试功能检查:
- Console 中的 JavaScript 异常;
- Network 中失败或发生重定向的请求;
- SSL、Cookie、CORS 和 mixed content 错误;
- 页面最终生成的 DOM 是否为空;
- 是否有加载层覆盖了整个页面。
如果 DOM 已经生成,但页面仍是白屏,应继续检查 CSS、视口设置和全屏遮罩,不必反复修改 Cordova 导航事件。
使用隐藏预加载改善体验
确认页面能够正常渲染后,可以用 hidden=yes 创建隐藏的 InAppBrowser,并在 loadstop 触发后调用 show():
var paymentUrl = 'https://certepayments.omannet.cbo.gov.om/';
var paymentBrowser = cordova.InAppBrowser.open(
paymentUrl,
'_blank',
'location=yes,hidden=yes'
);
var shown = false;
paymentBrowser.addEventListener('loadstop', function (event) {
console.log('Payment page loaded:', event.url);
if (!shown) {
shown = true;
paymentBrowser.show();
}
});
paymentBrowser.addEventListener('loaderror', function (event) {
console.error('Payment page failed:', {
code: event.code,
message: event.message,
url: event.url
});
paymentBrowser.close();
});
应用页面可以先显示加载提示,等 InAppBrowser 可以展示时再隐藏提示,避免用户直接看到空白的浏览器窗口。
支付流程通常包含多次重定向,因此 loadstop 可能会触发多次。代码应保证只在首次合适的页面加载完成后调用一次 show()。如果支付页面还要等待 JavaScript 异步渲染,仅依赖 loadstop 可能会过早显示。这种情况下,可以让可控制的页面发送就绪信号,或者在支付服务商支持时改用其原生 SDK。
不建议用 _self 规避问题
_self 会替换 Cordova 主页面,可能破坏应用状态和返回流程,也不利于可靠处理支付完成、取消和失败回调。它产生的 5 秒黑屏可以通过调整主 WebView 背景或添加加载页来遮挡,但这只是视觉上的补偿,无法解决 _blank 中实际存在的兼容问题。
支付集成通常可以按以下顺序选择:
- 支付服务商提供的原生 SDK;
_blankInAppBrowser,并通过受控回调 URL 判断支付结果;- 系统浏览器配合 Universal Link、App Link 或自定义 URL Scheme 返回应用;
- 最后再考虑
_self。
支付结果还必须由应用后端向支付网关服务端验证,不能只根据浏览器跳转地址或前端 JavaScript 判断支付是否成功。
备注:内容仅供参考。
