Swift 程式語言

如何在 iOS App 中整合 Facebook 廣告

如何在 iOS App 中整合 Facebook 廣告
如何在 iOS App 中整合 Facebook 廣告
In: Swift 程式語言

不久前有人問我如何在項目中整合 Facebook 廣告。因為之前沒用過,原以為這需要經過一個漫長、痛苦的準備過程,所以看過一堆文檔之後。在很快就看完了這些文檔之後,卻發現並不是想象中的那樣,僅僅幾分鐘我就搞定了我的第一個 Facebook 廣告 App!

想為你的app加入廣告?Facebook 廣告是一種方法讓你輕易將廣告嵌入到你的 app 中,使你可以通過廣告的點擊量來獲得收入。整合過程並不複雜,在 Facebook SDK (一個 Facebook 推出的 SDK 框架)中,有一個框架是和廣告相關的,那就是 Audience Network 框架。 你只需在 app 中使用這個框架就行了。

Facebook 為不同的平台提供了不同的廣告類型,但對於移動設備來說只有 3 種類型:Native, InterstitialBanners。下面簡單介紹一下這 3 種類型:

  • Native 廣告能放置在 app 的任何地方,它們能被重新定制,從外觀上看它們與視圖上的其它 UI 毫無區別。這些視圖可以來自於手動創建的 view (通過自定義控件展現廣告內容),也可以來自於 Audience Network 框架中的模板──但它們的某些屬性可以被定制。有一點特別的地方是,如果要在 table view 中顯示這些廣告,你只有兩種辦法:要麼使用自定義 view(也就是自定義 cell)顯示廣告,然後手動處理所有相關的 table view 回調,要麼使用 Audience Network 框架(誠摯感謝)提供的類,然後(幾乎)不用你處理 table view 的回調。唯一的缺點是用這種方式你無法自定義廣告的外觀,當然在某些情況下這也不是什麼問題。
  • Interstitial(插頁式)廣告是全屏廣告,如你所料,它們一旦顯示就會將 app 整個遮住。因此,這類廣告的外觀根本不需要任何定制。
  • Banner(橫幅)廣告是小幅面廣告,經常顯示在屏幕的頂部或底部,它們除高度外都不能被定制。

我們會在本文中介紹這 3 種廣告,此外還會演示如何在 Facebook Developers Portal 中進行必要的設置。也就是說,我會指引你配置 app 的廣告顯示能力以及其它(廣告內容、佈局信息等等)。給你一個永遠正確的老忠告:看文檔去(即「去讀該死的手冊」)。

你也許會問:「既然將 Facebook 廣告整合到 app 中很容易,那還寫什麼教程?」主要是出於兩個目的:第一,網上基本沒有能讓人一目了然的教程,我覺得有必要寫一個讓人立馬就明白怎樣在 app 中集成廣告的快捷指南,以節省大家的時間。第二,Facebook 文檔中的所有示例程式碼都是 Objective-C 的,對於只會 Swift 的新人來說,將 Objective-C 的示例程式碼翻譯成 Swift 會是一個不小的挑戰。

最後,需要說明的是,後面演示的範例專案(你可以下載它)都是用 Xcode 7.3.1 和 Swift 2.2 編寫的。這兩者都目前有效的正式版本,請不要在 Swift 3.0 中打開和運行它。

關於範例 App

能讓我們學習和研究的編程文章,毫無例外都會要求你親自動手做。本教程也不例外,它也會有一個 demo app。為了將注意力集中在將 Facebook 廣告集成到 app 中,這個 app 被設計得很簡單。你可以從這裡下載開始專案,通過它我們會一步一步完成最終的 app。

Facebook Ad Integration Demo

這個 app 是一個 tab bar app,包含了 4 個 tab,每個 tab 顯示一種廣告類型:

  • 第一個 tab 包含的 view controller 是`SingleAdsViewController`,這是 native 類型的廣告。注意,我們不僅會演示自定義 view 的 native 廣告,還會演示「模板化」的 native 廣告,我們通過覆蓋它的屬性(而不是自定義 view)來進行定制。
  • 第二個 tab 包含的 view controller 是 `TableViewAdsViewController`。它使用了 table view 來顯示廣告,只不過這次我們會使用到 Audience Network 框架提供的工具。如果你下載並運行開始專案,你會在 table view 中看到一些示範數據。我們的目的是在那些顯示示範數據的行之間插入廣告。
  • 第三個 tab 包含的 view controller 叫做 `FullScreenAdsViewController`。當我們點擊按鈕時它會顯示一個全屏廣告。
  • 最後一個 view controller 是 `BannerAdsViewController` 。你猜得不錯,它會顯示橫幅廣告。

下面的截圖顯示了我們的最終效果:

Native 廣告──使用自定義 view:

Facebook iOS Native Ads

在 table view 中顯示 Native 廣告:

Facebook Tableview Ads

全屏廣告:

Facebook Full Screen Ads

橫幅廣告:

Facebook iOS Banner Ads

接下來我們提到的內容在大部分情況下都適用。如果你想對某些方面進行更細緻的調整,你應當仔細閱讀官方文檔──這會讓你對這個主題有更深刻的理解!

準備工作

首先我們要介紹的是 Facebook Developers Portal,因為我們必須在這裡進行一些操作,並獲取一些重要數據。簡單說,你需要新建一個 Facebook app 並進行一些配置,最終獲得幾個 ID,要在你的 app 中顯示廣告,你必須用到這些 ID。

