概要
原生广告不同于以往横幅广告、插页广告会直接提供可立即呈现的广告内容,原生广告 API 提供了标题、图像等广告内容的组合,您可以透过这些属性的编排打造出最理想的原生广告风格。原生广告更打破以往对于广告的刻板印象,以最自然的方式呈现,提供更符合需求的广告体验。
完成串接准备
在开始串接广告之前,请确认您已经将 Vpon SDK 导入您的 Xcode 专案中。若您尚未完成,请先参考串接说明完成相关设定。
开始撰写 Native Ad
在应用程式中建立原生广告需要执行以下五个步骤:
- Import VpadnSDKAdKit
- 宣告 VponNativeAdView 及自定义 UI
- 初始化 VponNativeAdLoader 物件,并请求广告
- 实作 VponNativeAdLoaderDelegate
- 利用回传的资料建置自订的原生 UI
- (进阶)订阅 Native Ad 事件通知
- (进阶)订阅影片事件通知
建议您可以在应用程式的 ViewController 内执行上述步骤。
Import VpadnSDKAdKit
首先汇入 SDK ,宣告实作了 VpadnNativeAdDelegate, VpadnMediaViewDelegate protocol 以接收广告状态,同时也宣告了欲在原生广告中呈现的各种元件。 ( 原生广告呈现元件规范请参照Native Ad Spec )
Objective-C
@import VpadnSDKAdKit;
Swift
import VpadnSDKAdKit
宣告 VponNativeAdView 及自定义 UI
对于原生广告,Vpon 提供了继承 UIView
的 VponNativeAdView
型别作为 ad view,每个 VponNativeAdView
对应一个 VponNativeAd
物件。请使用 VponNativeAdView
来展示广告,并且每个欲呈现的 UIView
元件(如:headline、body⋯⋯)都必须是它的 subview。
请依序进行以下步骤来展示 native ad:
- 创建一个
UIView
xib 档案(以下用NativeAdView
为范例),在右上角 Identity inspector 指定 Custom Class 为VponNativeAdView
、Module 指定为VpadnSDKAdKit
,如图:
-
在 .xib 档案中布局您想要的 UI,并将各个 UI 元件(例如:欲呈现 headline 的
UILabel
)连接 IBOutlet 到VponNativeAdView
的对应属性,设定方式如图: *原生广告呈现元件规范请参照 Native Ad Spec如果无法顺利连接 IBOutlet 到
VponNativeAdView
的对应属性,我们提供一个解决方案供参: Objective-C 专案请新创一个 .h 档案 / Swift 专案请新创一个 .swift 档案,并把VponNativeAdView
header 内容贴上如下:
Obejctive-C (VponNativeAdViewCopy.h)
#ifndef VponNativeAdViewCopy_h
#define VponNativeAdViewCopy_h
#endif /* VponNativeAdViewCopy_h */
SWIFT_CLASS("_TtC13VpadnSDKAdKit16VponNativeAdView")
@interface VponNativeAdView : UIView
@property (nonatomic, weak) IBOutlet UIView * _Nullable iconView;
@property (nonatomic, weak) IBOutlet UIView * _Nullable coverImageView;
@property (nonatomic, weak) IBOutlet UIView * _Nullable ratingValueView;
@property (nonatomic, weak) IBOutlet UIView * _Nullable ratingScaleView;
@property (nonatomic, weak) IBOutlet UIView * _Nullable headlineView;
@property (nonatomic, weak) IBOutlet UIView * _Nullable bodyView;
@property (nonatomic, weak) IBOutlet UIView * _Nullable callToActionView;
@property (nonatomic, weak) IBOutlet UIView * _Nullable socialContextView;
@property (nonatomic, weak) IBOutlet VponMediaView * _Nullable mediaView;
@property (nonatomic, weak) IBOutlet UIView * _Nullable advertiseView;
@property (nonatomic, strong) VponNativeAd * _Nullable nativeAd;
- (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER;
@end
Swift (VponNativeAdViewCopy.swift)
import UIKit
import VpadnSDKAdKit
@MainActor @objc @objcMembers open class VponNativeAdView: UIView {
@MainActor @objc @IBOutlet weak public var iconView: UIView?
@MainActor @objc @IBOutlet weak public var coverImageView: UIView?
@MainActor @objc @IBOutlet weak public var ratingValueView: UIView?
@MainActor @objc @IBOutlet weak public var ratingScaleView: UIView?
@MainActor @objc @IBOutlet weak public var headlineView: UIView?
@MainActor @objc @IBOutlet weak public var bodyView: UIView?
@MainActor @objc @IBOutlet weak public var callToActionView: UIView?
@MainActor @objc @IBOutlet weak public var socialContextView: UIView?
@MainActor @objc @IBOutlet weak public var mediaView: VpadnSDKAdKit.VponMediaView?
@MainActor @objc @IBOutlet weak public var advertiseView: UIView?
@MainActor @objc public var nativeAd: VpadnSDKAdKit.VponNativeAd?
}
此时回到 xib 档案,应该就能在右侧栏 Outlets 面板看见 IBOutlet 并且连接。连结成功后即可视需求移除上述的 header copy 档案。
- 确认欲作为 mediaView 的
UIView
于右上角 Custom Class 指定型别为VponMediaView
: - 在您的 view controller 参考下方程式码让
NativeAdView
正确添加到画面上:
Objective-C
#import "VponSdkNativeViewController.h"
#import <VpadnSDKAdKit/VpadnSDKAdKit.h>
@interface VponSdkNativeViewController () <VponNativeAdLoaderDelegate, VponNativeAdDelegate, VponVideoControllerDelegate>
@property (weak, nonatomic) IBOutlet UIView *adContainerView;
@property(nonatomic, strong) VponNativeAdView *nativeAdView;
@end
@implementation VponSdkNativeViewController
- (void)viewDidLoad {
[super viewDidLoad];
_nativeAdView = [[NSBundle mainBundle] loadNibNamed:@"NativeAdView" owner:nil options:nil].firstObject;
[_adContainerView addSubview:_nativeAdView];
_nativeAdView.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[_nativeAdView.heightAnchor constraintEqualToAnchor: _adContainerView.heightAnchor],
[_nativeAdView.widthAnchor constraintEqualToAnchor: _adContainerView.widthAnchor]
]];
}
Swift
class VponSdkNativeViewController: UIViewController {
var nativeAdView: VponNativeAdView!
@IBOutlet weak var adContainer: UIView!
override func viewDidLoad() {
super.viewDidLoad()
guard let nibObjects = Bundle.main.loadNibNamed("NativeAdView", owner: nil, options: nil),
let adView = nibObjects.first as? VponNativeAdView else {
fatalError("Could not load nib file for nativeAdView")
}
nativeAdView = adView
adContainer.addSubview(adView)
nativeAdView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
nativeAdView.widthAnchor.constraint(equalTo: adContainer.widthAnchor),
nativeAdView.heightAnchor.constraint(equalTo: adContainer.heightAnchor)
])
}
初始化 VponNativeAdLoader 物件,并请求广告
要发出广告请求,请按照以下步骤:
- 宣告并初始化
VponNativeAdLoader
物件 - 设定 adLoader 的
delegate
属性,以便收到请求结果 - 呼叫
load(_ request: VponAdRequest)
方法,带入VponAdRequest
参数
请注意:VponNativeAdLoader
物件在广告载入过程一定要保持 strong reference 以免发生错误。
Objective-C
// Must keep a strong reference
@property(nonatomic, strong) VponNativeAdLoader *adLoader;
_adLoader = [[VponNativeAdLoader alloc] initWithLicenseKey:@"License Key"
rootViewController:self];
_adLoader.delegate = self;
[_adLoader load:request];
Swift
let request = VpadnAdRequest()
request.setTestDevices([ASIdentifierManager.shared().advertisingIdentifier.uuidString])
// Set your test device's IDFA here if you're trying to get Vpon test ad
vpadnNative.loadRequest(request)
// start to load ad
Note
- 您可以为每种类型的广告都建立不同的 VponAdRequest 物件,或是在所有的广告请求中都使用同一个 VponAdRequest 物件
- 如果您想要指定更多投放条件,请参考进阶设定
实作 VponNativeAdLoaderDelegate
发出广告请求后,实作 VponNativeAdLoaderDelegate
protocol 来处理请求成功与失败的情况。
- 请求成功时,Vpon SDK 会呼叫
adLoader(_ adLoader: VponNativeAdLoader, didReceive nativeAd: VponNativeAd)
并回传native ad 物件,如想收到native ad 相关事件通知,可以设定delegate
属性,详情参考订阅native ad 事件通知 。 - 请求失败时,Vpon SDK 会呼叫
adLoader(_ adLoader: VponNativeAdLoader, didFailToReceiveAdWithError error: Error)
并回传对应的 error。
Objective-C
- (void)adLoader:(VponNativeAdLoader *)adLoader didReceive:(VponNativeAd *)nativeAd {
nativeAd.delegate = self;
}
- (void)adLoader:(VponNativeAdLoader *)adLoader didFailToReceiveAdWithError:(NSError *)error {
// Handle error
}
Swift
extension VponSdkNativeViewController: VponNativeAdLoaderDelegate {
func adLoader(_ adLoader: VponNativeAdLoader, didReceive nativeAd: VponNativeAd) {
nativeAd.delegate = self
}
func adLoader(_ adLoader: VponNativeAdLoader, didFailToReceiveAdWithError error: Error) {
// Handle error
}
}
利用回传的资料建置自订的原生 UI
当adLoader(_ adLoader: VponNativeAdLoader, didReceive nativeAd: VponNativeAd)
被触发时,即取得可用的广告资料,此时可利用回传的nativeAd 设定您原生广告的标题、内文等文案内容,将资料布局至自定义的UI。设定完广告资料后,请务必设定您 nativeAdView 的 nativeAd
属性,才能让广告正常展示、被点击。
以下为建议的实作方式:
Objective-C
- (void)adLoader:(VponNativeAdLoader *)adLoader didReceive:(VponNativeAd *)nativeAd {
nativeAd.delegate = self;
((UILabel *)_nativeAdView.headlineView).text = nativeAd.headline;
_nativeAdView.mediaView.mediaContent = nativeAd.mediaContent;
if (nativeAd.mediaContent.hasVideoContent) {
nativeAd.mediaContent.videoController.delegate = self;
}
((UILabel *)_nativeAdView.bodyView).text = nativeAd.body;
[((UIButton *)_nativeAdView.callToActionView) setTitle:nativeAd.callToAction
forState:UIControlStateNormal];
((UIImageView *)_nativeAdView.iconView).image = nativeAd.icon.image;
// Necessary to show media content and make it clickable!
_nativeAdView.nativeAd = nativeAd;
}
Swift
extension VponSdkNativeViewController: VponNativeAdLoaderDelegate {
func adLoader(_ adLoader: VponNativeAdLoader, didReceive nativeAd: VponNativeAd) {
nativeAd.delegate = self
(nativeAdView.headlineView as? UILabel)?.text = nativeAd.headline
(nativeAdView.bodyView as? UILabel)?.text = nativeAd.body
(nativeAdView.callToActionView as? UIButton)?.setTitle(nativeAd.callToAction, for: .normal)
(nativeAdView.iconView as? UIImageView)?.image = nativeAd.icon?.image
nativeAdView.callToActionView?.isUserInteractionEnabled = false
nativeAdView.mediaView?.mediaContent = nativeAd.mediaContent
if nativeAd.mediaContent?.hasVideoContent ?? false {
nativeAd.mediaContent?.videoController?.delegate = self
}
// Necessary to show media content and make it clickable!
nativeAdView.nativeAd = nativeAd
}
}
(进阶)订阅 Native Ad 事件通知
要监听 Native Ad 事件,在 adLoader(_ adLoader: VponNativeAdLoader, didReceive nativeAd: VponNativeAd)
设定 nativeAd 的 delegate
属性,并实作 VponNativeAdDelegate
:
Objective-C
// MARK: - VponNativeAdLoaderDelegate
- (void)adLoader:(VponNativeAdLoader *)adLoader didReceive:(VponNativeAd *)nativeAd {
nativeAd.delegate = self;
}
// MARK: - VponNativeAdDelegate
- (void)nativeAdDidRecordImpression:(VponNativeAd *)nativeAd {
// Invoked if an impression has been recorded for an ad.
}
- (void)nativeAdDidRecordClick:(VponNativeAd *)nativeAd {
// Invoked if an click has been recorded for an ad.
}
Swift
// MARK: - VponNativeAdLoaderDelegate
func adLoader(_ adLoader: VponNativeAdLoader, didReceive nativeAd: VponNativeAd) {
nativeAd.delegate = self
}
// MARK: - VponNativeAdDelegate
func nativeAdDidRecordImpression(_ nativeAd: VponNativeAd) {
// Invoked if an impression has been recorded for an ad.
}
func nativeAdDidRecordClick(_ nativeAd: VponNativeAd) {
// Invoked if an click has been recorded for an ad.
}
(进阶)订阅影片事件通知
要监听 native ad 影片事件,在 adLoader(_ adLoader: VponNativeAdLoader, didReceive nativeAd: VponNativeAd)
时设定 videoController 的 delegate
属性,并实作 VponVideoControllerDelegate
:
Objective-C
// MARK: - VponNativeAdLoaderDelegate
- (void)adLoader:(VponNativeAdLoader *)adLoader didReceive:(VponNativeAd *)nativeAd {
nativeAd.mediaContent.videoController.delegate = self;
}
// MARK: - VponVideoControllerDelegate
- (void)videoControllerDidPlayVideo:(VponVideoController *)videoController {
}
- (void)videoControllerDidPauseVideo:(VponVideoController *)videoController {
}
- (void)videoControllerDidMuteVideo:(VponVideoController *)videoController {
}
- (void)videoControllerDidUnmuteVideo:(VponVideoController *)videoController {
}
- (void)videoControllerDidEndVideoPlayback:(VponVideoController *)videoController {
}
Swift
// MARK: - VponNativeAdLoaderDelegate
func adLoader(_ adLoader: VponNativeAdLoader, didReceive nativeAd: VponNativeAd) {
nativeAd.mediaContent?.videoController?.delegate = self
}
// MARK: - VponVideoControllerDelegate
func videoControllerDidPlayVideo(_ videoController: VponVideoController) {
}
func videoControllerDidPauseVideo(_ videoController: VponVideoController) {
}
func videoControllerDidEndVideoPlayback(_ videoController: VponVideoController) {
}
func videoControllerDidMuteVideo(_ videoController: VponVideoController) {
}
func videoControllerDidUnmuteVideo(_ videoController: VponVideoController) {
}
Native Ad Spec
红色
表示您必须显示的原生广告元件,其中 CoverImage 与 Icon 必须至少显示其中一个。
Properties | Description | VponNativeAd Properties |
---|---|---|
AdLabel | 让使用者了解此为广告 (例如:赞助、广告 等等) | advertise |
Title | 最少需显示8个中文字, 放不下时须显示... |
headline |
CoverImage | 1200 x 627px (可等比例缩放,不可变形,不可裁切) | coverImage |
Icon | 128 x 128px (可等比例缩放,不可变形,不可裁切) | icon |
CallToAction | 需要完整显示 | callToAction |
BodyText | 最少显示20个中文字,或不要显示 | body |
Tips
确认广告曝光是否成功发送
请注意,Vpon SDK 不允许广告以以下方式呈现,致使广告在画面上可能不可见:
- 将 AdView 设为 Hdden
- 将 AdView 的 Alpha 值设为 < 100%
- AdView 被其它 View(s) 遮盖住
当广告露出在页面上并达到曝光标准后,会印出以下的 Log 代表有送出广告曝光:
<VPON> [NOTE] Send impression successfully
下载范例
本页以基本的 Native Ad 为例进行说明, Sample Code 中另有 Table View 的范例以供参考。
适用于 Vpon SDK v5.6.0 以下版本的串接方法
如果您想了解 Vpon SDK v5.6.0 以下版本的串接方法,请参考原生广告