SwiftyAds
一个 Swift 库,用于显示横幅、插屏、激励视频和原生广告,由 Google AdMob 和支持的介质合作伙伴提供。
要求
- iOS 13.0+
- Swift 5.6+
创建账户
AdMob
注册 AdMob 账户 并为你要显示的广告类型创建所需的 AdUnitIDs。
资金选择(可选)
SwifyAds 使用 Google 的 用户消息平台 (UMP) SDK 来处理需要时的用户同意。此 SDK 可以处理 GDPR (EEA) 请求,也可以处理 iOS 14 ATT 提醒。
如果你想禁用用户同意请求,可以跳过此步骤,请参阅下文 用法部分 中的 Add SwiftyAds.plist
部分。否则,请阅读资金选择的 文档,确保它们正确设置以满足你的需求。
注意:苹果可能会拒绝使用 UMP SDK 来显示 iOS 14 ATT 提醒的应用程序。作为替代方案,你可能需要调整 解释消息 的措辞,或者你可以在配置 SwiftyAds 之前手动显示 ATT 提醒。
安装
Swift 包管理器
Swift 包管理器是一个用于自动化 Swift 代码分发工具,并集成到 swift 编译器中。
要将 swift 包添加到您的项目中,请打开您的项目到 xCode,然后点击 File > Swift Packages > Add Package Dependency。接着输入 https://github.com/crashoverride777/swifty-ads.git
作为代码库 URL 并完成安装向导。
或者,如果您有其他需要 SwiftyAds
作为依赖项的 swift 包,将其添加到 Package.swift 的依赖项值中同样简单。
dependencies: [
.package(url: "https://github.com/crashoverride777/swifty-ads.git", from: "14.0.0")
]
Cocoa Pods
Cocoa Pods 是 Cocoa 项目的依赖管理器。只需将以下行添加到您的 pod 文件中,即可简单安装 pod。
pod 'SwiftyAds'
手动安装
您还可以将 Sources
文件夹及其包含的文件复制到您的项目中,并安装所需的依赖。
使用前准备
更新 Info.plist
添加 SwiftyAds.plist
下载 模板 plist 并将其添加到您的项目主包中。然后输入所需广告单位 ID 和其他所需字段。所有条目均为可选项,如不需要,则可删除。
- bannerAdUnitId (String)
- interstitialAdUnitId (String)
- rewardedAdUnitId (String)
- rewardedInterstitialAdUnitId (String)
- nativeAdUnitId (String)
- 是否标记为儿童导向治疗方法(布尔值)(COPPA)
- 是否标记为未满同意年龄(布尔值)(GDPR)
- isUMPDisabled(布尔值)
注意:将isUMPDisabled
条目添加并设置其值为true意味着SwiftyAds不会使用用户消息平台(UMP)SDK执行任何同意请求。在这种情况下,如果需要,您必须手动支持GDPR(EEA)和ATT(苹果)提醒。
链接AppTrackingTransparency框架
链接在常规选项卡下的“框架、库和嵌入式内容”中链接AppTrackingTransparency框架,否则iOS 14 ATT提醒将不会显示。
如果您还支持iOS 13及以下版本,您还必须在BuildPhases->Link Binary With Libraries
中将其设置为可选,以避免崩溃。
使用方法
添加导入(CocoaPods或SwiftPackageManager)
- 如果您通过CocoaPods或SwiftPackageManager安装,请将导入语句添加到您的swift文件(们)中。
import SwiftyAds
使用 GADRequest 构建器
创建一个实现 SwiftyAdsRequestBuilderType
协议的 SwiftyAdsRequestBuilder
类,SwiftyAds 将使用该类来加载广告。一些第三方网络,如 Vungle,可能需要特定的 GADRequest 额外参数。请查阅 AdMob 中介 文档。
import SwiftyAds
import GoogleMobileAds
final class SwiftyAdsRequestBuilder {}
extension SwiftyAdsRequestBuilder: SwiftyAdsRequestBuilderType {
func build() -> GADRequest {
GADRequest()
}
}
创建中介配置器(可选)
创建一个实现 SwiftyAdsMediationConfiguratorType
协议的 SwiftyAdsMediationConfigurator
类,用于管理 COPPA/GDPR 免责声明状态变更时的中介网络更新。请查阅 AdMob 中介 文档。
App Lovin 示例
import SwiftyAds
import AppLovinAdapter
final class SwiftyAdsMediationConfigurator {}
extension SwiftyAdsMediationConfigurator: SwiftyAdsMediationConfiguratorType {
func updateCOPPA(isTaggedForChildDirectedTreatment: Bool)
// App Lovin mediation network example
ALPrivacySettings.setIsAgeRestrictedUser(isTaggedForChildDirectedTreatment)
}
func updateGDPR(for consentStatus: SwiftyAdsConsentStatus, isTaggedForUnderAgeOfConsent: Bool) {
// App Lovin mediation network example
ALPrivacySettings.setHasUserConsent(consentStatus == .obtained)
if !ALPrivacySettings.isAgeRestrictedUser() { // skip if already age restricted e.g. enableCOPPA called
ALPrivacySettings.setIsAgeRestrictedUser(isTaggedForUnderAgeOfConsent)
}
}
}
配置
创建并调用配置方法,最好是在应用程序启动时完成,例如在 AppDelegate 的 didFinishLaunchingWithOptions
中。这也会触发初始的免责声明流程(除非已禁用)。只有在调用 completion
处理器后,才可显示广告。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let rootViewController = window?.rootViewController {
configureSwiftyAds(from: rootViewController)
}
return true
}
private func configureSwiftyAds(from viewController: UIViewController) {
#if DEBUG
// testDeviceIdentifiers: The test device identifiers used for debugging purposes.
// consentConfiguration: The debug consent configuration:
// 1) .default(geography: UMPDebugGeography),
// 2) .resetOnLaunch(geography: UMPDebugGeography)
// 3) .disabled
let environment: SwiftyAdsEnvironment = .development(testDeviceIdentifiers: [], consentConfiguration: .resetOnLaunch(geography: .EEA))
#else
let environment: SwiftyAdsEnvironment = .production
#endif
SwiftyAds.shared.configure(
from: viewController,
for: environment,
requestBuilder: SwiftyAdsRequestBuilder(),
mediationConfigurator: SwiftyAdsMediationConfigurator(), // set to nil if no mediation is required
consentStatusDidChange: { status in
print("The consent status has changed")
},
completion: { result in
switch result {
case .success(let consentStatus):
print("Configure successful")
// Ads will preload and sohuld be ready for displaying
case .failure(let error):
print("Setup error: \(error)")
}
}
)
}
注意:如果您不使用 Google UMP SDK 来显示 iOS 14 应用跟踪透明度 (ATT) 提醒,请在配置 SwiftyAds 之前请求权限。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let rootViewController = window?.rootViewController {
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization { status in
self.configureSwiftyAds(from: rootViewController)
}
} else {
configureSwiftyAds(from: rootViewController)
}
}
return true
}
在UIViewController外部展示广告
SwiftyAds需要引用一个UIViewController
来展示广告。如果你不在一个ViewController
中使用SwiftyAds,你可以按以下步骤获取rootViewController的引用。
AppDelegate
if let viewController = window?.rootViewController {
SwiftyAds.shared.show(...)
}
SKScene
if let viewController = view?.window?.rootViewController {
SwiftyAds.shared.show(...)
}
横幅广告
在你的UIViewController
中为要显示的广告创建一个属性。
class SomeViewController: UIViewController {
private var bannerAd: SwiftyAdsBannerType?
}
在viewDidLoad
中准备横幅广告。
override func viewDidLoad() {
super.viewDidLoad()
bannerAd = SwiftyAds.shared.makeBannerAd(
in: self,
adUnitIdType: .plist, // set to `.custom("AdUnitId")` to add a different AdUnitId for this particular banner ad
position: .bottom(isUsingSafeArea: true) // banner is pinned to bottom and follows the safe area layout guide
animation: .slide(duration: 1.5),
onOpen: {
print("SwiftyAds banner ad did receive ad and was opened")
},
onClose: {
print("SwiftyAds banner ad did close")
},
onError: { error in
print("SwiftyAds banner ad error \(error)")
},
onWillPresentScreen: {
print("SwiftyAds banner ad was tapped and is about to present screen")
},
onWillDismissScreen: {
print("SwiftyAds banner ad presented screen is about to be dismissed")
},
onDidDismissScreen: {
print("SwiftyAds banner did dismiss presented screen")
}
)
}
并在viewDidAppear
中显示它。这是为了确保视图已被正确布局,且具有有效的安全区域。
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
bannerAd?.show(isLandscape: view.frame.width > view.frame.height)
}
要处理方向变化,只需在viewWillTransition
中再次调用显示方法。
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { [weak self] _ in
self?.bannerAd?.show(isLandscape: size.width > size.height)
})
}
你可以通过调用hide
方法来隐藏横幅。
bannerAd?.hide()
你可以通过调用remove
方法从父视图中移除横幅,之后将其引用设为nil。
bannerAd?.remove()
bannerAd = nil
插屏广告
SwiftyAds.shared.showInterstitialAd(
from: self,
afterInterval: 2, // every 2nd time method is called ad will be displayed. Set to nil to always display.
onOpen: {
print("SwiftyAds interstitial ad did open")
},
onClose: {
print("SwiftyAds interstitial ad did close")
},
onError: { error in
print("SwiftyAds interstitial ad error \(error)")
}
)
奖励型广告
奖励型广告可能是不可跳过的,并且只能当按下专用按钮时展示。
SwiftyAds.shared.showRewardedAd(
from: self,
onOpen: {
print("SwiftyAds rewarded ad did open")
},
onClose: {
print("SwiftyAds rewarded ad did close")
},
onError: { error in
print("SwiftyAds rewarded ad error \(error)")
},
onNotReady: { [weak self] in
guard let self = self else { return }
print("SwiftyAds rewarded ad was not ready")
// If the user presses the rewarded video button and watches a video it might take a few seconds for the next video to reload.
// Use this callback to display an alert incase the video was not ready.
let alertController = UIAlertController(
title: "Sorry",
message: "No video available to watch at the moment.",
preferredStyle: .alert
)
alertController.addAction(UIAlertAction(title: "Ok", style: .cancel))
DispatchQueue.main.async {
self.present(alertController, animated: true)
}
},
onReward: { [weak self] rewardAmount in
print("SwiftyAds rewarded ad did reward user with \(rewardAmount)")
// Provide the user with the reward e.g coins, diamonds etc
}
)
注意:AdMob 提供了一个新的奖励视频 API,允许您预加载具有不同 AdUnitIDs 的多个奖励视频。虽然 SwiftyAds 使用了新的 API,但目前它一次只能加载一个奖励广告。
奖励横幅广告
奖励横幅广告可以在您的应用程序流程中自然呈现,类似于横幅广告,并且不需要像常规奖励广告那样使用专用按钮。在显示奖励横幅广告之前,您必须向用户展示一个介绍屏幕,该屏幕提供清晰的奖励说明和选项,在广告开始之前可以跳过广告。
SwiftyAds.shared.showRewardedInterstitialAd(
from: self,
afterInterval: 2, // every 2nd time method is called ad will be displayed. Set to nil to always display.
onOpen: {
print("SwiftyAds rewarded interstitial ad did open")
},
onClose: {
print("SwiftyAds rewarded interstitial ad did close")
},
onError: { error in
print("SwiftyAds rewarded interstitial ad error \(error)")
},
onReward: { [weak self] rewardAmount in
print("SwiftyAds rewarded interstitial ad did reward user with \(rewardAmount)")
// Provide the user with the reward e.g coins, diamonds etc
}
)
原生广告
要展示原生广告,请调用加载方法。一旦收到原生广告,您可以使用原生广告内容更新您的自定义广告视图。
您可以通过 loaderOptions
参数设置要加载的广告数量(GADMultipleAdsAdLoaderOptions
)。设置为 .single
以使用默认选项。
根据谷歌的文档,对于已配置为调优的 AdMob 广告单元 ID,目前无法对多个原生广告进行请求。使用调优的出版商应避免在请求时使用 GADMultipleAdsAdLoaderOptions 类。在这种情况下,您还可以将 loaderOptions
参数设置为 .single
。
SwiftyAds.shared.loadNativeAd(
from: self,
adUnitIdType: .plist, // set to `.custom("AdUnitId")` to add a different AdUnitId for this particular native ad
loaderOptions: .single, // set to `.multiple(2)` to load multiple ads for example 2
onFinishLoading: {
// Native ad has finished loading and new ads can now be loaded
},
onError: { error in
// Native ad could not load ad due to error
},
onReceive: { nativeAd in
// show native ad (see demo app or google documentation)
}
)
注意:尽管预加载广告是一种很好的技术,但您很重要,不要永久保留旧的原生广告而不显示它们。任何在超过一小时后未显示的原生广告对象都应被丢弃,并用新的请求的新广告替换。
错误
您可以使用 SwiftyAdsError
枚举来处理 SwiftyAds 特定错误。
if let swiftyAdsError = error as? SwiftyAdsError {
switch swiftyAdsError {
case .interstitialAdNotLoaded:
// Ad was not loaded
default:
break
}
}
同意状态
// Check current consent status
SwiftyAds.shared.consentStatus
布尔值
// Check if interstitial ad is ready, for example to show an alternative ad
SwiftyAds.shared.isInterstitialAdReady
// Check if rewarded ad is ready, for example to show/hide button
SwiftyAds.shared.isRewardedAdReady
// Check if rewarded interstitial ad is ready, for example to show an alternative ad
SwiftyAds.shared.isRewardedInterstitialAdReady
// Check if child directed treatment is tagged on/off. Nil if not indicated how to be treated. (COPPA)
SwiftyAds.shared.isTaggedForChildDirectedTreatment
// Check if under age of consent is tagged on/off (GDPR)
SwiftyAds.shared.isTaggedForUnderAgeOfConsent
// Check if ads have been disabled
SwiftyAds.shared.isDisabled
禁用/启用应用内购买广告
调用 disable(_ isDisabled: Bool)
方法后,横幅广告、插页式广告和激励式插页式广告将不再显示。这不会阻止正常显示的激励式广告,因为它们应该有一个专门的按钮。这样您可以删除横幅广告、插页式广告和激励式插页式广告,但仍可显示激励式广告。
SwiftyAds.shared.setDisabled(true)
对于永久存储,您需要创建自己的布尔逻辑并将它保存在类似 NSUserDefaults
的地方,或者最好保存在 Keychain
中。然后在应用启动时,在调用 SwiftyAds.shared.configure(...)
之前,检查您保存的布尔值,并在必要时禁用广告。
if UserDefaults.standard.bool(forKey: "RemovedAdsKey") == true {
SwiftyAds.shared.setDisabled(true)
}
再次请求同意
必须允许用户更改他们的GDPR同意设置,通常通过设置中的按钮。
func consentButtonPressed() {
SwiftyAds.shared.askForConsent(from: self) { result in
switch result {
case .success(let status):
print("Did change consent status")
case .failure(let error):
print("Consent status change error \(error)")
}
}
}
如果不需要同意或用户为未成年用户,可以从隐藏同意按钮。
// If consent is not required e.g. outside EEA than we do not need to show consent button.
// If inside EEA we need to display the consentButton unless user is tagged for under age of consent
if SwiftyAds.shared.consentStatus == .notRequired {
consentButton.isHidden = true
} else {
consentButton.isHidden = SwiftyAds.shared.isTaggedForUnderAgeOfConsent
}
App Store 发布信息
确保为 Apple App Store 数据披露要求做好准备
演示
https://github.com/crashoverride777/swifty-ads-demo
许可协议
SwiftyAds 在 MIT 许可下发布。查看 LICENSE 详细信息。