讓我們詳細說明。首先,用任何一個瀏覽器登錄你的 Facebook 賬號(你肯定有的吧?)。進入 這個地址 並點擊綠色的 Start Now 按鈕。你會看到彈出一個窗口,在這個窗口中你需要:

  1. 輸入 app 的名字。
  2. 選擇目標平台為 iOS。
  3. 在輸入 app 名字時,點擊 Link to Facebook。這會創建一條新記錄,並添加在 Facebook Developer portal 的 My Apps 中。這一步至關重要,千萬不要遺漏。

Facebook Ads Sign up

然後,form 中會多出兩欄:一欄要你填入一個 email 地址作為你的電子郵箱,第二欄要你選擇一個和該 app 相符的類型。

t55_7_sign_up_additional

填完這些信息后,點擊 Sign Up 按鈕。通過安全檢查后進入下一步。如果沒有任何錯誤,你將看到一個設置界面,即 Audience Network 產品的 Placements 設置。這是一個關鍵的地方,這裡會創建 placement ID,這個 ID 將用於在 app 中顯示廣告。一個 placement 表示一個廣告在 app 中的位置,Facebook 通過創建這些 placement 來搜集用戶的點擊,並用於對廣告的顯示提供建議和優化。

向下滾動頁面,你會看到已經有一個 placement 自動創建了。在我們的 demo app 中,需要 4 個 placement ID,因此還需要創建其它的。你只需要點擊 Create Ad Placement 按鈕,然後在新彈出窗口中輸入信息。

demo 中的第一個廣告是一個 native 廣告,我們會用一個按鈕來加載和顯示這個廣告。這個新 placement 的詳細配置如下:

Facebook Ad Placement

配置完成后,請點擊 Save 按鈕,新建的 placement 會在設置頁面列出。第二個廣告實際上是在第二個 tab 的 view controller 的 table view 中顯示的一系列 native 廣告,因此第二個 placement 的詳細設置如下:

t55_9_ad_placement_2

第三個廣告是一個全屏廣告。

t55_10_ad_placement_3

我把第四個廣告的 placement ID 的配置留給你練習。對於這個 placement,你可以在自動添加的基礎上加以編輯,也可以創建一個新的。記住,橫幅廣告也可以在某個按鈕被點擊時顯示。

注意,每個新的 placement 添加到設置頁面后,都會被分配給一個 Placement ID 值,我們將在後面用到這個 ID。

t55_11_placement_id

另外,如果你點擊 Get Code 按鈕,你會立即看到關於使用這個廣告和 placement ID 的示例程式碼。遺憾的是:它們是 Objective-C 的,因此你需要自行轉換成 Swift 的。不用擔心,這會在後續步驟進行講解。

重要事項

繼續後面的內容之前,有一件事情是你必須知道的。根據文檔描述,只允許以兩種方式在 app 中運行 測試廣告

  1. 在模擬器中運行 app。
  2. 如果通過 Xcode 調試真機上的 app,則需要遵循如下步驟(摘自 Facebook 官方文檔):

要在設備上開啟測試廣告功能,要在加載廣告之前加入一行程式碼: [FBAdSettings addTestDevice:@”HASHED ID”]; 。這個 hashed ID 會在第一次在設備上請求加載廣告時打印到控制台中。

換句話說,當你在設備上運行 app 時,會分配一個 hashed ID 給指定設備(通過控制台中輸出)。你通過這個 ID 表示你想測試這台設備上的廣告。

除此之外,你的 app 從 Facebook 請求到的將是「真正的廣告」,在 Facebook 審查團隊審查 app 之前你不會看到廣告。審查會在你將 app 發佈到公網(比如 App Store 或者某個企業商店)之後開始,因為這時審查團隊才能夠下載你的 app。如果 app 通過審查,你的 app 就會播放真正的廣告,否則廣告不會顯示。

因此,需要你將 app 的 URL 輸入到文本框,以便審查團隊下載 app,這個文本框會顯示在 Facebook Developers portal 的 Placement 設置頁頂端(你可能已經看到它了)。在這個地方輸入 app 的下載地址(如果你已經有這個 URL 的話), 然後等候評審(幾天)。然後不時來 portal 看一下 app 的 Alerts 區域,評審結果會在這裡顯示。

App 的設置

做完 Facebook 的設置之後,下載開始專案,我們還需要在專案中進行一些設置。首先是加入 Facebook Audience Network 框架,有兩種加入方式:

  1. 使用 Cocoapods
  2. 下載 Facebook iOS SDK 並手動將框架加入到專案中

這篇文檔Set Up the SDK 一節,兩種方式都進行了介紹。對我來說,我寧可從這裡自己下載 SDK,然後將 Facebook Audience Network 框架直接拖進Xcode中。

當你以兩種方式中的任何一種將框架加到專案中以後,你必須添加另外三個依賴框架。在專案導航器中,點擊專案的名稱,然後在 General 窗口中找到 Linked Frameworks and Libraries 一節。點擊 + (加號) 按鈕三遍,依次添加這三個框架:

  1. StoreKit
  2. CoreMotion
  3. AdSupport

t55_12_frameworks

如我所說,Facebook SDK 是使用 Objective-C 編寫的,因此我們要使用一個 bridging header 文件去導入這個庫,這樣才能在 Swift 代碼中使用它。這個過程非常簡單,操作步驟如下:

  • 在 Xcode 中,點擊菜單 File > New > File…
  • 在文件模板窗口,選擇 iOS 下面的 Source
  • 選擇 header file 模板。
  • 將文件命名為 AdsTutorial-Bridging-Header.h 並保存。

