首页 > 解决方案 > 在 SwiftUI 项目中实现 AdMob 原生广告

问题描述

我正在尝试在 SwiftUI 项目中实现原生广告。我正在使用这些类来加载广告:

final class NativeMediaView: UIViewRepresentable {

var mediaView: GADMediaContent

init(mediaView: GADMediaContent){
    self.mediaView = mediaView
}

typealias UIViewType = GADMediaView

func makeUIView(context: Context) -> GADMediaView {
    let view = GADMediaView(frame: .zero)
    return view
}

func updateUIView(_ uiView: GADMediaView, context: Context) {
    uiView.mediaContent = self.mediaView
    uiView.frame(forAlignmentRect: CGRect(origin: .zero, size: CGSize(width: 250, height: 150)))
}
}

final class NativeViewController: UIViewControllerRepresentable {

let adUnitID: String
@Binding var adStatus: AdStatus

var adLoader: GADAdLoader?

init(adUnitID: String, adStatus: Binding<AdStatus>){
    self.adUnitID = adUnitID
    self._adStatus = adStatus
}

func makeCoordinator() -> Coordinator {
    Coordinator(nativeViewController: self)
}

func makeUIViewController(context: Context) -> UIViewController {
    let viewController = UIViewController()
    
    let multipleAdsOptions = GADMultipleAdsAdLoaderOptions()
    multipleAdsOptions.numberOfAds = 1
    
    adLoader = GADAdLoader(adUnitID: self.adUnitID, rootViewController: viewController, adTypes: [GADAdLoaderAdType.native], options: [multipleAdsOptions])
    adLoader?.delegate = context.coordinator
    adLoader?.load(GADRequest())
    
    let testLabel = GADNativeAdView()
    viewController.view.addSubview(testLabel)
    
    return viewController
}

func imageOfStars(from starRating: NSDecimalNumber?) -> UIImage? {
    guard let rating = starRating?.doubleValue else {
        return nil
    }
    if rating >= 5 {
        return UIImage(named: "stars_5")
    } else if rating >= 4.5 {
        return UIImage(named: "stars_4_5")
    } else if rating >= 4 {
        return UIImage(named: "stars_4")
    } else if rating >= 3.5 {
        return UIImage(named: "stars_3_5")
    } else {
        return nil
    }
}

func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
    
    print("STA => \(self.adStatus)")
    if self.adStatus == .success {
        let nativeAd = context.coordinator.nativeAd
        
        let nativeAdView = GADNativeAdView()
        (nativeAdView.headlineView as? UILabel)?.text = nativeAd?.headline
        
        (nativeAdView.bodyView as? UILabel)?.text = nativeAd?.body
        nativeAdView.bodyView?.isHidden = nativeAd?.body == nil
        
        (nativeAdView.callToActionView as? UIButton)?.setTitle(nativeAd?.callToAction, for: .normal)
        nativeAdView.callToActionView?.isHidden = nativeAd?.callToAction == nil
        
        (nativeAdView.iconView as? UIImageView)?.image = nativeAd?.icon?.image
        nativeAdView.iconView?.isHidden = nativeAd?.icon == nil
        
        (nativeAdView.advertiserView as? UILabel)?.text = nativeAd?.advertiser
        nativeAdView.advertiserView?.isHidden = nativeAd?.advertiser == nil
        nativeAdView.callToActionView?.isUserInteractionEnabled = false
        nativeAdView.nativeAd = nativeAd
        nativeAdView.translatesAutoresizingMaskIntoConstraints = false
        
        uiViewController.removeFromParent()
        uiViewController.view.addSubview(nativeAdView)

    }
    
}

class Coordinator: NSObject, GADNativeAdLoaderDelegate {
    
    var nativeViewController: NativeViewController
    var nativeAd: GADNativeAd?
    
    init(nativeViewController: NativeViewController){
        self.nativeViewController = nativeViewController
    }
    
    func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) {
        self.nativeAd = nativeAd
        self.nativeViewController.adStatus = .success
    }
    
    func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
        self.nativeViewController.adStatus = .failure
    }
}
}

