说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

从友盟微社区看Android第三方SDK架构实践

HTML文档下载 WORD文档下载 PDF文档下载
第三方SDK的开发需要考虑很多因素,比如稳定性、灵活性等,并且还要做到能让开发者能自由定制UI层、替换子系统。本文以友盟微社区为例,详细讲解了在开发SDK时架构方面的设计理念。

开发Android第三方SDK说难不难,但说简单也不简单,要开发一个给很多人使用的第三方SDK,如何在保证稳定性的同时,增强SDK的灵活性,让开发者能自由定制UI层、替换子系统,这是一个值得思考的问题。为了解决这个问题,开发第三方SDK必须要有良好的应用架构。本文就分享一下我在开发友盟微社区SDK时在架构方面的一些想法。

友盟的微社区是一款帮助开发者在应用中快速搭建一个社区(类似于新浪微博、朋友圈),目前正在内测当中。

技术架构

从项目结构上来说,友盟微社区SDK可以简单分为如下三层。

  • UI层(开源)。UI层对外开放,目的是让用户能够定制微社区的UI效果,使微社区SDK能够很自然的融入到用户的App中。
  • 业务逻辑层。业务逻辑层会通过一个统一的接口向UI层提供数据请求等功能,比如获取缓存的feed、好友列表等,因此业务逻辑层对于用户来说是一个数据操作接口,通过这个接口用户能够与SDK核心层进行一些数据方面的操作。
  • 核心层。核心层则包含了友盟SDK的核心系统抽象,比如账户系统、推送、数据库、网络操作等,这一层对外封闭,用户可以通过一些接口与核心层进行交互。而核心层定义的抽象使得用户可以很方便的实现定制化,即自己实现抽象接口,然后将具体的实现注入到微社区中,从而使自己的子系统替换掉微社区中的默认实现。

如图1所示,SDK层次非常分明,通过这三个层次的隔离,使得用户既可以自定义最外层的UI效果,也对外隐藏了业务逻辑层、核心层的实现细节。而核心层定义的子系统抽象,使得用户可以注入自己的实现,保证了整个微社区SDK的灵活性、扩展性。

图1 洋葱结构图


简单来说,就是用户在UI层通过逻辑层暴露的通用接口来操作SDK,从封闭的核心系统中获取、存储数据以及其他的相关操作。层次结构如图2所示。

图2 层次结构图

图1、图2都显示了SDK是通过不同的层次来分离职责,是一个较为典型的架构形式。对于用户来说,最关心的莫过于可定制化。UI层开放源码,自然可以通过修改代码来实现。其他的定制化用户就需要依赖注入来实现。微社区SDK内部依赖于抽象,而不依赖于具体实现,并且用户可以注入具体实现。也就是说用户可以根据我们的抽象接口实现自己的子系统,然后注入到SDK内部,SDK此时就会使用用户注入的实现,这样就达到了子系统替换的效果,也就是我们说的定制化。

友盟微社区的定制化

如何满足定制化?

那么如何来实现定制化呢?友盟微社区SDK内部定义了一些抽象,比如Loginable、Pushable、ImageLoader来分别代表登录系统接口、推送接口、图片加载接口,每种接口都有一个SDKManager来进行管理。比如管理登录子系统的就是LoginSDKManager,用户可以往这个Manager里面添加、移除具体的登录系统实现,然后通过useThis函数来指定使用某个具体的实现(SDK Manager里面可能有多个实现)。结构图如图3所示。


图3  LoginSDKManager功能

SDK Manager是一个泛型类,类型T就代表了接口类型,比如上述的Loginable等。通过泛型我们就可以将这些通用的添加、移除实现等操作抽象化,避免重复代码。代码如下所示:

public abstract class SDKManager<T> {

  //泛型Map

 private Map<String, T> mImplMap = new HashMap<String, T>();

 // 要使用的实现的key

 private String mCurrentKey = "";

 public void addImpl(String key, T impl) {

 mImplMap.put(mCurrentKey, impl);

  }

 public void removeImpl(String key) {

 mImplMap.remove(mCurrentKey);

  }

 public void useThis(String key) {

 mCurrentKey = key;

  }

 public T getCurrentImpl() {

 return mImplMap.get(mCurrentKey);

  }

}

