类加载器
- DexClassLoader 加载sdcard目录下的apk或jar文件
- PathClassLoader 加载路径必须在/data/app路径下
注意点
- 同一个Class = 相同的 ClassName + PackageName + ClassLoader
- DexClassLoader构造参数需要一个父加载器, 在父加载器里找不到类时,再从子加载器里加载
- DexClassLoader调用loadClass方法加载指定类
代码示例
加载apk里的一个类里的一个方法
插件apk
1 2 3 4 5 6 7 |
// package com.example.plug; public class GetPlug { public int getAdd(int a, int b) { return a + b; } } |
主应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
//DexClassLoader构造参数需要的父级加载器 ClassLoader localClassLoader = ClassLoader.getSystemClassLoader(); //要加载的文件所在的路径,DexClassLoader只能加载jar或apk文件 String dexpath = Environment.getExternalStorageDirectory() + "/plug.apk"; //加载的文件的要拷贝的文件夹, Context的getDir(String name, int mode)方法返回在data/data/下的dex文件,没有则创建 File dexOutputDir = MainActivity.this.getDir("dex", 0); DexClassLoader localDexClassLoader = new DexClassLoader(dexpath, dexOutputDir.getAbsolutePath(), null, localClassLoader); try { // 调用加载器加载指定的类 Class plugClass = localDexClassLoader.loadClass("com.example.plug.GetPlug"); // 下面是反射到方法 Object instance = plugClass.newInstance(); Class[] params = new Class[2]; params[0] = Integer.TYPE; params[1] = Integer.TYPE; Method method = plugClass.getMethod("getAdd", params); Integer i = (Integer) method.invoke(instance, 1, 2); showTextview.setText(i + ""); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } |
加载apk文件里的一个res资源
重新获取一个资源Resources
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/** * AssetManager mAssetManager = null; * Resources mResources; * String mDexPath; //apk文件路径 * Resources.Theme mTheme; */ protected void loadResources() { try { AssetManager assetManager = AssetManager.class.newInstance(); Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class); addAssetPath.invoke(assetManager, mDexPath); mAssetManager = assetManager; } catch (Exception e) { e.printStackTrace(); } Resources superRes = super.getResources(); mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); mTheme = mResources.newTheme(); mTheme.setTo(super.getTheme()); } |
使用插件里的资源
1 2 3 4 |
// 获取对应资源的id,参数为文件名,资源类型,插件apk包名 int id = mResources.getIdentifier("picc", "drawable", "com.example.sometest"); imageView.setImageDrawable(mResources.getDrawable(id)); |
一些方法
1 2 3 4 5 6 7 8 |
packageName = mResources.getResourcePackageName(R.string.app_name);//获取插件包名 Class<?> cls = Class.forName("com.android.internal.policy.PolicyManager"); Method m = cls.getMethod("makeNewLayoutInflater",Context.class); //传入当前PluginProxyContext类实例,创建一个布局加载器 mLayoutInflater = (LayoutInflater) m.invoke(null, this); |
自己写的一个工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
import android.content.Context; import android.content.ContextWrapper; import android.content.res.AssetManager; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; import java.io.File; import java.lang.reflect.Method; import dalvik.system.DexClassLoader; /** * 加载SD卡上的apk安装包 * 2016-03-14 */ public class PlugContext extends ContextWrapper { private Context context; private AssetManager mAssetManager = null; private Resources mResources; private String mDexPath; private DexClassLoader localDexClassLoader; private Resources.Theme mTheme; private String packageName; private LayoutInflater mLayoutInflater; /********* * 获取apk里的资源 ***********/ public static final String LAYOUT = "layout"; public static final String ID = "id"; public static final String DRAWABLE = "drawable"; public static final String STYLE = "style"; public static final String STRING = "string"; public static final String COLOR = "color"; public static final String DIMEN = "dimen"; public PlugContext(Context base) { super(base); this.context = base; } /** * 加载apk文件 * * @param apkPath apk文件的路径 * @param apkPackageName apk插件的包名 */ public void loadApk(String apkPath, String apkPackageName) { mDexPath = apkPath; packageName = apkPackageName; loadResources(); ClassLoader localClassLoader = ClassLoader.getSystemClassLoader(); //加载的文件的要拷贝的文件夹, Context的getDir(String name, int mode)方法返回在data/data/下的dex文件,没有则创建 File dexOutputDir = context.getDir("dex", 0); localDexClassLoader = new DexClassLoader(apkPath, dexOutputDir.getAbsolutePath(), null, localClassLoader); } /** * 获取插件里的类 * * @param className 包名+类名 * @return Class * @throws ClassNotFoundException */ public Class getClassInPlug(String className) throws ClassNotFoundException { Class plugClass = localDexClassLoader.loadClass(className); return plugClass; } /** * 获取插件里的方法 * * @param className 包名+类名 * @param methodName 方法名 * @param params 参数数组 * @return * @throws NoSuchMethodException * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException */ public Method getMethod(String className, String methodName, Class[] params) throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InstantiationException { Class plugClass = localDexClassLoader.loadClass(className); // 下面是反射到方法 Object instance = plugClass.newInstance(); Method method = plugClass.getMethod(methodName, params); return method; } /** * 获取插件里的方法 * * @param plugClass 类 * @param methodName 方法名 * @param params 参数数组 * @return * @throws IllegalAccessException * @throws InstantiationException * @throws NoSuchMethodException */ public Method getMethod(Class plugClass, String methodName, Class[] params) throws IllegalAccessException, InstantiationException, NoSuchMethodException { // 下面是反射到方法 Object instance = plugClass.newInstance(); Method method = plugClass.getMethod(methodName, params); return method; } /** * 获取对应的AssetManager,Resources */ protected void loadResources() { try { AssetManager assetManager = AssetManager.class.newInstance(); Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class); addAssetPath.invoke(assetManager, mDexPath); mAssetManager = assetManager; } catch (Exception e) { e.printStackTrace(); } Resources superRes = super.getResources(); mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); mTheme = mResources.newTheme(); mTheme.setTo(super.getTheme()); getSystemService(Context.LAYOUT_INFLATER_SERVICE); } /** * 获取资源的id * * @param name 资源名 * @param type 资源类型(drawable,layout,color...) * @return */ public int getResId(String name, String type) { return mResources.getIdentifier(name, type, packageName); } public int getId(String name) { return mResources.getIdentifier(name, ID, packageName); } public View getLayout(String name) { return mLayoutInflater.inflate(getResId(name, LAYOUT), null); } public String getString(String name) { return mResources.getString(getResId(name, STRING)); } public Drawable getDrawable(String name) { return mResources.getDrawable(getResId(name, DRAWABLE)); } public int getColor(String name) { return mResources.getColor(getResId(name, COLOR)); } public int getStyle(String name) { return getResId(name, STYLE); } public float getDimen(String name) { return mResources.getDimension(getResId(name, DIMEN)); } @Override public Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) { if (mLayoutInflater == null) { try { Class<?> cls = Class .forName("com.android.internal.policy.PolicyManager"); Method m = cls.getMethod("makeNewLayoutInflater", Context.class); mLayoutInflater = (LayoutInflater) m.invoke(null, this); } catch (Throwable e) { e.printStackTrace(); } } else { return mLayoutInflater; } } return super.getSystemService(name); } /** * 重写getResources方法,屏蔽原来的那一个 */ @Override public Resources getResources() { if (mResources != null) { return mResources; } return super.getResources(); } @Override public AssetManager getAssets() { if (mAssetManager != null) { return mAssetManager; } return super.getAssets(); } } |
0 Comments