Android聚合广告AFP的对接系统设计
工作需要,要对接阿里妈妈的广告聚合平台,简称AFP。对于一般的应用而言,想要流量变现,广告是显而易见的手段,尤其是在中国,打开一个千万级别的用户,肯定有某个地方是有对接广告的,只不过明不明显而已。
阿里妈妈的AFP广告聚合平台说穿了,就是一个平台聚合了多个第三方平台,像是百度,广点通,由他们平台来接入,然后推送相应的广告,当然也包括自售的广告。
如果我们不使用这种聚合平台,又想要提高自己的广告收入,增加广告曝光是唯一的选择,但是广告的填充是个大问题,因为单一的广告平台的物料填充并不能保证百分百,多个平台的接入,对客户端本身又是一个非常大的负担,想想看,要在确定百度平台拉取广告失败的时候,再去调用广点通拉取广告,或者是同时拉取两个平台广告,然后确定优先级,谁是首选,谁是备选,这些都是很头疼的问题,更严重的是,多个平台的SDK的接入,会增加包的体积。
阿里妈妈的AFP聚合平台解决了这个问题,只要接入他们的SDK就行,不用接入其他平台的SDK,因为他们自己后台去调用其他平台的SDK获取对应的广告。
考虑到以后广告的展示形式是多种的,像是开屏,插屏等,当然,AFP本身的API也已经是很简单了,但难免要根据不同的情况进行对应的配置。如果想要更好的管理,可以利用工厂模式+策略模式完成这些不同情况的配置问题。
我们的设想很简单:上层业务不需要理会具体的广告SDK的实现,甚至连对应的库都不用导入,他们只要和一个抽象对接就行,这个抽象就是负责调控和管理各种类型广告。
我们命名为AdManager。
Android的业务单位是Activity,根据AFP的API,我们需要传达的是广告位ID,对应的广告展示形式,广告平台。
AdManager adManager = AdManager.newInstance();
adManager.setup(id, AdManager.ShowType.Welcome, AdManager.Platform.Baidu);
我们并不对AdManager进行单例处理。并不是所有的高级抽象都需要单例处理,相反,单例会造成未知的错误,因为程序共享同一个实例,我们完全无法预知会在哪里这个实例就被修改。
这里的使用场景只要想要就直接new一个就行,不过为了避免每次都要写new代码,就用一个newInstance方法进行封装而已。
setup的代码实现是典型的策略模式,因为这里需要根据传入的广告类型返回不同的配置。
MmuProperties properties = null;
Object controller = null;
switch (showType) {
case Banner:
properties = createBannerProperties(activity, slotId, viewGroup, platforms);
controller = ((BannerProperties) properties).getController();
break;
case Feed:
properties = createFeedProperties(activity, slotId, platforms);
controller = ((MMUFeedProperties) properties).getController();
break;
case Insert:
properties = createInsertProperties(activity, slotId, platforms);
controller = ((InsertProperties) properties).getController();
break;
case LoopImage:
properties = createLoopImageProperties(activity, slotId, viewGroup, platforms);
break;
case Welcome:
properties = createWelcomeProperties(activity, slotId, viewGroup, platforms);
controller = ((WelcomeProperties) properties).getController();
break;
default:
break;
} if (properties == null) {
return null;
} MMUSDKFactory.getMMUSDK().attach(properties);
return controller;
我们不谈里面有关AFP的API调用代码,这里为了实现策略模式,使用了switch+Enum的方式。
在我们刚学习设计模式的时候,就知道策略模式要解决的代码场景是大量if-else if-else的使用,但实际上并不是所有类似这样的使用就必须得用策略模式,设计模式的使用初衷应该是为了让使用场景具有更好的扩展性,而不是针对某部分代码结构的优化,这也是为什么有些人参考了MVP的设计模式对自己应用的架构进行设计后,发现代码的编写更加困难了,而且为了切合MVP模式,对一些无关痛痒的业务场景也进行了非常重的设计,导致代码非但没有更加清晰,反倒更像是某个人的设计模式试验场,要是更加严苛点,就是垃圾场了。
我们这里需要根据不同的广告展示类型来进行不同的配置,这个场景是符合策略模式的使用场景的。虽然只是我们个人的小偏见,就是如果不同的情况如果可以定义为不同的Enum,像是上面的ShowType,就是广告展示类型的Enum,就可以配合Switch使用策略模式,因为可以归类为一个Enum,说明每个Enum实例的确是相同业务场景下需要的一组条件,根据这些条件实施不同的策略。
所以我们这里使用了策略模式。
这里我们可以注意到一个问题:条件不止一组,而是两组。
广告的展示形式是一组,广告的平台也是一组。我们是如何决定哪一组是先决条件呢?
可以明确的说,这两组条件并不分先决和后决之分,在代码组织上,之所以决定展示形式是第一组策略条件,也是第一个判断的条件,单纯只是因为我们觉得,第一组策略条件如果是比较多的,那么耐着性子看到第二组的人,发现第二组条件竟然如此简单,内心可能会有如释重负的感觉,也就是所谓先苦后甜的观后感吧。
当然,要真想找个客观的理由,就是AFP它允许我们自定义第三方平台,假设我们并不想要完全交给他们处理一些问题,像是UI,这点在开屏那里非常明显,虽然不知道具体的原因,但是绝大部分主流的广告平台都不允许暴露开屏数据,而是要交给他们去渲染,而且开屏那里不可避免的一个设计就是跳过按钮,广点通之前的版本是不允许自定义(现在的版本已经可以了),百度是可以的,所以想要加上自己的跳过按钮,就要采取数据对接的方式,这在AFP那里的实现就是让客户自己去定义第三方平台,自己去渲染和添加。
很不幸,我们就是后面那种情况,所以在有了需要添加不同平台的适配这个需求后,我们必须要构建一个广告平台的工厂类,来帮助我们更好的管理不同 的平台。
所以,我们的一个小小的经验就是:如果两组条件,其中某组条件是另一组条件中的共性,类似广告的展示形式是每个平台都应该具备的,可以将这组共性的条件放在第一个策略组中。
上面我们提到了广告平台的工厂类,这个类是很重要的,因为我们需要一个抽象来负责管理这些自定义的平台的调度,并且AdManager本身提供的应该是实现某种展示的广告平台,而根本无需理会这些不同广告平台是如何产生的,这并不是它的职责。
在考虑代码结构设计时,职责是一个很重要的概念。某个类应该承担什么样的职责,决定了这个类在整个设计中的角色。
AdManager这个抽象我们赋予的意义就是提供某种展示形式的广告,至于什么样的广告,这个并不是它决定的,根据单一职责的设计要求,它承担的职责已经足够了,决定广告平台的应该是另一个类。
我们将这个职责交给了AdAdapterFactory。
bannerProperties.addCustomAdapter(AdId, (MMUBannerCustomAdapter) AdAdapterFactory.createAdAdapter(platform, ShowType.Banner));
AdAdapterFactory需要产生对应广告展示形式的不同平台的适配器,所以这里又涉及到了策略模式。
switch (platform) {
case Baidu:
adAdapter = createBaiduAdAdapter(showType, viewGroup);
break;
case GDT:
adAdapter = createGDTAdAdapter(showType, viewGroup);
break;
default:
break;
}
值得注意的是,这里同样涉及到广告展示形式和广告平台两组条件,但是第一组条件的选择和AdManager是相反的。
我们的选择依据其实非常简单:AdManager注重的是广告平台的选择,而AdAdapterFactory更加注重的是广告展示形式的选择。
AdManager要解决的问题其实是展示什么平台的广告,因为它调度的是不同广告平台,而AdAdapterFactory要解决的问题是根据需要的广告平台去调用他们对应广告展示形式的API。
所以我们在选择策略条件组的先后顺序的时候,明确的条件组会放在第一组,而核心条件组放在第二组,强调核心问题永远都是放在最后最关键的地方,保证阅读代码的人在看到对应代码时候,是跟着业务场景中问题的明确度来的。
问题的明确度简单来讲,就是我们在解决一个问题的时候,就知道该问题的明确条件。
当我们调用AdManager的时候,我们就知道需要的广告展示形式,开屏的位置肯定是需要开屏的广告展示,但是不知道广告平台是如何选择的,所以这里的明确条件就是广告展示形式。
调用AdAdapterFactory的时候,我们也是明确知道要调度的广告平台,但是不知道该平台对应广告展示形式的代码。
createBaiduAdAdapter的核心是根据对应的展示形式选择对应的适配器:
switch (showType) {
case Banner:
break;
case Feed:
break;
case Insert:
break;
case LoopImage:
break;
case Welcome:
adapter = new BaiduWelcomeAdapter(viewGroup);
break;
default:
break;
}
到了这里,我们整体的广告管理设计系统的大概实现就已经出来,剩下的只是根据具体的情况做具体的调整。
虽然只是简单的业务场景代码,但我们在编码的时候,要考虑到业务本身的核心点在哪里,然后围绕这个核心点会有什么样的问题,如何去解决这样的问题,代码设计上如何更好的体现这些问题的解决思路,就是我们平时做业务时需要考虑的。
很多人都会抱怨自己刚出来工作,只是做一些简单的业务,类似我这种广告接入业务,本身就不具有任何技术含量,但编码质量水平并不取决于是否解决多复杂的问题,也不取决于能够解决更多问题,重要的是立足于当前问题提供更好更方便的思路。
Android聚合广告AFP的对接系统设计的更多相关文章
- 浅谈Android的广告欢迎界面(倒计时)
前些时候就是别人问我他的android APP怎么做一个广告的欢迎界面,就是过几秒后自动跳转到主界面的实现. 也就是下面这种类似的效果.要插什么广告的话你就换张图吧. 那么我就思考了下,就用了andr ...
- Android O HIDL的实现对接【转】
本文转载自:https://blog.csdn.net/gh201030460222/article/details/80551897 Android O HIDL的实现对接1. HIDL的定义1.1 ...
- 项目源码--Android聚合视频类播放器
下载源码 技术要点: 1.高效支持主流的视音频格式 2.本地视频的播放与管理 3.聚合电视在线直播 4.聚合优酷.搜狐.乐视.爱奇艺等多种在线视频 5.优质播放,包含播放.暂停,声音.亮度调整等功能 ...
- 新浪微博2.5.1 for Android 去广告
新浪微博更新到2.5.1版,就开始来广告了,伤不起啊... 亲,看到没,手机屏幕就那么一小块,还要往里面塞东西,另外是一个在后台运行的AdCenter服务. 所需要用到的工具有:apktool,JD- ...
- Android设备广告投放解决方案——大量网络图片、多个网络视频的轮播、缓存与更新
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7742996.html 一:业务场景 基于Android系统的设备上投放广告,诸如:地铁广告屏.自助服务机器上的 ...
- Android实现广告页图片无限轮播
一.概述 对于一个联网的Android应用, 首页广告无限轮播基本已经成为标配了. 那么它是怎么实现的呢? 有几种实现方式呢? 二.无限轮播的实现 1.最常规的手段是用 ViewPager来实现 2. ...
- Android平台Camera2数据如何对接RTMP推流到服务器
1. Camera2架构 在Google 推出Android 5.0的时候, Android Camera API 版本升级到了API2(android.hardware.camera2), 之前使用 ...
- android中广告轮播图总结
功能点:无限轮播.指示点跟随.点击响应.实现思路: 1.指示点跟随,指示点通过代码动态添加,数量由图片数量决定. 在viewpager的页面改变监听中,设置点的状态选择器enable,当前页时,set ...
- Android学习笔记_64_手机安全卫士知识点归纳(4) 流量统计 Log管理 混淆打包 加入广告 自动化测试 bug管理
android 其实就是linux 上面包装了一个java的框架. linux 系统下 所有的硬件,设备(网卡,显卡等) 都是以文件的方式来表示. 文件里面包含的有很多设备的状态信息. 所有的流量相关 ...
随机推荐
- 在CentOS上搭建svn服务器及注意事项
系统环境 CentOS 5.9 推荐使用yum install安装,比较简单 一.检查是否已经安装其他版本svn # rpm -qa subversion #卸载svn # yum remove ...
- 实现Ogre的脚本分离 - 天龙八部的源码分析(一)
目的 在研究天龙八部游戏的源码之时, 发现 Ogre 材质的模板部分被单独放在一个 material 文件之内, 继承模板的其他材质则位于另外的文件, 当我使用Ogre 官方源码, 加载脚本时其不会查 ...
- css使一行文字竖向排列
.tnt { margin:0 auto;width:20px;line-height:24px;} <div class="tnt" > <asp:Label ...
- SQLSERVER的一个不显眼的功能 备份文件的分割
SQLSERVER的一个不显眼的功能 备份文件的分割 当完整备份数据库的时候,我们有时候可能会遇到一种极端情况,比如服务器上C,D,E三个盘符都只剩下5G空间了 但是如果要完整备份业务库需要12G的空 ...
- Mac OS X上编写 ASP.NET vNext 系列中断和再开声明
这个系列其实已经中断有一段时间了,主要是由两个原因: 第一是微软那边把以前的KRE改成了XRE,所以导致前两篇有点过时了. 第二是自己年前1月份被裁员,Mac的机器被回收,再加上忙于和公司扯皮和找工作 ...
- objective-c(协议)
objective-c中不支持多重继承,其替代方案为Protocal(协议),下面给出一个基本实例: 定义一个协议 @protocol MyProtocal <NSObject> //协议 ...
- 作业八—Alpha阶段项目总结
一.项目的预期目标: 我们的图书管理系统之前的目标是做出可以让读者和管理员采用不同的搜索方式,并且时要做到读者和管理者两种不同的方式的!但是我们目前做到了部分搜索方式和管理员界面,主要原因是该项目如果 ...
- DDD领域驱动设计之聚合、实体、值对象
关于具体需求,请看前面的博文:DDD领域驱动设计实践篇之如何提取模型,下面是具体的实体.聚合.值对象的代码,不想多说什么是实体.聚合等概念,相信理论的东西大家已经知晓了.本人对DDD表示好奇,没有在真 ...
- 在.net中使用aquiles访问Cassandra(四)
数据的持久化我们都已经完成了,和所有应有程序一样,最重要的是要向用户展示数据.下面我们就推出这部分代码,读取任意行任何列: public IList<TRowResult> Execute ...
- Java8的新特性以及与C#的比较
函数式接口 VS 委托 在C中,可以使用函数指针来存储函数的入口,从而使得函数可以像变量一样赋值.传递和存储,使得函数的调用变得十分灵活,是实现函数回调的基础.然而函数指针不存在函数的签名信息,甚至可 ...