Android Studio 打包Jar

来源:互联网 发布:电脑数据恢复好用吗? 编辑:程序博客网 时间:2024/05/21 11:00

晨鸣的博客–Android Studio 打包Jar

最近公司一个新需求,需要将项目中某一个模块打包成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 文件的最后添加如下代码
//打jar包def SDK_BASENAME = "*****";  //打包后的名称def sdkJarPath = "build";  //打包输出目录def zipFile = file('build/intermediates/bundles/default/classes.jar') //将编译生成的classes.jar文件打包task makeJar(type: Jar) {    from zipTree(zipFile)    from fileTree(dir: 'src/main', includes: ['assets/**']) //需要保留的资源文件    baseName = SDK_BASENAME    destinationDir = file(sdkJarPath)}makeJar.dependsOn(build)
  • rebuild 项目,确保build/intermediates/bundles/default/目录下存在class.jar文件。
  • 打开Terminal命令行,或者直接用系统命令行进入项目目录,输入gradlew makeJar 回车,开始进行打包。第一次进行打包,可能会需要下载一些文件,需要一些时间,请耐心等待。
  • 当出现BUILD SUCCESSFUL时代表打包完成,打开输出目录就会有打包生成的jar包。

一些问题及注意事项

  1. 如果Jar包中包含Activity,在项目中引入这个Jar后,还需要在项目的AndroidManifest.xml中声明这个Activity,以及添加一些必要的权限声明。

  2. 打包时可以选择保留项目中的资源文件,但仅仅只有assets下的资源文件在jar包中可以正常使用。其他的资源文件,如drawable、layout等,都不可以用常见的方法引用。我们在正常使用某一个资源文件时,是通过R.**.**方法引用,而打包Jar时并不会保留资源文件id对应的映射R文件,所以这些资源文件就不能正常调用了。

  3. 如果Jar包中需要使用一些资源文件,可以将需要的资源文件,例如图片、布局等单独拿出来,项目中引入Jar时,同时添加这些必需的资源文件(类似友盟、腾讯等第三方jar的引入),这样Jar包中可以通过反射读取项目中资源文件。反射读取资源文件的代码如下:

/** * **************************************************************** * Author: LCM * Date: 2017/6/2 上午11:09 * Desc: 通过反射获取资源文件 * ***************************************************************** */public class MResource {    /**     *      * @param context 上下文     * @param className 资源文件的类型 layout、id、drawable     * @param name 资源文件的名字     * @return     */    public static int getIdByName(Context context, String className, String name) {        String packageName = context.getPackageName();        Class r = null;        int id = 0;        try {            r = Class.forName(packageName + ".R");            Class[] classes = r.getClasses();            Class desireClass = null;            for (int i = 0; i < classes.length; ++i) {                if (classes[i].getName().split("\\$")[1].equals(className)) {                    desireClass = classes[i];                    break;                }            }            if (desireClass != null)                id = desireClass.getField(name).getInt(desireClass);        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (IllegalArgumentException e) {            e.printStackTrace();        } catch (SecurityException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (NoSuchFieldException e) {            e.printStackTrace();        }        return id;    }     /**     * 从Assets中读取图片     */    public static Bitmap getImageFromAssetsFile(Context context, String fileName) {        Bitmap image = null;        AssetManager am = context.getResources().getAssets();        try {            InputStream is = am.open(fileName);            image = BitmapFactory.decodeStream(is);            is.close();        } catch (IOException e) {            e.printStackTrace();        }        return image;    }}
//代码中调用setContentView(MResource.getIdByName(getApplicationContext(), "layout", "layout_demo"));tvTitle = (TextView) findViewById(MResource.getIdByName(getApplicationContext(), "id", "demo_tv_title"));

额外发现

生成一个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

public static XmlResourceParser getIsFromAssetsFile(Context context, String fileName) {        AssetManager am = context.getResources().getAssets();        XmlResourceParser xmlResourceParser = null;        try {            xmlResourceParser = am.openXmlResourceParser("assets/" + fileName);        } catch (IOException e) {            e.printStackTrace();        }        return xmlResourceParser;    }
LinearLayout layout = (LinearLayout) LayoutInflater.from(this).inflate(MResource.getIsFromAssetsFile(this, "layout_demo.xml"), null,false);setContentView(layout);

把布局文件扔进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 的加载机制不同导致的。。

原创粉丝点击