Flutter集成Google原生广告iOS端如何用SwiftUI替代XIB实现
实现方案
核心误区:GADNativeAdView是UIKit框架下的UIView子类,SwiftUI的View是值类型结构体,无法直接继承或替代UIKit类返回给Admob SDK。你需要做UIKit和SwiftUI的桥接,整体实现不需要修改原有AppDelegate的注册逻辑,只需要替换原来XIB加载广告视图的部分即可。
步骤1:编写纯SwiftUI的广告内容视图
这部分完全用SwiftUI写布局,同时把需要被Admob SDK识别的广告控件实例桥接出来,用于后续绑定SDK要求的属性:
import SwiftUI import GoogleMobileAds // 纯SwiftUI实现的广告UI布局 struct NativeAdContentView: View { let nativeAd: GADNativeAd // 保留UIKit控件引用,供SDK绑定识别 let headlineRef = UILabel() let bodyRef = UILabel() let iconRef = UIImageView() let ctaRef = UIButton(type: .system) init(nativeAd: GADNativeAd) { self.nativeAd = nativeAd // 提前给控件填充广告数据 headlineRef.text = nativeAd.headline bodyRef.text = nativeAd.body bodyRef.isHidden = nativeAd.body == nil iconRef.image = nativeAd.icon?.image iconRef.isHidden = nativeAd.icon == nil ctaRef.setTitle(nativeAd.callToAction, for: .normal) ctaRef.isHidden = nativeAd.callToAction == nil ctaRef.isUserInteractionEnabled = false // 关闭按钮自身交互,由SDK统一处理点击 } var body: some View { HStack(spacing: 12) { IconView(iconRef: iconRef) .frame(width: 40, height: 40) .clipped() VStack(alignment: .leading, spacing: 4) { HeadlineView(labelRef: headlineRef) .font(.system(size: 16, weight: .medium)) .lineLimit(1) if nativeAd.body != nil { BodyView(labelRef: bodyRef) .font(.system(size: 14)) .lineLimit(2) .foregroundColor(.secondary) } } Spacer() CTAView(buttonRef: ctaRef) .padding(.horizontal, 12) .padding(.vertical, 6) .background(Color.accentColor) .foregroundColor(.white) .cornerRadius(6) } .padding(12) } } // 以下为UIKit控件桥接到SwiftUI的轻量包装,用于获取固定的UIView实例 struct HeadlineView: UIViewRepresentable { let labelRef: UILabel func makeUIView(context: Context) -> UILabel { labelRef } func updateUIView(_ uiView: UILabel, context: Context) {} } struct BodyView: UIViewRepresentable { let labelRef: UILabel func makeUIView(context: Context) -> UILabel { labelRef } func updateUIView(_ uiView: UILabel, context: Context) {} } struct IconView: UIViewRepresentable { let iconRef: UIImageView func makeUIView(context: Context) -> UIImageView { iconRef.contentMode = .scaleAspectFill return iconRef } func updateUIView(_ uiView: UIImageView, context: Context) {} } struct CTAView: UIViewRepresentable { let buttonRef: UIButton func makeUIView(context: Context) -> UIButton { buttonRef } func updateUIView(_ uiView: UIButton, context: Context) {} }
步骤2:实现桥接用的GADNativeAdView子类
这个类是UIKit类型,替代原来XIB加载的广告视图,负责承载SwiftUI布局,同时完成SDK要求的控件绑定、广告数据挂载:
class SwiftUINativeAdView: GADNativeAdView { private var hostingController: UIHostingController<NativeAdContentView>? func setup(with nativeAd: GADNativeAd) { let adContentView = NativeAdContentView(nativeAd: nativeAd) // 挂载SwiftUI视图到当前UIKit视图 if hostingController == nil { let host = UIHostingController(rootView: adContentView) hostingController = host guard let hostView = host.view else { return } hostView.translatesAutoresizingMaskIntoConstraints = false hostView.backgroundColor = .clear addSubview(hostView) // 让SwiftUI视图铺满整个广告容器 NSLayoutConstraint.activate([ hostView.topAnchor.constraint(equalTo: topAnchor), hostView.leadingAnchor.constraint(equalTo: leadingAnchor), hostView.trailingAnchor.constraint(equalTo: trailingAnchor), hostView.bottomAnchor.constraint(equalTo: bottomAnchor) ]) } else { hostingController?.rootView = adContentView } // 核心:必须绑定对应控件到SDK规定的属性,否则无法触发曝光、点击上报 self.headlineView = adContentView.headlineRef self.bodyView = adContentView.bodyRef self.iconView = adContentView.iconRef self.callToActionView = adContentView.ctaRef // 挂载广告数据对象 self.nativeAd = nativeAd } }
步骤3:修改广告工厂类
替换原来XIB加载的逻辑,直接初始化桥接的广告视图即可:
class PageAd: FLTNativeAdFactory { func createNativeAd(_ nativeAd: GADNativeAd, customOptions: [AnyHashable : Any]? = nil) -> GADNativeAdView? { let nativeAdView = SwiftUINativeAdView() nativeAdView.setup(with: nativeAd) return nativeAdView } }
步骤4:AppDelegate注册逻辑
原有注册代码不需要做任何修改,和XIB版本完全一致:
let listTileFactory = PageAd() FLTGoogleMobileAdsPlugin.registerNativeAdFactory(self, factoryId: "listTile", nativeAdFactory: listTileFactory)
注意事项
- 如果项目最低支持iOS 16及以上,可以简化桥接逻辑:不用
UIHostingController,直接在SwiftUINativeAdView中通过UIHostingConfiguration挂载SwiftUI视图即可 - 广告样式调整直接修改
NativeAdContentView里的SwiftUI布局代码即可,和普通SwiftUI页面开发逻辑完全一致 - 如果需要接入媒体素材(视频/大图),只需要在SwiftUI布局中新增对应的UIImageView/UIView桥接,赋值给
GADNativeAdView的mediaView属性即可
内容的提问来源于stack exchange,提问作者Lalit Rawat
相关产品推荐
相关产品推荐