t55_13_bridging_header_template

然後你會在專案導航器中看到新創建的這個文件,選中它,將下列內容粘貼進文件中:

#import 

接下來,再次在專案導航器中選中專案名稱,點擊 Build Settings tab,確保顯示的是 All 設置,然後在右邊搜索欄中搜索 Bridging Header 字串。雙擊搜索結果的內容區域(即 Objective-C Bridging Header 文字的右邊),輸入或者粘貼進如下內容:

AdsTutorial/AdsTutorial-Bridging-Header.h

t55_14_build_settings

回車,設置完畢。專案的設置就到這裡結束了,接下來開始實現。

顯示 Native 廣告

我也說過了,native 廣告的外觀可以被完全定制化,甚至可以和 app 中的其他 UI 變得一模一樣。有兩種方法可以做到這點。第一種方法是手動創建所有的 view 和 subview 然後顯示廣告內容。第二種方法是使用標準模板,然後覆蓋某些屬性(比如顏色和字體),這種方法不需要手動創建 view。我們兩種方法都會介紹,這一節先介紹第一種方法。無論是哪種方法,我們在 app 不會顯示其它無關的內容,以使問題簡化。

當你在 Interface Builder(即點擊 Main.storyboard 文件),你會看到一顆按鈕,我們會用它來加載廣告;以及一個 view(上面有幾個 subview ),我們將用它顯示我們請求到的廣告的內容。這些控件都已經和 SingleAdsViewController 類中的 IBOutlet 屬性建好了連接。讓我們一一列數一下:

  • viewAdContainer: 一個容器,包含了用於顯示廣告內容的其他 subview。在 app 一啟動時,這個 view 是隱藏的,因為廣告還沒有加載進來。
  • lblAdTitle: 一個 label,用於顯示廣告標題。
  • lblAdBody: 一個 label,用於顯示廣告的主體文字。
  • imgAdIcon: 一個 image view,用於顯示廣告圖標。
  • btnAdAction: 一個 call-to-action 按鈕,當它被點擊時,會打開廣告詳情(全屏方式)。另外,容器 view 也可以觸發全屏廣告的顯示。我兩者都會使用。
  • lblSocialContext: 一個 label,用於顯示類似於 “Available on the App Store” 的消息。

在請求廣告時,需要注意一件事情,廣告的基本字段總是有值的(比如 title 和 icon),但其它字段則有可能為空(nil),為了避免意外閃退,你必須對這種情況進行處理。正如稍後你會看到的。

現在,開始進入編碼。首先,在所有 IBOutlet 屬性聲明之後添加兩個屬性:

var nativeAd: FBNativeAd!

var coverMediaView: FBMediaView!

nativeAd 對象代表 app 中的 native 廣告,在我們的實現過程中我們會使用得非常多。你可以在 這裡 找到 FBNativeAd 類的所有細節。coverMediaView 是一種特殊的 view( UIView 對象),能夠顯示廣告中包含的各種媒體、圖片或視頻。它只能由程序員手動創建,无法在 Single Ads View Controller 場景(Interface Builder)中以可视化控件的方式使用它。 如果你想進一步了解 FBMediaView,可以閱讀 這裡

首先用到的是 nativeAd 對象,用它來嘗試下載一個廣告(也就是請求一個廣告)。這個動作會在 Load Ad 按鈕被點擊時發生,因此我們需要在 loadNativeAd(_:) IBAction 方法中編寫程式碼。這個方法在這個按鈕被點擊時觸發。這是該方法的實現:

@IBAction func loadNativeAd(sender: AnyObject) {
    nativeAd = FBNativeAd(placementID: "PLACEMENT_ID")
    nativeAd.delegate = self
    nativeAd.loadAd()
}

通常,我們先使用第一行程式碼去實例化 nativeAd 對象。在運行 app 之前,你應當將 “PLACEMENT_ID” 字符串替換成你自己的 Placement ID,這個 ID 是你先前所創建的。你可以從 Audience Network 設置頁面中複製該 native 廣告的 placement ID,並將它粘貼到這裡。然後,將 nativeAd 的委託設置為 self,以便我們下一步進行處理。最後,調用 loadAd() 方法請求並獲取一個廣告。

另外,你可以進一步指定 nativeAd 的「緩存選項」。這樣 Audience Network Framework 會事先緩存廣告中使用的圖片和視頻。例如,當你想讓視頻在被加載之後立即播放,你可以在加載廣告之前設置緩存選項為:

nativeAd.mediaCachePolicy = FBNativeAdsCachePolicy.Video

默認不使用預緩存機制。要查看所有可用的緩存選項列表,請閱讀 這裡

接下來我們應當採用 FBNativeAdDelegate 協議。先前我們已經將 SingleAdsViewController 類設置為 nativeAd 的委託屬性,但我們還沒有讓我們的類採用這個協議。找到類的第一行,將其修改為:

class SingleAdsViewController: UIViewController, FBNativeAdDelegate {
   ...
}

FBNativeAdDelegate 協議中包含的方法很少。但是,其中有兩個方法是必須實現是,因為它們是唯一可以讓我們知道廣告加載是否成功或失敗的方法,剩下的方法都是可選的,實現不實現隨便你了。這兩個方法分別實現如下:

func nativeAdDidLoad(nativeAd: FBNativeAd) {
    handleLoadedNativeAdUsingCustomViews()
}


