如果想在自己的应用中添加广告来增加收入的话,首先得具备一定的广告基础知识,此篇文章就是记录自己在学习在移动app端植入广告过程中的随笔。
首先得了解一些广告相关的术语:
广告平台:在国外常用的广告平台主要有facebook、admob、mopub等。这些广告平台的实际差别并不是很大,facebook的相对来说投放更加精准,admob的广告相对来说填充率会高,mophb则在美国地域优势明显一些。我们要做的通过对比不同广告平台的变现效率,选择其中与自己的产品匹配度好的广告平台作为主要的,然后保持一定的小流量测试其他广告平台的效果,用来做对比,然后根据效果选择最适合自己应用的平台。多平台的选择也能尽可能的降低应用中多个广告位出现同一广告的概率。
eCPM:是衡量广告效果的指标,你每展示一千次广告,能赚多少钱。这个指标是我们主要参考的因素,也是我们在应用中定义广告优先级的优选参考因素,一般情况下eCPM高的广告我们应该让他尽可能优先展示。
CTR:广告的点击率,点击率=点击数 / 浏览量
F.R.:填充率,广告的展示数/广告请求数。至于广告为什么请求了,却无法展示,可以简单的认为有很多的发布商在请求展示一个广告主的广告。这样一来,广告网络的服务器便会超负荷,并且会退出展示请求的广告,导致广告的填充率通常达不到理想状态的高百分比。填充率也是我们配置广告需要考虑的因素,因为eCPM高的广告通常填充率会低一些,所以在配置广告的时候要搭配合适,即最大程度保证eCMP高的广告展示的情况下,又不会出现请求不到广告的情况,导致广告位落空的窘况。
广告id:你可以简单的理解为就是一个展示广告的屏幕,就像我们在坐电梯里看到的那种播放广告的小荧幕。
CPM: Cost Per Mille ,千人展现成本,衡量广告效果的一种基本形式。按CPM计费模式的广告,只看展现量,按展现量收费、不管点击、下载、注册什么的。
CPC: Cost Per Click ,没产生一次点击所花费的成本。按点击采取收费的一种广告模式。在CPC的收费模式下,不管广告展现了多少次,只要不产生点击,广告主是不用付费的。只有产生了点击,才按点击数进行付费。
CPA: Cost Per Action,按行动收费。通俗的说就是在执行广告的投放的过程中,广告主与代理会事先约定好,按广告转换而来的安装,注册,购买等行为付费。在广告投放的过程中,只有产生了约定的行为才按量收费。
下面附一张模式图
关于广告系统背后的算法,有想了解的也可以自己去网上找,这里推荐一篇Facebook广告系统背后的Pacing算法
关于广告的在应用中的植入步骤我在这里不细说,FB的官网上和对应其他广告平台的官网上介绍的比较详细。简单的介绍下关于广告的形式:主要分为横幅广告:Banner Ads,主要是长而窄的横幅广告,因为尺寸所限,展示的广告内容较少,所以效果相对其他形式而言较差一些。插屏广告:全屏显示,可以是视频或其他形式的媒体单元,具有强烈的视觉冲击效果,此类广告所展示的内容丰富多彩,通常有较高的点击率。原生广告:原生广告让您能设计与应用完美契合的广告单元。借助广告平台的原生广告 API,可以容易的决定广告的外观、风格、尺寸和位置。由于可自行决定广告的格式,因此广告能与应用无缝衔接。
在应用中集成广告需要考虑的因素很多,下面简单说说一些注意点。
首先是广告配置文件加载策略:
采用三级缓存:首先是跟随包的json文件,保证能拿到广告配置。其次是内存缓存,再次是本地Document缓存。
配置文件更新时机:开启应用/后台进入前台
比如第一次开启应用时,此时会判断本地的配置文件版本与线上的版本,然后会去加载线上最新的配置文件,加载成功后会写入本地缓存。
杀了应用再进入应用时,此时首先判断线上 本地的配置文件版本与线上的版本一样,就不会异步请求最新的配置文件,内存中没有值,本地缓存已写入了文件,所以会从本地缓存中拿配置文件。
应用在后台时,更改了线上的配置文件,首先会判断configVersion与本地存的值是否不同,此时进入前台会同步最新的config1,但是这是一个异步请求,广告的加载没法等到这个请求回来,广告会在第一时间加载,所以加载的还是之前缓存的config0,但config的异步同步可能已经完成了config1。所以再次退到后台进入前台时,此时如果发现config有更新,会继续异步同步config2,但是如果没有发现更新会去缓存拿之前异步加载好的config1。这里简单介绍下iOS沙盒目录和应用程序包
沙盒目录主要包括三个子文件夹Documents、Library和tmp,每个文件夹的作用是不同的,以下分别介绍这三个子文件夹。
获取沙盒目录子文件夹路径可以使用NSHomeDirectory方法然后拼接Documents/ Library / tmp字符串的方式,也可以使用NSSearchPathForDirectoriesInDomains方法直接获取。
Documents目录
可读写的文件夹,可以用来存放图片,视频和其他重要数据。通过iTunes备份,应用程序升级时,不会改变里面的内容。
- 1.获取Documents文件夹的代码:
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
- 2.Library
获取Library文件夹的代码
NSString *library = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
打开文件夹,可以看到,Library文件夹下有两个子文件夹Preference和Cache。
- 1.Preference
主要用来存放配置文件、NSUserDefault 、plist文件等,通过iTunes备份,应用升级时,不会改变里面的内容。
- 2.Cache
Cache多用来保存临时数据、缓存文件等,iTunes不会备份此文件夹下的内容,有有效期限制。
- 3.tmp
存放临时数据,iTunes不会备份此文件夹下的内容,当应用程序关闭时,文件就被清空了。
获取tmp文件夹的代码:
NSLog(@"%@",NSTemporaryDirectory());
- 应用程序包
沙盒目录是用来保存App运行过程中产生的数据的,除了沙盒目录以外,App还有一个应用程序包目录,该目录不可读写,主要用来保存我们编写的程序、资源、xib文件等,比如我们在编写程序时拖入Xcode的图片资源就存放在这个包目录里。
每次应用启动时,会对包里面的所有数据进行CRC校验,如果增加、删除、修改里面的内容,则CRC校验,就会识别,应用程序将无法启动。
通常我们想要获取App目录里的内容,都是使用NSBundle获取。
1.使用NSBundle加载图片
NSBundle *bundle = [NSBundle mainBundle];
NSString *imageNamed = [bundle pathForResource:@"imageName" ofType:@"jpg"];
//通过文件全路径加载图片,无缓存
//imageNamed方法有缓存
UIImage *image = [UIImage imageWithContentsOfFile:imageNamed];
2.使用NSBundle加载xib文件
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"CenterView" owner:nil options:nil];
CenterView *cv =[nibViews objectAtIndex:0];
这里简单说一种广告的加载策略:
按优先级高到低请求,成功则显示,失败则请求下一个。代码简单展示
private func loadSingleAd(configure:[高到低优先级排序过广告模型], index:Int, view:InnerAdContainer) {
var adAdmin:BaseInnerAd?
self.isLoading = true
//判断广告类型,不同的广告采用不同的初始化方式
switch config.adUnitType ?? "" {
case AdType.NativeCoverOnTop.rawValue:
adAdmin = FbNativeAd.create()
adAdmin?.show(vc, view: view, adInfo: self.adInfo)
break
case AdType.Rect.rawValue:
adAdmin = AdmobRectAd()
adAdmin?.show(vc, view: view, adInfo: self.adInfo)
break
case AdType.VerseAdvance.rawValue:
adAdmin = AdmobNativeAd()
adAdmin?.show(vc, view: view, adInfo: self.adInfo)
break
case AdType.NativeHeight100.rawValue:
adAdmin = FBHeight100Ad()
adAdmin?.show(vc, view: view, adInfo: self.adInfo)
break
case AdType.NativeResult.rawValue:
adAdmin = FbNativeAd.create()
adAdmin?.show(vc, view: view, adInfo: self.adInfo)
break
default:
return
}
let priority = adAdmin?.adInfo?.adUnitPriority ?? 0
(adAdmin as? UIView)?.hidden = true
//调用广告的请求广告的方法
adAdmin?.requestAd()
//广告的block回调,判断广告是否加载成功
adAdmin?.addObserver({ (height, width, adView, isSuccess) in
//如果成功
if isSuccess {
self.isLoading = false
//通知代理显示广告
self.delegate?.showAdSuccess(height,width:width,adView:adView)
} else {
//如果失败了,index+1,如果没有越界,继续调用自己递归判断
let nextIndex = index + 1
if nextIndex < configArr.count {
self.loadSingleAd(configArr, index: nextIndex, view:view)
} else {
self.isLoading = false
}
}
})
}
}