feat(chat): 채팅 쿼터 광고 충전을 추가한다

This commit is contained in:
Yu Sung
2026-04-30 14:23:15 +09:00
parent 714ad459b0
commit 5823f6ddb2
10 changed files with 423 additions and 133 deletions

View File

@@ -27,6 +27,10 @@ enum YandexInterstitialPlacement {
case contentDetail
}
enum YandexRewardedPlacement {
case chatRoomQuota
}
enum YandexAdUnitIdProvider {
static func banner(for placement: YandexBannerPlacement) -> String {
@@ -64,6 +68,13 @@ enum YandexAdUnitIdProvider {
YANDEX_CONTENT_DETAIL_INTERSTITIAL_AD_UNIT_ID
}
}
static func rewarded(for placement: YandexRewardedPlacement) -> String {
switch placement {
case .chatRoomQuota:
YANDEX_CHAT_ROOM_QUOTA_REWARDED_AD_UNIT_ID
}
}
}
struct YandexInlineBannerView: View {
@@ -303,3 +314,128 @@ extension YandexInterstitialAdManager: InterstitialAdDelegate {
completePendingAction()
}
}
@MainActor
final class YandexRewardedAdManager: NSObject {
static let shared = YandexRewardedAdManager()
private var rewardedAd: RewardedAd?
private var rewardedAdLoader: RewardedAdLoader?
private var currentPlacement: YandexRewardedPlacement?
private var pendingRewardAction: (@MainActor () -> Void)?
private var rewardedPlacement: YandexRewardedPlacement?
private var isLoading = false
func preloadAd(for placement: YandexRewardedPlacement) {
guard !isLoading else {
return
}
if currentPlacement == placement, rewardedAd != nil {
return
}
let loader = RewardedAdLoader()
rewardedAdLoader = loader
rewardedAd = nil
currentPlacement = placement
isLoading = true
Task {
do {
let loadedAd = try await loader.loadAd(with: AdRequest(adUnitID: YandexAdUnitIdProvider.rewarded(for: placement)))
guard currentPlacement == placement else {
isLoading = false
return
}
loadedAd.delegate = self
rewardedAd = loadedAd
} catch {
if currentPlacement == placement {
rewardedAd = nil
}
}
if currentPlacement == placement {
isLoading = false
}
}
}
func showAdIfAvailable(for placement: YandexRewardedPlacement, onReward: @escaping @MainActor () -> Void) -> Bool {
guard let presenter = presentingViewController(), let rewardedAd, currentPlacement == placement else {
preloadAd(for: placement)
return false
}
pendingRewardAction = onReward
rewardedPlacement = placement
rewardedAd.show(from: presenter)
return true
}
private func completeRewardIfNeeded() {
let action = pendingRewardAction
pendingRewardAction = nil
action?()
}
private func resetAndPreload() {
pendingRewardAction = nil
rewardedAd = nil
if let rewardedPlacement {
self.rewardedPlacement = nil
preloadAd(for: rewardedPlacement)
}
}
private func presentingViewController() -> UIViewController? {
guard
let rootViewController = UIApplication.shared.connectedScenes
.compactMap({ $0 as? UIWindowScene })
.flatMap({ $0.windows })
.first(where: { $0.isKeyWindow })?
.rootViewController
else {
return nil
}
var topViewController = rootViewController
while let presentedViewController = topViewController.presentedViewController {
topViewController = presentedViewController
}
return topViewController
}
}
extension YandexRewardedAdManager: RewardedAdDelegate {
func rewardedAd(_ rewardedAd: RewardedAd, didReward reward: Reward) {
DEBUG_LOG("리워드 광고 보상 받기 성공")
completeRewardIfNeeded()
}
func rewardedAd(_ rewardedAd: RewardedAd, didFailToShow error: Error) {
DEBUG_LOG("리워드 광고 에러")
resetAndPreload()
}
func rewardedAdDidShow(_ rewardedAd: RewardedAd) {
}
func rewardedAdDidDismiss(_ rewardedAd: RewardedAd) {
DEBUG_LOG("리워드 광고 닫기")
resetAndPreload()
}
func rewardedAdDidClick(_ rewardedAd: RewardedAd) {
}
func rewardedAd(_ rewardedAd: RewardedAd, didTrackImpression impressionData: ImpressionData?) {
}
}