func nativeAd(nativeAd: FBNativeAd, didFailWithError error: NSError) {
    print(error)
}

你可以在這裡實現更好的錯誤處理,這裡我只是簡單打印錯誤而已。主要是 nativeAdDidLoad(_:) 委託方法,正如其名,它可以讓我們指定當廣告加載成功后的處理。在此我必須說明一點,我們將在下一部分(也就是視圖模板的使用)也會使用相同的委託方法,當然在廣告加載后的處理是截然不同的。因此,我會根據不同情況調用不同的自定義方法進行處理,在本文中這會讓事情變得簡單。

handleLoadedNativeAdUsingCustomViews() 方法,我們會將廣告數據賦給不同的 view,並確保數據有確定的值。我們先來看一下實現的第一步,後續還會在此基礎上不斷添加。為便於理解,程式碼中添加了註解:

func handleLoadedNativeAdUsingCustomViews() {
    // 設置廣告標題
    lblAdTitle.text = nativeAd.title

    // 設置廣告文本(如果有的話).
    if let body = nativeAd.body {
        lblAdBody.text = body
    }

    // 設置 call-to-action 按鈕的標題
    btnAdAction.setTitle(nativeAd.callToAction, forState: UIControlState.Normal)

    // 加載並顯示廣告圖片
    nativeAd.icon?.loadImageAsyncWithBlock({ (iconImage) in
        if let image = iconImage {
            self.imgAdIcon.image = image
        }
    })

    // 創建一個頂層的媒體 view,將 nativeAd 賦給它(它會根據廣告內容顯示圖片或視頻)

    let yPoint = lblAdBody.frame.origin.y + lblAdBody.frame.size.height + 8.0
    let coverMediaViewFrame = CGRectMake(lblAdBody.frame.origin.x, yPoint, lblAdBody.frame.size.width, lblSocialContext.frame.origin.y - yPoint - 8.0)
    let coverMediaView = FBMediaView(frame: coverMediaViewFrame)
    coverMediaView.clipsToBounds = true
    coverMediaView.nativeAd = nativeAd
    viewAdContainer.addSubview(coverMediaView)

    // 設置 social context 標題 (如果有的話)
    if let socialContext = nativeAd.socialContext {
        lblSocialContext.text = socialContext
    }
}

有三個地方需要注意:

  1. 我們並不知道廣告的 body 和 social context 屬性是否有值,因此我們需要檢查它們是否為空。如果你想萬無一失,甚至連基本屬性你都應該進行必要的檢查。
  2. 廣告的 icon 是以異步方式進行加載的。loadImageAsyncWithBlock(...) 負責異步加載,我們需要做的僅僅是在我們對 imgAdIcon 的 image view 進行賦值之前確保已經獲得圖片。
  3. coverMediaView 被初始化,並手動添加到 container view (即 viewAdContainer)中。注意 clipsToBounds 的使用,這是必須的。如果你不這樣做,很可能廣告媒體會超出 container view 的框架(寬度)。

此外,我們還要提供一個 AdChoices view,用戶可以用它設置與廣告有關的隱私選項。其实也很簡單,Audience Network 框架提供了一個 专门用於干这个的类

func handleLoadedNativeAdUsingCustomViews() {
    ...

    // 添加 AdChoices view
    let adChoicesView = FBAdChoicesView(nativeAd: nativeAd)
    viewAdContainer.addSubview(adChoicesView)
    adChoicesView.updateFrameFromSuperview()
}

我們調用了 updateFrameFromSuperview() 方法,以調整 AdChoice View 的 frame,除此之外什麼也沒干。當然,因為它是一個 view 對象,你要手動修改它的 frame 也是可以的。

一個廣告應該在用戶點擊它的時候能夠進行響應,並在全屏模式下展示廣告。準確點講,如果用戶點擊了整個廣告畫面,或者點擊了 call-to-action 按鈕,廣告應該能夠與用戶交互。使用哪種交互方式取決於你,但我會兩種方法都嘗試一下。要讓整個 view 可點擊,需要在上述方法中加入下面幾行:

func handleLoadedNativeAdUsingCustomViews() {
    ...

    // 使整個廣告的 container view 能夠被點擊。
    nativeAd.registerViewForInteraction(viewAdContainer, withViewController: self)
}

如果你只想讓 call-to-action 按鈕能夠被點擊,則可以將上述語句替換為下一句:

func handleLoadedNativeAdUsingCustomViews() {
    ...

    // 使用 call-to-action 按鈕和用戶交互。
    nativeAd.registerViewForInteraction(viewAdContainer, withViewController: self, withClickableViews: [btnAdAction])
}

上述調用的最後一個參數是一個 view 數組,意味著你除了 action 按鈕外,你還可以設置更多的控件與用戶交互。出於演示的目的,我們只在數組中放入了一個按鈕。

做完上面的一切,我們就只剩下一件事情要做了:讓 container view 變成可見的,而之前它一直是隱藏的:

func handleLoadedNativeAdUsingCustomViews() {
    ...

    // 讓 native 廣告的 container view 可見
    viewAdContainer.hidden = false
}

現在你終於可以運行 app 了,並點擊第一個 tab 的 view controller 中的 Load Ad 按鈕。 如果你前面的步驟完全正確,你應該能夠看到第一個測試廣告顯示出來(我建議你使用模擬器來進行測試):

Facebook iOS Native Ads

