精华内容
下载资源
问答
  • 将指定jar包,生成.dex文件, 获取 .dex包含的方法数, 只需要将jar包放入自定义文件夹,一键执行工具里面的脚本,即可生成.dex
  • 多个jar包合并成 dex

    千次阅读 2018-08-20 15:05:05
    1、将需要合并的jar放到同一目录 2、编写一 index.xml文件写入如下内容 <!--?xml version="1.0" encoding="utf-8"?--> <project basedir="F:\jar" ...

    1、将需要合并的jar放到同一个目录

    2、编写一个 index.xml文件写入如下内容

    <!--?xml version="1.0" encoding="utf-8"?-->
    <project basedir="F:\jar" default="makeSuperJar" name="base">
        <target description="description" name="makeSuperJar">
            <jar destfile="base.jar">
    			<zipfileset src="alicloud-android-monitor-2.5.1.1_for_bc_proguard.jar" />
    			<zipfileset src="alicloud-android-utils-1.1.1.jar" />
    			<zipfileset src="aliyun-oss-sdk-android-2.4.3.jar" />
    			<zipfileset src="AMap2DMap_5.2.0_AMapSearch_5.3.1_AMapLocation_3.6.1_20171012.jar" />
    			<zipfileset src="android-support-v4.jar" />
    			<zipfileset src="bugly_crash_release.jar" />
    			<zipfileset src="fileDownloader.jar" />
    			<zipfileset src="GCloudVoice.jar" />
    			<zipfileset src="jcore-android-1.1.7.jar" />
    			<zipfileset src="jpush-android-3.0.9.jar" />
    			<zipfileset src="libammsdk.jar" />
    			<zipfileset src="MobCommons-2018.0322.1145.jar" />
    			<zipfileset src="MobTools-2018.0322.1147.jar" />
    			<zipfileset src="okhttp-3.4.1.jar" />
    			<zipfileset src="okio-1.10.0.jar" />
    			<zipfileset src="OpenInstall_v2.1.0.jar" />
    			<zipfileset src="picasso-2.5.2.jar" />
    			<zipfileset src="ShareSDK-Alipay-3.1.4.jar" />
    			<zipfileset src="ShareSDK-Alipay-Core-3.1.4.jar" />
    			<zipfileset src="ShareSDK-Alipay-Moments-3.1.4.jar" />
    			<zipfileset src="ShareSDK-Core-3.1.4.jar" />
    			<zipfileset src="ShareSDK-Dingding-3.1.4.jar" />
    			<zipfileset src="ShareSDK-QQ-3.1.4.jar" />
    			<zipfileset src="ShareSDK-QZone-3.1.4.jar" />
    			<zipfileset src="ShareSDK-Yixin-3.1.4.jar" />
    			<zipfileset src="ShareSDK-Yixin-Core-3.1.4.jar" />
    			<zipfileset src="ShareSDK-Yixin-Moments-3.1.4.jar" />
    			<zipfileset src="utdid4all-1.1.5.3_proguard.jar" />
    			<zipfileset src="jg_filter_sdk_1.1.jar" />
    			<zipfileset src="mid-core-sdk-4.0.6.jar" />
    			<zipfileset src="wup-1.0.0.E-SNAPSHOT.jar" />
    			<zipfileset src="Xg_sdk_v3.2.3_20180403_1839.jar" />
    		</jar>
        </target>
    </project>

    3、执行命令 ant -buildfile ./index.xml

    4、将生成的 base.jar 转换成 classes2.dex 通过  命令 

    dx --dex --output classes2.dex base.jar

    展开全文
  • Unity3D修改classes.jardex2jar使用)

    千次阅读 2017-02-22 18:06:08
    Unity3D使用dex2jar魔改classes.dex来达到半屏输入

    本文源链接:http://blog.csdn.net/qq393830887/article/details/56492145

    工具

    开始

    目录结构


    - Unity里面有分il2cpp、mono,还有分Development、Release,找到自己用于测试的路径,不要搞错了
    - Unity为什么会有classes.dex又有classes.jar,真是神奇
    - 不管怎样,也备份一下上面那2个文件,以防手残

    jar2dex


    - 对比生成的dex,还是有些区别的,不过有什么区别不好判断,接下来反编译dex再看

    baksmali


    - 对比刚刚2个dex,发现有区别,但是还是看不懂,继续往下

    - 修改这个位置,具体参考 Unity半屏输入
    - 这里和那篇文章提到的不一样,这里看到的是十进制的,计算器算一下罗

    smali


    - 这下好了,3个dex都看不出来区别了

    dex2jar


    - 这次可以用Java Decompiler来对比生成的jar了
    - 看起来就是函数的声明区别比较大
    - 感觉用unity的classes.dex比较靠谱,莫非unity就是为了方便我偷偷改

    发apk测试


    1. 覆盖classes.jar无效
    2. 覆盖classes.dex发现可以实现半屏
    3. 说明unity使用的是classes.dex来生成apk,jar只是方便我们需要的时候引用jar

    补充

    • IDA可以做简单的修改,修改数值还行,但是涉及到类型,看来得老司机来才行

    展开全文
  • DexClassLoader动态加载apk、jardex

    千次阅读 2015-04-23 14:21:22
    DexClassLoder动态加载APK\jar\dex
    切忌眼高手低,过去看过好多关于动态加载的博客,觉得自己已经掌握,当自己动手去编写的时候,才发现有很多问题,今天自己动手写了一遍,总结了一下,希望能够帮到有需要的人。(其中部分内容,来自其他的博客,在文章的后面我已经注明链接)

    和java一样,Android也可以实现动态加载,现在Android中有以下两种方式可以实现动态加载:
    1.DexClassLoder
    这个可以加载jar\apk\dex,也可以从SD卡中加载
    2.PathClassLoader
    只能加载安装到Android系统中的apk文件

    今天我主要针对于DexClassLoader动态加载apk、jar、dex做一个详细的讲解:
    一、DexClassLoader的简单介绍
    类加载DexClassLoder的类结构:
    public class DexClassLoader extends BaseDexClassLoader
    java.lang.Object
         java.lang.ClassLoader
              dalvik.system.BaseDexClassLoader
                   dalvik.system.DexClassLoader

    这个类加载器从.jar和.apk类型的文件内部加载classes.dex文件,通过这种方式可以执行非安装的程序代码,作为程序的一部分进行运行。
    这个类只有一个构造函数:
    public DexClassLoader(String dexPath,String optimizedDirectory,String libraryPath,ClassLoader parent )
    各个参数表示的含义如下表所示:
    dexPath需要装载的apk、jar、dex文件的路径,多个路径用File.pathSeparator间隔开,在Android上默认是“:”
    optimizedDirectory优化后的dex文件的存放目录,不能为null
    libraryPath目标类中使用的c/c++库的列表,每个目录用File.pathSeparator间隔开,可以为null
    parent 该类装载器的父装载器,一般用当前执行类的装载器

    二、实际演练
    1.准备工作
    创建一个Android工程用于导出jar包,获得dex和apk文件。
    在工程里面新建一个DexDemo1.java
    源码如下:
    package com.henugao.dexdemo1;
    
    import android.telephony.SmsManager;
    import android.util.Log;
    
    public class DexDemo1 {
         private final static String TAG= "DexDemo1";
        
         public void SendMes(String mes){
            SmsManager sms=SmsManager. getDefault();
            sms.sendTextMessage( "55555" , null , mes, null , null );
            Log. i( TAG, "短信发送成功" );
        }
    
    }
    
    这个java类主要实现个一个发送短消息的功能,其中的mes是由调用方传递的。
    然后:获取apk、dex、jar文件
    运行该工程可以在工程的bin目录下面直接获取apk和dex文件,如下图所示:

    如何获取jar文件呢,右击工程,点击export,导出JAR file,如右图所示:
    将导出的jar包命名为demo.jar。然后把java的class文件转换成android能识别的字节码,使用dx工具,这个工具可以在android的SDK目录下面搜索一下这个工具,以前在platform-tools找目录下面可以找到,但是现在build-tools里面的子目录里面找到了不同版本的dx工具,我这里用的是android-4.2.2下面的。把demo.jar复制到该目录下,在cmd命令里面敲入如下命令:

    然后就可以生成一个dexdemo.jar文件
    2、正式工作
    新建一个android工程,将刚才准备的apk、dex、jar文件放在asset文件下面。该工程的目录结构如下所示:

    FileUtile源码如下:
    package com.henugao.testdexclassloader1;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    
    import android.content.Context;
    import android.os.Environment;
    
    /**
     * 
     * @author henugao
     * 将apk或者dex或者jar文件从工程的assets文件下面写到sdcard的根目录
     */
    public class FileUtile {
    	/**
    	 * 将apk或者dex或者jar文件从工程的assets文件下面写到sdcard的根目录
    	 * @param context 
    	 * @param filename 要加载的apk或者dex或者jar的名字
    	 * 
    	 */
        public static void CopyAssertJarToFile(Context context, String filename) {
            try {
     
                File file = new File(Environment.getExternalStorageDirectory()
                        .toString() + File.separator + filename);
                if (file.exists()) {
                    return;
                }
     
                InputStream inputStream = context.getAssets().open(filename);
                file.createNewFile();
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                byte buffer[] = new byte[1024];
                int len = 0;
                while ((len = inputStream.read(buffer)) != 0) {
                    fileOutputStream.write(buffer, 0, len);
                }
                fileOutputStream.close();
                fileOutputStream.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    该类的主要功能已经在源码中说明,这里就不一一赘述了。
    MainActivity.java的源码如下:
    package com.henugao.testdexclassloader1;
    
    import java.io.File;
    import java.lang.reflect.Method;
    import dalvik.system.DexClassLoader;
    import android.os.Bundle;
    import android.os.Environment;
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.content.Context;
    import android.telephony.TelephonyManager;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends Activity {
    
    	private final static String TAG="TestDexClassLoader1";
    	Button dexButton;
    	
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            dexButton =(Button)findViewById(R.id.DexClassLoader);
            dexButton.setOnClickListener(new View.OnClickListener() {
    			
    			@Override
    			public void onClick(View v) {
    				// TODO Auto-generated method stub
    				invokeOtherApk();
    			}
    		});
        }
    	@SuppressLint("NewApi")
    	public void invokeOtherApk(){
    		TelephonyManager telephonyManager=(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    		String mes=telephonyManager.getDeviceId();
    		//这个fileNames是指你要动态加载的apk或者jar或者dex文件的名字
    		String fileName="DexDemo1.apk";
    		FileUtile.CopyAssertJarToFile(this, fileName);
    		
    		//存放apk、jar.dex的文件
            File file = new File(Environment.getExternalStorageDirectory()
                    .toString() + File.separator + fileName);
            //apk、jar、dex所在的路径
            String sourPath=file.getAbsolutePath();
            System.out.println("sourPath--->"+sourPath);
            final File optimizedDexOutputPath = getDir("temp", Context.MODE_PRIVATE);
            DexClassLoader dcl = new DexClassLoader(sourPath,
                    optimizedDexOutputPath.getAbsolutePath(), null,
                    getClassLoader());
    		try {
    			Class<?> cla=dcl.loadClass("com.henugao.dexdemo1.DexDemo1");
    			Object obj=cla.newInstance();
    			Method action=cla.getMethod("SendMes", String.class);
    			Log.i(TAG, mes);
    			action.invoke(obj, mes);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		
    	}
    }
    在这个代码里面fileName="DexDemo1.apk"表明这里动态加载的是apk,如果写成classes.dex,表明这里动态加载的是dex,如果写的是dexdemo.jar则表明动态加载的是jar文件。
    运行该应用程序,界面显示如下图:
    点击按钮,查看日志,如图所示:
    表明动态加载成功,成功的调用DexDemo里面发送短信的函数,将IMEI号发送出去了。
     
     




    展开全文
  • Android一键生成包含.dexJar及动态加载方案 背景:谈到动态加载相信很小伙伴都会想到 热更新 及 动态加载dex 的技术,最近也因为项目重构的需求,折腾了下这方面的技术点,以前研究过但时间久了也就忘了,这里...

                                      Android一键生成包含.dex的Jar及动态加载方案

    背景:谈到动态加载相信很多小伙伴都会想到 热更新 动态加载dex 的技术,最近也因为项目重构的需求,折腾了下这方面的技术点,以前研究过但时间久了也就忘了,这里记录一下写个总结,也希望给有类似需求的小伙伴一点启发。

    此次记录大致可以总结为以下几点:

    1. 将项目中的模块进行剥离,独立成单独的module组件(一方面为了降低整个项目的耦合度让结构也更清晰;另一方面为了满足新的功能需求)。

    2. 将剥离的module构建为jar包(注意这里的jar包并非AS构建后自动生成的jar包,这个jar中包含的都是class为后缀的文件,并非我们最终需要的。对这些jar进行二次编译后生成包含dex后缀文件的jar才是我们需要的,编译的方法下面会提到),使用WinRAR打开包含dex的jar包:

     

    原因:Android使用Dalvik虚拟机加载可执行程序,故不能直接加载基于class的jar,而是需要将class转化为dex字节码才可执行代码。优化后的字节码文件可以存在一个.jar中,只要其内部存放的是.dex即可使用。

    3. 将编译好的含有dex文件的jar包通过服务器下发,App请求接口下载存放到本地,通过DexClassLoader类加载器进行加载操作。

    代码示例展示

    以下我们通过简单的示例来进一步了解大致操作步骤和需要注意的点,先来看一下已完成Demo的目录结构

    很简单,除了一个app外还有另外两个作为library的module,module的创建在一个已有的项目中新增或者新建一个项目进行添加都可以,示例中之所以放了2个,主要是为了展示清晰的调用gradle中task任务构建打包dex的问题,先来看一下 dexlibrary1 中的代码,也很简单,一个接口,一个类,这里仅仅是示例,具体代码怎么写都行,如下图:

    /**
     * 动态加载测试接口
     */
    public interface IMessage_one {
        String showMessage(Context context);
    }
    

    ShowMessageImpl_one 实现类:

    /**
     * 动态加载测试实现(这里仅仅是一个示例)
     */
    public class ShowMessageImpl_one implements IMessage_one {
        @Override
        public String showMessage(Context context) {
            Toast.makeText(context, "dexlibrary1生成的dex文件已加载", Toast.LENGTH_LONG).show();
            return "大家好才是真的好";
        }
    }
    

     

    编译生成Jar及进行转化

    OK,接下来要做的就是将dexlibrary1打包为jar了,这里需要注意将哪些文件进行打包,从哪里获取到需要打包的文件呢?如下图所示:

    即:对应module或project目录下—>build—>intermediates—>classes—>debug下(如果没有classes目录,需要先进行编译<bulid或Make Projrect>),如下图所示:

    然后我们通过在build.gradle中定义task任务进行构建,构建的方式有多种,不过都大同小异,例如:

    //删除jar包任务
    task clearJar(type: Delete) {
        delete 'build/libs/dexlibrary1.jar'
    }
    task makeJar(type: Jar) {
        //指定生成的jar名
        baseName 'dexlibrary1'
        //archiveName = 'dexlibrary1'   //这样指定名称也可以
        //从哪里打包class文件
        from('build/intermediates/classes/debug/org/gaochun/dexlibrary1/')
        //将assets目录打入jar包
        //from fileTree(dir: 'src/main', includes: ['assets/**'])
        //打包到jar后的目录结构
        into('org/gaochun/dexlibrary1/')
        //去掉不需要打包的目录和文件
        exclude('test/', 'BuildConfig.class', 'R.class')
        //去掉R$开头的文件
        exclude { it.name.startsWith('R$') }
    }
    makeJar.dependsOn(clearJar, build)

    代码中注释也描述的比较清晰了,这个涉及到Groovy脚本相关的一些知识点,感兴趣的同学可以去网上搜索资料进行学习,个人也推荐一个不错的资料:Gradle学习系列 ,这里也不多说我们继续,上面的task定义好之后就可以进行打包dex了,方式有两种,一种是在AS的Terminal输入命令:gradlew makeJar,另外一种就是在AS工具右边的Gradle中找到上面定义的Task,双击该任务就可以了,dexlibrary1--->other--->makeJar,如图:

    任务执行完成之后,我们会发现在 build 目录下生成了一个jar包,但这个包并非我们所需要的,前面有提到,我们需要对其进行再次编译,生成对应的包含dex的jar,如下图所示:

    接下来我们对该jar包进行编译转化,转化需要用到dx命令,在 android-sdk\build-tools\对应的sdk版本[如:27.0.0] 下,所以需要将该jar拷贝到对应目录下,在Android Studio的Terminal终端cd到对应的sdk版本目录(例如我们将jar拷贝到了27.0.0的目录下,此时就需要在终端将路径切到对应的目录下),然后输入编译命令:

    dx --dex --output=dexlibrary1_dex.jar dexlibrary1.jar

    注:--output是输出目录,默认在当前的根目录下,执行完后在当前目录下生成了Davilk虚拟机可执行的dex文件,
    因为该命令同时会打包dex文件,因此后缀是jar,可使用WinRaR即可看到里面的class.dex文件)

    以上操作完成后,我们可以拿到命令执行完后所生成的 dexlibrary1_dex.jar 文件进行动态加载了。

     

    动态加载dex

    关于动态加载技术相信移动端的小伙伴或多或少都有了解,毕竟Android中当初火热流行的热更新其原理就基于此。Java程序中JVM虚拟机通过类加载器ClassLoader来加载class文件和jar文件(本质还是class文件)。Android与Java类似,只不过Android使用的是Dalvik/ART虚拟机,加载的是dex文件(可以理解为一种对class文件优化的产物),Android中类加载器分为两种类型,一种是系统 ClassLoader 另一种是自定义 ClassLoader ,其中系统ClassLoader包括三种,分别是 BootClassLoader PathClassLoader 和 DexClassLoader,如下图所示:

    根据图中所示,我们大致可以总结下 ClassLoader 继承关系,我们大致说下其原理就行,更深入的研究还请小伙伴们自己去探索:

    1. ClassLoader是一个抽象类,其中定义了ClassLoader的主要功能;
    2. BootClassLoader是ClassLoader的内部类,用于预加载preload()常用类以及一些系统Framework层级需要的类;
    3. BaseDexClassLoader继承ClassLoader,是抽象类ClassLoader的具体实现类,PathClassLoader和DexClassLoader都继承它;
    4. PathClassLoader加载系统类和应用程序的类,如果是加载非系统应用程序类,则会加载data/app/目录下的dex文件以及包含dex的apk文件或jar文件;
    5. DexClassLoader可以加载自定义的dex文件以及包含dex的apk文件或jar文件,也支持从SD卡进行加载。

    所以我们这里需要用到的就是 DexClassLoader 类,对比 PathClassLoader ,DexClassLoader 的不同点是它可以加载任意目录下的 jar | dex | apk | zip 文件,比PathClassLoader更加灵活,是实现热修复和插件化技术的重点,划重点,下次要考,源码如下图所示:

    /**
         * DexClassLoader类参数含义
         * @param dexPath   待加载的dex文件路径,如果是外存路径,一定要加上读外存文件的权限
         * @param optimizedDirectory    解压后的.dex文件存储路径,不可为空,此位置一定要是可读写且仅该应用可读写
         * @param librarySearchPath     指向包含本地库(so)的文件夹路径,可以设为null
         * @param parent    父级类加载器,一般可以通过Context.getClassLoader获取到,也可通过ClassLoader.getSystemClassLoader()获取到
         */
        public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent)

    注:4.1以后不能够将第二个参数 optimizedDirectory 设置到sd卡目录, 否则抛出异常,强烈建议使用内部私有存储路径(即应用的data/data/xx包名/下面创建一个app_dex文件夹),不要放到sdcard上,代码容易被注入攻击。

    下面我们将编译好的含有dex文件的 dexlibrary1_dex.jar 文件放到app下的assets目录下,当然也可以通过其他手段进行加载,例如放到服务器上Download下来 等等,下面演示通过放置到assets目录进行加载:

     /**
         * 加载dex文件中的class,并调用其中的showMessage方法
         */
        private void loadDexClass() {
            File dexOutputDir = getDir("dex", 0);//在data/data/xx包名/下面创建一个app_dex文件夹
            String internalPath = dexOutputDir.getAbsolutePath() + File.separator + "dexlibrary1_dex.jar";
            File dexFile = new File(internalPath);
            try {
                if (!dexFile.exists()) {
                    dexFile.createNewFile();
                    //将assets目录下的文件copy到app/data/cache目录
                    FileUtils.copyFiles(this, "dexlibrary1_dex.jar", dexFile);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            //加载dex class
            DexClassLoader dexClassLoader = new DexClassLoader(internalPath, dexOutputDir.getAbsolutePath(), null, getClassLoader());
            try {
                //该name就是internalPath路径下的dex文件里面的ShowMessageImpl_one这个类的包名+类名
                Class<?> clz = dexClassLoader.loadClass("org.gaochun.dexlibrary1.ShowMessageImpl_one");
                IMessage_one impl = (IMessage_one) clz.newInstance();//通过该方法得到IMessage_one类
                if (impl != null) {
                    String value = impl.showMessage(this);//调用打开弹窗并获取值
                    mTextView.setText(value);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    

    划重点:Class<?> clz = dexClassLoader.loadClass("org.gaochun.dexlibrary1.ShowMessageImpl_one"); 这个loadClass的包名必须保持一致,即app下的包名和 dexlibrary1 组件下的包名必须保持一致,不然会出现java.lang.ClassCastException或ClassNotFoundException 等错误,所以需要保持一致,如下图所示:

    这里给个这样的建议,定义了一个Common的基类Module,里面存放各种interface接口文件,然后剥离出来的组件引用了Common且都implements了对应的接口,宿主app也同样引用了Common,这样在宿主app中加载dex包时就不会出现上面转换错误或者找不到类的错误了,也让项目变得更加清晰一些,画个粗糙的图吧,绿色箭头表示依赖,红色箭头表示对打包好的dex进行加载,大致是这么个意思:

    ok,加载成功前后的效果图:

             

    到此我们知识点和功能也都基本完善了,按照上面的操作流程,Demo也能正常的运行起来,用着用着,因为项目的需求,独立出来的module越来越多,每个module的build.gradle文件中都有一大坨clearJar、makeJar的任务代码,看着有些碍眼,这是其一,其二就是每次都需要将编译好的jar拷贝到指定目录通过命令再生成包含dex的jar,这重复机械性的工作做多了也是有点头皮发麻,所以针对这个下面做了一些优化。

     

    优化编译脚本

    优化的目的总结下来有以下几点:

         Module统一版本管理
          将clearJar/makeJar等任务抽离开,不要在每个module中都写一大堆
         ③ 通过自定义的Task一键生成包含class.dex的jar,省去手动编译重复性的工作
          上传到Git后确保让每个协同开发的小伙伴也能直接执行task任务进行编译,无需修改其他配置

    下面分别来简单进行说明:

    一、Module统一版本管理

    首先可以在我们在项目的根目录创建一个 versionConfig.gradle 文件,该文件中定义的内容只做版本相关的定义和配置(也可以在根目录的build.gradle目录定义),例如:

    ext {
        versions = [
                sdkMinVersion       : 14,
                sdkTargetVersion    : 27,
                sdkCompileSdkVersion: 27
                //其他...
        ]
    
        depVersion = [
                appCompatVersion       : "27.1.1",
                recyclerViewVersion    : "27.1.1",
                constraintLayoutVersion: "1.1.0"
        ]
    
        deps = [
                suport: [
                        appcompat        : "com.android.support:appcompat-v7:${depVersion.appCompatVersion}",
                        recyclerview     : "com.android.support:recyclerview-v7:${depVersion.recyclerViewVersion}",
                        constraint_layout: "com.android.support.constraint:constraint-layout:${depVersion.constraintLayoutVersion}"
                ]
        ]
    }
    

    注意由于各个module都需要引用到该配置信息,所以该文件需要在 根目录build.gradle中apply

    接下来在各个module中使用:

    apply plugin: 'com.android.application'
    android {
    
        def versions = rootProject.ext.versions
        compileSdkVersion versions.sdkCompileSdkVersion
        defaultConfig {
            minSdkVersion versions.sdkMinVersion
            targetSdkVersion versions.sdkTargetVersion
            versionCode 1
            versionName "1.0"
            applicationId "org.gaochun.dexlibrary"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        def dependencies = rootProject.ext.deps
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation dependencies.suport.appcompat
        implementation dependencies.suport.constraint_layout
        //implementation 'com.android.support.constraint:constraint-layout:1.1.0'
    }

    二、抽离clearJar/makeJar等编译任务并自定义Task任务执行编译dex任务

    同样我们单独定义个文件:makeDexJar.gradle,将上面我们编译jar所定义的 clearJar/makeJar 任务放到这个文件中,如下图所示:

    这个时候问题来了,如何引用这个文件;这个给多个module引用的打包编译任务有很多公共的属性,怎么封装成方法;另外生成包含class.dex的jar编译命令怎么写;下面是优化好的代码,根据注释可以清楚每一行代码的含义及作用,供大家参考:

     

    //-------------------------  构建Jar和包含Dex的Jar  ---------------------------------
    
    ext {
        readLocalSDKPropertiesToMakeDexJar = this.&readLocalSDKPropertiesToMakeDexJar
       }
    
    def readLocalSDKPropertiesToMakeDexJar(outputDexJarName, jarName, packagePath) {
        //println("我被调用了")
        //编译工具
        //def buildingToolPath = 'D:\\Android\\android-sdk\\build-tools\\28.0.0\\dx.bat'
        def dxbatVersion = '25.0.0' //因为项目用的是25Level,所以此处用25.0.0的版本构建
        def dxbat = '\\build-tools\\' + dxbatVersion + '\\dx.bat'
        def buildingToolPath
    	
    	//主要是为了读取local.properties文件中的sdk.dir路径,设置编译工具的位置
    	//这样其他成员拉取代码后打包就不用手动更改编译工具的路径了
        File file = rootProject.file('local.properties')
        if (file.exists()) {
            InputStream inputStream = rootProject.file('local.properties').newDataInputStream();
            Properties properties = new Properties()
            properties.load(inputStream)
            if (properties.containsKey("sdk.dir")) {
                buildingToolPath = properties.getProperty("sdk.dir") + dxbat
            }
        }
    	
        //删除jar包任务
        task clearJar(type: Delete) {
            delete 'build/libs/' + jarName
        }
    
        //生成不带dex的jar
        task makeJar(type: Jar) {
            //baseName 'SmartWebAPI'   //指定生成的jar名
            archiveName = jarName      //打包普通jar名称
            from('build/intermediates/classes/debug/' + packagePath)    //从哪里打包class文件
            into(packagePath)       //打包到jar后的目录结构
            exclude('test/', 'BuildConfig.class', 'R.class')    //去掉不需要打包的目录和文件
            exclude { it.name.startsWith('R$') }    //去掉R$开头的文件
        }
    	
        //执行makeJar任务时会在之前执行clearjar任务 和 build
        makeJar.dependsOn(clearJar, build)
    
        //执行此任务生成包含dex的jar
        task makeDexJar(type: Exec) {
            def mCommond = [
                    buildingToolPath, '--dex',//输出包含dex的jar路径及名称
                    '--output=build/libs/' + outputDexJarName,
                    'build/libs/' + jarName //使用dx将jar中的代码优化成dex文件,该步骤也可以手动命令行完成
            ]
            commandLine mCommond
        }
    	
        //执行makeDexJar的时候会在之前执行makeJar
        makeDexJar.dependsOn(makeJar)
    }

    上面代码中新增了一个task任务:task makeDexJar(type: Exec) ,这个任务就是将编译好的jar通过sdk中的编译工具再次打包为含有dex的jar包,这样就不用将jar拷贝到指定目录再手动用命令打包了。还有上面有一段去读取 local.properties 的操作,代码注释中有提到,主要是为了获取sdk下的编译工具路径,动态读取出来其他小伙伴也不用去单独修改这个文件的路径了,读取示例:

    def readLocalProperties(){
        File file = rootProject.file('local.properties')
        if(file.exists()){
            InputStream inputStream = rootProject.file('local.properties').newDataInputStream();
            Properties properties = new Properties()
            properties.load(inputStream)
    
            if (properties.containsKey("sdk.dir")){
                println properties.getProperty("sdk.dir")
            }
        }
    }

    三、多个Gradle文件中方法相互调用

    这里要着重说明的是这一段代码:

    ext {
        readLocalSDKPropertiesToMakeDexJar = this.&readLocalSDKPropertiesToMakeDexJar
       }

    gradle提供了ext,所以我们可以很容易获取其他gradle的属性,例如 2.gradle 需要调用 1.gradle 文件中的方法,这个时候就需要像上面的写法一样,注意左右的方法名字是一样,this 后面多了一个 & 符号,其他Gradle文件如果想调用这个方法,一般可以这样:

    def outputDexJarName = 'Smart24Decode_dex.jar'
    def jarName = 'Smart24Decode.jar'
    def packagePath = 'com/ccn/Smart24Decode/'
    //直接调用
    readLocalSDKPropertiesToMakeDexJar(outputDexJarName, jarName, packagePath)

    或者通过task调用:

    task CustomTask << {
        def outputDexJarName = 'Smart24Decode_dex.jar'
        def jarName = 'Smart24Decode.jar'
        def packagePath = 'com/ccn/Smart24Decode/'
        readLocalSDKPropertiesToMakeDexJar(outputDexJarName, jarName, packagePath)
    }

    CustomTask << ,是gradle的语法,如果不加 << 的话,每次编译时都会执行这个task,加了<< ,只有执行这个task的时候才会执行里面的代码。包括后面如果有用到构建打包自动上传到服务器或者第三方的蒲公英平台,也会运用到类似的方式。

    OK 下面我们在 dexlibrary1 的build.gradle引用并调用打包方法,传递相关参数:

    测试一下看看效果如何,在右边的Gradle工具栏找到dexlibrary1这个module,在 other下找到 makeDexJar 任务并双击,你会发现dexlibrary1下build目录中生成了一个libs目录,里面有我们构建成功的文件:

     

    文章到此详细的讲述了整个demo示例和一些需要注意技术点,零零散散的整理了3天,如果有不清楚的地方就参考源码吧,最后祝大家生活愉快。

    Demo下载地址:

    https://github.com/gaochunchun/MakeDexJar_Application

     

    尊重博主劳动成果,转载注明:https://gaochun.blog.csdn.net/article/details/102553809

     

    展开全文
  • implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.3' ...
  • 编写Smali,生成dex

    2020-05-31 13:52:27
    .class public LHelloWord; .super Ljava/lang/Object; .method public static main...使用smali.jar将写好的smali文件生成dex文件,语法如下: java -jar smali.jar a -o xxxxx\xxxx\xx\test.dex xxxx\xxxx\xx\test.s
  • 一、生成 dex 文件、 二、生成 dex 文件代码示例、 三、生成 dex 结果
  • 最近在做一android项目,由于项目需要。在对
  • 遇到问题 在使用apktool做apk逆向工程时,我们一般都需要将apk反编译为smail,然后将要加入其中的SDK也编译成smail,然后将二者合并起来之后打包成一个新的apk,其中...​ sdk.jar sdk2.jar… sdk的jar文件,可以是多个
  • dex2jar反编译dex文件

    2014-04-30 11:39:25
    反编译dex文件 反编译apk解压后生成的class.dex文件 内附使用说明
  • Android动态加载jardex,apk文件

    千次阅读 2016-07-23 20:55:43
    最近发现Android有一发展方向,插件化,像360等等,他把功能索引放在主界面,当使用哪个功能就调用哪个jardex,或者apk,这种技术叫做动态加载,那么我们来看看这个dex实现了什么功能 插件化的原理实际是 Java ...
  • 最近一直在搞android动态加载这一块内容,感觉还是学会到了很新的东西,下面就分享给大家。  熟悉java的朋友,肯定知道ClassLoader这东西,我们可以使用ClassLoader去灵活的加载某个类,但是在android中大家有...
  • Android动态加载jar/dex

    千次阅读 2014-09-30 11:22:45
    前言  在目前的软硬件环境下,Native App与Web...本文对网上Android动态加载jar的资料进行梳理和实践在这里与大家一起分享,试图改善频繁升级这一弊病。 声明  欢迎转载,但请保留文章原始出处:)  
  • Android中单个dex文件所能包含的最大方法数是65536,这包含所依赖所有jar以及应用代码中的所有方法。简单的apk方法数很难达到这么,但是对于一些复杂大型的应用来说65536就很容易超过,当方法数达到65536后,...
  • 1、生成dex需要用到一 dx.bat,具体目录是在Android\sdk\build-tools\21.0.1(21.0.1不特指,每tools下都有的) 2.配置一下 环境变量:路径是dx.bat下的目录 3、打开命令行cmd dx --dex --output = C:\...
  • 同时在工程中引入了多个第三方jar包,导致调用的方法数超过了android设定的65536个(DEX 64K problem),进而导致dex无法生成,也就无法生成APK文件。 解决办法如下: 1、谷歌官方已经给出了相关的文档,参照...
  • [android反编译小结]apktool/ AXMLPrinter2.jar/ dex2jar.bat/ jd-gui/ Jodeclipse/ JadClipse
  • 然后在当前目录下在命令行中输入: d2j-dex2jar classes.dex 就会生成 classes.jar 包,此时会报如下错误: dex2jar classes.dex -> .\classes-dex2jar.jar Detail Error Information in File .\classes-...
  • 文章出自:... 三相关软件,都是最新版本: jd-gui-0.3.3.windows.zip(691.67 KB,) dex2jar-0.0.7.8-SNAPSHOT.zip(579.83 KB) apktool.rar(1.31 MB,) 也可以在
  •  dex2jar  apktool.rar 也可以在文中提到的链接里自己下载; 序: 总结反编译主要的目的在于学习。利用反编译进行相关的汉化或修改,都是不道德的! 大家都知道,将apk文件解压后有两
  • 开篇:“对于软件开发人员来说,保护代码安全也是比较重要的因素之一,不过目前来说Google Android平台选择了Java ...类似Sun JavaMe的Jar压缩格式一样,不过比较去别的是Android上的二进制代码被编译成为Dex的字节码
  • 这两天在研究应用的热修复,热修复的原理比较复杂昨天看了一天也没弄明白,不过大致流程弄明白了,有想研究热修复的可以参考鸿神...其中有一class->jar->dex的过程, 将class文件弄成jar(根据自己的需求将class文件
  • 反编译Apk(包括apktool、dex2jar和JD-GUI)下载

    千次下载 热门讨论 2017-01-05 16:21:14
    首先要使用到下载的这两工具:dex2jar和JD-GUI,前者是将apk中的classes.dex转化成Jar文件,而JD-GUI是一反编译工 具,可以直接查看Jar包的源代码。 具体步骤: 首先将apk文件,将后缀改为zip,解压,得到其中的...
  • 使用dex2jar反编译APK中的classes.dex

    千次阅读 2016-03-21 10:26:20
    先说下写这篇博文的初衷。 为了应用的代码不直接被他人窥视,我们一般都会在...我使用的反编译工具是dex2jar,反编译之后,项目中的classes.dex会相应的生成classes-dex2jar.jar文件(可使用jd-gui查看,工具下载地
  • dex2jar反编译apk报错

    2020-10-10 12:00:22
    使用工具dex2jar反编译apk。记得之前一直用的好好的,突然有一天,发现无法正常使用了,反编译报错!!! 报错信息: Detail Error Information in File .\classes-error.zip Please report this file to ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,094
精华内容 4,837
关键字:

多个jar生成dex