代码很简单,就是在SDK Manager内部维护了一个Map,key是用户为这个实现指定的一个字符串值,value就是具体的实现。用户可以通过这个key来移除实现,更常用的是我们需要调用useThis(String key)接口来指定使用某个具体的实现。 

我们并没有直接使用SDKManager,因为它是一个抽象泛型类,因此我们定义了一些子类来对不同的实现进行管理,这些子类都是单例类,例如LoginSDKManager,代码如下所示。

public final class LoginSDKManager extendsSDKManager<Loginable> {

 // 单例对象

 static LoginSDKManager sInstance = new LoginSDKManager();

 private LoginSDKManager() {

  }

 // 获取单例对象

 public static LoginSDKManager getInstance() {

 return sInstance;

  }

}

在用户需要对登录系统进行管理时,通过LoginSDKManager.getInstance()就可以获取到负责管理登录系统的SDKManager,此时用户可以通过addImpl(String key, T impl)、useThis(String key)等接口对登录系统进行管理,这就可以灵活使用用户自定义的子系统。

示例

下面还是以一个示例来说明问题吧。在与用户沟通的过程中,我们发现登录模块是用户自定义概率最高的子系统。通常情况下,用户可能有自己的账户系统或者使用了第三方登录,此时用户就不需要友盟微社区SDK中附带的登录实现,完全依赖自己的账户系统或者其他第三方登录SDK来实现一个登录系统。下面我们就以实现登录系统(其他子系统的自定义原理一样)来演示自定义过程。在开始之前,我们需要对登录的抽象接口Loginable进行了解。代码如下所示:

public interface Loginable {

 public void login();

 public void logout();