FBNativeAdDelegate 協議還有一些可選方法可用。在 Xcode 中輸入 “nativeAd”(不帶雙引號),你可以閱讀官方文檔中關於這些方法的說明。例如,下面這個方法可用於處理廣告的點擊(不管是整個 view 還是 call-to-action 按鈕):

func nativeAdDidClick(nativeAd: FBNativeAd) {
    print("Did tap on the ad")
}

在本節結束之前,還需要做一件事情。找到 loadNativeAd(_:) IBAction 方法,修改為:

@IBAction func loadNativeAd(sender: AnyObject) {
    if coverMediaView != nil {
        coverMediaView.removeFromSuperview()
        coverMediaView = nil
    }

    if nativeAd != nil {
        nativeAd.unregisterView()
    }

    nativeAd = FBNativeAd(placementID: "PLACEMENT_ID")
    nativeAd.delegate = self
    nativeAd.loadAd()
}

想必你也看到了,在加載廣告之前我們又做了兩件事情:首先將 coverMediaView 從 superview 上移除(如果它不為空),並將它置為空。你應該記得這個對象是每次廣告被加載后都會重新創建的。其次,如果 nativeAd 對象已經初始化,並且不為空,我們會在加載新的廣告前將它(不管是 container view,還是是 call-to-action)從交互中註銷。這是必須的,因為接下來在廣告加載后,對應的 view 會根據你的命令再次進行註冊。

關於 native 廣告的更多資料,請看 這裡這裡

Native 廣告模板

現在我們已經了解如何在自定義 view 中使用 native 廣告了,接下來我們來試試如何使用 Audience Network 內置的 native 廣告模板。這種方式不像前者一樣,需要手工創建 view 並將廣告屬性賦值給它們。它只需要你指定廣告 view 的 frame(這個 view 會自動創建),然後進行一些設置,比如顯示內容的顏色、字體等。

SingleAdsViewController 類中,我們將創建一個新方法,名叫 code>handleLoadedNativeAdUsingTemplate(),我們會改變 nativeAdDidLoad(_:) 委託方法,當廣告加載后,調用新方法而不是 handleLoadedNativeAdUsingCustomViews() 方法。 在最簡單的情況下,新方法將包含如下語句:

func handleLoadedNativeAdUsingTemplate() {
    let nativeAdView = FBNativeAdView(nativeAd: nativeAd, withType: FBNativeAdViewType.GenericHeight300)
    nativeAdView.frame = CGRectMake(20.0, 100.0, UIScreen.mainScreen().bounds.size.width - 40.0, 300.0)
    self.view.addSubview(nativeAdView)

    nativeAd.registerViewForInteraction(nativeAdView, withViewController: self)
}

在這裡我們見到了一個新類 FBNativeAdView。類如其名,這個類負責建立一個 view,用於顯示 native 廣告的內容。程式碼很簡單,創建一個 FBNativeAdView 對象,設置它的 frame,然後將它加到你想放置它的 view 中。最後一句將新創建的 nativeAdView 註冊到 native ad 對象,以便用戶點擊廣告時它能夠進行響應。

要想讓這個方法生效,我們需要將 nativeAdDidLoad(_:) 方法修改為:

func nativeAdDidLoad(nativeAd: FBNativeAd) {
    // handleLoadedNativeAdUsingCustomViews()

    handleLoadedNativeAdUsingTemplate()
}

現在,運行 app 並點擊 Load Ad 按鈕。你將看到如下所示的畫面:

t55_15_native_ad_template_1

FBNativeAdView 有 4 種可以預先指定的高度。你可以在初始化時通過 withType 參數進行指定。這 4 個 FBNativeAdViewType 枚舉值分別是:

  • GenericHeight100
  • GenericHeight120
  • GenericHeight300
  • GenericHeight400

顯然,在修改 frame 時,高度必須和這個值一致。例如,如果你指定了 native 廣告 view 為 GenericHeight120 類型,則在設置 frame 時,必須將高設置為 120.0 pt。

在使用 FBNativeAdView 時,你可以設置某些屬性,你可以參考 FBNativeAdViewAttributes 類的文檔。簡單說,它們是:

  • Height
  • Width
  • Background Color
  • Title Color
  • Title Font
  • Description Color
  • Description Font
  • Button Color
  • Button Title Color
  • Button Title Font
  • Button Border Color

上述屬性必須在 native 廣告 view 初始化之前指定,否則不會生效。下面來看個例子。在handleLoadedNativeAdUsingTemplate() 方法中,我們可以在 native 廣告 view 初始化之前設置這些屬性:

func handleLoadedNativeAdUsingTemplate() {
    let attributes = FBNativeAdViewAttributes()
    attributes.buttonColor = UIColor.magentaColor()
    attributes.buttonTitleColor = UIColor.yellowColor()
    attributes.backgroundColor = UIColor.purpleColor()
    attributes.titleFont = UIFont(name: "Noteworthy", size: 20.0)
    attributes.titleColor = UIColor.whiteColor()
    attributes.buttonTitleFont = UIFont(name: "Futura", size: 12.0)
    attributes.descriptionColor = UIColor.whiteColor()

    ...
}

你可以設置更多的屬性,或者隨意修改上面的這些屬性值。無疑,配置方式的 native 廣告 view 使用起來更加簡單。現在,前面所用的初始化方法無法滿足我們了,因为我們還有一個 attributes 對象要傳遞。 我們需要調用 nativeAdView 的另一個初始化方法:

