动态加载dex

动态加载dex

  1. 新建一个工程

  2. 新建一个类,在类中加一个方法,添加一个 TextView 调用

    package com.example.myloaddex;

    import androidx.appcompat.app.AppCompatActivity;

    import android.os.Bundle;

    public class MainActivity extends AppCompatActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            // 调用
            LoadDex.createView(this);
       }
    }

    MyLoadDex

    package com.example.myloaddex;

    import android.app.Activity;
    import android.view.Gravity;
    import android.widget.FrameLayout;
    import android.widget.TextView;

    public class LoadDex {
        // 一个静态方法
        public static void createView(Activity ac){
            // 创建一个TextView
            TextView tv= new TextView(ac);
            // 创建布局设置参数
            FrameLayout.LayoutParams params=new FrameLayout.LayoutParams(
                    FrameLayout.LayoutParams.WRAP_CONTENT,
                    FrameLayout.LayoutParams.WRAP_CONTENT
           );
            // 设置控件到顶点
            params.topMargin=0;
            // 设置控件的位置
            params.gravity= Gravity.TOP|Gravity.CENTER_HORIZONTAL;
            tv.setText("MyTestActivity Textview!");
            // 添加TextView到Activity
            ac.addContentView(tv,params);
       }
    }
  3. 编译成 apk 1570429664735

  4. 反编译 apk,将新建的类的 smali 文件提取出来

  5. 单独将一个 smali 文件转成 dex 文件 E:\MyLoadDex\app\build\intermediates\javac\debug\classes

    整个文件夹复制出来,因为要保留路径,不然会出错(版本不同路径可能不同,直接在文件夹下搜classes文件夹)

    然后用./d2j-jar2dex.bat LoadDex.class -o test.dex命令将LoadDex.class文件转成test.dex

1570428171277

  1. 将 dex 文件放到 assets 文件夹中,assets自己右键新建

1570428189167

  1. 把原本的那个类代码删除,进文件夹直接删除文件夹里面的那个类文件就可以

  2. 写代码动态加载 dex,让程序正常跑起来

调用

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 1. 拷贝dex到安装目录下
        String path = copyDex("test.dex");
        // 2. 使用DexClassLoader,加载dex
        DexClassLoader dex = loadDex(path);
        // 3. 使用返回的dex对象,加载类,获取方法对象,调用方法
        useClass(dex);
   }

使用Java反射机制,动态加载dex,并调用

// 使用Java反射机制,动态加载dex,并调用
    public void useClass(DexClassLoader dex) {
        try {
            // 获取加载的类信息
            // 包名+工程名+类名
            Class TestDex = dex.loadClass("com.bluelesson.app34_3.MyTestActivity");
           // 参数为构造方法参数数组
            // 获取成员方法
            Method methodTest = TestDex.getDeclaredMethod("createView",     // 方法名称
                    new Class[]{Activity.class});   // 方法参数类型数组
            // 取消java访问检查,提高反射速度
            methodTest.setAccessible(true);
            // 调用方法,this指针传进去
            methodTest.invoke(null,        // 类对象
                    new Object[] { this });   // 方法参数数组
       } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
       }
   }
   

获得指定文件的dex加载器

// 获得指定文件的dex加载器
    public DexClassLoader loadDex(String path) {
        // 创建dex文件的类加载器,返回DexClassLoader对象
        DexClassLoader dex = new DexClassLoader(
                path,       // dex路径
                getCacheDir().toString(),   // 优化之后的文件的路径
                null,      // 原生库路径
                getClassLoader());          // 父类加载器
        return dex;
   }

拷贝指定的文件从assets目录中到/data/data/包名/files中

    // 拷贝指定的文件从assets目录中到/data/data/包名/files中
    String copyDex(String dexName) {
        // 获取assets目录管理器
        AssetManager as = getAssets();
        // 合成路径
        // getFilesDir返回的就是/data/data/包名/files
        String path = getFilesDir() + File.separator + dexName; // File.separator 分隔符
        Log.i("15pb-log", path);
        try {
            // 创建文件流
            FileOutputStream out = new FileOutputStream(path);
            // 打开文件
            InputStream is = as.open(dexName);
            // 循环读取文件,拷贝到对应路径
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = is.read(buffer)) != -1) {
                out.write(buffer, 0, len);
           }
            // 关闭文件
            out.close();

       } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            return "";
       }
        return path;
   }
posted @ 2019-10-07 15:43  ltyandy  阅读(799)  评论(0编辑  收藏  举报