final class NativeViewController2: NSObject, GADNativeAdLoaderDelegate {
@Binding var adStatus: AdStatus

var adLoader: GADAdLoader?
var nativeAd: GADNativeAd?

init(adStatus: Binding<AdStatus> = .constant(AdStatus.loading)){
    self._adStatus = adStatus
}

func loadAd(adStatus: Binding<AdStatus>){
    self._adStatus = adStatus
    
    let options = GADNativeAdMediaAdLoaderOptions()
    options.mediaAspectRatio = .square
    
    let root = UIApplication.shared.windows.first?.rootViewController
    
    adLoader = GADAdLoader(adUnitID: "ca-app-pub-3940256099942544/3986624511", rootViewController: root!, adTypes: [GADAdLoaderAdType.native], options: [options])
    adLoader?.delegate = self
    adLoader?.load(GADRequest())
}

func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) {
    self.nativeAd = nativeAd
    self.adStatus = .success
}

func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
    self.adStatus = .failure
}

func nativeAds() -> GADNativeAd? {
    self.nativeAd
}

这些结构显示广告:

struct NativeView: View {
@State var adStatus: AdStatus = .loading

var nativeViewController = NativeViewController2()

var body: some View {
    VStack {
        if adStatus == .success {
            if let nativeAd = nativeViewController.nativeAds() {
                NativeAdView(nativeAd: nativeAd)
                    .frame(maxWidth: 375)
            }
        }
        else {
            ProgressView(value: /*@START_MENU_TOKEN@*/0.5/*@END_MENU_TOKEN@*/)
                .progressViewStyle(CircularProgressViewStyle())
            
            Text("Loading ad")
                .foregroundColor(.secondary)
        }
    }
    .onAppear {
        nativeViewController.loadAd(adStatus: $adStatus)
    }
}
}

struct NativeAdView: View {

var nativeAd: GADNativeAd

var body: some View {
    VStack {
        HStack {
            Text("Advertisement")
                .font(.system(size: 12, 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(.top, 10)
        
        HStack {
            Image(uiImage: (nativeAd.icon?.image)!)
                .resizable()
                .scaledToFill()
                .frame(width: 60, height: 60)
                .mask(Circle())
            
            VStack(alignment: .leading) {
                Text(nativeAd.headline!)
                    .fontWeight(.semibold)
                    .fixedSize(horizontal: false, vertical: true)
                    .font(.title3)
                    .lineLimit(2)
                    .multilineTextAlignment(/*@START_MENU_TOKEN@*/.leading/*@END_MENU_TOKEN@*/)
                    .lineSpacing(1)
                
                Text(nativeAd.advertiser ?? "Advert")
                    .font(.subheadline)
            }
            Spacer()
        }
        .padding(.horizontal, 15)
        
        HStack {
            Text(nativeAd.body!)
                .multilineTextAlignment(.leading)
            Spacer()
        }
        .padding(.horizontal, 15)
        
        HStack(spacing: 15) {
            Spacer()
            Text(nativeAd.price ?? "")
                .multilineTextAlignment(.leading)
            
            HStack {
                ForEach(0..<Int(truncating: nativeAd.starRating ?? 0)) { _ in
                    Image(systemName: "star")
                }
            }
            
            if let cTA = nativeAd.callToAction {
                Button(action: {
                    
                }, label: {
                    Text(cTA)
                        .fontWeight(/*@START_MENU_TOKEN@*/.bold/*@END_MENU_TOKEN@*/)
                        .padding(.horizontal, 10)
                        .padding(.vertical, 5)
                        .background(
                            RoundedRectangle(cornerRadius: 10)
                                .fill(Color(.systemBlue))
                        )
                        .foregroundColor(.white)
                })
            }
        }
        .padding([.horizontal, .bottom])
        
    }.frame(maxWidth: 375)
    .background(
        RoundedRectangle(cornerRadius: /*@START_MENU_TOKEN@*/25.0/*@END_MENU_TOKEN@*/)
            .fill((Color.white))
            .shadow(color: Color(#colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.76)), radius: 5, x: /*@START_MENU_TOKEN@*/0.0/*@END_MENU_TOKEN@*/, y: 0)
    )
    .padding()
}
}

我的问题有两个:首先,为什么选择按钮没有正确显示?它应该显示自动,但它不存在。那么,如何管理标注按钮呢?

我从这里得到了代码,但我编辑了它。

展示广告:https ://i.stack.imgur.com/WXU35.png

标签: swiftswiftuiadmobnative-ads

解决方案


推荐阅读