e.printStackTrace();
}
}
public static Object createInstance(String className, Class<?>[] paramTypes, Object...params) { Object object = null; try { Class<?> cls = Class.forName(className);
Constructor<?> constructor = cls.getConstructor(paramTypes);
constructor.setAccessible(true);
object = constructor.newInstance(params);
}catch (Exception e) {
e.printStackTrace();
}
return object;
}
/**
- Locates a given field anywhere in the class inheritance hierarchy.
- @param instance an object to search the field into.
- @param name field name
- @return a field object
- @throws NoSuchFieldException if the field cannot be located
*/
public static Field findField(Object instance, String name) throws NoSuchFieldException {
for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
try {
Field field = clazz.getDeclaredField(name);
if (!field.isAccessible()) {
field.setAccessible(true);
}
return field;
} catch (NoSuchFieldException e) {
// ignore and search next
}
}
throw new NoSuchFieldException("Field " + name + " not found in " + instance.getClass());
}
/**
- Locates a given field anywhere in the class inheritance hierarchy.
- @param cls to search the field into.
- @param name field name
- @return a field object
- @throws NoSuchFieldException if the field cannot be located
*/
public static Field findField2(Class<?> cls, String name) throws NoSuchFieldException { Class<?> clazz = null;
for (clazz = cls; clazz != null; clazz = clazz.getSuperclass()) {
try {
Field field = clazz.getDeclaredField(name);
if (!field.isAccessible()) {
field.setAccessible(true);
}
return field;
} catch (NoSuchFieldException e) {
// ignore and search next
}
}
throw new NoSuchFieldException("Field " + name + " not found in " + clazz);
}
/**
- Locates a given method anywhere in the class inheritance hierarchy.
- @param instance an object to search the method into.
- @param name method name
- @param parameterTypes method parameter types
- @return a method object
- @throws NoSuchMethodException if the method cannot be located
*/
public static Method findMethod(Object instance, String name, Class<?>... parameterTypes) throws NoSuchMethodException { for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
try {
Method method = clazz.getDeclaredMethod(name, parameterTypes);
if (!method.isAccessible()) {
method.setAccessible(true);
}
return method;
} catch (NoSuchMethodException e) {
// ignore and search next
}
}
throw new NoSuchMethodException("Method " + name + " with parameters " +
Arrays.asList(parameterTypes) + " not found in " + instance.getClass());
}
}
MyApplication.java 这个类用实现替换mClassLoader
package com.example.dexclassloaderactivity;
import java.io.File;
import java.lang.ref.WeakReference;
import dalvik.system.DexClassLoader;
import android.annotation.SuppressLint;
import android.app.Application;
import android.os.Environment;
import android.util.ArrayMap;
import android.util.Log;
public class MyApplication extends Application{
public static final String TAG = “MyApplication”;
public static final String AppName = “test.apk”;
public static int i = 0;
public static DexClassLoader mClassLoader;
@Override
public void onCreate() {
Log.d(TAG, “替换之前系统的classLoader”);
showClassLoader();
try {
String cachePath = this.getCacheDir().getAbsolutePath();
String apkPath = /Environment.getExternalStorageState() + File.separator/“/sdcard/”+ AppName;
mClassLoader = new DexClassLoader(apkPath, cachePath,cachePath, getClassLoader());
loadApkClassLoader(mClassLoader);
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, “替换之后系统的classLoader”);
showClassLoader();
}
@SuppressLint(“NewApi”)
public void loadApkClassLoader(DexClassLoader loader) {
try {
Object currentActivityThread = ReflectHelper.invokeMethod(“android.app.ActivityThread”, “currentActivityThread”, new Class[] {},new Object[] {});
String packageName = this.getPackageName();
ArrayMap mpackages = (ArrayMap) ReflectHelper.getField(“android.app.ActivityThread”, “mPackages”, currentActivityThread);
WeakReference wr= (WeakReference)mpackages.get(packageName);
Log.e(TAG, “mClassLoader:” + wr.get());
ReflectHelper.setField(“android.app.LoadedApk”, “mClassLoader”, wr.get(), loader);
Log.e(TAG, “load:” + loader);
} catch (Exception e) {
Log.e(TAG, “load apk classloader error:” + Log.getStackTraceString(e));
}
}
/**
- 打印系统的classLoader
*/
public void showClassLoader() {
ClassLoader classLoader = getClassLoader();
if (classLoader != null){
Log.i(TAG, “[onCreate] classLoader " + i + " : " + classLoader.toString());
while (classLoader.getParent()!=null){
classLoader = classLoader.getParent();
Log.i(TAG,”[onCreate] classLoader " + i + " : " + classLoader.toString());
i++;
}
}
}
}
然后就是MainActivity.java文件,里面包含了下面另外一种方式,打开activity,所以我把函数 inject(DexClassLoader loader)先注释掉。
package com.example.dexclassloaderactivity;
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import dalvik.system.DexClassLoader;
import dalvik.system.PathClassLoader;
public class MainActivity extends ActionBarActivity{
public static final String TAG = “MainActivity”;
public static final String AppName = “test.apk”;
public static DexClassLoader mDexClassLoader = null;
public static final String APPName = “test.apk”;
public TextView mText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.text2).setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
try {
// inject(MyApplication.mClassLoader);
String apkPath = Environment.getExternalStorageDirectory().toString() + File.separator + APPName;
Class clazz = MyApplication.mClassLoader.loadClass(“com.example.testapkdemo.MainActivity”);
Intent intent = new Intent(MainActivity.this, clazz);
startActivity(intent);
finish();
} catch (Exception e) {
Log.e(TAG, “name:” + Log.getStackTraceString(e));
}
}
});
}
private void inject(DexClassLoader loader){
PathClassLoader pathLoader = (PathClassLoader) getClassLoader();
try {
Object dexElements = combineArray(
getDexElements(getPathList(pathLoader)),
getDexElements(getPathList(loader)));
Object pathList = getPathList(pathLoader);
setField(pathList, pathList.getClass(), “dexElements”, dexElements);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static Object getPathList(Object baseDexClassLoader)
throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
ClassLoader bc = (ClassLoader)baseDexClassLoader;
return getField(baseDexClassLoader, Class.forName(“dalvik.system.BaseDexClassLoader”), “pathList”);
}
private static Object getField(Object obj, Class<?> cl, String field)
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field localField = cl.getDeclaredField(field);
localField.setAccessible(true);
return localField.get(obj);
}
private static Object getDexElements(Object paramObject)
throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException {
return getField(paramObject, paramObject.getClass(), “dexElements”);
}
private static void setField(Object obj, Class<?> cl, String field,
Object value) throws NoSuchFieldException,
IllegalArgumentException, IllegalAccessException {
Field localField = cl.getDeclaredField(field);
localField.setAccessible(true);
localField.set(obj, value);
}
private static Object combineArray(Object arrayLhs, Object arrayRhs) {
Class<?> localClass = arrayLhs.getClass().getComponentType();
int i = Array.getLength(arrayLhs);
int j = i + Array.getLength(arrayRhs);
Object result = Array.newInstance(localClass, j);
for (int k = 0; k < j; ++k) {
if (k < i) {
Array.set(result, k, Array.get(arrayLhs, k));
} else {
Array.set(result, k, Array.get(arrayRhs, k - i));
}
}
return result;
}
}
这里一定要注意,我们犯了3个错,
1、test.apk的路径写错了,下次写文件路径的时候,我们应该需要加上File file = new File(path); 用file.exist()函数来判断是否存在
2、从sdcard卡里面读取test.apk,没加上权限,
3、写了Application,忘了在AndroidManifest.xml文件里面声明。
我们还需要注意要加上开启activity 在AndroidManifest.xml里面注册,切记,希望下次不要再次犯错。
AndroidManifest.xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
运行结果如下:
然后这里又出现了插件资源和宿主资源冲突问题,我们后面再来研究。
4、合并PathClassLoader和DexClassLoader中的dexElements数组
我们首先来看一下PathClassLoader和DexClassLoader类加载器的父类BaseDexClassloader的源码:
(这里需要注意的是PathClassLoader和DexClassLoader类的父加载器是BaseClassLoader,他们的父类是BaseDexClassLoader)
这里有一个DexPathList对象,在来看一下DexPathList.java源码:
Elements数组,我们看到这个变量他是专门存放加载的dex文件的路径的,系统默认的类加载器是PathClassLoader,本身一个程序加载之后会释放一个dex出来,这时候会将dex路径放到里面,当然DexClassLoader也是一样的,那么我们会想到,我们是否可以将DexClassLoader中的dexElements和PathClassLoader中的dexElements进行合并,然后在设置给PathClassLoader中呢?这也是一个思路。我们来看代码:
/**
- 以下是一种方式实现的
- @param loader
*/
private void inject(DexClassLoader loader){
PathClassLoader pathLoader = (PathClassLoader) getClassLoader();
try {
Object dexElements = combineArray(
getDexElements(getPathList(pathLoader)),
getDexElements(getPathList(loader)));
Object pathList = getPathList(pathLoader);
setField(pathList, pathList.getClass(), “dexElements”, dexElements);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static Object getPathList(Object baseDexClassLoader)
throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
ClassLoader bc = (ClassLoader)baseDexClassLoader;
return getField(baseDexClassLoader, Class.forName(“dalvik.system.BaseDexClassLoader”), “pathList”);
}
private static Object getField(Object obj, Class<?> cl, String field)
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field localField = cl.getDeclaredField(field);
localField.setAccessible(true);
return localField.get(obj);
}
private static Object getDexElements(Object paramObject)
throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException {
return getField(paramObject, paramObject.getClass(), “dexElements”);
}
private static void setField(Object obj, Class<?> cl, String field,
Object value) throws NoSuchFieldException,
IllegalArgumentException, IllegalAccessException {
Field localField = cl.getDeclaredField(field);
localField.setAccessible(true);
localField.set(obj, value);
}
private static Object combineArray(Object arrayLhs, Object arrayRhs) {
Class<?> localClass = arrayLhs.getClass().getComponentType();
int i = Array.getLength(arrayLhs);
int j = i + Array.getLength(arrayRhs);
Object result = Array.newInstance(localClass, j);
for (int k = 0; k < j; ++k) {
先自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以扫码领取!!!!
最后
希望本文对你有所启发,有任何面试上的建议也欢迎留言分享给大家。
好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划,来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。
好了~如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。
为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可免费领取!
升自己,对于自己的未来还不够了解不知道给如何规划,来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。
[外链图片转存中…(img-RFX1qS5U-1711247559324)]
好了~如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。
[外链图片转存中…(img-W1LY6W7J-1711247559324)]
为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可免费领取!