最近公司一个新需求,需要将项目中某一个模块打包成SDK提供给第三方公司使用。
打包SDK?我只会用啊!!没办法,硬着头皮也得上!
选择打包方式
说干就干,撸起袖子就Google。。。
通过Google可以确定常见的几种打包SDK的方式
直接以Library Module的方式引入
优点
简单方便,直接把模块抠出来放进一个Library中扔给第三方公司用就行了
缺点
只能适合于Android Studio开发的项目,假如第三方公司用的是Eclipse,那不就懵逼了.
不安全,相当于把源码完全暴露给第三方。泄露资料事小,代码写的差被嘲笑事大啊!!
以aar包的方式引入
优点
生成简单,Android Studio的项目在编译完成后,Library Module 的build目录中会自动生成 aar包,不用做额外操作
缺点
还是比较适合Android Studio开发的项目,虽然Eclipse 也能引入aar包,但是比较复杂,我可不想写一堆接入文档,还不一定说的清。
以jar包的方式引入
优点
接入方便,是个Android开发应该都会引入jar包吧。。
缺点
打包比较麻烦,而且Jar包中关于一些资源文件的引用比较麻烦
经过一番比较,最终我选择以Jar包的形式提供一个对外的SDK。毕竟是给别人使用的东西,用户的使用体验最重要,通过jar包方式可以以最简单的方式集成SDK,减少接入SDK的成本以及时间。
打包Jar
相关知识
Android Studio 生成Jar包,还是需要借助 Library Module来操作。创建一个Library Module ,然后在主项目中依赖这个Module,当项目经过编译后,我们会发现在Library Module 的 build/intermediates/bundles/default/目录下会有一个class.jar文件
我们生成Jar文件就是需要将这个class.jar文件进行打包处理
操作
- 将项目中需要生成SDK的模块分离出来,单独放入一个Module中,并将这个Module切换为Library,使主项目依赖这个Library。
- 在Library Module 的build.gradle 文件的最后添加如下代码
1 | //打jar包 |
- rebuild 项目,确保
build/intermediates/bundles/default/目录下存在class.jar文件。 - 打开Terminal命令行,或者直接用系统命令行进入项目目录,输入
gradlew makeJar回车,开始进行打包。第一次进行打包,可能会需要下载一些文件,需要一些时间,请耐心等待。 - 当出现
BUILD SUCCESSFUL时代表打包完成,打开输出目录就会有打包生成的jar包。
一些问题及注意事项
如果Jar包中包含Activity,在项目中引入这个Jar后,还需要在项目的
AndroidManifest.xml中声明这个Activity,以及添加一些必要的权限声明。如果module中已经引用了第三方Jar包,例如Gson.jar,直接打包后,也会将第三方Jar打包到你的JAR文件中。如果不想让第三方jar被打包进去,可以在module的build.gradle中引用第三方jar包时 使用
provided替换compile。例如compile files('libs/tbs_sdk_thirdapp.jar')替换成provided files('libs/tbs_sdk_thirdapp.jar')。这样在打包Jar包时就不会包含第三方的内容,在使用的时候只要将第三方jar包与你的Jar包同时引入就可。打包时可以选择保留项目中的资源文件,但仅仅只有assets下的资源文件在jar包中可以正常使用。其他的资源文件,如drawable、layout等,都不可以用常见的方法引用。我们在正常使用某一个资源文件时,是通过
R.**.**方法引用,而打包Jar时并不会保留资源文件id对应的映射R文件,所以这些资源文件就不能正常调用了。如果Jar包中需要使用一些资源文件,可以将需要的资源文件,例如图片、布局等单独拿出来,项目中引入Jar时,同时添加这些必需的资源文件(类似友盟、腾讯等第三方jar的引入),这样Jar包中可以通过反射读取项目中资源文件。反射读取资源文件的代码如下:
1 | /** |
1 | //代码中调用 |
额外发现
生成一个Jar,还需要另外提供一些资源文件给别人,对我这种有代码洁癖的人来说是不能忍的。我的理想状态是,就一个jar包,你想用的都在里面,干净简洁。
本着不作死就不会死的精神,竟然真的被我发现了一种从assets中加载布局文件的方式!!!!!!
我们知道生成布局文件一般有两种方式
findViewById- 直接new一个布局文件,代码中添加属性
其实还有一种容易被我们忽略的方法 LayoutInflater,我们常在ListView或者RecyclerView 的Adapter中通过Layoutinflater加载Item项的布局,那么能不能通过它来加载一个Activity的布局呢?
我们通常使用的是这两个public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)public View inflate(@LayoutRes int resource, @Nullable ViewGroup root)
方法来加载布局
但其实LayoutInflater还有两个重载的方法public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)public View inflate(XmlPullParser parser, @Nullable ViewGroup root)
看见XmlPullParser是不是感觉到希望了呢?
没错!XmlPullParser可以用来解析Xml文件,这样我们就不用通过R文件来映射资源文件,而是直接通过解析Xml文件来加载布局。
解析资源布局文件需要用XmlResourceParser类
1 | public static XmlResourceParser getIsFromAssetsFile(Context context, String fileName) { |
1 | LinearLayout layout = (LinearLayout) LayoutInflater.from(this).inflate(MResource.getIsFromAssetsFile(this, "layout_demo.xml"), null,false); |
把布局文件扔进assets目录,来来来!接下来就是见证奇迹的时刻!

f**k ………
淡定淡定。。发现问题还是要解决问题嘛。。。
经过一番艰苦卓越的google ,发现这里XmlResourceParser解析的布局必需是编译过后的布局文件。
那么怎么获取编译后的布局文件呢,很简单也很无脑,把你需要的布局文件放到任意一个正常项目的layout目录下,编译项目,在build/output/apk文件夹中会有一个 apk包,解压就可在layout目录下获得编译后的布局文件
重新将编译后的布局文件扔到assets目录中,运行
布局文件能找到,那么布局中的控件呢,肯定不能findViewById了,别担心,android中还有另一个findview的方法 findViewByTag,你可以在布局中给每一个控件添加一个android:tag=""属性,然后你就可以通过findViewByTag方法来找到指定的控件了。
终于我成功的将SDK封装的只剩一个Jar包!!
然鹅!!我最终还是放弃了这种方式!!!因为这种方式打包的jar包在Android Studio中可以正常使用,但是在Eclipse中不能使用!!!解析不了这个布局!!!!网上关于这方面的资料又比较少,我只能猜测这是因为Eclipse 与Android Studio 的加载机制不同导致的。。