FBNativeAdView(nativeAd: nativeAd, withType: FBNativeAdViewType.GenericHeight300, withAttributes: attributes)

這個方法增加了一個可空的參數 withAttributes,它是一個 FBNativeAdViewAttributes 對象。通過這個參數,我們可以在 native ad view 实例化之后應用我們自定義設置。

下面是修改之後的完整方法實現:

func handleLoadedNativeAdUsingTemplate() {
    let attributes = FBNativeAdViewAttributes()
    attributes.buttonColor = UIColor.magentaColor()
    attributes.buttonTitleColor = UIColor.yellowColor()
    attributes.backgroundColor = UIColor.purpleColor()
    attributes.titleFont = UIFont(name: "Noteworthy", size: 20.0)
    attributes.titleColor = UIColor.whiteColor()
    attributes.buttonTitleFont = UIFont(name: "Futura", size: 12.0)
    attributes.descriptionColor = UIColor.whiteColor()

    // let nativeAdView = FBNativeAdView(nativeAd: nativeAd, withType: FBNativeAdViewType.GenericHeight300)
    let nativeAdView = FBNativeAdView(nativeAd: nativeAd, withType: FBNativeAdViewType.GenericHeight300, withAttributes: attributes)
    nativeAdView.frame = CGRectMake(20.0, 100.0, UIScreen.mainScreen().bounds.size.width - 40.0, 300.0)
    self.view.addSubview(nativeAdView)

    nativeAd.registerViewForInteraction(nativeAdView, withViewController: self)
}

再次運行 app,效果如圖:

t55_16_native_ad_template_2

關於 native 廣告模板的更多內容,請參考 這裡

在 table view 中顯示 native 廣告

本地廣告可以很容易就集成到 table view 中,因為 Audience Network Framework 提供了專門做這件事的附加工具。當然,你可以創建自定義 native view 然後將它們添加到 table view 的 cell 中,但這種方式很傻。當同時使用廣告和 table view 時,我們可以使用兩個新類:FBNativeAdsManagerFBNativeAdTableViewCellProvider (見 這裡這裡)。第一個類負責下載 一組廣告 並為 app 管理它們。這個類的一個特點是會 克隆 已經下載的廣告,因此它們可以反復在一張很長 table view 里顯示(不僅僅如此)。第二個類提供一種機制,用於自動將 native 廣告集成到 table view 中,例如它擁有創建 cell 或者計算行高的方法。這些方法和 table view 內置的委託方法和數據源方法配合使用。除了第二個類的方法以外,我們還可以使用 FBNativeAdTableViewAdProvider 類中的方法,這個類隨 FBNativeAdTableViewCellProvider 類一起提供。

後面我們會看到它們是如何使用的,在此之前先打開 TableViewAdsViewController.swift 文件,聲明 3 個屬性:

let adRowStep = 4

var adsManager: FBNativeAdsManager!

var adsCellProvider: FBNativeAdTableViewCellProvider!

adRowStep 表示廣告在 table view 上顯示的頻次,在我們的例子里,廣告將每隔 3 個單元格出現一次(每 4 行 cell 中會有一個 cell 用於顯示廣告)。另外兩個屬性是前面討論的兩個新類的實例。

然後實現一個新方法。在這個方法中,我們初始化 adsManager 對象,加載一堆廣告以便在 table view 中顯示:

func configureAdManagerAndLoadAds() {
    if adsManager == nil {
        adsManager = FBNativeAdsManager(placementID: "PLACEMENT_ID", forNumAdsRequested: 5)
        adsManager.delegate = self
        adsManager.loadAds()
    }
}

初始化方法需要兩個參數:第一個參數是我們在 Facebook Developer portal 中生成的 placement ID,我們將它複製粘貼到這裡。第二個參數告訴 adsManager 要下載多少個廣告,最大不能超過 10。當然,如果 adsManager 已經初始化,就不需要再次初始化了,所以我們檢查了它是否為空。在調用 loadAds() 方法下載廣告之前,我們設置 TableViewAdsViewController 類作為 adsManager 的委託。因為只有通過委託方法,我們才能在後面實現這些方法時知道廣告是否下載成功,這也是我們接下來要進行的工作。

光實現這個方法當然不行,我們必須調用它。找到 viewWillAppear(_:) 方法,在最後一行加上:

override func viewWillAppear(animated: Bool) {
    ...

    configureAdManagerAndLoadAds()
}

現在需要採用兩個協議。第一個是 FBNativeAdsManagerDelegate 協議,它讓我們知道廣告是否下載成功或者有錯誤發生,第二個是 FBNativeAdDelegate 協議(我們在前面已經使用過它了),它允許我們控制發生在廣告上的動作。找到類的第一行,聲明使用這兩個協議:

class TableViewAdsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, FBNativeAdDelegate, FBNativeAdsManagerDelegate {
   ...
}

首先是 FBNativeAdsManagerDelegate 協議方法。第一個方法會在廣告下載成功後調用,在這裡我們需要實例化 adsCellProvider 對象並刷新 table view,這樣廣告將夾在其他內容中一起顯示:

func nativeAdsLoaded() {
    adsCellProvider = FBNativeAdTableViewCellProvider(manager: adsManager, forType: FBNativeAdViewType.GenericHeight120)
    adsCellProvider.delegate = self

    if tblAdsDemo != nil {
        tblAdsDemo.reloadData()
    }
}

