看板 KnucklesNote
作者 標題 [Xcode][Swift3] 加入 Facebook Audience Network 原生廣告
時間 2017-09-12 Tue. 04:34:29
在 FB 新增一個廣告版位
先到 FB 廣告的官方說明文件
https://developers.facebook.com/docs/audience-network
建議先看一下新手指南的 5 步驟設定指南
建立廣告版位
點「立即開始」後,新增或進入已有的企業管理平台
進入營利管理工具,選擇或建立一個資產
資產名稱就設定為 APP 的名稱即可,例如 Disp BBS
在資產中新增平台,這邊新增「iOS 應用程式」
每個平台中可以建立四個廣告空間,預設已經建立好一個了
修改一下廣告空間的名稱,例如修改為「iOS 熱門文章」
在廣告空間中新增版位,選擇新增「原生橫幅」
取得版位編號,後面在程式中會用到
在 Xcode 加入 Audience Network SDK
這邊使用 CocoaPods 來安裝
CocoaPods 的使用方法可參考 這篇
在 Podfile 加上 pod 'FBAudienceNetwork'
在專案目錄執行 pod install
因為 Audience Network SDK 是使用 Objective-C 寫的,
要在 Swift 專案中使用 Objective-C 的話,要加上 BridgingHeader
如果之前沒加過的話,點 command+n 新增檔案,選「Header File」
檔案名稱輸入「BridgingHeader」
在專案設定的「Build Settings」,選「All」,
在右邊的搜尋框輸入「bridging」,
在下面出現的 Objective-C Bridging Header 輸入「$(PROJECT_NAME)/BridgingHeader.h」
修改 BridgingHeader.h
在 #define ... 與 #endif 之間加上
#import <FBAudienceNetwork/FBAudienceNetwork.h>
在 TableViewController 中插入 FB 原生廣告範本
Audience Network 有提供專門給 TableViewController 使用的類別
FBNativeAdsManager 和 FBNativeAdTableViewCellProvider
可以很方便的在列表加上多個相同大小的廣告
例如我們要在熱門文章頁加上廣告,
所以要修改熱門文章頁的類別 HotTextViewController
先加上兩個成員變數
var fbAdsManager: FBNativeAdsManager!
var fbAdsCellProvider: FBNativeAdTableViewCellProvider!
var fbAdsCellProvider: FBNativeAdTableViewCellProvider!
新增用來初始化 fbAdsManager 的函數
func initAdsManager() {
if fbAdsManager == nil {
fbAdsManager = FBNativeAdsManager(placementID: "PLACEMENT_ID", forNumAdsRequested: 1)
fbAdsManager.delegate = self
fbAdsManager.loadAds()
}
}
在 PLACEMENT_ID 填入之前申請到的版位編號if fbAdsManager == nil {
fbAdsManager = FBNativeAdsManager(placementID: "PLACEMENT_ID", forNumAdsRequested: 1)
fbAdsManager.delegate = self
fbAdsManager.loadAds()
}
}
forNumAdsRequested 代表要載入幾個廣告,這邊我們只要一個就好
fbAdsManager.delegate = self 委託函數給目前的類別,這行現在會出現錯誤,因為還沒在類別加上協定
fbAdsManager.loadAds() 預先載入廣告
在 viewVillAppear() 中執行 initAdsManager()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// ...
initAdsManager()
}
super.viewWillAppear(animated)
// ...
initAdsManager()
}
在 class HotTextViewController: UITableViewController, 後面加上
兩個協定:FBNativeAdDelegate, FBNativeAdsManagerDelegate
class HotTextViewController: UITableViewController, FBNativeAdDelegate, FBNativeAdsManagerDelegate {
協定 FBNativeAdsManagerDelegate 會需要加上兩個 Delegate 函數: nativeAdsLoaded(), nativeAdsFailedToLoadWithError()
// MARK: - FBNativeAdsManagerDelegate
func nativeAdsLoaded() {
fbAdsCellProvider = FBNativeAdTableViewCellProvider(manager: fbAdsManager, for: FBNativeAdViewType.genericHeight100)
fbAdsCellProvider.delegate = self
tableView.reloadData()
}
func nativeAdsFailedToLoadWithError(_ error: Error) {
print(error)
}
func nativeAdsLoaded() {
fbAdsCellProvider = FBNativeAdTableViewCellProvider(manager: fbAdsManager, for: FBNativeAdViewType.genericHeight100)
fbAdsCellProvider.delegate = self
tableView.reloadData()
}
func nativeAdsFailedToLoadWithError(_ error: Error) {
print(error)
}
函數 nativeAdsLoaded() 用來確認廣告是否有載入了
使用 FBNativeAdViewType.genericHeight100 代表設定廣告高度為 100
有四個高度可以選擇:100, 120, 300 和 400 pt
使用 tableView.reloadData() 更新 tableView 的顯示資料
函數 nativeAdsFailedToLoadWithError() 用來在廣告載入失敗時顯示錯誤訊息
協定 FBNativeAdDelegate 的 Delegate 函數為選用的,
只要打開頭 nativeAd 就會列出可以用的函數,例如
func nativeAdDidClick(_ nativeAd: FBNativeAd) {
print("Ad tapped: \(nativeAd.title)")
}
可以在點擊廣告時,顯示廣告的標題print("Ad tapped: \(nativeAd.title)")
}
能夠載入廣告後,再來是調整 TableView 的顯示
先調整 TableView 會顯示幾個 Row
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let dataNum = 10 //原本熱門文章的筆數
if fbAdsCellProvider != nil {
return dataNum + 1
} else {
return dataNum
}
}
let dataNum = 10 //原本熱門文章的筆數
if fbAdsCellProvider != nil {
return dataNum + 1
} else {
return dataNum
}
}
設定 TableView 中每個 Row 要顯示的 Cell
例如要在第六列插入一個廣告
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if fbAdsCellProvider != nil && indexPath.row == 5) {
return fbAdsCellProvider.tableView(tableView, cellForRowAt: indexPath)
} else {
// 原本用來顯示熱門文章的程式
}
}
if fbAdsCellProvider != nil && indexPath.row == 5) {
return fbAdsCellProvider.tableView(tableView, cellForRowAt: indexPath)
} else {
// 原本用來顯示熱門文章的程式
}
}
執行看看,在第六列有出現廣告了
修改廣告的樣式
修改 Delegate 函數 nativeAdsLoaded()
將 fbAdsCellProvider = FBNativeAdTableViewCellProvider(manager: fbAdsManager, for: FBNativeAdViewType.genericHeight100)
改為多傳入一個 attributes 變數,例如
let attributes = FBNativeAdViewAttributes()
attributes.backgroundColor = UIColor.black
attributes.titleColor = UIColor(red: 0x39/255.0, green: 0x91/255.0, blue: 0xFF/255.0, alpha: 1)
attributes.descriptionColor = UIColor.white
attributes.buttonColor = UIColor(red: 0x09/255.0, green: 0x50/255.0, blue: 0xD0/255.0, alpha: 1)
attributes.buttonTitleColor = UIColor.white
fbAdsCellProvider = FBNativeAdTableViewCellProvider(manager: fbAdsManager, for: FBNativeAdViewType.genericHeight100, for: attributes)
就可以修改背景色、標題和說明文字的顏色、按鈕的背景色和文字顏色attributes.backgroundColor = UIColor.black
attributes.titleColor = UIColor(red: 0x39/255.0, green: 0x91/255.0, blue: 0xFF/255.0, alpha: 1)
attributes.descriptionColor = UIColor.white
attributes.buttonColor = UIColor(red: 0x09/255.0, green: 0x50/255.0, blue: 0xD0/255.0, alpha: 1)
attributes.buttonTitleColor = UIColor.white
fbAdsCellProvider = FBNativeAdTableViewCellProvider(manager: fbAdsManager, for: FBNativeAdViewType.genericHeight100, for: attributes)
執行結果像這樣
在實機上使用測試廣告
如果不是用模擬器,而是將App裝到實體裝置上的話
必需要加上測試廣告的設定
在載入廣告前加上以下程式碼
例如前面的例子是加在函數 initAdsManager() 最前面
FBAdSettings.setLogLevel(FBAdLogLevel.log)
FBAdSettings.addTestDevice("HASHED_ID")
FBAdSettings.addTestDevice("HASHED_ID")
在實機執行後,在 Console 視窗找到以下訊息
When testing your app with Facebook ad units,
you must specify the device hashed ID to ensure the delivery of test ads,
add the following code before loading an ad:
Test mode device hash: bd675f960298a92003630d76fa612b1706b745ab
將上方顯示的 device hash 填入程式中的 "HASHED_ID"you must specify the device hashed ID to ensure the delivery of test ads,
add the following code before loading an ad:
[FBAdSettings addTestDevice:@"HASHED_ID"]
Test mode device hash: bd675f960298a92003630d76fa612b1706b745ab
在重新執行一次,就會出現測試廣告了
之後如果不想要 Console 出現一大堆 FB 廣告的 log 記錄
可以將 setLogLevel(FBAdLogLevel.log) 改為
// 不要顯示 FB 廣告的 log 記錄
FBAdSettings.setLogLevel(FBAdLogLevel.none)
// 或是只顯示錯訊訊息
FBAdSettings.setLogLevel(FBAdLogLevel.error)
FBAdSettings.setLogLevel(FBAdLogLevel.none)
// 或是只顯示錯訊訊息
FBAdSettings.setLogLevel(FBAdLogLevel.error)
想要取消實機為測試裝置的話,將 addTestDevice() 改為
FBAdSettings.clearTestDevice("HASHED_ID")
將 "HASHED_ID" 改為之前取得的 device hash使用完全客制化的原生廣告
如果不想使用FB的原生廣告範本,要自己拉所有元件的話
先按 command+n 新增一個 TableViewCell 的類別
Class: NativeAdsCell
Subclass of: UITableViewCell
修改新增的檔案 NativeAdsCell.swift
加入這些成員變數
@IBOutlet weak var adContainerView: UIView!
@IBOutlet weak var adTitle: UILabel!
@IBOutlet weak var adBody: UILabel!
@IBOutlet weak var adIconImage: FBAdIconView!
@IBOutlet weak var adActionBtn: FBAdChoicesView!
@IBOutlet weak var adSocialContext: UILabel!
@IBOutlet weak var adCoverMediaView: FBMediaView!
@IBOutlet weak var adTitle: UILabel!
@IBOutlet weak var adBody: UILabel!
@IBOutlet weak var adIconImage: FBAdIconView!
@IBOutlet weak var adActionBtn: FBAdChoicesView!
@IBOutlet weak var adSocialContext: UILabel!
@IBOutlet weak var adCoverMediaView: FBMediaView!
修改 Storyboard
在 TableView 增加一個 Prototype Cell
將 Identifier 設為「FBNativeAdsCell」
Custome Class 設為「NativeAdsCell」
先拉一個與 Cell 相同大小的 adContainerView (UIView)
然後將其他廣告元件拉到這個新增的 adContainerView
再將 Cell 的 Outlet 連結到這些元件
像這樣:
其中 adSocialContext 與 adCoverMediaView 因為沒位子放了所以略過不放
在 adContainerView 的屬性檢視器將「Hidden」打勾
修改 HotTextViewController.swift
在 class 後面加上協定 FBNativeAdDelegate,例如
class HotTextViewController: UITableViewController, FBNativeAdDelegate {
新增成員變數
var fbNativeAd: FBNativeAd!
新增自訂的成員函數 loadFBNativeAd()
func loadFBNativeAd() {
fbNativeAd = FBNativeAd(placementId: "YOUR_PLACEMENT_ID")
fbNativeAd.delegate = self
fbNativeAd.loadAd()
將 YOUR_PLACEMENT_ID 改為之前申請的版位編號fbNativeAd = FBNativeAd(placementId: "YOUR_PLACEMENT_ID")
fbNativeAd.delegate = self
fbNativeAd.loadAd()
在 viewDidLoad() 中執行 loadFBNativeAd()
override func viewDidLoad() {
// ...
loadFBNativeAd()
}
// ...
loadFBNativeAd()
}
新增 FBNativeAdDelegate 的兩個 Delegate 函數
// MARK: - FBNativeAdDelegate
func nativeAdDidLoad(_ nativeAd: FBNativeAd) {
if self.fbNativeAd != nil {
self.fbNativeAd.unregisterView()
}
self.fbNativeAd = nativeAd
self.tableView.reloadData()
}
func nativeAd(_ nativeAd: FBNativeAd, didFailWithError error: Error) {
print(error)
}
廣告載入後會執行 nativeAdDidLoad()func nativeAdDidLoad(_ nativeAd: FBNativeAd) {
if self.fbNativeAd != nil {
self.fbNativeAd.unregisterView()
}
self.fbNativeAd = nativeAd
self.tableView.reloadData()
}
func nativeAd(_ nativeAd: FBNativeAd, didFailWithError error: Error) {
print(error)
}
將取得的廣告內容存入成員變數 fbNativeAd
然後重載 tableView 的顯示內容
修改顯示 cell 內容的函數 tableView(_:cellForrowAt:)
例如要在第6列顯示一個原生廣告的話,在前面加上
if indexPath.row == 5 { // 執行自訂的成員函數 getFBAdsCell()
return getFBAdsCell(cellForRowAt: indexPath)
}
return getFBAdsCell(cellForRowAt: indexPath)
}
新增一個成員函數 getFBAdsCell()
func getFBAdsCell(cellForRowAt indexPath: IndexPath) -> NativeAdsCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FBNativeAdsCell", for: indexPath) as! NativeAdsCell
if let nativeAd = self.fbNativeAd {
// 設定廣告標題
cell.adTitle.text = nativeAd.advertiserName
// 設定廣告文本(如果有的話).
if let body = nativeAd.bodyText {
cell.adBody?.text = body
}
// 設定 call-to-action 按鈕的標題
cell.adActionBtn.setTitle(nativeAd.callToAction, for: UIControlState.normal)
// 載入並顯示廣告圖片
nativeAd.icon?.loadAsync(block: { (iconImage) in
if let image = iconImage {
cell.adIconImage.image = image
}
})
// 設定 social context 字串 (如果有的話)
if let socialContext = nativeAd.socialContext {
cell.adSocialContext?.text = socialContext
}
// 載入媒體圖片 (如果有的話)
if let adCoverMediaView = cell.adCoverMediaView {
let coverMediaView = FBMediaView(frame: adCoverMediaView.frame)
coverMediaView.nativeAd = nativeAd
coverMediaView.clipsToBounds = true
cell.adContainerView.addSubview(coverMediaView)
}
// 設定 AdChoices view
let adChoicesView = FBAdChoicesView(nativeAd: nativeAd)
cell.adContainerView.addSubview(adChoicesView)
// 加上四個 Constraints,大小20x20 固定在右上角
cell.adContainerView.addConstraint(NSLayoutConstraint(item: adChoicesView, attribute: .top, relatedBy: .equal, toItem: cell.adContainerView, attribute: .top, multiplier: 1, constant: 0))
cell.adContainerView.addConstraint(NSLayoutConstraint(item: adChoicesView, attribute: .trailing, relatedBy: .equal, toItem: cell.adContainerView, attribute: .trailing, multiplier: 1, constant: 0))
cell.adContainerView.addConstraint(NSLayoutConstraint(item: adChoicesView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 20))
cell.adContainerView.addConstraint(NSLayoutConstraint(item: adChoicesView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 20))
adChoicesView.updateFrameFromSuperview()
// 設定整個廣告的 container view 能夠被點擊。
nativeAd.registerView(forInteraction: cell.adContainerView, with: self)
cell.adContainerView.isHidden = false
}
return cell
}
其中 adChoicesView 必需使用程式建立,然後用程式加上 Constraints 才行let cell = tableView.dequeueReusableCell(withIdentifier: "FBNativeAdsCell", for: indexPath) as! NativeAdsCell
if let nativeAd = self.fbNativeAd {
// 設定廣告標題
cell.adTitle.text = nativeAd.advertiserName
// 設定廣告文本(如果有的話).
if let body = nativeAd.bodyText {
cell.adBody?.text = body
}
// 設定 call-to-action 按鈕的標題
cell.adActionBtn.setTitle(nativeAd.callToAction, for: UIControlState.normal)
// 載入並顯示廣告圖片
nativeAd.icon?.loadAsync(block: { (iconImage) in
if let image = iconImage {
cell.adIconImage.image = image
}
})
// 設定 social context 字串 (如果有的話)
if let socialContext = nativeAd.socialContext {
cell.adSocialContext?.text = socialContext
}
// 載入媒體圖片 (如果有的話)
if let adCoverMediaView = cell.adCoverMediaView {
let coverMediaView = FBMediaView(frame: adCoverMediaView.frame)
coverMediaView.nativeAd = nativeAd
coverMediaView.clipsToBounds = true
cell.adContainerView.addSubview(coverMediaView)
}
// 設定 AdChoices view
let adChoicesView = FBAdChoicesView(nativeAd: nativeAd)
cell.adContainerView.addSubview(adChoicesView)
// 加上四個 Constraints,大小20x20 固定在右上角
cell.adContainerView.addConstraint(NSLayoutConstraint(item: adChoicesView, attribute: .top, relatedBy: .equal, toItem: cell.adContainerView, attribute: .top, multiplier: 1, constant: 0))
cell.adContainerView.addConstraint(NSLayoutConstraint(item: adChoicesView, attribute: .trailing, relatedBy: .equal, toItem: cell.adContainerView, attribute: .trailing, multiplier: 1, constant: 0))
cell.adContainerView.addConstraint(NSLayoutConstraint(item: adChoicesView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 20))
cell.adContainerView.addConstraint(NSLayoutConstraint(item: adChoicesView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 20))
adChoicesView.updateFrameFromSuperview()
// 設定整個廣告的 container view 能夠被點擊。
nativeAd.registerView(forInteraction: cell.adContainerView, with: self)
cell.adContainerView.isHidden = false
}
return cell
}
不能在 storyboard 中建立,不然使用 Constraints 固定在右上角後會無法顯示
執行結果
使用 FBMediaView
FBMediaView 可顯示大型圖片、可水平捲動的多張圖片、或是影片
要使用 FBMediaView 的話,先在 storyboard 的 prototype cell 拉一個比較大的版位
像這樣:
FBMediaView 也是要用程式產生才行
中間用 UIView 拉的一大塊 adCoverMediaView 是用產生定位的 frame
圖片的高度需要 200pt,超過的話上下會被裁掉,
或是之後再用程式將圖片縮小
修改之前加上的自定函數 getFBAdsCell()
將 if let adCoverMediaView = cell.adCoverMediaView { … }
這段的內容改為
// 載入媒體圖片 (如果有的話)
if let adCoverMediaView = cell.adCoverMediaView {
let coverMediaView = FBMediaView(frame: adCoverMediaView.frame)
coverMediaView.nativeAd = nativeAd
coverMediaView.clipsToBounds = true
coverMediaView.delegate = self
cell.adContainerView.addSubview(coverMediaView)
}
加上了一行 coverMediaView.delegate = selfif let adCoverMediaView = cell.adCoverMediaView {
let coverMediaView = FBMediaView(frame: adCoverMediaView.frame)
coverMediaView.nativeAd = nativeAd
coverMediaView.clipsToBounds = true
coverMediaView.delegate = self
cell.adContainerView.addSubview(coverMediaView)
}
為了要在載入 FBMediaView 後執行 delegate 函數
在 class 後面加上協定 FBMediaViewDelegate,例如
class HotTextViewController: UITableViewController, FBNativeAdDelegate, FBMediaViewDelegate {
加上 delegate 函數
// MARK: - FBMediaViewDelegate
func mediaViewDidLoad(_ mediaView: FBMediaView) {
mediaView.frame.size.width = tableView.frame.size.width
}
要在這邊將取得的 mediaView 設為跟 tableView 的寬度相同func mediaViewDidLoad(_ mediaView: FBMediaView) {
mediaView.frame.size.width = tableView.frame.size.width
}
沒辦法使用 Constraints 自動調整寬度
如果版面配置沒辦法使用到 200pt 高的話
也可以在這邊將高度縮小
執行結果
更新廣告內容
例如想在點擊重整頁面按鈕時,更換顯示的廣告內容
可以在執行重整的函數(例如 refresh())中加上
func refresh() {
// ...
if fbNativeAd != nil {
fbNativeAd.unregisterView()
}
loadFBNativeAd()
}
// ...
if fbNativeAd != nil {
fbNativeAd.unregisterView()
}
loadFBNativeAd()
}
參考
AppCoda 如何在 iOS App 中整合 Facebook 廣告
--
※ 作者: Knuckles 時間: 2017-09-12 04:34:29
※ 編輯: Knuckles 時間: 2018-09-12 02:06:50
※ 看板: KnucklesNote 文章推薦值: 0 目前人氣: 0 累積人氣: 738
回列表(←)
分享