开屏广告时长不够是因app端原生容器回收js线程导致settimeout失效,必须将倒计时交由原生层托管,js仅接收show/minduration/skipable参数及关闭回调,禁用onlaunch中纯js定时器。

开屏广告时长不够,setTimeout 被销毁怎么办
App 启动后开屏广告还没展示完,页面就跳走了——这不是代码没写完,而是 uni-app 在 App 端(尤其是 iOS)会主动销毁 JS 上下文,导致未完成的 setTimeout 或 setInterval 直接失效。你写的 5 秒倒计时,可能刚到 2 秒就没了。
根本原因:App 端原生容器在首页渲染完成后,会回收首屏 JS 线程,而 onLaunch 或 onShow 中启动的定时器并不受 Vue 实例生命周期保护。
- 别在
App.vue的onLaunch里用setTimeout控制广告跳转 - 必须把倒计时逻辑交由原生层托管,JS 只负责接收回调
-
uni-app 官方插件
uni-ad不支持动态时长,需绕过它走自定义原生桥接
如何让原生层真正控制广告时长(Android/iOS 通用思路)
核心是把「广告展示」和「跳转时机」拆开:JS 触发广告展示后,立刻把期望的最小时长(比如 3000ms)、可跳过条件(如用户点击、网络加载完成)告诉原生,由原生决定何时关闭广告页并跳转。
你需要在原生侧实现一个最小化广告控制器,例如 Android 的 SplashAdManager、iOS 的 UNISplashAdView,并在 JS 层通过 uni.requireNativePlugin 调用:
const splash = uni.requireNativePlugin('CustomSplash');
splash.show({
minDuration: 3000,
skipable: true,
imageUrl: 'https://xxx.jpg'
}, () => {
// 原生通知 JS:广告已关闭,可以跳转了
uni.navigateTo({ url: '/pages/index/index' });
});
-
minDuration是硬性下限,即使用户秒点跳过,也至少展示这么久 - 原生层需监听图片加载完成事件,若加载超时(如 10s),自动 fallback 到默认时长并关闭
- iOS 上注意
launchImage与广告页的视觉衔接,避免白屏闪动
uni.navigateTo 跳转前必须等 splash.hide() 回调
很多开发者在广告页 onLoad 里直接调用 uni.navigateTo,结果广告还没关,新页面就叠上去了——这在 iOS 上尤其容易触发黑屏或导航卡死。
正确流程是:所有跳转动作必须收口到原生广告关闭后的回调中,且不能依赖页面生命周期钩子。
- 不要在广告页的
onReady或mounted里调用跳转 - 禁止使用
uni.switchTab替代uni.navigateTo,tabBar 页面无法被原生广告页覆盖 - 如果广告页是独立的
splash.vue,确保其onUnload不做任何异步操作,否则可能干扰原生销毁逻辑
动态时长怎么传参?服务端下发 + 本地缓存兜底
所谓“动态”,是指不写死在代码里,而是从接口取值。但冷启动时网络不可用,必须有降级策略。
推荐做法:App 启动时优先读取本地缓存的 ad_duration(带时间戳),若过期或不存在,则用内置默认值(如 3000),同时静默请求服务端更新并缓存:
uni.getStorage({
key: 'ad_config',
success: res => {
const { duration, expires } = res.data;
if (Date.now() useDefaultAndFetchNew()
});
- 服务端返回的
expires建议设为 1 小时,避免每次启动都刷接口 - 务必校验
duration范围(如 2000–5000),防止恶意值导致广告卡死 - Android 上若启用 splash screen XML(
android:windowBackground),需确保它和 JS 层广告页背景色一致,否则会有明显色差
webview 销毁比 Android 更激进,连 beforeUnload 都不一定触发——所以别试图在 JS 里“抢救”倒计时,老老实实把控制权交给原生。











