第15 章
使用Google AdMob來播放橫幅廣告
就跟許多開發者一樣,你或許想要找到從 App 盈利的方式,最簡單的方式,就是將你的 App 放進 App Store,以$0.99美元或以上的售價來銷售,這個付費模式對某些 App 來說非常適合,不過,這並非唯一的獲利模式。本章,我們將介紹如何使用 Google AdMob來盈利。
有點不懂,為何要使用Google AdMob呢?我們開發的是 iOS App,為何我們不使用 Apple 的 iAd 呢?
在2016年初,Apple宣布要停止 iAd App 網路服務。因此,你將不再使用 iAd 作為 iOS App的廣告方案。你必須重新尋找其他放置橫幅廣告的替代的方式。
在所有行動網路廣告中,Google 的 AdMob 無庸置疑是最受歡迎的。跟 iAd 類似,Google 提供了SDK 讓開發者能夠在自己的 iOS App中嵌入廣告。Google 販售它們的廣告空間(譬如橫幅廣告(banner))給許多的廣告主。你便可以透過使用者的瀏覽或點擊廣告來獲利。
想要在 App 中使用 AdMob,你只需要使用 Google 的行動廣告 SDK(Google Mobile Ads SDK),這個整合的工作並不困難,只需要幾行程式就可以播放一個簡單的橫幅廣告,馬上就可以開始賺錢了。
沒有比直些試做如何整合 AdMob 更好的方式。如以往一樣,我們會從一個簡單的專案來開始,然後加入一個橫幅廣告,你可以從 http://www.appcoda.com/resources/swift55/GoogleAdDemoStarter.zip. 來下載Xcode專案模板。
除了 AdMob 的整合之外,你也會學習如何以 Swift 來執行延遲載入(lazy loading)。
申請Google AdMob帳號
在以 Google AdMob整合你的 App之前,你需要先申請 AdMob 服務。現在使用 Safari 或你偏好的瀏覽器來打開以下這個連結:
因為 AdMob 已經成為 Google的一部分,你只要以自己的 Google 帳號登入即可,或者你也可以註冊一個新帳號。AdMob 需要你提供一個有效的 AdSense 以及 AdWords 帳戶。倘若沒有的話,請跟著以下的登入步驟來連接你的Google帳號。
註冊完成之後,你會被導引至 AdMob 儀表板(Dashboard),在左側的導覽列表,選取 Apps
選項。
在這裡,選取 Add Your First App 選項。然後,您需要選擇應用平台,即 iOS。 AdMob 將會詢問你的 App 是否已經在 App Store 上架了,選取「No」選項。我們將手動填入這些表單資訊來註冊 App。在未來,倘若你的 App 已經在 App Store上架,你便可以讓 AdMob 來取得你的 App 資訊。
將 App 名稱設定為 GoogleAdMobLiveDemo 並點擊 Add App
來繼續下一個步驟。你應該會看到一條確認訊息,提示已成功建立App。 然後,你可以點擊 Done 按鈕返回到 App Overview 。
接著,我必須至少要建立一個廣告單元( Ad unit)。點選 Add Ad Unit
來繼續。針對這個範例,我們使用橫幅(banner)的廣告格式,所以選取「Banner」並接受預設的選項。而廣告單元名稱( Ad unit name) 設定為 Banner Ad。
點擊 Create Ad Unit
來產生單元 ID。這完成了你的新 App 的設置。你將會在實作的過程介紹中找到 App ID與 廣告單元ID(Ad unit ID)。請儲存這些資訊,當我們整合 AdMob 到 Xcode 專案時,我們會用到它們。
安裝 Google 行動廣告框架
在使用 AdMob 之前,你必須在 Xcode 項目中安裝 Google Mobile Ads SDK。 其中一個安裝 SDK 的方法就是使用 CocoaPods。 此書有一整章解釋了什麼是 CocoaPods 以及如何使用它。 如果你還沒有讀過第 33 章,請先參考它。
假設你的 Xcode 項目保存在 Desktop 文件夾中,打開終端並鍵入以下命令以更改文件夾:
cd ~/Desktop/GoogleAdDemo
然後通過輸入 pod init
建立 Podfile
。 打開項目的 Podfile 並將這一行添加到 target
中:
pod 'Google-Mobile-Ads-SDK'
最後,儲存更改並鍵入以下命令以安裝 SDK:
pod install
採用 Google 行動廣告框架
現在你已經在 AdMob 完成了設置,我們開始進行實作。打開 Xcode 並開啟起始專案的 GoogleAdDemo.xcworkspace
。請注意是開啟 GoogleAdDemo.xcworkspace
,而不是 GoogleAdDemo.xcodeproj
。如果你仔細查看項目導航器,你會發現兩個項目:GoogleAdDemo 和 Pods。 前者是原始項目,而 Pods 是捆綁 Google Mobile Ads SDK 的項目。
如果你嘗試編譯並運行這個項目,會在 Console 發現一個問題。 這是正常的,因為我們沒有為 SDK 提供應用App ID。 稍後,我們將進行一些更改並對其進行調整以顯示廣告。
要在你的程式中,使用 Google Mobile Ads SDK 的話,你需要匯入框架,並註冊你的 App ID。我們將AppDelegate.swift
檔中做初始化。插入這個 import 敘述至檔案的最前面:
import GoogleMobileAds
接下來,插入以下的程式至 application(_:didFinishLaunchingWithOptions:)
方法中:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GADMobileAds.sharedInstance().start(completionHandler: nil)
return true
}
在App啟動時初始化 Google Mobile Ads SDK ,可以讓 SDK 儘早執行配置。
接下來,打開 Info.plist
並添加一個名為 GADApplicationIdentifier
的新行。 回想一下,AdMob 為你的App建立了一個獨一無二的App ID,你必須在此條目中設置那個 ID。 對我來說,會將其設置為:
ca-app-pub-6371581406920912~3037490636
請確保將 App ID 設定為你自己的 ID。 另外,請為SKAdNetworkItems
添加另一個條目。 要添加這兩個 key,可以在項目導航器中右鍵單擊 Info,然後選擇 Open As > Source Code。 這使你可以在程式碼編輯器中編輯 Info.plist 文件。
在 Info.plist 插入以下內容並將其放在</dict>
之前:
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-6371581406920912~3037490636</string>
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cstr6suwn9.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4fzdc2evr5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>2fnua5tdw4.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ydx93a7ass.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>5a6flpkh64.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>p78axxw29g.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v72qych5uu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>c6k4g5qg8m.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>s39g8k73mm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3qy4746246.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3sh42y64q3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>f38h382jlk.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>hs6bdukanm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>prcb7njmu6.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v4nxqhlyqp.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>wzmmz9fp6w.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>yclnxrl5pm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>t38b2kh725.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>7ug5zh24hu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>9rd848q2bz.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>n6fk4nfna4.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>kbd757ywx3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>9t245vhmpl.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4468km3ulz.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>2u9pt9hc89.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8s468mfl3y.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>av6w8kgt66.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>klf5c3l5u5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ppxm28t8ap.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>424m5254lk.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>uw77j35x4d.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>578prtvx9j.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4dzt52r2t5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>e5fvkxwrpn.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8c4e2ghe7u.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>zq492l623r.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>3qcr597p9d.skadnetwork</string>
</dict>
</array>
你必須使用自己的Ad ID 設置為 GADApplicationIdentifier
的值。 好了!我們終於完成所有設定。
在表格視圖標題顯示橫幅廣告
我們開始以最簡單的方式在你的 App 中呈現橫幅廣告。我們將會從 Google 請求一個橫幅廣告,並將這幅廣告顯示在表格標題(header)。
要在該位置呈現一個橫幅廣告,你所需要做的便是建立一個 GADBannerView
物件,設定它的委派,以及根視圖控制器(root view controller)。然後你以取得一個橫幅廣告的廣告請求來呼叫它的 load
方法。當廣告準備要顯示時,他會呼叫 GADBannerViewDelegate
協定的 adViewDidReceiveAd(bannerView:)
方法。所以你只需要實作這個方法就可以在表格視圖標題來顯示橫幅廣告。
好的,我們來進行實作的部分。
現在開啟 NewsTableViewController.swift
。首先,匯入GoogleMobileAds 框架:
import GoogleMobileAds
接下來, 宣告一個 GADBannerView
型態的變數。這是用來存放橫幅視圖(banner view)的變數:
lazy var adBannerView: GADBannerView = {
let adBannerView = GADBannerView(adSize: GADPortraitAnchoredAdaptiveBannerAdSizeWithWidth(300))
adBannerView.adUnitID = "ca-app-pub-8501671653071605/1166331146"
adBannerView.delegate = self
adBannerView.rootViewController = self
return adBannerView
}()
以上的程式中,我們使用一個閉包( closure)來初始化 adBannerView
變數,也就是產生一個 GADBannerView
的實例(instance)。在初始化過程中,我們告訴這個 SDK 我們想要取得一個自適應橫幅廣告(adaptive banner)(GADPortraitAnchoredAdaptiveBannerAdSizeWithWidth
) 。如同名稱的意涵,自適應橫幅廣告可以很聰明的偵測螢幕寬度並根據寬度來調整螢幕大小。同時我們也設定廣告單元 ID,委派(delegate)與根視圖控制器(root view controller)。同樣的,請將 ID 換成你自己的。
我們使用延遲初始化(lazy initialization,有時候稱作延遲實例化(lazy instantiation)或延遲載入(lazy loading))來初始化 adBannerView
變數。在 Swift,你使用 lazy
關鍵字來指示某個變數可以稍後才初始化,更精確地說法是,這個變數只有在使用時才會被實例化。這個技術對於延遲物件的建立,尤其是對需要花點時間來載入物件或者是你所參照的物件還沒準備好物件的建立時特別有用。在初始化期間,我們設定 delegate
與 rootViewController
屬性為 self
。不過 NewsTableViewController
在這時候還沒準備好。我們使用lazy
來延遲 adBannerView
的初始化。
一定要使用延遲初始化來建立橫幅廣告視圖嗎?不,我是想要利用這個機會來介紹延遲初始化,並示範如何使用閉包來做變數的初始化。你也可以像這樣,不使用延遲初始化:
var adBannerView: GADBannerView?
override func viewDidLoad() {
super.viewDidLoad()
adBannerView = GADBannerView(adSize: kGADAdSizeSmartBannerPortrait)
adBannerView?.adUnitID = "ca-app-pub-8501671653071605/1166331146"
adBannerView?.delegate = self
adBannerView?.rootViewController = self
}
不過,如你所見,前面一種初始化方式可以讓我們將所有的初始化程式放在閉包中,程式的可讀性更高,也更易於管理。
現在我們已經建立了adBannerView
變數,下一步就是廣告的請求。你只需要加入以下這一行程式至 viewDidLoad
方法中就可以辦到:
GADMobileAds.sharedInstance().requestConfiguration.testDeviceIdentifiers = [ GADSimulatorID ]
adBannerView.load(GADRequest())
要在測試環境中加載生產廣告,Google 會要求你設置測試設備。 這是第一行程式碼的目的。
你可能想知道為何你需要定義這個測試裝置。如果省略這行程式會如何呢?你的 App 一樣能夠運作並顯示廣告。不過這是 Google 的政策,你必須要去跟隨。
當你在 AdMob UI 註冊一個 App 並且建立之後可以在你的 App 中使用的單元 ID 後,在開發時,你需要將你的裝置明確地設定為測試裝置。這是非常重要的。以真實的廣告來測試將違反 AdMob 政策,也因而會讓你的帳號被暫停。
- AdMob 整合指南
最後,我們需要採用 GADBannerViewDelegate
協定。如下所示,我們將會建立一個擴展來採用這個協定並實作兩個可選方法:
extension NewsTableViewController: GADBannerViewDelegate {
func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
print("Banner loaded successfully")
tableView.tableHeaderView?.frame = bannerView.frame
tableView.tableHeaderView = bannerView
}
func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) {
print("Fail to receive ads")
print(error)
}
}
當廣告成功載入後, bannerViewDidReceiveAd
方法會被呼叫。在這個方法中,我們只是指定這個橫幅視圖至表格視圖的標題視圖(header view)。這可以讓 App 在表格標題顯示橫幅廣告。倘若廣告載入失敗,我們只要印出錯誤訊息至主控台即可。
試著執行範例 App 並測試一下。當 App 啟動時,你會見到在表格視圖的最前面出現了一個橫幅廣告。
注意:如果你的App未能取得廣告,請嘗試將 adUnitId 的值更改為 ca-app-pub-3940256099942544/2934735716
,即 Google 提供的示範廣告。 另外,有時 Google 需要一些時間來啟用你的廣告單元,不想等待的話,可以先使用這個示範廣告 ID 進行測試。
添加動畫效果
有時候在橫幅廣告加入點精緻的動畫像是廣告如何轉場至畫面中,使用者的體驗會更棒。在這一節,我會告訴你如何讓橫幅廣告動起來。當廣告轉場至畫面時,我們將加入一個滑下動畫(slide-down animation)。
這個技巧是應用 UIView
動畫至橫幅廣告。當廣告第一次載入時,我們重新調整橫幅廣告的位置讓它離開畫面。然後我們使用滑下動畫。
如同之前所述,bannerViewDidReceiveAd
方法在廣告準備好時被呼叫。要讓廣告動起來,我們需要修改方法如下:
func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
print("Banner loaded successfully")
// 重新調整橫幅廣告位置來建立滑下特效
let translateTransform = CGAffineTransform(translationX: 0, y: -bannerView.bounds.size.height)
bannerView.transform = translateTransform
UIView.animate(withDuration: 0.5) {
self.tableView.tableHeaderView?.frame = bannerView.frame
bannerView.transform = CGAffineTransform.identity
self.tableView.tableHeaderView = bannerView
}
}
我們先建立一個 translateTransform
來移動橫幅廣告視圖離開畫面,然後呼叫UIView.animate
來將廣告滑下至畫面中。
執行這個專案並測試 App,這個廣告將會以動畫效果來呈現。
緊貼的橫幅廣告
當你滾動表格視圖時,廣告便消失了。它並沒有緊貼表格視圖標題。你可能想知道,要如何顯示一個隨時緊貼的橫幅廣告。這也是本節所要探索的內容。
這個橫幅廣告現在已經插入表格標頭視圖。倘若你想要能夠將廣告貼緊不放,你可以將其加在區塊(section)的標題視圖而不是表格的標題視圖。
讓我們來看如何實作。
在 NewsTableViewController
類別插入以下的方法:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return adBannerView
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return adBannerView.frame.height
}
我們以自己的方法來覆寫(override)預設的 tableView(_:viewForHeaderInSection:)
方法,並回傳橫幅廣告視圖。
預設標題的高度對橫幅廣告來說太小。所以我們同時覆寫了tableView(_:heightForHeaderInSection:)
方法,並回傳橫幅廣告視圖框(frame)的高度。
最後,修改 bannerViewDidReceiveAd
方法如下:
func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
print("Banner loaded successfully")
// 重新調整橫幅廣告位置來建立滑下特效
let translateTransform = CGAffineTransform(translationX: 0, y: -bannerView.bounds.size.height)
bannerView.transform = translateTransform
UIView.animate(withDuration: 0.5) {
bannerView.transform = CGAffineTransform.identity
}
}
我們只是移除了跟表格視圖標題有關的程式,因為已經用不到了。
如此,現在可以再次準備測試這個 App。橫幅廣告已經在固定位置顯示了。
播放插播廣告
除了在 App 中使用橫幅廣告之外,Google Mobile Ads SDK 也可以讓你很容易地播放插播廣告(interstitial ads,也就是全螢幕的廣告)。一般來說,你可以透過插播廣告來賺取更多廣告費,因為它完全蓋住了App的內容,並獲得了使用者的注意。
這種廣告的缺點就是有點惱人,因為它強迫使用者來檢視廣告除非他們點擊取消。不過這還是依照所設計的頻率以及在什麼情況下你要播放全螢幕廣告而定。我用過一些 App,每幾分鐘持續出現插播廣告。透過謹慎規劃的廣告編排,可以讓你的 App 不那麼擾人。舉例來說,你可以只出現一次廣告,倘若你正在開發遊戲的話,你可以設計在遊戲關卡之間播放。無論如何,我的重點是告訴你如何在 iOS App 中播放插播廣告。我的規劃是在使用者打開這個範例 App 時播放這個廣告。
首先,你必須先回到 AdMob 的儀表板((https://apps.admob.com),來幫範例 App 建立一個插播廣告。在側邊選單選取 Apps
,並選取 GoogleAdMobDemo
,在下一個畫面,點選 Add Ad Unit
來建立一個新的廣告單元並選擇 Interstitial。
這一次,我們建立一個插播廣告。賦予這個廣告單元一個名稱並點擊 Create Ad Unit
來建立這個單元。AdMob 應該會為你產生另一個廣告單元 ID。
現在回到 Xcode 專案。
插播廣告的實作跟橫幅廣告非常相似。這邊我們使用GADInterstitial
類別來取代GADBannerView
類別。所以先在 NewsTableViewController
類別宣告一個變數來儲存GADInterstitial
物件:
var interstitial: GADInterstitial?
不過, GADBannerView
與 GADInterstitial
的差異在於,GADInterstitial
是只使用一次的物件。這表示此插播廣告出現過後,就無法再載入其他廣告。
由於這個因素,我們建立了一個輔助方法,稱作 createAndLoadInterstitial()
來建立廣告。在 NewsTableViewController
類別插入這個廣告:
private func loadInterstitialAd() {
let request = GADRequest()
GADInterstitialAd.load(withAdUnitID: "ca-app-pub-8501671653071605/5691915429", request: request) { ad, error in
if error != nil { return }
self.interstitial = ad
self.interstitial?.fullScreenContentDelegate = self
self.interstitial?.present(fromRootViewController: self)
}
}
我們首先初始化一個 GADRequest
物件, 然後我們建立一個GADInterstitialAd
物件,使用我們的廣告單元ID和廣告請求來呼叫load
方法。 加載廣告後,我們在完成處理程序塊中顯示廣告。 插頁式廣告允許你設置委託以進行進一步處理。 在這裡,我們將委託設置為 self
。
當視圖載入時,我們會建立這個廣告。所以插入以下的程式碼至 viewDidLoad()
方法中:
loadInterstitialAd()
跟 GADBannerView
類似,為了檢查廣告的狀態,我們需要採用一個協定。建立一個擴展來實作 GADFullScreenContentDelegate
協定:
extension NewsTableViewController: GADFullScreenContentDelegate {
func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
print("Interstitial ad loaded successfully")
}
func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
print("Failed to receive interstitial ads")
}
}
現在你已經準備好測試這個 App。在啟動 App之後,你應該會見到一個全螢幕的測試廣告。
本文摘自《iOS 15 App程式設計進階攻略》一書。如果你想繼續閱讀和下載完整程式碼,你可以從AppCoda網站購買完整電子版,全書範例檔皆可下載。