You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI项目中AdMob原生广告Callout按钮集成问题求助

SwiftUI集成AdMob原生广告:Callout按钮点击逻辑实现

在SwiftUI项目中集成AdMob原生广告后,广告内容已正常显示,但不清楚如何实现Callout按钮的点击逻辑。以下是现有代码及广告展示效果:

广告状态枚举与加载管理类

enum AdStatus {
    case loading, success, failure
}

final class NativeViewController2: NSObject, ObservableObject, GADNativeAdLoaderDelegate, GADNativeAdDelegate {

    @Published var adStatus: AdStatus = .loading
    
    var adLoader: GADAdLoader?
    var nativeAd: GADNativeAd?
    // 广告单元ID
    let adUnitID = Pub.AdMob.nativeAdUnitId

    
    func loadAd(adStatus: AdStatus){
        self.adStatus = adStatus
        
        let options = GADNativeAdMediaAdLoaderOptions()
        options.mediaAspectRatio = .square
        
        let root = UIApplication
            .shared
            .connectedScenes
            .flatMap { ($0 as? UIWindowScene)?.windows ?? [] }
            .first { $0.isKeyWindow }!.rootViewController
        
        adLoader = GADAdLoader(adUnitID: adUnitID, rootViewController: root!, adTypes: [GADAdLoaderAdType.native], options: [options])
        adLoader?.delegate = self
        adLoader?.load(GADRequest())
    }

    func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) {
        // 设置原生广告代理,监听广告事件
        nativeAd.delegate = self
        
        self.nativeAd = nativeAd
        self.adStatus = .success
        print("广告加载成功")
        
    }
    
    func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
        self.adStatus = .failure
        print("广告加载失败")
    }
    
    func nativeAds() -> GADNativeAd? {
        self.nativeAd
    }
}

广告展示SwiftUI视图

struct NativeView: View {
    
    @State var adStatus: AdStatus
    @State var nativeViewController = NativeViewController2()

    
    var body: some View {
        VStack {
            if nativeViewController.adStatus == .success {
                if let nativeAd = nativeViewController.nativeAds() {
                    NativeAdView2(nativeAd: nativeAd)
                        .frame(height: 140, alignment: .center)
                    
                }
            }
        }
        .onAppear {
            nativeViewController.loadAd(adStatus: adStatus)
        }
    }
}


struct NativeAdView2: View {
    
    var nativeAd: GADNativeAd
    
    var body: some View {
        VStack {
            HStack {
                Spacer()
                Text("广告")
                    .font(.system(size: 11, weight: .semibold, design: .rounded))
                    .padding(.horizontal, 5)
                    .foregroundColor(.white)
                    .background(
                        RoundedRectangle(cornerRadius: 5)
                            .fill(Color(#colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)))
                    )
                
            }
            .padding(.horizontal, 15)
            .padding(.bottom, -10)
            
            HStack {
                Image(uiImage: (nativeAd.icon?.image)!)
                    .resizable()
                    .scaledToFill()
                    .frame(width: 65, height: 65)
                    .cornerRadius(5)
                
                VStack(alignment: .leading) {
                    Text(nativeAd.headline!)
                        .fontWeight(.semibold)
                        .fixedSize(horizontal: false, vertical: true)
                        .font(.body)
                        .lineLimit(2)
                        .lineSpacing(1)
                    
                    Text(nativeAd.advertiser ?? "广告主")
                        .font(.subheadline)
                }
                Spacer()
            }
            .padding(.horizontal, 15)
            
            
            HStack(spacing: 15) {
                Text(nativeAd.price ?? "")
                
                if let starRating = nativeAd.starRating {
                    HStack {
                        ForEach(0..<Int(truncating: starRating), id: \.self) { _ in
                            Image(systemName: "star")
                        }
                    }
                }
                
                if let cTA = nativeAd.callToAction {
                    Button(action: {
                        // 待实现点击逻辑
                    }, label: {
                        Text(cTA)
                            .padding(.horizontal, 10)
                            .padding(.vertical, 5)
                            .background(
                                RoundedRectangle(cornerRadius: 10)
                                    .fill(Color(.systemBlue))
                            )
                            .foregroundColor(.white)
                    })
                }
            }
            .font(.subheadline)
            
        }
        .modifier(forEachDesign())
        .frame(height: 140, alignment: .center)
        .background(BlurView(style: .dark))
        .cornerRadius(10)
    }
}

广告展示效果

广告展示效果


实现Callout按钮点击逻辑的步骤

由于SwiftUI视图并非直接的UIKit视图,需要手动关联AdMob的点击追踪逻辑,具体实现如下:

1. 添加视图追踪工具

创建一个ViewModifier,用来获取SwiftUI视图对应的UIKit UIView实例,供AdMob调用点击方法使用:

struct ViewTracker: ViewModifier {
    @Binding var trackedView: UIView?
    
    func body(content: Content) -> some View {
        content
            .background(UIViewRepresentableHelper(view: $trackedView))
    }
}

struct UIViewRepresentableHelper: UIViewRepresentable {
    @Binding var view: UIView?
    
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        self.view = view
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {}
}

2. 修改NativeAdView2实现点击逻辑

在NativeAdView2中引入视图追踪,并在按钮点击时调用AdMob原生广告的performClick方法:

struct NativeAdView2: View {
    var nativeAd: GADNativeAd
    // 存储追踪到的UIView实例
    @State private var adContainerView: UIView?
    
    var body: some View {
        VStack {
            // 原有广告内容...
            
            if let cTA = nativeAd.callToAction {
                Button(action: {
                    guard let containerView = adContainerView else { return }
                    // 调用AdMob的点击方法,传入对应的视图
                    nativeAd.performClick(on: containerView)
                    // 可选:记录广告曝光(若未在其他地方调用)
                    nativeAd.recordImpression()
                }, label: {
                    Text(cTA)
                        .padding(.horizontal, 10)
                        .padding(.vertical, 5)
                        .background(
                            RoundedRectangle(cornerRadius: 10)
                                .fill(Color(.systemBlue))
                        )
                        .foregroundColor(.white)
                })
            }
        }
        // 添加视图追踪modifier
        .modifier(ViewTracker(trackedView: $adContainerView))
        .modifier(forEachDesign())
        .frame(height: 140, alignment: .center)
        .background(BlurView(style: .dark))
        .cornerRadius(10)
    }
}

关键说明

  • performClick(on:)是AdMob处理原生广告点击的核心方法,必须传入UIView实例用于事件追踪;
  • recordImpression()用于统计广告曝光数据,若在广告加载完成后已调用过,此处可省略;
  • 确保已设置nativeAd.delegate(现有代码中已在adLoader(_:didReceive:)中完成设置),AdMob会自动处理后续跳转逻辑。

内容的提问来源于stack exchange,提问作者dibs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 17:56:09