 public boolean isLogined();

}

  • login():登录函数,用户需要在登录成功后将用户信息回调给友盟微社区SDK(具体过程可以参考友微社区集成文档http://dev.umeng.com/wsq/android/detail-integration#1);
  • logout():登出函数,注销用户的登录即可;
  • isLogined():用户是否登录,返回true表示已登录,否则为未登录。

微社区SDK内部通过抽象了几个简单接口来定义登录模块的功能,用户通过实现这几个函数即可定制自己的登录系统,最后将实现注入到SDK即可。例如,如果你的应用中已经有了自己的账户系统逻辑,你可以在Loginable的几个函数中通过调用你的账户系统逻辑实现这几个功能;如果你使用了友盟社会化组件那么你可以通过该社会化组件的登录、登出功能实现对应的功能,例如你可以在login()函数中调用UMSocialService对象的doOauthVerify(Context context、SHARE_MEDIA platform、UMAuthListenerlistener)接口来实现登录。

一句话概括就是:自定义一个实现了Loginable接口的类,在这个类的各个函数中调用你原有的登录、登出、判断是否已登录的函数来实现对应的功能。实现了登录类之后,通过LoginSDKManager的addImpl(String key, Loginable impl)来将该实现注入到SDK中,最后通过LoginSDKManager的useThis(String key)函数来指定要使用的登录实现,这个key就是addImpl(String key、Loginable impl)中设置的key。

自定义登录类示例代码如下:

/**

* 友盟社会化组件的登录实现,这里可以替换成自己的账户系统、第三方登录等,实现几个接口函数即可。

*/

public class SocialLoginImpl implementsLoginable {

 @Override

  public void login() {

 // 登录的具体实现,可以调用你自己的登录代码或者第三方SDK的登录函数

  }

 @Override

 public void logout() {

 // 登出的具体实现,可以调用你自己的登录代码或者第三方SDK的登录函数

  }

 @Override

 public boolean isLogined() {

 // 检测是否登录

 return true /* 代码省略 */;

  }

}

**注入登录实现 :** 

// 登录系统管理器

LoginSDKManager loginMgr =LoginSDKManager.getInstance() ;

// key

String clzKey =SocialLoginImpl.class.getName() ;

// 注入实现

loginMgr.addImpl(clzKey, newSocialLoginImpl());

// 指定使用的具体实现

loginMgr.useThis(clzKey);

为了更简单,这个过程被我们封装到一个函数中,使用的代码最后简化为 : 

// 一行代码搞定!这个函数封装了上述所有的代码。

LoginSDKManager.getInstance().addAndUse(newSocialLoginImpl()) ;

通过这几步,登录系统就被替换掉了。当微社区需要登录时,微社区SDK就会通过LoginSDKManager获取当前使用的登录实现,然后触发login()函数,此时就会执行你的登录代码了。登录成功之后,通过login()函数的回调listener(这个简单示例中没有给出该listener,具体可参考友盟微社区使用已有账户系统)将用户信息传回给友盟SDK,就完成了整个登录过程。

目前友盟微社区SDK还处在内测阶段(内测申请地址:http://wsq.umeng.com/),不过已经可以投入使用。已经有一部分集成了友盟微社区的App上线,并且运行良好。希望本文能有开发第三方Android SDK的同学一些帮助,让开发中的坑更少一些。

本文作者:何红辉,Android工程师,现任职于友盟。乐于分享,热爱开源,开源项目有AndroidEventBus、android-tech-frontier、Android源码设计模式分析。

CSDN博客:http://blog.csdn.net/bboyfeiyu,GitHub
主页:https://github.com/bboyfeiyu


游戏手柄也能编程 极客打造不用键盘输入的IDE 开源不只是程序员的专利 政府也可以 开源搜索Elasticsearch:PB级数据的快速搜索 月下载量已达20万次 乐视网联手富士康推超级电视 欲颠覆传统盈利/营销模式 IBM 2012IT实践达人赛圆满落幕 宣布成立新兴技术大学 对比MapReduce 流处理框架没有所谓的查询层 美国政府:修复漏洞仍有风险 应禁用Java插件 AppGlu应用辅助工具:帮助开发者处理善后工作 iOS!你这几个方面该向Android好好学习 小于1%,中国有真正自主的移动操作系统吗? 张小龙专访系列(下):不一样的产品思维 Gartner:截止到2016年公有云市场复合增长为17.7% Appcore:在企业内部部署IaaS平台 B轮融资600万美元 超现实主义!用脑电波控制你的计算机设备 搜狐否认“情理之中”的退市 上市仍是最优选择 六大BaaS产品推荐:移动开发必备的后端云服务 未遵守承诺 微软遭遇欧盟7.31亿美元巨额罚单 PaaS正能量:6人团队,仅1人全职后端 支撑6000万用户 三星:我不抽成,收益100%让开发者拿去! 腾讯开放平台推“送红利计划” 承诺半年内不参与分成 JavaEE快速开发框架Wabacus 4.0发布,开发效率提高五倍以上 市盈率创新高 谷歌为什么会在苹果博弈中暂时胜出 从Rovio遇到危机,看现在应用市场的演变 Windows Azure支持Android应用 面向东亚推广云服务 抛弃DRAM、拥抱闪存,Facebook重做Memcached 夏普三星联姻 电子行业或将多元化发展 从下拉菜单设计细节看Amazon对用户体验的把握 Chartboost美女CEO:40人团队服务3亿移动玩家 Distimo:新晋开发者想让产品得到关注越来越难 OpenFeint绝迹后,开源项目OpenKit继续前进 美FDA通过搜索引擎和社交平台预警药品副作用 hehe GCC不认识sockaddr_in,但认识sockaddr,哪位大侠指点一下是什么地方没有配置好 asp中的过程和函数是否可以传递两个以上的参数? 假设我在dataGrid中的修改某一个单元格内容之后,焦点还没有离开,再去保存,就保存不了! 求助!!!鲁文易盘无法驱动,急!!!!!!!!!! 为什么只能用localhost访问? 还是烦人乱码问题~~JSP 连不上网。 人家说我有热情没天分,当不了程序员 中秋节给大家助助兴,小游戏一只,最终获胜的可获全部分数,100大分哦! 简单问题,急! 请教零长度问题(不好意思没分了救命啊) 请教零长度问题(不好意思没分了救命啊) sizeof的问题 今天的最近一问.... 写一个参数有默认值的函数出现的问题! 请教零长度问题(不好意思没分了救命啊) 有个关于可见性的问题,请指点, Delphi6中控制Excell2000的Chart的问题 看哪个地方出名人多 c++ 求学 (更上一层楼) 请教零长度问题(不好意思没分了救命啊) 高分寻求jtest4.5的破解 或注册方法 关于批量删除不同目录下相同文件的问题。 如何在VFP中运行VFP代码? 如何调用chm帮助文件? iptables问题 请教零长度问题(不好意思没分了救命啊) 大家來討論工作的問題 能用c语言编有关网络的程序吗?谢谢大侠们了:) 要在程序中控制在DBCHART显示不同颜色部分的内容及数值,如'34 丰田',来者有分? 提个建议:在祝福 璇玑大力 的贴子中,有不少的“名句妙词”,我们花点时间,搜集于一贴,同意的举手!(我的分数太紧张) 低级问题:如何把TFileStream中的一个字节读到一个byte变量中? 串口编程问题 jsp+mysql用的的resin服务器,运行一段时间,网站访问速度就很慢了,一般会是什么原因引起的呢? 两个字符串,前面是任意字符,后面必须是数字,怎么验证这两个字符串前面的字符是否一样? 怎么才能不关?? 祝大家中秋节快乐,进来帮小妹一把!关于JavaMail收邮件的问题! 一段列表筐代码不知道能不能短一些(请高手帮忙) 一个关于安装控件的问题? 请教SNMP的命令? Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); 如何在formload时就确定TabControl1显示第3页?菜鸟提问 css的问题,如何使字体大一点??? 紧急求救 datagrid选中的颜色(我重新画了一个datagrid,设置颜色) 在access中如何控制查询 avg(某字段)的小数位数,比如要两位小数 如何起死回生 一道题目 做文件上传系统时,当上传较大容量的文件时如大于2M的文件时出差,请问是什么问题? 请教一个insert into select...语句的问题! 18世纪末19世纪初期,中国正处在哪个封建王朝的统治下 正方形ABCD的边长大于4.正方形ABCD的边长大于4.厘米,如果从距离4个顶点2厘米处沿45度画线,将正方形分成5部分,那么中间阴影部分的面积是( ). 果园里桃树的棵树比梨树的棵树多560棵,桃树的棵树是梨树的2.4倍,桃树和梨树各有多少棵?(列方程解答) 全部,不想做了, 已知反比例函数经过点A(4,3),B(3,m) 1:求点B的坐标.2:求证:角AOx=角BOy 黄色帽子应该配什么颜色的围巾 三人()()填空,成语 三人成什么【成语】 利用幂的运算性质计算:(根号5)×(5分之根号5)的负2次×五次根号(25分之1) 18世纪末19世纪初,中国正处在哪个封建王朝的统治下? 18世纪末19世纪初,中国正处于哪个封建王朝的统治下? 肯德基“半价桶”遭遇争论 小薯条代替宁海查获一万多罐假红牛 包装味道都和外国驻韩外交官5年犯法48起 外交豁农业部:农垦有望率先实现农业现代化朴槿惠为韩职棒总决赛开球 穿日本运动美媒揭白宫工作准则:不让总统为坏消息叙利亚总统警告:外国停止支持反对派才杨澜提问郎朗\"工作有何意义\"惹争金华餐饮业遭遇寒流 高档酒店与农家乐奥巴马医改网站安全漏洞细节曝光 内测金华看守所推启迪教室 给在押未成年人乱批评员工,小心遭殃!全球首款骨传导手机完秒iPhone 一个晚上,14道难题,陈春花把领导力英格兰海岸: 灯塔与航标的邮轮之旅吉利7月销量分析:一招鲜能够吃遍天下『artnet丨盘点』 In & O盘点超级联赛那些非ban必选的英雄香港 | Haven 避风塘内的古推荐 | 京沪粤一周活动好用助手2.0新增“达人部落” 告自主SUV中的下一匹黑马,没准就是它重生之财源滚滚百鬼全书最强宫主乐在江湖血刀客三国之黄巾无敌官盗四门死亡骨牌限时杀戮红绫魂妻憾梦西游路环村旅游禹王宫旅游世界性文化博物馆旅游飞虎队纪念馆旅游帽峰山旅游永登青龙山旅游大兴南海子麋鹿苑旅游南海子郊野公园旅游梅岭休闲度假区旅游金象山滑雪场旅游北山摩崖造像旅游
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