初始化時我們需要提供兩個參數。第一個參數是我們早先用到過的 adsManager 對象,第二個參數是 native 廣告 view 的類型 (FBNativeAdViewType) ,這個類型我們在模板廣告 view 一節中已經見過了。通過這個類型,我們可以設置廣告要顯示的高度,根據前面所述,高度值分別是 4 者之一:100, 120, 300 和 400 pt。你可以分別嘗試以找出最適合你的值。除此之外,我們還要將我們的類設置為 adsCellProvider 的委託,這樣當廣告上有事件發生時,我們可以通過 em>FBNativeAdDelegate 協議方法獲得通知。當然,這是可選的動作,你完全可以不做。

不要忘記,廣告有可能下載失敗,因此我們必須處理這種情況。為了簡單起見,我們這樣實現它(另一個協議方法):

func nativeAdsFailedToLoadWithError(error: NSError) {
    print(error)
}

我們會實現下面的 FBNativeAdDelegate 協議方法,備註:僅僅是演示。在這個方法里,我們會「捕捉」到廣告上的點擊事件,然後打印被點擊的廣告的標題:

func nativeAdDidClick(nativeAd: FBNativeAd) {
    print("Ad tapped: \(nativeAd.title)")
}

你還可以實現其它協議方法,只需要輸入 nativeAd,Xcode 會自動提示這些方法。當然,你也可以閱讀協議文檔中關於 Showing Native Ads 的部分。

實現完委託方法之後,為了將廣告集成到 table view 中,我們還需要使用 FBNativeAdTableViewCellProviderFBNativeAdTableViewAdProvider 類提供的機制。首先,我們需要調整的地方是 table view 要顯示的 cell 行數:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if adsCellProvider != nil {
        return Int(adsCellProvider.adjustCount(UInt(self.sampleData.count), forStride: UInt(adRowStep)))
    }
    else {
        return sampleData.count
    }
}

我再次建議你去閱讀 FBNativeAdTableViewCellProviderFBNativeAdTableViewAdProvider 類文檔。如果你沒有看過這些文檔,那麼你可以認為上述程式碼調整了 tableview 的行數,將廣告條數也加進了返回結果中。

然後,我們需要根據行的索引創建並加入廣告 cell。我們沒有必要進行手動檢查,相反,你會看到我們只是簡單調用了另一個方法進行檢查,然後再調用另一個方法來創建和返回廣告 cell。

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if adsCellProvider != nil && adsCellProvider.isAdCellAtIndexPath(indexPath, forStride: UInt(adRowStep)) {
        return adsCellProvider.tableView(tableView, cellForRowAtIndexPath: indexPath)
    }
    else {
        let cell = tableView.dequeueReusableCellWithIdentifier("idCellSample", forIndexPath: indexPath) as! SampleCell
        cell.lblTitle.text = sampleData[indexPath.row - Int(indexPath.row / adRowStep)]
        return cell
    }
}

想必你也看到了,這些來自於 Audience Network 框架的新方法全都使用 Uint(unsigned int)值作為參數,因此需要在 UInt 和 Int 之間進行強制類型轉換。剩下來的就簡單了,判斷某一行是否是廣告 cell,然後用 FBNativeAdTableViewCellProvider 類為我們準備相應的 cell。這裡有一個地方需要注意,就是 else 語句中數組的索引。注意之前的語句是:

sampleData[indexPath.row]

… 原來用 indexPath.row 來檢索數組,現在則變成了:

sampleData[indexPath.row - Int(indexPath.row / adRowStep)]

這樣,我們將避免 app 發生閃退,因為有可能滾到某些行的時候,行的索引就已經大過 sampleData 數組的長度了。可以假設一下這種情況會發生什麼,例如會發生 indexPath.row 為 20 行(剛好等於數組的長度)的情況,因為其中還有 6 行廣告被插入了 table view 中。所以我們要在這裡調整數組的索引,這是必須的。

最終,我們要給每一行一個正確的高度:

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if adsCellProvider != nil && adsCellProvider.isAdCellAtIndexPath(indexPath, forStride: UInt(adRowStep)) {
        return adsCellProvider.tableView(tableView, heightForRowAtIndexPath: indexPath)
    }
    else {
        return 60.0
    }
}

運行 app,切換到第二個 tab。稍等片刻,廣告將在 table view 的其它內容之間交叉顯示。

Facebook Tableview Ads

全屏廣告

全屏廣告(即 interstitial 廣告),和我們將在下一節看到的橫幅廣告,則相對要簡單得多。我們只需要下載廣告,然後直接在 View controller 中呈現即可。要實現這個目的,我們將用到新的協議 FBInterstitialAdDelegate。該協議提供了讓我們知道廣告加載成功和出現錯誤的方法,以及廣告被點擊或關閉的方法。首先,我們將從協議的聲明開始。打開 FullScreenAdsViewController.swift 文件,將類的第一行修改為:

class FullScreenAdsViewController: UIViewController, FBInterstitialAdDelegate {
   ...
}

聲明一個 FBInterstitialAd 屬性,用於表示一個全屏廣告。

var fullScreenAd: FBInterstitialAd!

如果你曾經運行過開始專案,你會發現有一個用於顯示全屏廣告的按鈕。我已經為這個按鈕創建了一個 IBAction 方法,你只需要將方法中的程式碼補全即可。這個過程你應該很熟悉了。

@IBAction func showFullScreenAd(sender: AnyObject) {
    fullScreenAd = FBInterstitialAd(placementID: "PLACEMENT_ID")
    fullScreenAd.delegate = self
    fullScreenAd.loadAd()
    btnShowAd.enabled = false
}

