前言

最近由于工作需要,将应用里的部分功能独立了出来,封装成 SDK 提供给合作伙伴使用。由于经验不足,网上也没多少写这方面内容的文章,遇到了不少的坑,决定记录下来。

SDK

其实,刚说到要写SDK也有点慌,印象中SDK一直是个复杂的东西,脑海中浮现的是Java SDK ,Android SDK这类庞然大物。
SDK全称 Software Development Kit,广义上的 SDK 是为特定的软件包、软件框架、硬件平台、操作系统等建立应用程序时所使用的开发工具的集合,狭义上的 SDK 则是基于系统 SDK 进行开发包装的、新的、独立的、能够完成特定功能并返回相关数据的一组工具的集合。
听起来一愣一愣的,其实,将一些业务逻辑独立出来,打包成jar、so、aar,暴露一些APIs给外部调用,也可以称为SDK。如推送SDK,支付SDK,地图SDK...既然是所谓的集合,那么自然有大有小。
下面说说我在封装SDK与使用的时候遇到的那些事,希望对大家有些帮助吧!

一、二次打包aar

大多时候,我们的业务依赖于第三方库,载体可能为jar、so、aar,如果是jar包那好办,直接丢进libs目录下就可以了;so库就不简单了,不少开发商只提供少数abi的so库,这时就需要根据需求选择了,要么全部一份,要么只保留一个目录,否则就会报错;aar则是包含了代码、资源(图片、布局等)、so库等的集合。
那么需求来了,如何将第三方aar包二次封装,加入自己的业务逻辑再打包成一个aar呢?其实这个问题我也没有找到直接的解决方案,如果你有,请联系我,感激不尽!但是这个问题又是可以曲线解决的,aar其实就是个压缩包而已,如下图所示:

 
aar解压包.png

Android Studio导入aar时也是将其视为一个module(library),使用其中的classes以及其他资源文件,那我们可不可以直接将其解压,直接导入?这样就避免了在aar的基础上封装成aar!跳过这个坑?实践证明确实是可以的。如果你要封装的aar只包含了jar包和so库,那就简单了,解压出来分别导入项目相关目录即可!不然可能就要手动合并某些资源了...更新:详情请看 二次打包(封装)AAR实用指南
还是期待谷歌能给出一个傻瓜式的一键合并方案吧!

二、SDK中Application对象的初始化

有次SDK接入方反馈说某个地方崩溃了,一看Log,是调用Application对象中的方法空指针了。我一想,混淆?不是。导入姿势不对?不是。文档没认真看?也不是?Demo可以正常运行啊......随即想到是接入方自定义Application对象的问题。
如果aar中定义了Application,theme,icon,那么编译时就要抛出如下异常:

 
编译错误AndroidManifest合并异常

由于项目与aar都定义了自己的Application,编译器不知道用谁的,这就产生了上图的异常,按照提示,在Application标签下添加如下代码:

tools:replace="android:name"

合并方案可以参考官方文档:合并多个清单文件| Android Studio - Android Developers
理虽如此,但是你很大概率就掉坑了,这个方案直接将SDK中的Application对象替换为你的,换句话说就是SDK中的Application对象根本没有初始化,这就是上文说的空指针的罪魁祸首了!确实之前在写文档的时候没有考虑到自定义Application的情况,还是经验不足啊!甚至一度将Application里初始化的方法全部移出来,后来转念一想,让接入方继承我的Application不就OK了吗!!测试一波,赶紧更新下文档,不然又被吐槽了...这下理解为什么接入某些第三方SDK时,有的会要求继承SDK里定义的Application对象。

三、Application多继承

作为一个SDK提供方,假如你的SDK需要用户继承你的Application,我觉得应当提供一个Application多继承的解决方案,毕竟用户可能不仅仅只用你一个SDK,当有多个SDK有这个需求时就尴尬了。
java 多继承,这里的需求是继承两个类,并不是通过实现接口的方式“继承”多个接口上的方法声明。语言原生不支持,这样就比较麻烦了。解决办法如下:
通过接口实现 + 反射 的方式来创建代理Application对象,曲线实现Application的多继承,由于代码较多,这里就不贴源码了,解决方案:ApplicationProxyDemo 源码配合注释食用,风味更佳!

四、导入aar的两种方法

解决一:采用Android Studio新建module的方法,选择jar/aar即可。

 
导入.AAR

解决二:使用gradle脚本直接导入:

  1. 在项目build.gradle文件内android{}标签中加入如下代码申明本地仓库:
repositories {
flatDir {
dirs 'libs'
}
}
}
  1. 然后将aar包放入libs目录(没有就在app目录下创建一个),随后加入dependencies :
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
...
compile(name: 'xxxxxx-xxxx', ext: 'aar') //name为aar文件全名
}

解决三:来自网友精彩评论:

implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])

五、SDK中不可忽视的混淆问题

  1. 常规的避免混淆,比如一些第三方类库中的要求
  2. 避免混淆对外提供方法与数据实体的类,并且添加到接入方的proguard-rules.pro中。

最后

