类加载器调用dex文件

本文详细介绍了在Android应用中如何通过类加载器调用Dex文件,包括直接获取编译后的dex文件、通过jar包转换为dex、以及从网上下载并动态加载dex文件的过程。
摘要由CSDN通过智能技术生成

获取dex文件的方式

直接获取

  • 项目运行后 在as工程build\intermediates\project_dex_archive\debug\out\com 这个目录下会生成对应脚本的dex文件
    缺点:一个dex文件内只有一个脚本

jar包转dex

新建了两个脚本 loadTest NetTool

task clearJar(type: Delete){
    delete 'libs/test.jar'
}

task makeJar(type: org.gradle.api.tasks.bundling.Jar){
    baseName('test')
    from('build/intermediates/javac/debug/classes/com/test/myapplication')
    into('com/test/myapplication/')
    exclude('MainActivity.class', 'BuildConfig.class', 'MainActivity$1.class')  //屏蔽掉多余的文件
    exclude{ it.name.startsWith('R$');}
}
makeJar.dependsOn(clearJar, build)

运行后获得jar包
在这里插入图片描述
使用dx工具
在这里插入图片描述
在这里插入图片描述
jadx查看dex文件的结构
在这里插入图片描述

加载dex

将dex文件复制到另一个工程的assets目录下
在这里插入图片描述
因为DexClassLoader 参数需要一个文件路径 但是assets 中的文件并不是一个普通的文件路径,而是一个封装在 APK 中的资源。因此,你必须先将 dex 文件从 assets 复制到设备上的一个可访问的目录,然后再使用 DexClassLoader 加载它。

    private void LoadDexClass(){

        File cache = this.getCacheDir();  // 获取内置缓存目录 dex文件大的话可以换成SD卡
        String file = cache.getAbsolutePath() + File.separator + "mpl";  //新建一个目录用于存放复制的dex

        FileTool.copyFile(this, "loadTest.dex", file);
        DexClassLoader dexClassLoader = new DexClassLoader(file, cache.getAbsolutePath(), null, getClassLoader());  // 第一个参数:dex的位置、第二个参数:存放优化后dex的位置
        try{
            Class libClazz = dexClassLoader.loadClass("com.test.myapplication.loadTest");
            Object obj = libClazz.newInstance();  //类似反射的使用
            Method  method = libClazz.getDeclaredMethod("Say");
            method.invoke(obj);

            Field field = libClazz.getField("url");
            String url = (String) field.get(obj);
            Log.i("main", url);

        }catch (Exception e){
            e.printStackTrace();
        }

    }
    private void LoadDexClass2(){

        File cache = this.getCacheDir();
        String file = cache.getAbsolutePath() + File.separator + "mpl";

        FileTool.copyFile(this, "NetTool.dex", file);
        DexClassLoader dexClassLoader = new DexClassLoader(file, cache.getAbsolutePath(), null, getClassLoader());
        try{
            Class libClazz = dexClassLoader.loadClass("com.test.myapplication.NetTool");
            Object obj = libClazz.newInstance();
            Method  method = libClazz.getDeclaredMethod("getDizhi");
            int dizhi = (int)method.invoke(obj);
            Log.i("main", String.valueOf(dizhi));
            Method  method2 = libClazz.getDeclaredMethod("setDizhi", int.class);
            method2.invoke(obj,99);
            int dizhi23 = (int)method.invoke(obj);
            Log.i("main", String.valueOf(dizhi23));

        }catch (Exception e){
            e.printStackTrace();
        }

    }
import android.content.Context;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class FileTool {
    //默认dex路径在assests里面
    public static void copyFile(Context context, String fileName, String toPath){

        try{
            InputStream inputStream = context.getAssets().open(fileName);
            File to = new File(toPath);
            if(!to.exists()){
                to.createNewFile();
            }
            OutputStream outputStream = new FileOutputStream(to.getAbsoluteFile());
            byte[] buffer = new byte[1024];
            int i;
            while ((i = inputStream.read(buffer)) != -1){
                outputStream.write(buffer, 0 ,i);
            }
            if(inputStream != null)
                inputStream.close();
            else
                Log.i("FileTool", "input null");
            if(outputStream != null)
                outputStream.close();
            else
                Log.i("FileTool", "output null");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}


package com.test.myapplication;

import android.util.Log;

public class loadTest {
    public String url = "https://www.baidu.com";

    public void Say(){
        Log.i("dex", url);
    }
}

---------------------------------------------------
package com.test.myapplication;

import android.util.Log;

public class NetTool {
    private int dizhi = 12138;
    public int getDizhi(){
        return dizhi;
    }

    public void setDizhi(int a){
        dizhi = a;
        Log.i("dex", "修改成功?");
    }
}

从网上下载dex加载

import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Environment;
import android.widget.Toast;

public class FileDownloader {

    private Context context;

    public FileDownloader(Context context) {
        this.context = context;
    }

    public void downloadFile(String url, String fileName) {
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE)
                .setAllowedOverRoaming(false)
                .setTitle(fileName)
                .setDescription("Downloading")
                .setDestinationInExternalFilesDir(context, null, fileName);  //null 为下载到私有目录

        DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
        if (downloadManager != null) {
            long downloadId = downloadManager.enqueue(request);
            registerDownloadReceiver(downloadId, fileName);
        }
    }


    private void registerDownloadReceiver(final long downloadId, final String fileName) {
        BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
                if (id == downloadId) {
                    Toast.makeText(context, "Download completed", Toast.LENGTH_SHORT).show();
                    // You can perform further operations here, such as moving the downloaded file to a different location
                }
            }
        };

        context.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }
}

public class MainActivity extends AppCompatActivity {

    private Dynamic dynamic;
    private FileDownloader fileDownloader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.tx).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                LoadDexClass();
//                LoadDexClass2();
                fileDownloader = new FileDownloader(getApplicationContext());
                String url = "---------";
                String fileName = "out.dex";
                fileDownloader.downloadFile(url, fileName);

                loadDownloadedDexFile("out.dex");
            }
        });
    }

    private void loadDownloadedDexFile(String fileName) {
        File dexFile = new File(this.getExternalFilesDir(null), fileName); // 获取下载的 dex 文件路径
        if (!dexFile.exists()) {
            Toast.makeText(this, "Dex file not found", Toast.LENGTH_SHORT).show();
            return;
        }

        String dexPath = dexFile.getAbsolutePath();
        DexClassLoader dexClassLoader = new DexClassLoader(dexPath, this.getCacheDir().getAbsolutePath(), null, this.getClassLoader());
        try {
            Class libClazz = dexClassLoader.loadClass("com.test.myapplication.loadTest");
            Object obj = libClazz.newInstance();
            Method  method = libClazz.getDeclaredMethod("Say");
            method.invoke(obj);

            Field field = libClazz.getField("url");
            String url = (String) field.get(obj);
            Log.i("main", url);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值