亿帆SDK对接文档: V5.0.0
1.开发文档修改记录
版本号 | 修改内容 | 更新步骤 | 更新时间 |
---|---|---|---|
5.0.0 | 2023.09.13 |
2.支持的SDK平台及广告位
平台 | 版本 | 开屏广告 | 激励视频 | 横幅广告 | 插屏广告 | 信息流广告 | 全屏视频广告 |
---|---|---|---|---|---|---|---|
穿山甲 | 5.2.0.5 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
优量汇 | 4.14.42 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
百青藤 | 5.313 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
快手 | 3.3.51.1 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
注意: 1.该版本是基于上述SDK平台版本进行开发的 2.SDK支持的架构有:armv7 x86_64 arm64 3.支持iOS版本为9.0及以上
3. 快速接入
3.1 开发环境准备
- 开发工具:推荐使用Xcode 12及以上版本
- 部署目标:iOS 9.0及以上版本
- 开发管理工具:CocoaPods
3.2 引入SDK
方法一:
右键点击工程,选择“添加文件到...”,选择解压SDK包后得到的FCAdsSDK.framework,点击“添加”。或者将文件拖入XCode工程目录结构中,在弹出的界面中勾选“将项复制到目标组的文件夹中(如果需要)”,并确保“添加到目标”复选相应的target。同时将FCAdsSDK.framework目录下的FCAdsSDK.bundle文件导入Xcode。
方法二(推荐):
通过Cocoapods导入第三方广告SDK,以及第三方依赖(如果遇到拉不下来,可能是github访问问题,可以使用VPN解决)。
#优量汇⼴告
pod 'GDTMobSDK', '4.14.42'
#穿⼭甲⼴告
pod 'Ads-CN', '5.2.0.5'
#快⼿⼴告SDK
pod 'KSAdSDK', '3.3.51.1', :inhibit_warnings => false
#百度⼴告SDK
pod 'BaiduMobAdSDK', '5.313'
注意事项:
1.HTTP权限设置:
设置HTTP权限请求,需要在info.plist中添加一条App Transport Security Settings,添加Allow Arbitrary Loads(NSAllowsArbitraryLoads),值为YES。
2.删除Scene:
1.首先直接删除SceneDelegate.h .m文件 2.在AppDelegate.h添加@property (strong, nonatomic) UIWindow * window;属性 3.移除AppDelegate中的UIScene代理 4.最后在info.plist文件中移除Application Scene Manifest
3.头文件冲突:
如果遇到头文件冲突的问题,可能是,other linker flags的设置问题。删除TARGETS->Linking->Other Linker Flags中的-all_load
4.Bitcode:
由于第三方库的原因,我们需要在Xcode中关闭Bitcode。设置TARGETS->Build Settings->Enable Bitcode为NO。
5.位置权限:
如果应用开启了位置权限,SDK可以获取应用位置信息用以精准推送广告,需要在应用的信息.plist中添加相应权限提示信息,避免AppStore审核被拒:
Privacy - Location When In Use Usage Description
Privacy - Location Always and When In Use Usage Description
Privacy - Location Always Usage Description
Privacy - Location Usage Description
6.iOS14适配(重要):
由于iOS14.5系统策略更新,我们需要在App中添加SKAdNetwork标识和ATT权限,以避免广告收益降低。
1.升级穿山甲iOS SDK 3.4.2.3及以上版本,升级广点通4.12.3及以上版本,提供了iOS14与SKAdNetwork支持 2.将SKAdNetwork ID添加到info.plist中,以保证SKAdNetwork的正确运行,以下内容复制到您的info.plist中,
穿⼭甲:238da6jt44.skadnetwork,22mmun2rn5.skadnetwork,x2jnk7ly8j.skadnetwork
⼴点通:f7s53z58qe.skadnetwork
爱奇艺:27a282f54n.skadnetwork
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>238da6jt44.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>22mmun2rn5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>f7s53z58qe.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>r3y5dwb26t.skadnetwork</string>
</dict>
</array>
3、获取App Tracking Transparency 权限,请更新您的 Info.plist,添加 NSUserTrackingUsageDescription 字段和自定义文槐描述
<key>NSUserTrackingUsageDescription</key>
<string>该标识符将⽤于向您投放个性化⼴告</string>
4、从 iOS 14 开始,在应用程序调用 App Tracking Transparency 向用户提跟踪授权请求之前,IDFA将不可用。如果应用未提出此请求,应用获取到的 IDFA 将自动清零,可能会导致您的广告收入的降低
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import <AdSupport/AdSupport.h>
- (void)requestIDFA {
[ATTrackingManager
requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthoriza
tionStatus status) {
}];
//
[self loadAd];
}
3.3 跳转须知
广告接口中的所有ViewController均为必传项,用来处理广告跳转。SDK中的所有跳转均采用present的方式进行,请确保传入的rootViewController不能为空且没有present其他的控制器,否则会出现presentedViewController已经存在而致present失败。
3.4 请求失败可能的原因
- 应用包名,appID, appKey, posID 必须匹配。(不能直接用demo中的appkey和posID在你的工程中请求广告)。
- 确保网络连接正常。(可用Wi-Fi和手机网络分别请求广告验证)。
- 同一天,同一设备,广告展示有次数限制。(可更换不同设备请求广告)。
- 测试设备不要限制广告跟踪(广告请求需要获取idfa)。
- 广告请求不能保证每次都有广告返回。(广告不能频繁请求)。
3.5 初始化SDK及全局配置
[FCAdSDKManager setupSDKWithAppId:@"c5074e30-2310-4bf3-958a-5c933f029f4c" config:^FCAdSDKConfig * (FCAdSDKConfig * c) {
#ifdef DEBUG
// 打开日志开关,线上环境请关闭z
c.level = FCAdLogLevel_Info;
#endif
c.customIDFA = @"00000000-0000-0000-0000-000000000001";
return c;
}];
3.6 扩展字段参数
目前支持多维度的扩展字段,可以设置自定义数据,后台可以根据维度做云控和数据统计
#import <FCAdsSDK/FCAdSplash.h>
4. 广告渲染
4.1 开屏广告
*开屏广告目前不支持横屏,支持的广告源:穿山甲、广点通、快手、百度
添加头文件
#import <FCAdsSDK/FCAdSplash.h>
1.请求代码
FCAdSplash *splash = [[FCAdSplash alloc] initWithAdUnitID:@"0bbcfd82-779d-4ff8-9a38-781b31c5ab61"viewController:self];
splash.delegate = self;
splash.showLogoRequire = YES;
splash.logoImage = [UIImage imageNamed:@"app_logo"];
splash.backgroundImage = [UIImage imageNamed:@"LaunchImage_img"];
splash.timeout = 5;
[splash loadAndShowAd];
2.回调方法
/// 广告数据拉取成功
- (void)fcAdUnifiedViewDidLoad {
}
/// 广告曝光成功
- (void)fcAdExposured {
}
/// 广告加载失败
- (void)fcAdFailedWithError:(NSError *)error description:(NSDictionary *)description{
}
/// 内部渠道开始加载时调用
- (void)fcAdSupplierWillLoad:(NSString *)supplierId {
}
/// 广告点击
- (void)fcAdClicked {
}
/// 广告关闭
- (void)fcAdDidClose {
}
/// 广告倒计时结束
- (void)fcAdSplashOnAdCountdownToZero {
}
/// 点击了跳过
- (void)fcAdSplashOnAdSkipClicked {
}
开屏广告闪屏问题 1、首页闪现之后在弹出广告。这种现象对用户体验不友好。我们的方案是backgroundImage需要保持和App启动页一致,这样在加载开屏广告的时候,会覆盖在首页上,用户感受不到是在加载App还是加载广告过程。
4.2 横幅广告
添加头文件
#import <FCAdsSDK/FCAdBanner.h>
1.请求代码
- (void)loadAdAndShow {
UIView *contentV = [[UIView alloc] initWithFrame:CGRectMake(0, 100, self.view.bounds.size.width, self.view.bounds.size.width * 400.0 /600.0)];
[self.view addSubview:contentV];
FCAdBanner * fcAdBanner = [[FCAdBanner alloc] initWithAdUnitID:pID adContainer:contentV viewController:self];
fcAdBanner.delegate = self;
[fcAdBanner loadAndShowAd];
}
2.回调方法
/// 广告数据拉取成功回调
- (void)fcAdUnifiedViewDidLoad {
}
/// 广告加载失败
- (void)fcAdFailedWithError:(NSError *)error description:(NSDictionary *)description{
}
/// 内部渠道开始加载时调用
- (void)fcAdSupplierWillLoad:(NSString *)supplierId {
}
/// 广告曝光
- (void)fcAdExposured {
}
/// 广告点击
- (void)fcAdClicked {
}
/// 广告关闭回调
- (void)fcAdDidClose {
}
4.3 插屏广告
添加头文件
#import <FCAdsSDK/FCAdInterstitial.h>
1.请求代码
- (void)loadAdAndShow {
FCAdInterstitial * fcAdInterstitial = [[FCAdInterstitial alloc] initWithAdUnitID:PID viewController:self];
fcAdInterstitial.delegate = self;
[fcAdInterstitial loadAndShowAd];
}
2.回调方法
/// 广告数据拉取成功回调
- (void)fcAdUnifiedViewDidLoad {
}
/// 广告加载失败
- (void)fcAdFailedWithError:(NSError *)error description:(NSDictionary *)description{
}
/// 内部渠道开始加载时调用
- (void)fcAdSupplierWillLoad:(NSString *)supplierId {
}
/// 广告曝光
- (void)fcAdExposured {
}
/// 广告点击
- (void)fcAdClicked {
}
/// 广告关闭回调
- (void)fcAdDidClose {
}
4.4 全屏视频广告
添加头文件
#import <FCAdsSDK/FCAdFullScreenVideo.h>
1.请求代码
- (void)loadAdAndShow {
FCAdFullScreenVideo * fcAdFullScreenVideo = [[FCAdFullScreenVideo alloc] initWithAdUnitID:@"728b5f9b-9b97-404b-8897-1e7b3d719aaf" viewController:self];
fcAdFullScreenVideo.delegate=self;
[fcAdFullScreenVideo loadAndShowAd];
}
2.回调方法
/// 请求广告数据成功后调用
- (void)fcAdUnifiedViewDidLoad {
}
/// 广告曝光
- (void)fcAdExposured {
}
/// 广告点击
- (void)fcAdClicked {
}
- (void)fcAdFailedWithError:(NSError *)error description:(NSDictionary *)description{
}
/// 内部渠道开始加载时调用
- (void)fcAdSupplierWillLoad:(NSString *)supplierId {
}
/// 广告关闭
- (void)fcAdDidClose {
}
/// 广告播放完成
- (void)fcAdFullScreenVideoOnAdPlayFinish {
}
4.4 激励视频广告
添加头文件
#import <FCAdsSDK/FCAdRewardVideo.h>
1.请求代码
- (void)loadAdAndShow {
FCAdRewardVideo * fcAdRewardVideo = [[FCAdRewardVideo alloc] initWithAdUnitID:PID viewController:self];
fcAdRewardVideo.delegate=self;
[fcAdRewardVideo loadAndShowAd];
}
2.回调方法
/// 广告数据加载成功
- (void)fcAdUnifiedViewDidLoad {
}
/// 视频缓存成功
- (void)fcAdRewardVideoOnAdVideoCached {
}
/// 到达激励时间
- (void)fcAdRewardVideoAdDidRewardEffective {
}
/// 广告曝光
- (void)fcAdExposured {
}
/// 广告点击
- (void)fcAdClicked {
}
/// 广告加载失败
- (void)fcAdFailedWithError:(NSError *)error description:(NSDictionary *)description{
}
/// 内部渠道开始加载时调用
- (void)fcAdSupplierWillLoad:(NSString *)supplierId {
}
/// 广告关闭
- (void)fcAdDidClose {
}
/// 播放完成
- (void)fcAdRewardVideoAdDidPlayFinish {
}
4.5 信息流广告
添加头文件
#import <FCAdsSDK/FCAdNativeExpress.h>
#import <FCAdsSDK/FCAdNativeExpressView.h>
1.请求代码
- (void)loadAdAndShow {
FCAdNativeExpress * advanceFeed = [[FCAdNativeExpress alloc] initWithAdUnitID:PID adContainer:nil viewController:self adSize:CGSizeMake(self.view.bounds.size.width, 0)];
advanceFeed.delegate = self;
[advanceFeed loadAndShowAd];
}
2.回调方法
// 信息流广告比较特殊, 渲染逻辑需要自行处理
- (void)showNativeAd {
for (NSInteger i = 0; i < self.arrViewsM.count; i++) {
FCAdNativeExpressView *view = self.arrViewsM[i];
[view render];
[_dataArrM insertObject:self.arrViewsM[i] atIndex:1];
}
[self.tableView reloadData];
}
/// 广告数据拉取成功
- (void)fcAdNativeExpressOnAdLoadSuccess:(NSArray<FCAdNativeExpressView *> *)views {
NSLog(@"广告拉取成功 %s", __func__);
self.arrViewsM = [views mutableCopy];
if (_isLoadAndShow) {
[self showNativeAd];
}
}
/// 广告曝光
- (void)fcAdNativeExpressOnAdShow:(FCAdNativeExpressView *)adView {
}
/// 广告点击
- (void)fcAdNativeExpressOnAdClicked:(FCAdNativeExpressView *)adView {
}
/// 广告渲染成功
/// 注意和广告数据拉取成功的区别 广告数据拉取成功, 但是渲染可能会失败
/// 广告加载失败 是广点通 穿山甲 mercury 在拉取广告的时候就全部失败了
/// 该回调的含义是: 比如: 广点通拉取广告成功了并返回了一组view 但是其中某个view的渲染失败了
/// 该回调会触发多次
- (void)fcAdNativeExpressOnAdRenderSuccess:(FCAdNativeExpressView *)adView {
[self.tableView reloadData];
}
/// 广告渲染失败
/// 注意和广告加载失败的区别 广告数据拉取成功, 但是渲染可能会失败
/// 广告加载失败 是广点通 穿山甲 mercury 在拉取广告的时候就全部失败了
/// 该回调的含义是: 比如: 广点通拉取广告成功了并返回了一组view 但是其中某个view的渲染失败了
/// 该回调会触发多次
- (void)fcAdNativeExpressOnAdRenderFail:(FCAdNativeExpressView *)adView {
[_dataArrM removeObject: adView];
[self.tableView reloadData];
}
/// 广告加载失败
/// 该回调只会触发一次
- (void)fcAdFailedWithError:(NSError *)error description:(NSDictionary *)description{
[self deallocAd];
}
/// 内部渠道开始加载时调用
- (void)fcAdSupplierWillLoad:(NSString *)supplierId {
}
/// 广告被关闭
- (void)fcAdNativeExpressOnAdClosed:(FCAdNativeExpressView *)adView {
//需要从tableview中删除
[_dataArrM removeObject: adView];
[self.tableView reloadData];
}
// MARK: ======================= UITableViewDelegate, UITableViewDataSource =======================
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// return _expressAdViews.count*2;
// return 2;
return _dataArrM.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([_dataArrM[indexPath.row] isKindOfClass:[BYExamCellModelElement class]]) {
return ((BYExamCellModelElement *)_dataArrM[indexPath.row]).cellh;
} else {
CGFloat height = ([_dataArrM[indexPath.row] expressView]).frame.size.height;
NSLog(@"=======> %f", height);
return height;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
if ([_dataArrM[indexPath.row] isKindOfClass:[BYExamCellModelElement class]]) {
cell = [tableView dequeueReusableCellWithIdentifier:@"ExamTableViewCell"];
((ExamTableViewCell *)cell).item = _dataArrM[indexPath.row];
return cell;
} else {
cell = [self.tableView dequeueReusableCellWithIdentifier:@"nativeexpresscell" forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UIView *subView = (UIView *)[cell.contentView viewWithTag:1000];
if ([subView superview]) {
[subView removeFromSuperview];
}
UIView *view = [_dataArrM[indexPath.row] expressView];
view.tag = 1000;
[cell.contentView addSubview:view];
cell.accessibilityIdentifier = @"nativeTemp_ad";
// [view mas_remakeConstraints:^(MASConstraintMaker *make) {
// make.edges.equalTo(@0);
// }];
return cell;
}
}