其实在最近的SDK开发与对接中遇到了不少问题,但是也学到了不少东西,由于缺少相关经验,也在不断的摸索之中。正所谓实战出真知,纸上谈兵容易,真刀真枪时就会暴露出一些问题,还是要多动手。当然了,技术都是业务驱动的。

后续更新见:Android SDK 开发纪要

Android SDK开发与使用的那些事儿的更多相关文章

  1. Android SDK 开发指南

    Android SDK 开发指南 视频详解 以下视频是对融云 Android SDK 开发使用的详细讲解,您可以在阅读文档时配合学习.   更多视频教程如下: CSDN 融云 Android SDK ...

  2. 配置Android SDK 开发环境(转)

    1. 下载Eclipse 在前面我们配置好了JDK环境后,就可以开始配置Android的集成开发环境了,官方Google推荐的集成开发环境为Eclipse,所以我们就以Eclipse作为集成开发环境. ...

  3. Android SDK 开发——发布使用踩坑之路

    前言 在 Android 开发过程中,有些功能是通用的,或者是多个业务方都需要使用的. 为了统一功能逻辑及避免重复开发,因此将该功能开发成一个 SDK 是相当有必要的. 背景 刚好最近自己遇到了类似需 ...

  4. 基于虹软人证核验 2.0 Android SDK开发集成入门

    一.功能介绍虹软人证核验 2.0 SDK(以下简称SDK)包含人脸检测.人脸跟踪.人证核验等能力,主要实现人证的1:1比对.其中暴露对外的功能方法有:active 引擎激活init 引擎初始化inpu ...

  5. Android SDK开发常用工具的使用及其异常处理

    由于以下操作都是命令操作,所以在执行以下操作之前确保环境变量 ANDROID_HOME 指向的是正确的Android SDK的路径: 一.启动Android SDK Manager: android ...

  6. Google Android SDK开发范例------------20141119

    一.Edit和Checkbox完成对登陆密码的查看:添加Edit的setOnCheckedChageListener和对CheckBox的状态通过isCHecked判断 大体代码如下 CheckBox ...

  7. android SDK开发 -- TitleBar封装(一)

    假设app的title 统一的都是这种左中右结构的 代码如下 <LinearLayout xmlns:android="http://schemas.android.com/apk/r ...

  8. Google Android SDK开发范例大全笔记 二

    网络设备管理相关相关 代码地址 1 WifiManager LocationManager分别控制 wifi及GPS WifiManager 判断网络状态 ,LocationManager判断定位状态 ...

  9. Google Android SDK开发范例大全笔记 一

    方法讲解 1 获取手机分辨率方法 DisplayMetrics private void getDiaplayMetrics() { DisplayMetrics dm = new DisplayMe ...

随机推荐

  1. angluarjs的tab标签

    JS代码 $scope.tabs = []; $rootScope.data = { current: "3" // 1代表张三,2代表李四,3代表王五 }; $rootScope ...

  2. [转] gitlab 的 CI/CD 配置管理

    [From] http://blog.51cto.com/flyfish225/2156602 gitlab 的 CI/CD 配置管理 (二) 标签(空格分隔):运维系列 一:gitlab CI/CD ...

  3. C#高效新增数据到数据库(十万级别测试)

    我们在对数据库进行新增数据时,怎么能把速度提到最快,时间缩到最短呢?下面针对三种方法进行比较 新增 逐条新增数据模式 Stopwatch s2 = new Stopwatch(); s2.Start( ...

  4. (转)生活中的OO智慧——大话面向对象五大原则

    一·单一职责原则(Single-Responsibility Principle) 定义:一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中. 宿舍里并不能好好学习,自习还是得去图书馆.这 ...

  5. dubbo接口快速测试技巧

    在分布式系统的开发中,用到了dubbo+zookeeper技术,最近遇到一个问题,产品上线后,我负责的模块出了问题,某个bean中某个字段的值一直为null,而这个bean是我调用注册在zookeep ...

  6. python-wsgi测试服务器

    #!/usr/bin/python from wsgiref.simple_server import make_server def application(environ,start_respon ...

  7. Kaggle之路,与强者为伍——记Santander交易预测

    Kaggle--Santander Customer Transaction Prediction 原题链接 题目 Description 预测一个乘客在未来会不会交易,不计交易次数,只要有交易即为1 ...

  8. C#中判断系统的架构(32位,还是64位)

    一种很简单的方法就是根据IntPtr类型的Size属性来判断, //IntPtr.Size在64位为8,在32位为4 public static Boolean Is64Bit() { ) retur ...

  9. redis数据类型(五)set类型

    一. set类型 set是无序集合,最大可以包含(2 的 32 次方-1)个元素. set 的是通过 hash table 实现的,所以添加,删除,查找的复杂度都是 O(1). hash table ...

  10. Delphi 通得进程ID获取主窗口句柄

    只知道进程ID,获取主窗口句柄的方法如下: 通过EnumWindows枚举所有窗口 使用GetWindowThreadProcessID,通过窗口句柄获取进程ID 比便获取的进程ID与当前已知的进程I ...