「SDK8 AdMob Mediation Native」修訂間的差異
CharlesWang(留言 | 貢獻) (→已知問題) |
CharlesWang(留言 | 貢獻) |
||
| 行 271: | 行 271: | ||
} | } | ||
</nowiki> | </nowiki> | ||
<!-- | |||
= 簡介 = | |||
將說明如何將 TAmedia SDK 原生廣告與 Google AdMob 原生廣告([https://developers.google.com/admob/ios/native/advanced Native advanced])做 mediation 整合,關於 AdMob mediation 請參考:https://developers.google.com/admob/ios/mediate | |||
= 串接準備 = | |||
首先先完成 mediation 基本 setup [[AdMob Mediation Setup]], TADCustomEvent 將會透過此客製化 class 取得 TADNativeAd。 | |||
= 實作方式 = | |||
TADCustomEventNative.swift | |||
<source> | |||
import Foundation | |||
import GoogleMobileAds | |||
import TAMediaAdsFramework | |||
class TADCustomEventNative: NSObject { | |||
var tadNativeAd: TADNativeAd? | |||
var tadNativeAdView: TADNativeAdView? | |||
var mappedImages = [GADNativeAdImage]() | |||
var mapIcon: GADNativeAdImage? | |||
var delegate: GADMediationNativeAdEventDelegate? | |||
/// Completion handler called after ad load | |||
var completionHandler: GADMediationNativeLoadCompletionHandler? | |||
deinit { | |||
print("TADCustomEventNative - TADMediatedUnifiedNativeAd deinit") | |||
} | |||
func loadNativeAd(for adConfiguration: GADMediationNativeAdConfiguration, | |||
completionHandler: @escaping GADMediationNativeLoadCompletionHandler) { | |||
self.completionHandler = completionHandler | |||
let request = TADRequest() | |||
request.showLog = true | |||
let option = TADNativeAdOptions() | |||
/// 參見 http://wiki.tamedia.com.tw/iosDoc/Classes/TADNativeAdOptions.html | |||
// option.disableImageLoading = true //SDK 將不自動下載圖片 | |||
// option.mediaPreferImage = true //只會呈現圖片廣告 | |||
// option.startUnmuted = true //影片廣告會以非靜音方式呈現 | |||
// option.customControlsRequested = true //自行定義影音廣告的靜音/取消靜音、倒計時標籤和了解更多按鈕 | |||
// option.allowAudioSessionControl = false //設為false則需自行設定影音廣告出現時 AVAudioSession 狀態 | |||
tadNativeAd = TADNativeAd(adUnitId: adConfiguration.credentials.settings["parameter"] as? String) | |||
tadNativeAd?.delegate = self | |||
tadNativeAd?.load(request, withOption: option) | |||
} | |||
private func setup(nativeAd: TADNativeAd, nativeAdView: TADNativeAdView) { | |||
tadNativeAd = nativeAd | |||
tadNativeAdView = nativeAdView | |||
tadNativeAd?.delegate = self | |||
tadNativeAdView?.mediaView?.statusDelegate = self | |||
guard let mediaContent = tadNativeAd?.adContent.mediaContent else { | |||
return | |||
} | |||
if let tadImage = mediaContent.image1200x627?.image { | |||
let adImage = GADNativeAdImage(image: tadImage) | |||
tadNativeAdView?.mediaView?.setMainImage(image: tadImage) | |||
mappedImages.append(adImage) | |||
} | |||
if let iconImage = tadNativeAd?.adContent.iconSquare?.image { | |||
mapIcon = GADNativeAdImage(image: iconImage) | |||
} | |||
} | |||
} | |||
extension TADCustomEventNative: TADNativeAdDelegate { | |||
func nativeAdDidReceive(_ ad: TADNativeAd!) { | |||
let nativeAdView = TADNativeAdView() | |||
let mediaView = TADNativeMediaView(frame: .zero) | |||
mediaView.mediaContent = ad.adContent.mediaContent | |||
/// 參見 http://wiki.tamedia.com.tw/iosDoc/Classes/TADNativeMediaView.html | |||
// mediaView.setCallToActionVisible(false) //是否顯示 CTA 按鈕 | |||
// mediaView.setCallToActionTextSize(12) //設定 CTA 文字大小 | |||
// mediaView.setVolumeImageSize(24) //設定影音廣告靜音圖片大小 | |||
// mediaView.setVideoCountdownTextSize(17) //設定影音倒數文字大小 | |||
nativeAdView.addSubview(mediaView) | |||
nativeAdView.mediaView = mediaView | |||
setup(nativeAd: ad, nativeAdView: nativeAdView) | |||
if let handler = completionHandler { | |||
delegate = handler(self, nil) | |||
} | |||
} | |||
func nativeAd(_ ad: TADNativeAd!, didFailToReceiveAdWithError error: TADRequestError!) { | |||
if let handler = completionHandler { | |||
delegate = handler(nil, error) | |||
} | |||
} | |||
func nativeAdDidImpression(_ ad: TADNativeAd!) { | |||
print("TADCustomEventNative - nativeAdDidImpression") | |||
delegate?.reportImpression() | |||
} | |||
func nativeAdDidClick(_ ad: TADNativeAd!) { | |||
print("TADCustomEventNative - nativeAdDidClick") | |||
delegate?.reportClick() | |||
} | |||
} | |||
extension TADCustomEventNative: TADVideoStatusDelegate { | |||
func didStartVideo() { | |||
delegate?.didPlayVideo() | |||
} | |||
func didPlayVideo() { | |||
delegate?.didPlayVideo() | |||
} | |||
func didPauseVideo() { | |||
delegate?.didPauseVideo() | |||
} | |||
func didEndVideoPlayback() { | |||
delegate?.didEndVideo() | |||
} | |||
func didMuteVideo() { | |||
delegate?.didMuteVideo() | |||
} | |||
func didUnmuteVideo() { | |||
delegate?.didUnmuteVideo() | |||
} | |||
} | |||
extension TADCustomEventNative: GADMediationNativeAd { | |||
var headline: String? { | |||
return tadNativeAd?.adContent.longSubject | |||
} | |||
var images: [GADNativeAdImage]? { | |||
return mappedImages | |||
} | |||
var body: String? { | |||
return tadNativeAd?.adContent.body | |||
} | |||
var icon: GADNativeAdImage? { | |||
return mapIcon | |||
} | |||
var callToAction: String? { | |||
return tadNativeAd?.adContent.callToAction | |||
} | |||
var starRating: NSDecimalNumber? { | |||
return nil | |||
} | |||
var store: String? { | |||
return nil | |||
} | |||
var price: String? { | |||
return nil | |||
} | |||
var advertiser: String? { | |||
return nil | |||
} | |||
var extraAssets: [String: Any]? { | |||
return nil | |||
} | |||
var mediaView: UIView? { | |||
return tadNativeAdView?.mediaView | |||
} | |||
var hasVideoContent: Bool { | |||
guard let mediaContent = tadNativeAd?.adContent.mediaContent else { | |||
return false | |||
} | |||
return mediaContent.isVideoContent | |||
} | |||
func handlesUserClicks() -> Bool { | |||
return true | |||
} | |||
func handlesUserImpressions() -> Bool { | |||
return true | |||
} | |||
func didRender(in view: UIView, clickableAssetViews: [GADNativeAssetIdentifier : UIView], nonclickableAssetViews: [GADNativeAssetIdentifier : UIView], viewController: UIViewController) { | |||
guard let tadNativeAdView = tadNativeAdView else { return } | |||
view.subviews.first { $0 is TADNativeAdView }?.removeFromSuperview() | |||
view.insertSubview(tadNativeAdView, at: 0) | |||
fillSuperView(view: tadNativeAdView) | |||
if let titleLabel = clickableAssetViews[GADNativeAssetIdentifier.headlineAsset] as? UILabel { | |||
titleLabel.isUserInteractionEnabled = true | |||
tadNativeAdView.longSubjectLabel = titleLabel | |||
} | |||
if let bodyLabel = clickableAssetViews[GADNativeAssetIdentifier.bodyAsset] as? UILabel { | |||
bodyLabel.isUserInteractionEnabled = true | |||
tadNativeAdView.bodyLabel = bodyLabel | |||
} | |||
if let ctaLabel = clickableAssetViews[GADNativeAssetIdentifier.callToActionAsset] { | |||
ctaLabel.isUserInteractionEnabled = true | |||
tadNativeAdView.callToActionView = ctaLabel | |||
} | |||
if let icon = clickableAssetViews[GADNativeAssetIdentifier.iconAsset] as? UIImageView { | |||
icon.isUserInteractionEnabled = true | |||
tadNativeAdView.squareImgeView = icon | |||
} | |||
if let mediaView = clickableAssetViews[GADNativeAssetIdentifier.mediaViewAsset], let tadMediaView = tadNativeAdView.mediaView { | |||
mediaView.subviews.first { $0 is TADNativeMediaView }?.removeFromSuperview() | |||
mediaView.addSubview(tadMediaView) | |||
fillSuperView(view: tadMediaView) | |||
} | |||
tadNativeAdView.nativeAd = tadNativeAd | |||
} | |||
func didUntrackView(_ view: UIView?) { | |||
print("TADMediatedUnifiedNativeAd - didUntrackView") | |||
tadNativeAdView?.removeFromSuperview() | |||
tadNativeAdView?.mediaView?.removeFromSuperview() | |||
} | |||
} | |||
extension TADCustomEventNative { | |||
func fillSuperView(view: UIView) { | |||
view.frame = view.superview?.bounds ?? .zero | |||
} | |||
} | |||
</source> | |||
--> | |||
於 2023年3月1日 (三) 10:34 的修訂
簡介
將說明如何將 TAmedia SDK 原生廣告與 Google AdMob 原生廣告(Native advanced)做 mediation 整合,關於 AdMob mediation 請參考:https://developers.google.com/admob/ios/mediate
串接準備
開始串接前請間確定已將 TAmedia SDK 整合至專案,並且完成初始化 SDK步驟,若您尚未完成請先參考開始使用教學完成相關設定。
確認已成功串接 AdMob 原生廣告,若還沒請參考 Google 教學AdMob原生廣告教學。新增自訂義事件請參考Google 說明。
最後,在專案中加入與 Custom Event 對應的 Class,其中 Custom Event 的 Class Name 需要和專案新增的 Class Name 保持一致,例如新增的 Class Name 為 TADCustomNative,Custom Event 的 Class Name 則必須是 專案名稱.TADCustomNative。(以 Swift 編寫的專案需加上專案名稱;若為以 OC編寫,則放入 Class Name)
整合方式
整合 AdMob 原生廣告需要兩個客製化 class,TADCustomNative 及 TADMediatedUnifiedNativeAd,可直接下載加入專案內或參考下方範例
TADCustomNative
AdMob 將透過這支程式來取得 TAmedia 廣告,其中關於 TADNativeAdOptions 及 TADMediaView 的客製化設定,可以自行參考教學文件進行設定,或保持預設值。
import Foundation
import GoogleMobileAds
import TAMediaAdsFramework
class TADCustomNative: NSObject, GADCustomEventNativeAd {
weak var delegate: GADCustomEventNativeAdDelegate?
private var nativeAd: TADNativeAd?
override required init() {
super.init()
}
deinit {
print("TADCustomNative deinit")
}
func request(withParameter serverParameter: String, request: GADCustomEventRequest, adTypes: [Any], options: [Any], rootViewController: UIViewController) {
loadTADNativeAd(adUnitId: serverParameter)
}
func handlesUserClicks() -> Bool {
return true
}
func handlesUserImpressions() -> Bool {
return true
}
}
extension TADCustomNative {
private func loadTADNativeAd(adUnitId: String) {
let request = TADRequest()
request.showLog = true
let option = TADNativeAdOptions()
///參見 http://wiki.tamedia.com.tw/iosDoc/Classes/TADNativeAdOptions.html
// option.disableImageLoading = true //SDK 將不自動下載圖片 TADMediatedUnifiedNativeAd 內需更改
// option.mediaPreferImage = false //只會呈現圖片廣告
// option.startUnmuted = true //影片廣告會以非靜音方式呈現
// option.customControlsRequested = true //
// option.allowAudioSessionControl = false //設為false則需自行設定影音廣告出現時 AVAudioSession 狀態
nativeAd = TADNativeAd(adUnitId: adUnitId)
nativeAd?.delegate = self
nativeAd?.load(request, withOption: option)
}
}
extension TADCustomNative: TADNativeAdDelegate {
func nativeAdDidReceive(_ ad: TADNativeAd!) {
let nativeAdView = TADNativeAdView()
let mediaView = TADNativeMediaView(frame: .zero)
mediaView.mediaContent = ad.adContent.mediaContent
///參見 http://wiki.tamedia.com.tw/iosDoc/Classes/TADNativeMediaView.html
// mediaView.setCallToActionVisible(false) //是否顯示 CTA 按鈕
// mediaView.setCallToActionTextSize(12) //設定 CTA 文字大小
// mediaView.setVolumeImageSize(24) //設定影音廣告靜音圖片大小
// mediaView.setVideoCountdownTextSize(17) //設定影音倒數文字大小
nativeAdView.addSubview(mediaView)
nativeAdView.mediaView = mediaView
let mapNativeAd = TADMediatedUnifiedNativeAd(tadNativeAd: ad, tadNativeAdView: nativeAdView)
delegate?.customEventNativeAd(self, didReceive: mapNativeAd)
}
func nativeAd(_ ad: TADNativeAd!, didFailToReceiveAdWithError error: TADRequestError!) {
delegate?.customEventNativeAd(self, didFailToLoadWithError: error)
}
}
TADMediatedUnifiedNativeAd
將取得的 TAmedia 廣告整合後透過 AdMob 提供的介面回傳給 AdMob
import Foundation
import GoogleMobileAds
import TAMediaAdsFramework
class TADMediatedUnifiedNativeAd: NSObject {
var tadNativeAd: TADNativeAd
var tadNativeAdView: TADNativeAdView
var mappedImages = [GADNativeAdImage]()
var mapIcon: GADNativeAdImage?
init(tadNativeAd: TADNativeAd, tadNativeAdView: TADNativeAdView) {
self.tadNativeAdView = tadNativeAdView
self.tadNativeAd = tadNativeAd
super.init()
self.tadNativeAd.delegate = self
self.tadNativeAdView.mediaView?.statusDelegate = self
guard let mediaContent = tadNativeAd.adContent.mediaContent else {
return
}
if let tadImage = mediaContent.image1200x627?.image {
let adImage = GADNativeAdImage(image: tadImage)
tadNativeAdView.mediaView?.setMainImage(image: tadImage)
mappedImages.append(adImage)
}
if let iconImage = tadNativeAd.adContent.iconSquare?.image {
mapIcon = GADNativeAdImage(image: iconImage)
}
}
deinit {
print("TADMediatedUnifiedNativeAd - TADMediatedUnifiedNativeAd deinit")
}
}
extension TADMediatedUnifiedNativeAd: TADNativeAdDelegate {
func nativeAdDidImpression(_ ad: TADNativeAd!) {
GADMediatedUnifiedNativeAdNotificationSource.mediatedNativeAdDidRecordImpression(self)
print("TADMediatedUnifiedNativeAd - nativeAdDidImpression")
}
func nativeAdDidClick(_ ad: TADNativeAd!) {
GADMediatedUnifiedNativeAdNotificationSource.mediatedNativeAdDidRecordClick(self)
print("TADMediatedUnifiedNativeAd - nativeAdDidClick")
}
}
extension TADMediatedUnifiedNativeAd: TADVideoStatusDelegate {
func didStartVideo() {
GADMediatedUnifiedNativeAdNotificationSource.mediatedNativeAdDidPlayVideo(self)
}
func didPlayVideo() {
GADMediatedUnifiedNativeAdNotificationSource.mediatedNativeAdDidPlayVideo(self)
}
func didPauseVideo() {
GADMediatedUnifiedNativeAdNotificationSource.mediatedNativeAdDidPauseVideo(self)
}
func didEndVideoPlayback() {
GADMediatedUnifiedNativeAdNotificationSource.mediatedNativeAdDidEndVideoPlayback(self)
}
func didMuteVideo() {}
func didUnmuteVideo() {}
}
extension TADMediatedUnifiedNativeAd: GADMediatedUnifiedNativeAd {
var headline: String? {
return tadNativeAd.adContent.longSubject
}
var images: [GADNativeAdImage]? {
return mappedImages
}
var body: String? {
return tadNativeAd.adContent.body
}
var icon: GADNativeAdImage? {
return mapIcon
}
var callToAction: String? {
return tadNativeAd.adContent.callToAction
}
var starRating: NSDecimalNumber? {
return nil
}
var store: String? {
return nil
}
var price: String? {
return nil
}
var advertiser: String? {
return nil
}
var extraAssets: [String: Any]? {
return nil
}
var mediaView: UIView? {
return tadNativeAdView.mediaView
}
var hasVideoContent: Bool {
guard let mediaContent = tadNativeAd.adContent.mediaContent else {
return false
}
return mediaContent.isVideoContent
}
func didRender(in view: UIView, clickableAssetViews: [GADNativeAssetIdentifier: UIView], nonclickableAssetViews: [GADNativeAssetIdentifier: UIView], viewController: UIViewController) {
view.subviews.first { $0 is TADNativeAdView }?.removeFromSuperview()
view.insertSubview(tadNativeAdView, at: 0)
fillSuperView(view: tadNativeAdView)
if let titleLabel = clickableAssetViews[GADNativeAssetIdentifier.headlineAsset] as? UILabel {
titleLabel.isUserInteractionEnabled = true
tadNativeAdView.longSubjectLabel = titleLabel
}
if let bodyLabel = clickableAssetViews[GADNativeAssetIdentifier.bodyAsset] as? UILabel {
bodyLabel.isUserInteractionEnabled = true
tadNativeAdView.bodyLabel = bodyLabel
}
if let ctaLabel = clickableAssetViews[GADNativeAssetIdentifier.callToActionAsset] {
ctaLabel.isUserInteractionEnabled = true
tadNativeAdView.callToActionView = ctaLabel
}
if let icon = clickableAssetViews[GADNativeAssetIdentifier.iconAsset] as? UIImageView {
icon.isUserInteractionEnabled = true
tadNativeAdView.squareImgeView = icon
}
if let mediaView = clickableAssetViews[GADNativeAssetIdentifier.mediaViewAsset], let tadMediaView = tadNativeAdView.mediaView {
mediaView.subviews.first { $0 is TADNativeMediaView }?.removeFromSuperview()
mediaView.addSubview(tadMediaView)
fillSuperView(view: tadMediaView)
}
tadNativeAdView.nativeAd = tadNativeAd
}
func didUntrackView(_ view: UIView?) {
print("TADMediatedUnifiedNativeAd - didUntrackView")
tadNativeAdView.removeFromSuperview()
tadNativeAdView.mediaView?.removeFromSuperview()
}
}
extension TADMediatedUnifiedNativeAd {
func fillSuperView(view: UIView) {
view.frame = view.superview?.bounds ?? .zero
}
}
已知問題
點擊及曝光的事件當 TAmedia 廣告觸發後並沒有觸發 GADNativeAdDelegate 內 nativeAdDidRecordClick 及 nativeAdDidRecordImpression,目前推測為 Google SDK 的問題,若需要做相關紀錄須在 TADMediatedUnifiedNativeAd 內自行加入。
extension TADMediatedUnifiedNativeAd: TADNativeAdDelegate {
func nativeAdDidImpression(_ ad: TADNativeAd!) {
GADMediatedUnifiedNativeAdNotificationSource.mediatedNativeAdDidRecordImpression(self)
print("TADMediatedUnifiedNativeAd - nativeAdDidImpression")
/// 若需要紀錄曝光事件請在此自行加入
}
func nativeAdDidClick(_ ad: TADNativeAd!) {
GADMediatedUnifiedNativeAdNotificationSource.mediatedNativeAdDidRecordClick(self)
print("TADMediatedUnifiedNativeAd - nativeAdDidClick")
/// 若需要紀錄點擊事件請在此自行加入
}
}