顯示廣告
隱藏 ✕
看板 KnucklesNote
作者 Knuckles (站長 那克斯)
標題 [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!


新增用來初始化 fbAdsManager 的函數
    func initAdsManager() {
        if fbAdsManager == nil {
            fbAdsManager = FBNativeAdsManager(placementID: "PLACEMENT_ID", forNumAdsRequested: 1)
            fbAdsManager.delegate = self
            fbAdsManager.loadAds()
        }
    }
在 PLACEMENT_ID 填入之前申請到的版位編號
forNumAdsRequested 代表要載入幾個廣告,這邊我們只要一個就好
fbAdsManager.delegate = self 委託函數給目前的類別,這行現在會出現錯誤,因為還沒在類別加上協定
fbAdsManager.loadAds() 預先載入廣告


在 viewVillAppear() 中執行 initAdsManager()
    override func viewWillAppear(_ animated: Bool) {
        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)
    }

函數 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)")
    }
可以在點擊廣告時,顯示廣告的標題


能夠載入廣告後,再來是調整 TableView 的顯示

先調整 TableView 會顯示幾個 Row
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        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 {
            // 原本用來顯示熱門文章的程式
        }
    }


執行看看,在第六列有出現廣告了
[圖]



修改廣告的樣式

修改 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)
就可以修改背景色、標題和說明文字的顏色、按鈕的背景色和文字顏色

執行結果像這樣
[圖]



在實機上使用測試廣告

如果不是用模擬器,而是將App裝到實體裝置上的話
必需要加上測試廣告的設定

在載入廣告前加上以下程式碼
例如前面的例子是加在函數 initAdsManager() 最前面
        FBAdSettings.setLogLevel(FBAdLogLevel.log)
        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: [FBAdSettings addTestDevice:@"HASHED_ID"]
Test mode device hash: bd675f960298a92003630d76fa612b1706b745ab
將上方顯示的 device hash 填入程式中的 "HASHED_ID"

在重新執行一次,就會出現測試廣告了


之後如果不想要 Console 出現一大堆 FB 廣告的 log 記錄
可以將 setLogLevel(FBAdLogLevel.log) 改為
        // 不要顯示 FB 廣告的 log 記錄
        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!


修改 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 改為之前申請的版位編號

在 viewDidLoad() 中執行 loadFBNativeAd()
    override func viewDidLoad() {
        // ...

        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()
將取得的廣告內容存入成員變數 fbNativeAd
然後重載 tableView 的顯示內容


修改顯示 cell 內容的函數 tableView(_:cellForrowAt:)
例如要在第6列顯示一個原生廣告的話,在前面加上
        if indexPath.row == 5 { // 執行自訂的成員函數 getFBAdsCell()
            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 才行
不能在 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 = self
為了要在載入 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 的寬度相同
沒辦法使用 Constraints 自動調整寬度

如果版面配置沒辦法使用到 200pt 高的話
也可以在這邊將高度縮小


執行結果
[圖]

[圖]



更新廣告內容

例如想在點擊重整頁面按鈕時,更換顯示的廣告內容
可以在執行重整的函數(例如 refresh())中加上
    func refresh() {
        // ...

        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 累積人氣: 735 
分享網址: 複製 已複製
r)回覆 e)編輯 d)刪除 M)收藏 ^x)轉錄 同主題: =)首篇 [)上篇 ])下篇