不久前有人問我如何在項目中集成 Facebook 的廣告。因為之前沒用過,以為一定很難,所以事先查閱了大量文檔。在通讀完文檔之後,發現其實並不是很難,僅僅幾分鐘我就能夠搞定我的第一個 Facebook 廣告 App!
Facebook 廣告是一種將廣告集成到你的 app 中的方法,使你可以通過廣告的點擊量來獲得收入。這個方法(集成廣告)並不復雜,在Facebook SDK(一個 Facebook 推出的 SDK 框架)中,有一個框架是和廣告相關的,那就是 Audience Network 框架。 你只需在 app 中使用這個框架就行了。
Facebook 為不同的平台提供了不同的廣告類型,但對於移動設備來說只有 3 種類型:Native, Interstitial, 和 Banners。下面簡單介紹一下這 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 的新人來說,將 O-C 的示例程序代碼翻譯成 Swift 會是一個不小的挑戰。
最後,需要說明的是,後面演示的示例項目(你可以下載它)都是用 Xcode 7.3.1 和 Swift 2.2 編寫的。這兩者都目前有效的正式版本,請不要在 Swift 3.0 中打開和運行它。
能讓我們學習和研究的編程文章,毫無例外都會要求你親自動手。本教程也不例外,它也會有一個 demo app。為了將注意力集中在將 Facebook 廣告集成到 app 中,這個 app 被設計得很簡單。你可以從這裡下載開始項目,通過它我們會一步一步完成最終的 app。
這個 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:
在 table view 中顯示 Native 廣告:
全屏廣告:
橫幅廣告:
接下來我們提到的內容在大部分情況下都適用。如果你想對某些方面進行更細致的調整,你應當仔細閱讀官方文檔──這會讓你對這個主題有更深刻的理解!
首先我們要介紹的是 Facebook Developers portal,因為我們必須在這裡進行一些操作,並獲取一些重要數據。簡單說,你需要新建一個 Facebook app 並進行一些配置,最終獲得幾個 ID,要在你的 app 中顯示廣告,你必須用到這些 ID。
讓我們詳細說明。首先,用任意浏覽器登錄你的 Facebook 賬號(你肯定有的吧?)。進入 這個地址 並點擊綠色的 Start Now 按鈕。你會看到彈出一個窗口,在這個窗口中你需要:
輸入 app 的名字。 選擇目標平台為 iOS。 在輸入 app 名字時,點擊 Link to Facebook。這會創建一條新記錄,並添加在 Facebook Developer portal 的 My Apps 中。這一步至關重要,千萬不要遺漏。然後,form 中會多出兩欄:一欄要你填入一個 email 地址作為你的聯系郵箱,第二欄要你選擇一個和該 app 相符的類型。
填完這些信息後,點擊 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 的詳細配置如下:
配置完成後,請點擊 Save 按鈕,新建的 placement 會在設置頁面列出。第二個廣告實際上是在第二個 tab 的 view controller 的 table view 中顯示的一系列 native 廣告,因此第二個 placement 的詳細設置如下:
第三個廣告是一個全屏廣告。
我把第四個廣告的 placement ID 的配置留給你練習。對於這個 placement,你可以在自動添加的基礎上加以編輯,也可以創建一個新的。記住,橫幅廣告也可以在某個按鈕被點擊時顯示。
注意,每個新的 placement 添加到設置頁面後,都會被分配給一個 Placement ID 值,我們將在後面用到這個 ID。
另外,如果你點擊 Get Code 按鈕,你會立即看到關於使用這個廣告和 placement ID 的示例程序代碼。遺憾的是:它們是 Objective-C 的,因此你需要自行轉換成 Swift 的。不用擔心,這會在後續步驟進行講解。
繼續後面的內容之前,有一件事情是你必須知道的。根據文檔描述,只允許以兩種方式在 app 中運行 測試廣告:
在仿真器中運行 app。 如果通過 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 區域,評審結果會在這裡顯示。
做完 Facebook 的設置之後,下載開始項目,我們還需要在項目中進行一些設置。首先是加入 Facebook Audience Network 框架,有兩種加入方式:
使用 Cocoapods 下載 Facebook iOS SDK 並手動將框架加入到項目中在這篇文檔的 Set Up the SDK 一節,兩種方式都進行了介紹。對我來說,我寧可從這裡自己下載 SDK,然後將 Facebook Audience Network 框架直接拖進Xcode中。
當你以兩種方式中的任何一種將框架加到項目中以後,你必須添加另外三個依賴框架。在項目導航器中,點擊項目的名稱,然後在 General 窗口中找到 Linked Frameworks and Libraries 一節。點擊 + (加號) 按鈕三遍,依次添加這三個框架:
StoreKit CoreMotion AdSupport如我所說,Facebook SDK 是使用 Objective-C 編寫的,因此我們要使用一個 bridging header 文件去導入這個庫,這樣才能在 Swift 代碼中使用它。這個過程非常簡單,操作步驟如下:
在 Xcode 中,點擊菜單 File > New > File…。 在文件模板窗口,選擇 iOS 下面的 Source。 選擇 header file 模板。 將文件命名為 AdsTutorial-Bridging-Header.h 並保存。然後你會在項目導航器中看到新創建的這個文件,選中它,將下列內容粘貼進文件中:
#import
接下來,再次在專案導航器中選中項目名稱,點擊 Build Settings tab,確保顯示的是 All 設置,然後在右邊搜索欄中搜索 Bridging Header 字符串。雙擊搜索結果的內容區域(即 Objective-C Bridging Header 文字的右邊),輸入或者粘貼進如下內容:
AdsTutorial/AdsTutorial-Bridging-Header.h
回車,設置完畢。項目的設置就到這裡結束了,接下來開始實現。
我也說過了,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 } }
有三個地方需要注意:
我們並不知道廣告的 body 和 social context 屬性是否有值,因此我們需要檢查它們是否為空。如果你想萬無一失,甚至連基本屬性你都應該進行必要的檢查。 廣告的 icon 是以異步方式進行加載的。loadImageAsyncWithBlock(...) 負責異步加載,我們需要做的僅僅是在我們對 imgAdIcon 的 image view 進行賦值之前確保已經獲得圖片。 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 按鈕。 如果你前面的步驟完全正確,你應該能夠看到第一個測試廣告顯示出來(我建議你使用仿真器來進行測試):
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 廣告的更多資料,請看 這裡 和 這裡。
現在我們已經了解如何在自定義 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 按鈕。你將看到如下所示的畫面:
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,效果如圖:
關於 native 廣告模板的更多內容,請參考 這裡。
本地廣告可以很容易就集成到 table view 中,因為 Audience Network Framework 提供了專門做這件事的附加工具。當然,你可以創建自定義 native view 然後將它們添加到 table view 的 cell 中,但這種方式很傻。當同時使用廣告和 table view 時,我們可以使用兩個新類:FBNativeAdsManager 和 FBNativeAdTableViewCellProvider (見 這裡 和 這裡)。第一個類負責下載 一組廣告 並為 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 中,我們還需要使用 FBNativeAdTableViewCellProvider 和 FBNativeAdTableViewAdProvider 類提供的機制。首先,我們需要調整的地方是 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 } }
我再次建議你去閱讀 FBNativeAdTableViewCellProvider 和 FBNativeAdTableViewAdProvider 類文檔。如果你沒有看過這些文檔,那麼你可以認為上述程序代碼 調整了 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 的其它內容之間交叉顯示。
全屏廣告(即 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。點擊按鈕,稍等片刻,全屏廣告就會顯示在屏幕上。
關於全屏廣告的更多內容,請參考 這裡 。
如果你想在 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 進行測試。
更多內容,請參考 這裡。
一旦你決定在 app 中集成 Facebook 廣告,所有選項你都可以使用。我們前面討論過的所有內容沒有任何深奧的地方。本文盡量覆蓋大部分內容,但仍然建議你通讀一遍官方文檔,那裡會有本文遺漏的一些細節。對於每個開發者來說,都應該了解如何通過 Audience Network 框架集成 Facebook 廣告,這樣可增加一種從 app 自身以外獲得收入途徑。無論如何,我希望本文能夠激發你的興趣,並從中學到新的東西。本文到此結束,祝你玩的開心!
完整的 Xcode 專案,請從 GitHub.com 下載。