#pragma mark - 申请IDFA权限
#import <AdSupport/AdSupport.h>
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#warning - iOS 15,申请广告权限弹窗,要在applicationDidBecomeActive执行
- (void)applicationDidBecomeActive:(UIApplication *)application {
if (@available(iOS 14, *)) {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
}];
}
}
根据苹果App Store隐私规则(《用户隐私和数据使用》以及《应用商店上的应用程序隐私详细信息》),自2020年12月8日起,新App和App更新需向App Store Connect提交App隐私信息的答复。为便于开发者掌握SDK收集的数据类型、使用目的,为开发者提供如下说明文档,以便开发者在其App隐私信息答复中补充SDK数据收集和使用情况。
CocoaPods是一个Swift和Objective-C项目的依赖管理器。它拥有超过49,000个第三方库,超过3,000,000个app都在使用cocoaPods做依赖管理,CocoaPods可以帮助你优雅的扩展你的项目。 如果您未安装过cocoaPods,可以通过以下命令行进行安装。更多详情请访问CocoaPods官网。
$ sudo gem install cocoapods
在您的工程文件所在文件夹下有一个名为Podfile的文件。如果您第一次使用CocoaPods,可以在通过以下命令初始化一个Podfile文件:
$ pod init
打开Podfile文件,应该是如下内容(具体内容可能会有一些出入):
# platform :ios, '9.0'
target 'podTest' do
# use_frameworks!
# Pods for podTest
end
修改Podfile文件,将pod与source添加到Podfile中,如下所示:
source 'https://gitee.com/mobad/Specs.git'
source 'https://github.com/CocoaPods/Specs.git'
# platform :ios, '9.0'
target 'podTest' do
# use_frameworks!
pod 'Aspects'
pod 'AFNetworking'
pod 'MJExtension'
pod 'ReactiveObjC'
pod 'SDWebImage'
pod 'Ads-CN', '~> 4.3.0.5'
pod 'GDTMobSDK', '~> 4.13.53'
pod 'KSAdSDKFull', '~> 3.3.28'
pod 'SigmobAd-iOS', '~> 3.5.4'
pod 'MobADSDK', '~> 2.4.11'
# Pods for podTest
end
通过CocoaPods安装SDK前,确保CocoaPods索引已经更新。可以通过运行以下命令来更新索引:
$ pod repo update
运行命令进行安装:
$ pod install
也可以将上述两条命令合成为如下命令:
$ pod install --repo-update
详见文章尾部其他问题2
// 创建初始化配置实例
MobADConfigModel *config = [[MobADConfigModel alloc] init];
// 渠道id,必填(由我司分配),下面的是测试用
config.appId = @"ba0063bfbc1a5ad878";
/***********关于userId的设置**********/
// userId为可选参数,但是设置userId可以方便追查问题,请接入方按下面步骤设置
// 1.如果已登录,可以直接在初始化的时候设置userId
// config.userId = @"userId007";
// 2.如果未登录,可以在登录成功后获取配置,再设置userId
// MobADConfigModel *config = [MobADSDKApi getConfig];
// config.userId = @"userId";
// 3.退出登录后,置空userId
// MobADConfigModel *config = [MobADSDKApi getConfig];
// config.userId = nil;
// 设置跳转scheme , 浮标广告需要设置,URL Type需要同步设置
config.scheme = @"com.scheme.cn";
// 初始化SDK
BOOL result = [MobADSDKApi setupWithConfig:config];
NSLog(@"MobADSDK setup success:%d", result);
NSLog(@"MobADSDK version:%@", [BloomADSDKApi sdkVersion]);
/**
* 显示开屏广告(不需要自己添加View)
* @param window App根window
* @param placeholder 加载开屏广告时的占位视图
* @param customSkipView 自定义跳转按钮
* @param customView 显示在开屏广告底部的自定义视图(一般可以放上logo)
* @param timeout 超时时间(1-10秒)
* @param launch 是否是启动,从后台进入前台设置NO
* @param group 广告组,一般可以传@"s1"
*/
+ (UIView *)splashAdViewFromWindow:(UIWindow *)window delegate:(id<MADSplashAdCallbackDelegate>)delegate placeHolder:(UIView *)placeholder customSkipView:(UIView *)customSkipView customView:(UIView *)customView timeout:(CGFloat)timeout isLaunch:(BOOL)launch group:(NSString *)group;
/**
* SDK 开屏广告回调接口
* @param event MADSplashAdCallbackEvent枚举类型
* @param error 错误信息
* @param info 包含 id
*
*/
- (void)ad_splashAdCallbackWithEvent:(MADSplashAdCallbackEvent)event error:(NSError *)error andInfo:(NSDictionary *)info;
AppDelegate.m
@interface AppDelegate ()<MADSplashAdCallbackDelegate>
@property (nonatomic, strong) UIView *splashView;
@end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/*
SDK初始化
*/
// 开屏广告
// 开屏占位视图(加载开屏广告时的占位视图)
LaunchPlaceHolder *placeHolder = [LaunchPlaceHolder loadViewFromXib];
placeHolder.frame = self.window.bounds;
// 开屏自定义logo视图(显示在开屏广告底部)
SplashLogoView *logoView = [SplashLogoView loadViewFromXib];
logoView.frame = CGRectMake(0, 0, self.window.bounds.size.width, floor(self.window.bounds.size.height/4.0));
UIButton *custormSkipButton = [UIButton buttonWithType:UIButtonTypeCustom];
[custormSkipButton setTitle:@"跳转" forState:UIControlStateNormal];
[custormSkipButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[custormSkipButton addTarget:self action:@selector(skipButtonTapped) forControlEvents:UIControlEventTouchUpInside];
custormSkipButton.frame = CGRectMake(self.window.bounds.size.width - 56 - 12, 88, 56, 36);
// 加载开屏
self.splashView = [MobADSDKApi splashAdViewFromWindow:self.window delegate:self placeHolder:placeHolder customSkipView:custormSkipButton customView:logoView timeout:3 isLaunch:YES group:@"s1"];
return YES;
}
- (void)skipButtonTapped {
if ([self.splashView respondsToSelector:@selector(hideSplash)]) {
[self.splashView performSelector:@selector(hideSplash)];
}
[self.splashView removeFromSuperview];
self.splashView = nil;
}
回调:
- (void)ad_splashAdCallbackWithEvent:(MADSplashAdCallbackEvent)event error:(NSError *)error andInfo:(NSDictionary *)info {
NSLog(@"splash event:%zd, error:%@, info:%@", event, error, info);
// 移除开屏
if (event == MADSplashAdCallbackEventAdDidClose || event == MADSplashAdCallbackEventNoAd || event == MADSplashAdCallbackEventAdLoadError) {
[self.splashView removeFromSuperview];
self.splashView = nil;
}
}
#pragma mark - 激励视频
/** 获取激励视频广告加载器实例
* @return 激励视频广告加载器实例
*/
+ (id<MADRewardVideoAdManagerProtocol>)rewardVideoAdManager;
/**
* 加载激励视频
* @param vc 广告展示基于的viewController
* @param delegate 回调代理
* @param timeout 超时时间
* @param group 广告组,一般可以传@"rv1"
*/
- (void)loadRewardVideoWithViewController:(UIViewController *)vc delegate:(id<MADRewardVideoAdCallbackDelegate>)delegate timeout:(CGFloat)timeout group:(NSString *)group;
/**
* SDK 激励视频广告回调接口
* @param event MADRewardVideoCallbackEvent枚举类型
* @param error 错误信息
* @param info 包含 id
*
*/
- (void)ad_rewardVideoCallbackWithEvent:(MADRewardVideoCallbackEvent)event error:(NSError *)error andInfo:(NSDictionary *)info;
@interface RewardVideoVC ()<MADRewardVideoAdCallbackDelegate>
{
id<MADRewardVideoAdManagerProtocol> _rewareVideoAd;
UILabel *_loading;
}
@end
@implementation RewardVideoVC
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)loadRwardVideo:(id)sender {
// 显示loading
UILabel *loading = [[UILabel alloc] initWithFrame:self.view.bounds];
loading.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3];
loading.text = @"加载中。。。";
loading.textAlignment = NSTextAlignmentCenter;
loading.textColor = [UIColor whiteColor];
[self.view addSubview:loading];
_loading = loading;
// 生成激励视频加载器
if (!_rewareVideoAd) {
_rewareVideoAd = [MobADSDKApi rewardVideoAdManager];
}
// 加载激励视频
[_rewareVideoAd loadRewardVideoWithViewController:self delegate:self timeout:10 group:@"rv1"];
}
- (void)ad_rewardVideoCallbackWithEvent:(MADRewardVideoCallbackEvent)event error:(NSError *)error andInfo:(NSDictionary *)info {
if (event == MADRewardVideoCallbackEventAdLoadSuccess || event == MADRewardVideoCallbackEventAdLoadError) {
[_loading removeFromSuperview];
}
NSLog(@"reward video -> event:%zd, %@", event, error);
// 奖励成功弹窗
if (event == MADRewardVideoCallbackEventAdDidClose) {
// 模拟奖励到达上限
static int i = 0;
BOOL didReachLimit = NO;
if (i > 1) {
didReachLimit = YES;
}
i++;
if (didReachLimit) {
[PopTipView showOnWindowWithDuration:-1 info:@{@"text": @"当日奖励已达上限"}];
} else {
NSInteger rewardNum = arc4random_uniform(5) + 5;
[RewardPopView showOnWindowWithDuration:1.5 info:@{@"text": [NSString stringWithFormat:@"金币+%zd个", rewardNum]}];
}
}
}
/** 获取横幅广告加载器实例
* @return 横幅广告加载器实例
*/
+ (id<MADBannerAdManagerProtocol>)bannerAdManager;
/**
* 加载横幅广告
* @param frame 广告的位置和大小
* @param vc 广告展示基于的viewController
* @param delegate 回调代理
* @param interval 轮播间隔时间(30-120秒)
* @param group 广告组,一般可以传@"b1"
*/
- (void)loadBannerAdWithFrame:(CGRect)frame viewController:(UIViewController *)vc delegate:(id<MADBannerAdCallbackDelegate>)delegate interval:(NSInteger)interval group:(NSString *)group;
/**
* SDK 横幅广告回调接口
* @param event MADBannerAdCallbackEvent枚举类型
* @param error 错误信息
* @param info 包含 id
*
*/
- (void)ad_bannerAdView:(UIView<MADBannerAdViewProtocol> *)adView callbackWithEvent:(MADBannerAdCallbackEvent)event error:(NSError *)error andInfo:(NSDictionary *)info;
@interface BannerAdVC ()<MADBannerAdCallbackDelegate>
{
id<MADBannerAdManagerProtocol> _bannerAd;
__weak UIView *_bannerView1;
}
@end
@implementation BannerAdVC
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
CGFloat width = [UIScreen mainScreen].bounds.size.width;
// 生成bannerAd加载器
_bannerAd = [MobADSDKApi bannerAdManager];
// 加载bannerAd
[_bannerAd loadBannerAdWithFrame:CGRectMake(0, 100, width, width / 6.4) viewController:self delegate:self interval:30 group:@"b1"];
}
// 回调
- (void)ad_bannerAdView:(UIView<MADBannerAdViewProtocol> *)adView callbackWithEvent:(MADBannerAdCallbackEvent)event error:(NSError *)error andInfo:(NSDictionary *)info {
NSLog(@"banner ad event:%zd, info:%@, error:%@, group:%@", event, info, error, adView.group);
if (event == MADBannerAdCallbackEventAdLoadSuccess) {
[self.view addSubview:adView];
if (adView != _bannerView1) {
_bannerView1 = adView;
}
} else if (event == MADBannerAdCallbackEventAdDidClose) {
[_bannerAd removeBannerAd:adView];
[adView removeFromSuperview];
adView = nil;
}
}
@end
/**
* 显示插屏广告
* 随机显示不同大小的插屏广告
* @param vc 广告展示基于的viewController
* @param delegate 回调代理
* @param group 广告组,一般可以传@"i1"
*/
+ (void)showInterstitialAdWithViewController:(UIViewController *)vc delegate:(id<MADInterstitialAdCallbackDelegate>)delegate group:(NSString *)group;
/**
* SDK 插屏广告回调接口
* @param event MADInterstitialAdCallbackEvent枚举类型
* @param error 错误信息
* @param info 包含 id
*
*/
- (void)ad_interstitialAdCallbackWithEvent:(MADInterstitialAdCallbackEvent)event error:(NSError *)error andInfo:(NSDictionary *)info;
@interface InterstitialAdVC ()<MADInterstitialAdCallbackDelegate>
{
UILabel *_loading;
}
@end
@implementation InterstitialAdVC
- (void)viewDidLoad {
[super viewDidLoad];
}
// 点击加载
- (IBAction)loadIntersticialAd:(id)sender {
// 显示loading
UILabel *loading = [[UILabel alloc] initWithFrame:self.view.bounds];
loading.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3];
loading.text = @"加载中。。。";
loading.textAlignment = NSTextAlignmentCenter;
loading.textColor = [UIColor whiteColor];
[self.view addSubview:loading];
_loading = loading;
// 加载插屏广告
[MobADSDKApi showInterstitialAdWithViewController:self delegate:self group:@"i1"];
}
// 回调
- (void)ad_interstitialAdCallbackWithEvent:(MADInterstitialAdCallbackEvent)event error:(NSError *)error andInfo:(NSDictionary *)info {
NSLog(@"intersticial ad event:%zd, error:%@, info:%@", event, error, info);
if (event == MADInterstitialAdCallbackEventAdWillVisible || event == MADInterstitialAdCallbackEventAdLoadError) {
[_loading removeFromSuperview];
}
}
@end
/** 获取原生广告加载器实例
* @return 原生广告加载器实例
*/
+ (id<MADNativeExpressAdManagerProtocol>)nativeExpressAdManager;
/**
* 加载原生模板广告
* @param count 加载个数(以实际返回的为准)
* @param width 原生广告的宽度
* @param delegate 回调代理
* @param group 广告组,一般可以传@"n1"
*/
- (void)loadNativeExpressAdWithCount:(NSInteger)count width:(CGFloat)width delegate:(id<MADNativeExpressAdDelegete>)delegate group:(NSString *)group;
// 广告加载成功/失败
- (void)ad_nativeExpressAdManager:(id<MADNativeExpressAdManagerProtocol>)manager didFinishLoad:(NSArray<id<MADNativeExpressAdProtocol>> *)ads error:(NSError *)error;
// 渲染成功
- (void)ad_nativeExpressAdViewRenderSuccess:(id<MADNativeExpressAdProtocol>)ad;
// 渲染失败
- (void)ad_nativeExpressAdViewRenderFail:(id<MADNativeExpressAdProtocol>)ad;
// 广告展示
- (void)ad_nativeExpressAdViewWillShow:(id<MADNativeExpressAdProtocol>)ad;
// 点击广告
- (void)ad_nativeExpressAdViewClicked:(id<MADNativeExpressAdProtocol>)ad;
// 点击关闭
- (void)ad_nativeExpressAdViewClosed:(id<MADNativeExpressAdProtocol>)ad reason:(NSString *)reason;
详见Demo中原生模板广告(NativeAdVC)
/** 获取Draw视频广告加载器实例
* @return Draw视频广告加载器实例
*/
+ (id<MADExpressDrawVideoAdManagerProtocol>)expressDrawVideoAdManager;
/**
* 加载Draw视频广告
* @param vc 广告展示基于的viewController
* @param delegate 回调代理
* @param count 加载个数(以实际返回的为准)
* @param size 视频宽高
* @param cfg 其他配置信息(bottomOffset:按钮距离底部距离)
* @param group 广告组,一般可以传@"dv1"
*/
- (void)loadVideoAdWithViewController:(UIViewController *)vc delegate:(id<MADExpressDrawVideoAdCallbackDelegate>)delegate adCount:(NSInteger)count adSize:(CGSize)size config:(NSDictionary *)cfg group:(NSString *)group;
// 广告加载成功/失败
- (void)ad_drawVideoAdManager:(id<MADExpressDrawVideoAdManagerProtocol>)manager didFinishLoad:(NSArray<id<MADExpressDrawVideoAdProtocol>> *)ads error:(NSError *)error;
// 广告即将展现
- (void)ad_drawVideoAdViewWillShow:(NSString *)adId;
// 广告点击
- (void)ad_drawVideoAdViewDidClick:(NSString *)adId;
// 视频播放状态改变
- (void)ad_drawVideoAdView:(NSString *)adId stateDidChanged:(MADPlayerPlayState)playerState;
// 视频播放结束
- (void)ad_drawVideoAdPlayerDidPlayFinish:(NSString *)adId error:(NSError *)error;
详见Demo 中 Draw视频广告(DrawVideoAdVC)
#pragma mark - DrawFeed视频
/** 获取DrawFeed视频加载器实例
* @param delegate delegate回调
* @param backImage 返回按钮图片,若不需要,传nil。
* @param group 广告组,一般可以传@"df1"
* @return DrawFeed视频加载器实例
*/
+ (UIViewController *)drawFeedViewControllerWithDelegate:(id<MADDrawFeedCallbackDelegate>)delegate backImage:(UIImage *)backImage group:(NSString *)group;
/**
* publicContentId : 内容标识
* type : 内容类型 Unknown:未知,正常不会出现; Normal:普通信息流; Ad:广告;
*/
// 视频开始播放
- (void)ad_drawFeedDidStartPlay:(NSString *)publicContentId type:(MADVideoType)type;
// 视频暂停播放
- (void)ad_drawFeedDidPause:(NSString *)publicContentId type:(MADVideoType)type;
// 视频恢复播放
- (void)ad_drawFeedDidResume:(NSString *)publicContentId type:(MADVideoType)type;
// 视频停止播放
- (void)ad_drawFeedDidEndPlay:(NSString *)publicContentId type:(MADVideoType)type isFinished:(BOOL)finished;
// 视频播放失败
- (void)ad_drawFeedDidFailedToPlay:(NSString *)publicContentId type:(MADVideoType)type withError:(NSError *)error;
详见Demo
/** 获取EntryElement视频加载器实例
* @return EntryElement视频加载器实例
*/
+ (id<MobDrawEntryElementCallbackProtocol>)drawEntryElementAdManager;
/**
* 加载DrawEntry视频
* @param delegate 回调代理
* @param width View宽度(默认为屏幕宽度)
* @param group 广告组,一般可以传@"de1"
*/
- (void)loadDrawEntryElementWithDelegate:(id<MobDrawEntryElementCallbackDelegate>)delegate group:(NSString *)group;
- (void)loadDrawEntryElementWithDelegate:(id<MobDrawEntryElementCallbackDelegate>)delegate width:(CGFloat)width group:(NSString *)group;
/// 成功回调通知
/*
通过 entryView 获取具体的视图
entryExpectedSize 为期望的宽高
*/
- (void)ad_entryElementSuccessToLoad:(id<MobEntryElementProtocol>)entryElement;
/// 点击单个feed事件回调
/*
内部构造 UIViewController
外部对 viewController 处理,具体 push / present 或者 容器组操作
*/
- (void)ad_entryElement:(id<MobEntryElementProtocol>)entryElement didFeedClickCallBack:(id<MobContentPageProtocol>)contentPage;
/// 失败回调
- (void)ad_entryElement:(id<MobEntryElementProtocol>)entryElement didFailWithError:(NSError *_Nullable)error;
详见Demo中DrawEntry视频(DrawEntryViewController)
/** 获取浮标广告入口View
* @return 浮标广告入口View
*/
+ (UIView *)floatADViewWithGroup:(NSString *)group delegate:(id<MADFloatViewCallbackDelegate>)delegate;
/**
* SDK 浮标广告回调接口
* @param event MADFloatViewEvent枚举类型
* @param error 错误信息
* @param info 包含 id
*
*/
- (void)ad_floatViewCallbackWithEvent:(MADFloatViewEvent)event error:(NSError *)error andInfo:(NSDictionary *)info;
详见Demo
CPA 任务平台是一个用户互助、接单赚钱的众包平台。接入 CPA 任务平台可以有效提升 App 留存和用户活跃度,助力项目构建完善的生态系统。
CPA 任务平台以 H5 方式接入,需要 WebView 支持跳转外链等能力。
CPA 任务平台支持手机号登录、与接入方的用户系统打通的静默登录两种方式。静默登录接入 CPA 任务平台具体示例详见 Demo 中的 MoreVC。
服务端通知回调接口和更多其他接入方式请参考 CPA 任务接入文档。
#import <MobADSDK/MobADSDK.h>
@interface MoreVC ()<WKNavigationDelegate>
@property (nonatomic, strong) MobADJSWebView *webView;
@end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
/**
* 1、在Info.plist中添加CFBundleLocalizations字段,并增加zh_CN元素,webview中调用系统方法将显示为中文(如:调用系统相机、相册)。
* 2、添加相机、相册相关权限
* Privacy - Photo Library Additions Usage Description
* Privacy - Photo Library Usage Description
* Privacy - Camera Usage Description
**/
#warning 使用MobADJSWebView的前提条件是已经设置了config.userId 否则会弹出请先登录APP的弹框
NSURL *url = [NSURL URLWithString:@"https://squirrel.kxbwmedia.com/ditch/task?union_id=10013"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.allowsInlineMediaPlayback = YES;
if (@available(iOS 10.0, *)) {
config.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
} else {
config.mediaPlaybackRequiresUserAction = NO;
}
self.webView = [[MobADJSWebView alloc] initWithFrame:self.view.bounds configuration:config];
[self.webView loadRequest:request];
self.webView.navigationDelegate = self;
[self.view addSubview:self.webView];
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL *URL = navigationAction.request.URL;
NSString *url = [URL absoluteString];
if ([url hasPrefix:@"weixin://"]) {
if ([[UIApplication sharedApplication] canOpenURL:URL]) {
[[UIApplication sharedApplication] openURL:URL];
}
decisionHandler(WKNavigationActionPolicyCancel);
} else {
decisionHandler(WKNavigationActionPolicyAllow);
}
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.webView.frame = self.view.bounds;
}
接口头文件 MobADSDKApi.h 查看
/**当前:2.1.0(1)
* SDK 版本
*/
+ (NSString *)sdkVersion;
sudo sh install.sh
git lfs version
然后再 pod install
pod install
结束后,查看/Pods/Bytedance-UnionAD目录的大小,如果只有几百KB,说明安装失败,请先清除pod的本地缓存(pod cache clean Bytedance-UnionAD),再重新pod install