发新帖

DexClassLoader自定义加载Assets目录下的dex、jar文件

[复制链接]
16791 6
本帖最后由 小白 于 2015-3-7 12:40 编辑

就像网上网上有些朋友说的 dex文件的方法数貌似有上限,在网上找了好久也没找到可以完全把整个dex文件放在外部加载的方法 下面这个方法,是我从某个游戏中提取的,贴出代码,如果有错误之处,还望指点出来
转自:http://blog.csdn.net/zhuanshenai/article/details/43890235小坑说了:过年还在敲代码,活该没对象
[Java] 纯文本查看 复制代码
package com.example.dextest;

import android.app.Application;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
import dalvik.system.DexClassLoader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Myapp extends Application {
        private static String AssetsDexFilePath = "_data";// Assets文件夹下的jar文件
        private static String DexDir = "dex";
        private static String ExtractedDexFileName = "_data.jar";// 导出
        private static String TAG = "packer";
        private Application mApp;
        //ContextWrapper contextWrapper;
        
        

        public Myapp() {
                super();
        }

        @Override
        public void onTerminate() {
                // TODO Auto-generated method stub
                super.onTerminate();
        }

        @Override
        public void onConfigurationChanged(Configuration newConfig) {
                // TODO Auto-generated method stub
                super.onConfigurationChanged(newConfig);
                if (this.mApp != null) {
                        this.mApp.onConfigurationChanged(newConfig);
                }
        }

        @Override
        public void onLowMemory() {
                // TODO Auto-generated method stub
                super.onLowMemory();
             if(this.mApp != null) {
                    this.mApp.onLowMemory();
                }
        }

        @Override
        public void onTrimMemory(int level) {
                // TODO Auto-generated method stub
                super.onTrimMemory(level);
                 if(this.mApp != null) {
                    this.mApp.onTerminate();
                }
        }

        @Override
        public void onCreate() {
                // TODO Auto-generated method stub
                super.onCreate();
                copyDex();
                String dexfilepath = getDir(DexDir, 0).getPath();
                setApkClassLoader(new DexClassLoader(getDir(DexDir, 0).getPath() + "/" + ExtractedDexFileName, dexfilepath, getApplicationInfo().nativeLibraryDir, getClassLoader()));
                //如果程序原来存在application 下面这个 就是替换原来application
                //this.mApp = this.getClassLoader().loadClass(this.getPackageManager().getApplicationInfo( this.getPackageName(), 128).metaData.getString("packerApp")).newInstance();
                Method v7;
                try {
                        v7 = Class.forName("android.content.ContextWrapper").getDeclaredMethod("attachBaseContext", 
                                Context.class);
                        v7.setAccessible(true);
            v7.invoke(this);
            v7.setAccessible(false);
            /*如果存在原来的application 
             *v7.invoke(this.mApp, this);
             *v7.setAccessible(false);
             *this.mApp.onCreate();
             * 
             */
            
            //this.mApp.onCreate();
                } catch (NoSuchMethodException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (ClassNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (IllegalArgumentException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (IllegalAccessException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (InvocationTargetException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
       
        }

        /**类加载器
         * @param paramClassLoader
         */

        @SuppressWarnings("unused")
        private void setApkClassLoader(ClassLoader paramClassLoader) {
                try {
                      Class localClass = Class.forName("android.app.ActivityThread");
                      Object localObject1 = localClass.getMethod("currentActivityThread", new Class[0]).invoke(null, new Object[0]);
                      Field localField1 = localClass.getDeclaredField("mPackages");
                      localField1.setAccessible(true);
                      Object localObject2 = localField1.get(localObject1);
                      localField1.setAccessible(false);
                      Method localMethod = localObject2.getClass().getMethod("get", new Class[] { Object.class });
                      Object[] arrayOfObject = new Object[1];
                      arrayOfObject[0] = getPackageName();
                      Object localObject3 = ((WeakReference)localMethod.invoke(localObject2, arrayOfObject)).get();
                      Field localField2 = localObject3.getClass().getDeclaredField("mClassLoader");
                      localField2.setAccessible(true);
                      localField2.set(localObject3, paramClassLoader);
                      localField2.setAccessible(false);
                } catch (ClassNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        Log.e(TAG, "err 2");
                } catch (IllegalArgumentException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        Log.e(TAG, "err 3");
                } catch (IllegalAccessException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        Log.e(TAG, "err 4");
                } catch (InvocationTargetException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        Log.e(TAG, "err 5");
                } catch (NoSuchMethodException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        Log.e(TAG, "err 6");
                } catch (NoSuchFieldException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        Log.e(TAG, "err 1");
                }
        }

        /**
         * 复制要加载jar文件
         */
        private void copyDex() {
                deleteFile(DexDir);// 如果文件存在则删除文件
                File dexFile = getDir(DexDir, 0);// 需要导出的的文件路径
                
                try {
                        InputStream localInputStream = getAssets().open(AssetsDexFilePath);// 获取Assets下的文件
                        FileOutputStream localFileOutputStream = new FileOutputStream(new File(dexFile,
                                        ExtractedDexFileName));
                        byte[] arrayOfByte = new byte[1024];
                        //int i = localInputStream.read(arrayOfByte);
                      for (;;)
                      {
                        int i = localInputStream.read(arrayOfByte);
                        if (i == -1) {
                          break;
                        }
                        localFileOutputStream.write(arrayOfByte, 0, i);
                        localFileOutputStream.flush();
                        }
                        
                        localFileOutputStream.close();
                        localInputStream.close();
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        Log.e(TAG, "exception in copyDex: " + e.toString());
                        return;
                }

        }
}

附件地址:http://pan.baidu.com/s/1bn0Hs7P

举报 使用道具

回复

精彩评论6

默小坑    发表于 2015-2-21 22:34:40 | 显示全部楼层
大过年的

举报 使用道具

回复
wutp    发表于 2015-3-6 17:31:06 | 显示全部楼层
学习,manifest文件是否需要相应修改?楼主能否传个完整工程,只贴主要代码不好学习测试呀:(

感谢!

点评

manifest application标签要把 这个类即: android:name="com.example.dextest.Myapp"设置为全局变量  详情 回复 发表于 2015-3-7 12:36

举报 使用道具

回复 支持 反对
小白    发表于 2015-3-7 12:36:03 | 显示全部楼层
本帖最后由 小白 于 2015-3-7 12:37 编辑
wutp 发表于 2015-3-6 17:31
学习,manifest文件是否需要相应修改?楼主能否传个完整工程,只贴主要代码不好学习测试呀:(

感谢! ...

manifest application标签要把 这个类即: android:name="com.example.dextest.Myapp"设置为全局变量   
<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:name="com.example.dextest.Myapp" >我在帖子后面上传了一个测试工程   要注意的原来的dex文件要压缩成zip文件

举报 使用道具

回复 支持 反对
wutp    发表于 2015-3-12 15:35:00 | 显示全部楼层
谢谢,试了下测试工程,需要把assets/_data 文件改名为 data后,显示了helloworld,这是正常状态吗?
data文件是一个helloworld的DEX文件(ZIP压缩过)?

点评

正常的,这是个,测试工程, 经过zip压缩的的的 然后 复制到assets文件夹即可  详情 回复 发表于 2015-3-12 19:28

举报 使用道具

回复 支持 反对
小白    发表于 2015-3-12 19:28:13 | 显示全部楼层
wutp 发表于 2015-3-12 15:35
谢谢,试了下测试工程,需要把assets/_data 文件改名为 data后,显示了helloworld,这是正常状态吗?
data ...

正常的,这是个,测试工程, 经过zip压缩的的的 然后 复制到assets文件夹即可

举报 使用道具

回复 支持 反对
wutp    发表于 2015-3-13 17:35:19 | 显示全部楼层
我把自己写的APK的 DEX文件压缩zip,更名为data放在assets文件夹后,运行报错:

03-13 05:19:38.190: E/AndroidRuntime(1447): FATAL EXCEPTION: main
03-13 05:19:38.190: E/AndroidRuntime(1447): Process: com.example.sodex, PID: 1447
03-13 05:19:38.190: E/AndroidRuntime(1447): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.sodex/com.example.sodex.MainActivity}: java.lang.ClassNotFoundException: Didn't find class "com.example.sodex.MainActivity" on path: DexPathList[[zip file "/data/data/com.example.sodex/app_cas/_data.jar"],nativeLibraryDirectories=[/data/app-lib/com.example.sodex-2, /system/lib]]

看你的测试代码中也没有将zip 解压缩还原为dex 的过程,是不是不应该压缩为zip?
给你发了站内信息,有空私聊,请教!谢谢!

举报 使用道具

回复 支持 反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表