FrameWork内核解析之XMS内核管理(一)上篇,计算机应届毕业生面试题

本文详细介绍了Android中反射Helper类的使用,包括invokeStaticMethod、invokeMethod等方法,以及如何通过反射替换ClassLoader实现动态加载APK。文章还提到了在实际操作中可能遇到的问题,如文件路径错误、权限问题和AndroidManifest.xml的配置。此外,文中还展示了如何通过反射创建实例、获取和设置字段、调用方法,并提供了实际的MyApplication和MainActivity的代码示例。
摘要由CSDN通过智能技术生成

ReflectHelper.java  这个是的我的反射帮助类

package com.example.dexclassloaderactivity;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

/**

  • 反射辅助函数
  • @author

*/
public class ReflectHelper {
public static final Class<?>[] PARAM_TYPE_VOID = new Class<?>[]{};

public static Object invokeStaticMethod(String className, String methodName, Class<?>[] paramTypes, Object…params) {
try {
Class<?> clazz = Class.forName(className);
Method method = clazz.getMethod(methodName, paramTypes);
method.setAccessible(true);
return method.invoke(null, params);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

public static Object invokeMethod(String className, String methodName, Class<?>[] paramTypes, Object obj, Object…params) {
try {
Class<?> clazz = Class.forName(className);
Method method = clazz.getMethod(methodName, paramTypes);
method.setAccessible(true);
return method.invoke(obj, params);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

public static Object getStaticField(String className, String fieldName) {
try {
Class<?> clazz = Class.forName(className);
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(null);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

public static Object getField(String className, String fieldName, Object obj) {
try {
Class<?> clazz = Class.forName(className);
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

public static void setStaticField(String className, String fieldName, Object value) {
try {
Class<?> clazz = Class.forName(className);
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(null, value);
} catch (Exception e) {
e.printStackTrace();
}
}

public static void setField(String className, String fieldName, Object obj, Object value) {
try {
Class<?> clazz = Class.forName(className);
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
} catch (Exception e) {
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"?>

<manifest xmlns:android=“http://schemas.android.com/apk/res/android”
package="com.example.dexclassload

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

eractivity"
android:versionCode=“1”
android:versionName=“1.0” >

<application
android:name=“com.example.dexclassloaderactivity.MyApplication”
android:allowBackup=“true”
android:icon="@drawable/ic_launcher"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值