對於 fullScreenAd 對象的初始化,我們只需要一個參數,即我們所創建的全屏廣告的 placement ID。因此請確保你已經有這個 ID 並將之粘貼到第一行代碼中。剩下的事情就簡單了。注意,當按鈕被點擊后,我們 disable 掉了按鈕, 以免重複發送廣告請求。

然後是委託方法。首先處理廣告加載成功的情況,在這時我們只需要顯示廣告:

func interstitialAdDidLoad(interstitialAd: FBInterstitialAd) {
    interstitialAd.showAdFromRootViewController(self)
    btnShowAd.enabled = true
}

注意,我們又 enable 了按鈕控件。

然後是加載出錯的情況:

func interstitialAd(interstitialAd: FBInterstitialAd, didFailWithError error: NSError) {
    print(error)
    btnShowAd.enabled = true
}

一般,我們只需要打印錯誤信息並 enable 掉按鈕就可以了,但這種簡單處理的方式不推薦在真實 app 中採用。

出於演示的目的,我們又實現了兩個委託方法(當然也沒有做什麼有意義的處理):

func interstitialAdDidClick(interstitialAd: FBInterstitialAd) {
    print("Did tap on ad")
}


func interstitialAdDidClose(interstitialAd: FBInterstitialAd) {
    print("Did close ad")
}

這就不需要多說了吧。

運行 app,切到第三個 tab。點擊按鈕,稍等片刻,全屏廣告就會顯示在屏幕上。

Facebook Full Screen Ads

關於全屏廣告的更多內容,請參考 這裡

橫幅廣告

如果你想在 app 中使用橫幅廣告,你可以使用 FBAdView 類和 FBAdViewDelegate 協議。類似全屏廣告,我們只需要初始化一個 FBAdView 對象並下載一個廣告,然後在 view controller 中顯示它即可。初始化時略有不同,我們稍後會討論。

首先打開 BannerAdsViewController.swift 文件聲明一個屬性:

var bannerAdView: FBAdView!

然後修改類的第一行,讓它採用 FBAdViewDelegate 協議:

class BannerAdsViewController: UIViewController, FBAdViewDelegate {
   ...
}

loadBannerAd(_:) IBAction 方法中,我們必須初始化 bannerAdView 對象,然後加載廣告。然後,我們還需要制定橫幅廣告的 frame

@IBAction func loadBannerAd(sender: AnyObject) {
    bannerAdView = FBAdView(placementID: "PLACEMENT_ID", adSize: kFBAdSizeHeight50Banner, rootViewController: self)
    bannerAdView.frame = CGRectMake(0.0, 20.0, UIScreen.mainScreen().bounds.size.width, 50.0)
    bannerAdView.delegate = self
    bannerAdView.hidden = true
    self.view.addSubview(bannerAdView)

    bannerAdView.loadAd()
}

初始化方法需要 3 個參數:廣告的 placement ID(在這裡請複製﹣粘貼你自己的 ID),廣告的大小 size,顯示廣告的 view controller。這裡列有你可以使用的 size 值。具體使用哪個值,應該取決於 app 的實際需要,或者和其他 UI 相協調。注意,在我們將橫幅廣告添加進 view 之前,我們先將它設置為隱藏,而當廣告下載成功后我們才會將它設置為顯示。

接下來實現委託方法。首先是加載成功方法。在這裡,我們需要讓橫幅廣告顯示出來:

func adViewDidLoad(adView: FBAdView) {
    bannerAdView.hidden = false
}

然後是其他委託方法:

func adView(adView: FBAdView, didFailWithError error: NSError) {
    print(error)
}

func adViewDidClick(adView: FBAdView) {
    print("Did tap on ad view")
}

這樣就可以在 app 中顯示一個橫幅廣告。運行 app,切到最後一個 tab 進行測試。

Facebook iOS Banner Ads

更多內容,請參考 這裡

總結

一但你決定在 app 中集成 Facebook 廣告,所有選項你都可以使用。我們前面討論過的所有內容沒有任何深奧的地方。本文盡量覆蓋大部分內容,但仍然建議你通讀一遍官方文檔,那裡會有本文遺漏的一些細節。對於每個開發者來說,都應該了解如何通過 Audience Network 框架集成 Facebook 廣告,這樣可增加一種從 app 自身以外獲得收入途徑。無論如何,我希望本文能夠激發你的興趣,並從中學到新的東西。本文到此結束,祝你玩的開心!

完整的 Xcode 專案,請從 GitHub.com 下載

譯者簡介:楊宏焱,CSDN 博客專家(個人博客 http://blog.csdn.net/kmyhy)。2009 年開始學習蘋果 iOS 開發,精通 O-C/Swift 和 Cocoa Touch 框架,開發有多個商店應用和企業 App。熱愛寫作,著有和翻譯有多本技術專著,包括:《企業級 iOS 應用實戰》、《iPhone & iPad 企業移動應用開發秘笈》、《iOS8 Swift 編程指南》,《寫給大忙人看的 Swift》、《iOS Swift game Development cookbook》等

原文Displaying Facebook Ads in Your iOS Apps

作者
Gabriel Theodoropoulos
資深軟體開發員,從事相關工作超過二十年,專門在不同的平台和各種程式語言去解決軟體開發問題。自2010年中,Gabriel專注在iOS程式的開發,利用教程與世界上每個角落的人分享知識。可以在Google+或推特關注 Gabriel。
評論
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。