Fix AdMob history banner and refine Felica history mapping

This commit is contained in:
2026-04-24 21:32:56 +07:00
parent 8f0b001501
commit 7882f77a27
6 changed files with 289 additions and 38 deletions

View File

@ -63,6 +63,10 @@ final class HomeViewController: UIViewController {
// Ads
private let promoCard = UIView()
private var bannerView = GADBannerView()
private var bannerRetryWorkItem: DispatchWorkItem?
private var isBannerAdLoaded = false
private var isBannerLoadInFlight = false
private let bannerRetryDelay: TimeInterval = 20
// Dynamic layout: toggle based on ad load state
private var lastTxTopNoAd: NSLayoutConstraint!
@ -106,6 +110,7 @@ final class HomeViewController: UIViewController {
name: Notification.Name("refreshScreen"),
object: nil
)
loadBannerAdIfNeeded(reason: "viewDidAppear")
}
override func viewDidDisappear(_ animated: Bool) {
@ -113,6 +118,10 @@ final class HomeViewController: UIViewController {
NotificationCenter.default.removeObserver(self, name: Notification.Name("refreshScreen"), object: nil)
}
deinit {
bannerRetryWorkItem?.cancel()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
cardGradient.frame = cardView.bounds
@ -266,9 +275,55 @@ final class HomeViewController: UIViewController {
}
func loadBannerAd() {
loadBannerAdIfNeeded(reason: "external")
}
private func loadBannerAdIfNeeded(reason: String) {
guard !isBannerAdLoaded, !isBannerLoadInFlight else { return }
guard isViewLoaded, view.window != nil else {
logAdMob("skip load: view is not visible", reason: reason)
return
}
bannerRetryWorkItem?.cancel()
bannerView.rootViewController = self
isBannerLoadInFlight = true
logAdMob("loading banner", reason: reason)
bannerView.load(GADRequest())
}
private func scheduleBannerRetry(after delay: TimeInterval = 20) {
bannerRetryWorkItem?.cancel()
let workItem = DispatchWorkItem { [weak self] in
self?.loadBannerAdIfNeeded(reason: "retry")
}
bannerRetryWorkItem = workItem
logAdMob("scheduling retry in \(Int(delay))s")
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: workItem)
}
private func logAdMob(_ message: String, reason: String? = nil, error: Error? = nil) {
var parts = ["[AdMob][Home]", message]
if let reason {
parts.append("reason=\(reason)")
}
parts.append("adUnitID=\(bannerView.adUnitID ?? "-")")
parts.append("visible=\(viewIfLoaded?.window != nil)")
parts.append("loaded=\(isBannerAdLoaded)")
parts.append("inFlight=\(isBannerLoadInFlight)")
parts.append("rootVC=\(String(describing: type(of: bannerView.rootViewController)))")
if let nsError = error as NSError? {
parts.append("errorDomain=\(nsError.domain)")
parts.append("errorCode=\(nsError.code)")
parts.append("error=\(nsError.localizedDescription)")
}
debugLog(parts.joined(separator: " | "))
}
private func setupLastTransaction() {
lastTxHeader.text = L10n.lastTransaction
lastTxHeader.font = Theme.Font.subtitle(weight: .bold)
@ -562,6 +617,10 @@ struct LastTransactionItem {
extension HomeViewController: GADBannerViewDelegate {
func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
bannerRetryWorkItem?.cancel()
isBannerLoadInFlight = false
isBannerAdLoaded = true
logAdMob("banner loaded")
lastTxTopNoAd.isActive = false
lastTxTopWithAd.isActive = true
UIView.animate(withDuration: 0.3) {
@ -571,12 +630,16 @@ extension HomeViewController: GADBannerViewDelegate {
}
func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) {
isBannerLoadInFlight = false
isBannerAdLoaded = false
logAdMob("banner failed", error: error)
lastTxTopWithAd.isActive = false
lastTxTopNoAd.isActive = true
UIView.animate(withDuration: 0.3) {
self.promoCard.isHidden = true
self.view.layoutIfNeeded()
}
scheduleBannerRetry(after: bannerRetryDelay)
}
}