I integrate Admob interstitial to my project. For the moment test with test interstitial key “ca-app-pub-3940256099942544/1033173712”.
After admob initilisation ad load success.
But when I try to show this interstitial, I get error:
onAdFailedToShowFullScreenContent {
"Code": 0,
"Message": "Timeout for show call succeed.",
"Domain": "com.google.android.gms.ads",
"Cause": "null"
}
Project – single activity with navigation grap. Also use Koin.
Admob version “com.google.android.gms:play-services-ads:23.5.0”
Banner ad is showing correct.
What was try:
- Account admob key was inserted to google sample app with test inter key. Result: Inter showing
- New project with navgraph and single activity was created and my AdmobManager with keys was inserted to it. Result: Inter showing
- Migrate files from old project to new. Result: Inter wasn’t show with “Timeout for show call succeed.” error
From this I can understand that keys and account is correct. Also my AdmobManager work for clean project - By debug I can see that show called from main thread
- Activity for showing alive, not paused or stoped
- Inrestitial object not null, contains data
- Trying to add timeout after ad loading before showing doesn’t help
- Addig to Koin as module doesn’t help
Additional information from logs:
Data before calling inter show: activity com.example.x.MainActivity@c05dd82 interAd adUnitId ca-app-pub-3940256099942544/1033173712 interAd com.google.android.gms.internal.ads.zzbml@8817dd0
Data after calling inter show: After show activity com.example.x.MainActivity@c05dd82 interAd adUnitId ca-app-pub-3940256099942544/1033173712 interAd com.google.android.gms.internal.ads.zzbml@8817dd0
Activity lifecircle:
before calling inter show:
onStart
onResume
After show activity com.example.x.MainActivity@c05dd82 interAd adUnitId ca-app-pub-3940256099942544/1033173712 interAd com.google.android.gms.internal.ads.zzbml@8817dd0
onPause
onAdFailedToShowFullScreenContent {
"Code": 0,
"Message": "Timeout for show call succeed.",
"Domain": "com.google.android.gms.ads",
"Cause": "null"
}
onResume
My code:
object AdmobManager {
private var interAd: InterstitialAd? = null
private var loadedAdNumber = 0
private var failedCount = 0
fun init(context: Context) {
MobileAds.initialize(context){}
MobileAds.setRequestConfiguration(
RequestConfiguration.Builder()
.setTestDeviceIds(listOf("xxxxxxxx")).build()
)
}
fun preloadAd(context: Context, adsDelegateShow: AdsDelegateLoad) {
InterstitialAd.load(
context,
"ca-app-pub-3940256099942544/1033173712",
AdRequest.Builder().build(),
object : InterstitialAdLoadCallback() {
override fun onAdLoaded(interstitialAd: InterstitialAd) {
super.onAdLoaded(interstitialAd)
Log.i("AdsWrapper", "onAdLoaded")
failedCount = 0
interAd = interstitialAd
adsDelegateShow.onAdsLoaded()
}
override fun onAdFailedToLoad(p0: LoadAdError) {
super.onAdFailedToLoad(p0)
Log.i("AdsWrapper", "onAdFailedToLoad " + p0.toString())
adsDelegateShow.onAdsLoaded()
if(failedCount < 15){
interAd = null
failedCount++
preloadAd(context){}
}
}
})
}
fun showInterstitial(activity: Activity, adsDelegateShow: AdsDelegateShow) {
Log.i("AdsWrapper", "showInterstitial")
if (interAd == null) {
adsDelegateShow.onAdsClosed()
Toast.makeText(activity.applicationContext, "Load waiting", Toast.LENGTH_LONG).show()
return
}
Log.i("AdsWrapper", "activity " + activity.toString() + " interAd adUnitId " + interAd!!.adUnitId +" interAd " + interAd)
interAd?.fullScreenContentCallback = object : FullScreenContentCallback() {
override fun onAdShowedFullScreenContent() {
super.onAdShowedFullScreenContent()
adsDelegateShow.onAdsOpened()
Log.i("AdsWrapper", "onAdShowedFullScreenContent ")
}
override fun onAdDismissedFullScreenContent() {
super.onAdDismissedFullScreenContent()
Log.i("AdsWrapper", "onAdDismissedFullScreenContent ")
interAd = null
preloadAd(activity.applicationContext)
adsDelegateShow.onAdsClosed()
}
override fun onAdFailedToShowFullScreenContent(p0: AdError) {
super.onAdFailedToShowFullScreenContent(p0)
Log.i("AdsWrapper", "onAdFailedToShowFullScreenContent " + p0)
interAd = null
Toast.makeText(activity.applicationContext, p0.toString(), Toast.LENGTH_LONG).show()
preloadAd(activity.applicationContext)
adsDelegateShow.onAdsClosed()
}
}
interAd!!.show(activity)
Log.i("AdsWrapper", "After show activity " + activity.toString() + " interAd adUnitId " + interAd!!.adUnitId +" interAd " + interAd)
}
interface AdsDelegateShow {
fun onAdsClosed()
fun onAdsOpened() {}
}
interface AdsDelegateLoad{
fun onAdsLoaded() {}
}
}
Application:
class App : Application() {
companion object {
lateinit var instance: App
}
override fun onCreate() {
super.onCreate()
instance = this
startKoin {
androidContext(this@App)
modules(
listOf(
viewModelModule
)
)
}
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_NO
)
AdmobManager.init(this)
FirebaseApp.initializeApp(this)
FirebaseAnalytics.getInstance(this).setAnalyticsCollectionEnabled(true)
FirebaseAnalytics.getInstance(this).logEvent("open_app", bundleOf())
val remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig
val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = 0
}
remoteConfig.setConfigSettingsAsync(configSettings)
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
}
}
My Activity:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}
My activity layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background_screen"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment_activity_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph"/>
</androidx.constraintlayout.widget.ConstraintLayout>
My Fragment
class SplashFragment : Fragment() {
private var _binding: FragmentSplashBinding? = null
private val binding get() = _binding!!
private var progressStatus = 0
private var answerAdsLoadGet = false
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentSplashBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
AdmobManager.preloadAd(requireActivity(),
object : AdmobManager.AdsDelegateLoad {
override fun onAdsLoaded() {
Log.d("AdsWrapper", "answer got")
answerAdsLoadGet = true
}
})
binding.progressBar.progress = 0
binding.progressBar.progressDrawable.mutate()
requestNotificationPermission()
getInstalledApps()
lifecycleScope.launch {
while (progressStatus < PROGRESS_BAR_MAX) {
if(answerAdsLoadGet && progressStatus < 99){
progressStatus += 2
} else {
progressStatus += 1
}
withContext(Dispatchers.Main) {
binding.progressBar.progress = progressStatus
val loadingPercent = getString(R.string.storage_percent_info, progressStatus)
binding.progressText.text = loadingPercent
}
delay(SPLASH_TIME_OUT)
}
withContext(Dispatchers.Main) {
AdmobManager.showInterstitial(requireActivity(), object : AdmobManager.AdsDelegateShow {
override fun onAdsClosed() {
findNavController().navigate(R.id.action_splashFragment_to_mainFragment)
}
})
}
}
}
//some other code
companion object {
const val SPLASH_TIME_OUT = 60L
const val PROGRESS_BAR_MAX = 100
const val REQUEST_NOTIFICATION_PERMISSION = 1001
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
My Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application
android:name=".App"
android:allowBackup="false"
android:requestLegacyExternalStorage="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.My_theme"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:process=":lottieProcess"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-APPLICATION_ID"/>
<meta-data
android:name="com.google.android.gms.ads.flag.OPTIMIZE_AD_LOADING"
android:value="true" />
</application>
</manifest>
1