版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tanzui/article/details/85990403
项目需要在 Android shell 下执行 Java 代码,很多时候需要用到Context,不是常规的 Android 程序执行没办法直接获取到 Context 于是在经过一番阅读 Android 源码之后找到解决方案,手动创建一个Context。
先看 Context.java 的源码,发现是一个抽象类,具体实现是在 ContextImpl.java
创建 ContextImpl 的方法如下:
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
null);
context.setResources(packageInfo.getResources());
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
return context;
}
是一个私有静态方法,有一个 ActivityThread 参数,这样的话只需要反射得到它并给他一个参数就可以了
继续看 ActivityThread 的实现,发现有个静态方法 systemMain:
public static ActivityThread systemMain() {
// The system process on low-memory devices do not get to use hardware
// accelerated drawing, since this can add too much overhead to the
// process.
if (!ActivityManager.isHighEndGfx()) {
ThreadedRenderer.disable(true);
} else {
ThreadedRenderer.enableForegroundTrimming();
}
ActivityThread thread = new ActivityThread();
thread.attach(true);
return thread;
}
只需要反射执行它就能拿到 ActivityThread 创建的实例,这样的话 获取 ContextImpl 的方法和参数都拿到了,只需要反射执行就可以了,代码如下:
Looper.prepareMainLooper();
Class<?> ActivityThread = Class.forName("android.app.ActivityThread");
Method systemMain = ActivityThread.getDeclaredMethod("systemMain");
Object object = systemMain.invoke(null);
Class<?> ContextImpl = Class.forName("android.app.ContextImpl");
Method createSystemContext = ContextImpl.getDeclaredMethod("createSystemContext", ActivityThread);
createSystemContext.setAccessible(true);
Context contextInstace = (Context)createSystemContext.invoke(null, object);
Context context = contextInstace.createPackageContext("com.tanzui.test", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);