React Native AdMob插屏广告仅展示一次 报Ad is already loaded错误
问题现象
- 运行时报错:
AdMobInterstitial [Unhandled promise rejection: Error: Ad is already loaded.] - 实际表现:插屏广告仅首次可以正常弹出,用户关闭广告后再次触发展示逻辑时广告无响应,必须重启应用才能再次展示
- 错误截图:AdMob广告加载报错截图
核心原因
- 依赖严重冲突:当前项目同时安装了6个功能完全重叠的AdMob广告SDK,分别是
@react-native-admob/admob、@react-native-firebase/admob、expo-ads-admob、react-native-admob、react-native-admob-ads、react-native-google-mobile-ads,另外还装了react-native-ad-manager广告管理包。多个独立的SDK会同时操作广告实例、监听广告生命周期事件,实例状态标记互相覆盖:广告关闭后部分SDK判定实例已销毁需重新加载,另一部分SDK判定实例仍处于已加载状态,此时调用加载接口就会触发「广告已加载」报错,同时阻塞广告展示逻辑。 - 广告生命周期逻辑错误:插屏广告属于单次消耗型资源,广告展示完成后旧实例会自动回收,必须重新加载新的广告资源才能再次展示。绝大多数出现该问题的场景,都是没有在广告关闭的回调中触发下一轮广告预加载,同时没有在调用加载接口前判断广告当前状态,重复触发加载动作。
- 异步调用未做异常捕获:广告加载、展示的Promise接口没有加
try/catch兜底,导致状态异常时直接抛出未处理的Promise rejection。
修复步骤
第一步:清理冗余依赖
只保留1个和项目技术栈匹配的官方维护AdMob SDK即可,当前是Expo 45项目,直接保留内置的expo-ads-admob即可,其余所有AdMob相关包全部卸载:
yarn remove @react-native-admob/admob @react-native-firebase/admob react-native-admob react-native-admob-ads react-native-google-mobile-ads react-native-ad-manager
卸载完成后重新安装依赖、重启打包服务,清除缓存后重新编译应用。
第二步:修正插屏广告调用逻辑
按照插屏广告的生命周期规范实现加载、展示逻辑,核心要点是:广告关闭后自动预加载下一条、调用加载/展示接口前先判断当前广告状态、所有异步操作加异常捕获。
参考实现(React Hook封装):
import { AdMobInterstitial } from 'expo-ads-admob'; import { useEffect, useCallback, Platform } from 'react-native'; // 测试阶段请替换为AdMob官方测试插屏广告ID,上线前替换为自己的正式广告ID const INTERSTITIAL_UNIT_ID = Platform.select({ android: 'ca-app-pub-3940256099942544/1033173712', ios: 'ca-app-pub-3940256099942544/4411468910', }); export default function useInterstitial() { const loadInterstitial = useCallback(async () => { try { AdMobInterstitial.setAdUnitID(INTERSTITIAL_UNIT_ID); // 先判断广告是否已经加载完成,避免重复调用加载接口 const isReady = await AdMobInterstitial.getIsReadyAsync(); if (!isReady) { await AdMobInterstitial.requestAdAsync({ servePersonalizedAds: true, }); } } catch (err) { console.log('插屏广告加载异常:', err); } }, []); const showInterstitial = useCallback(async () => { try { const isReady = await AdMobInterstitial.getIsReadyAsync(); if (isReady) { await AdMobInterstitial.showAdAsync(); } else { // 广告未就绪时先触发预加载,等下一次触发时机再展示 loadInterstitial(); } } catch (err) { console.log('插屏广告展示异常:', err); } }, [loadInterstitial]); useEffect(() => { // 组件挂载时首次预加载广告 loadInterstitial(); // 监听广告关闭事件,广告关闭后立刻预加载下一条 const closeSub = AdMobInterstitial.addListener( 'interstitialDidClose', loadInterstitial ); // 监听广告加载失败事件,失败后延迟重试 const failSub = AdMobInterstitial.addListener( 'interstitialDidFailToLoad', () => { setTimeout(loadInterstitial, 3000); } ); return () => { closeSub.remove(); failSub.remove(); }; }, [loadInterstitial]); return { showInterstitial }; }
业务页面中调用时,直接引入hook拿到showInterstitial方法,在需要触发广告的时机(比如通关、页面切换、任务完成)直接调用即可,不需要手动处理加载逻辑。
注意事项
- 测试阶段严禁使用正式广告ID频繁请求、展示广告,否则会触发AdMob账号风控,导致广告无法加载、账号被封禁。
- 不要在应用启动、页面刚加载时立刻弹出插屏广告,会违反AdMob政策导致应用被下架。
- 如果清理依赖后仍然存在冲突,可以删除
node_modules、yarn.lock/package-lock.json后重新安装依赖,同时清除Expo/Metro打包缓存。
内容的提问来源于stack exchange,提问作者The.Kingslayer
相关产品推荐
相关产品推荐

