Android插件化开发原理
来源:互联网 发布:java 系统登录界面 编辑:程序博客网 时间:2024/05/21 18:44
现在很多企业都在开始实施插件化开发,来实现目前减少包体积、模块独立化、模块独立更新,那么如果整个插件化时的功能都在一个Activity中就好说了,直接用反射把宿主的一个用于插件使用的Activity的各种生命周期映射到插件中某个类中对应的方法就可以关联起来了;如果插件中想实现多Activity的方式,但又不想在宿主AndroidManifest中去注册该怎么做呢,接下来我们只针对Activity非注册方式启动做一些讲解。
在讲解之前我们先来了解一下Activity启动流程,这里以4.4源码来讲
从startActivity来始看最终都会调用startActivityForResult方法中
public void startActivityForResult(Intent intent, int requestCode, Bundle options) { if (mParent == null) { Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } if (requestCode >= 0) { // If this start is requesting a result, we can avoid making // the activity visible until the result is received. Setting // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the // activity hidden during this time, to avoid flickering. // This can only be done when a result is requested because // that guarantees we will get information back when the // activity is finished, no matter what happens to it. mStartedActivity = true; } final View decor = mWindow != null ? mWindow.peekDecorView() : null; if (decor != null) { decor.cancelPendingInputEvents(); } // TODO Consider clearing/flushing other event sources and events for child windows. } else { if (options != null) { mParent.startActivityFromChild(this, intent, requestCode, options); } else { // Note we want to go through this method for compatibility with // existing applications that may have overridden it. mParent.startActivityFromChild(this, intent, requestCode); } } }
在上面方法中又调用了Instrumentation这个类的execStartActivity方法,再继续看
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) { synchronized (mSync) { final int N = mActivityMonitors.size(); for (int i=0; i<N; i++) { final ActivityMonitor am = mActivityMonitors.get(i); if (am.match(who, null, intent)) { am.mHits++; if (am.isBlocking()) { return requestCode >= 0 ? am.getResult() : null; } break; } } } } try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(); int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { } return null; }
看上面方法黑体部分,在看ActivityMangerNative.getDefault().startActivity()方法之前,我们先来看看这个checkStartActivityResult做了什么
static void checkStartActivityResult(int res, Object intent) { if (res >= ActivityManager.START_SUCCESS) { return; } switch (res) { case ActivityManager.START_INTENT_NOT_RESOLVED: case ActivityManager.START_CLASS_NOT_FOUND: if (intent instanceof Intent && ((Intent)intent).getComponent() != null) throw new ActivityNotFoundException( "Unable to find explicit activity class " + ((Intent)intent).getComponent().toShortString() + "; have you declared this activity in your AndroidManifest.xml?"); throw new ActivityNotFoundException( "No Activity found to handle " + intent); case ActivityManager.START_PERMISSION_DENIED: throw new SecurityException("Not allowed to start activity " + intent); case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: throw new AndroidRuntimeException( "FORWARD_RESULT_FLAG used while also requesting a result"); case ActivityManager.START_NOT_ACTIVITY: throw new IllegalArgumentException( "PendingIntent is not an activity"); default: throw new AndroidRuntimeException("Unknown error code " + res + " when starting " + intent); } }
看到这个熟悉的异常了吧,Unable to find explicit activity class "((Intent)intent).getComponent().toShortString(); have you declared this activity in your AndroidManifest.xml?应该很熟悉吧,平时忘记注册Activity就会报错,我们回过头来继续ActivityMangerNative.getDefault().startActivity()往下看
static public IActivityManager getDefault() { return gDefault.get(); }
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { protected IActivityManager create() { IBinder b = ServiceManager.getService("activity"); if (false) { Log.v("ActivityManager", "default service binder = " + b); } IActivityManager am = asInterface(b); if (false) { Log.v("ActivityManager", "default service = " + am); } return am; } };
ActivityMangerNative.getDefault返回的是IActivityManager,是一个接口,gDefault是一个内部类,get()方法会调用create(),从而创建了IActivityManager实现者,如果对源码全局搜索发现ActivityManagerService继承ActivityManagerNative,而ActivityManagerNative继承Binder又实现IActivityManager,因此ActivityManagerService就是IActivityManager具体实现类,那么我们把ActivityMangerNative.getDefault().startActivity()转移至ActivityManagerService类中去看
public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) { return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, UserHandle.getCallingUserId());} public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) { enforceNotIsolatedCaller("startActivity"); userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivity", null); // TODO: Switch to user app stacks here. return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, null, null, bOptions, false, userId, null, null);}
上面为ActivityManagerService中方法,又转到了ActivityStackSupervisor中startActivityMayWait方法里去了,在startActivityMayWait方法中我们重点看startActivityLocked()方法然后 startActivityUncheckedLocked()方法
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, int startFlags, boolean doResume, Bundle options) { if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) { } if (sourceRecord == null) { } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { } if (sourceRecord != null) { if (sourceRecord.finishing) { if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { } } } else { sourceStack = null; } if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { } if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { if (r.resultTo == null) { if (intentActivity != null) { if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { } if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) { } if ((launchFlags & (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) { } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { } else { }if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) { } if (!addingToTask && reuseTask == null) { // We didn't do anything... but it was needed (a.k.a., client // don't use that intent!) And for paranoia, make // sure we have correctly resumed the top activity. if (doResume) { targetStack.resumeTopActivityLocked(null, options); } else { ActivityOptions.abort(options); } if (r.task == null) Slog.v(TAG, "startActivityUncheckedLocked: task left null", new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_TASK_TO_FRONT; } } } }}
在startActivityUncheckedLocked方法中有对Intent.FLAG启动模式做了细分,假如我们以未设置FLAG方式来启动的
重点在targetStack.resumeTopActivityLocked(null, options)这一句,执行到这逻辑开始转到了ActivityStack中的resumeTopActivityLocked方法了,在resumeTopActivityLocked方法中我们看mStackSupervisor.startSpecificActivityLocked()这一句,又回到了ActivityStackSupervisor里面
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP); app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration), r.compat, app.repProcState, r.icicle, results, newIntents, !andResume, mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop); return true;}该方法又调用了app.thread.scheduleLaunchActivity,app.thread是IApplicationThread的实例,IApplicationThread又是一个接口,里面实现了好多与生命周期相关方法
public interface IApplicationThread extends IInterface { void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges) throws RemoteException; void scheduleStopActivity(IBinder token, boolean showWindow, int configChanges) throws RemoteException; void scheduleWindowVisibility(IBinder token, boolean showWindow) throws RemoteException; void scheduleSleeping(IBinder token, boolean sleeping) throws RemoteException; void scheduleResumeActivity(IBinder token, int procState, boolean isForward) throws RemoteException; void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException; void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, int procState, Bundle state, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException; void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, int configChanges, boolean notResumed, Configuration config) throws RemoteException; void scheduleNewIntent(List<Intent> intent, IBinder token) throws RemoteException;}
问题是谁是IApplicationThread的具体实现呢,源码全局搜索会发现在ActivityThread类中的一个内部类ApplicationThread继承ApplicationThreadNative,
而ApplicationThreadNative继承Binder并实现了IApplicationThread接口,又是进程间通信了,我们看看ApplicationThread的scheduleLaunchActivity
做了什么
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, int procState, Bundle state, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { updateProcessState(procState, false); ActivityClientRecord r = new ActivityClientRecord(); r.token = token; r.ident = ident; r.intent = intent; r.activityInfo = info; r.compatInfo = compatInfo; r.state = state; r.pendingResults = pendingResults; r.pendingIntents = pendingNewIntents; r.startsNotResumed = notResumed; r.isForward = isForward; r.profileFile = profileName; r.profileFd = profileFd; r.autoStopProfiler = autoStopProfiler; updatePendingConfiguration(curConfig); sendMessage(H.LAUNCH_ACTIVITY, r); }private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { if (DEBUG_MESSAGES) Slog.v( TAG, "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj); Message msg = Message.obtain(); msg.what = what; msg.obj = obj; msg.arg1 = arg1; msg.arg2 = arg2; if (async) { msg.setAsynchronous(true); } mH.sendMessage(msg); }private class H extends Handler { public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { case LAUNCH_ACTIVITY: { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); ActivityClientRecord r = (ActivityClientRecord)msg.obj; r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));}private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {............. Activity a = performLaunchActivity(r, customIntent); if (a != null) {.............. } else { // If there was an error, for any reason, tell the activity // manager to stop us. try { ActivityManagerNative.getDefault() .finishActivity(r.token, Activity.RESULT_CANCELED, null); } catch (RemoteException ex) { // Ignore } }}private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity != null) { component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } Activity activity = null; try { java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); if (r.state != null) { r.state.setClassLoader(cl); } } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to instantiate activity " + component + ": " + e.toString(), e); } } try { Application app = r.packageInfo.makeApplication(false, mInstrumentation); if (localLOGV) Slog.v(TAG, "Performing launch of " + r); if (localLOGV) Slog.v( TAG, r + ": app=" + app + ", appName=" + app.getPackageName() + ", pkg=" + r.packageInfo.getPackageName() + ", comp=" + r.intent.getComponent().toShortString() + ", dir=" + r.packageInfo.getAppDir()); if (activity != null) { Context appContext = createBaseContextForActivity(r, activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config); if (customIntent != null) { activity.mIntent = customIntent; } r.lastNonConfigurationInstances = null; activity.mStartedActivity = false; int theme = r.activityInfo.getThemeResource(); if (theme != 0) { activity.setTheme(theme); } activity.mCalled = false; mInstrumentation.callActivityOnCreate(activity, r.state); if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onCreate()"); } r.activity = activity; r.stopped = true; if (!r.activity.mFinished) { activity.performStart(); r.stopped = false; } if (!r.activity.mFinished) { if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } if (!r.activity.mFinished) { activity.mCalled = false; mInstrumentation.callActivityOnPostCreate(activity, r.state); if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPostCreate()"); } } } r.paused = true; mActivities.put(r.token, r); } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to start activity " + component + ": " + e.toString(), e); } } return activity; }
上面的重点来了,看加粗部分,使用ClassLoader把Activity类加载到内存中,通过Instrumentation.newActivity方法进行反射创建Activity对象,看看Instrumentation部分
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return (Activity)cl.loadClass(className).newInstance();}
接着又调用Activity的attact方法初始化Activity的所需参数
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config) { attachBaseContext(context); mFragments.attachActivity(this, mContainer, null); mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); } mUiThread = Thread.currentThread(); mMainThread = aThread; mInstrumentation = instr; mToken = token; mIdent = ident; mApplication = application; mIntent = intent; mComponent = intent.getComponent(); mActivityInfo = info; mTitle = title; mParent = parent; mEmbeddedID = id; mLastNonConfigurationInstances = lastNonConfigurationInstances; mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); if (mParent != null) { mWindow.setContainer(mParent.getWindow()); } mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config; }接着调用Instructmentation.callActivityOnCreate方法
public void callActivityOnCreate(Activity activity, Bundle icicle) { if (mWaitingActivities != null) { synchronized (mSync) { final int N = mWaitingActivities.size(); for (int i=0; i<N; i++) { final ActivityWaiter aw = mWaitingActivities.get(i); final Intent intent = aw.intent; if (intent.filterEquals(activity.getIntent())) { aw.activity = activity; mMessageQueue.addIdleHandler(new ActivityGoing(aw)); } } } } activity.performCreate(icicle); if (mActivityMonitors != null) { synchronized (mSync) { final int N = mActivityMonitors.size(); for (int i=0; i<N; i++) { final ActivityMonitor am = mActivityMonitors.get(i); am.match(activity, activity, activity.getIntent()); } } } }
看看Activity的performCreate方法
final void performCreate(Bundle icicle) { onCreate(icicle); mVisibleFromClient = !mWindow.getWindowStyle().getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay, false); mFragments.dispatchActivityCreated(); }我们终于看到Activity的onCreate被调用了
了解Activity启动流程后我们再来进行对framework层进行HOOK就知道在哪入手了,我们看到一个Activity最终是在Instrumentation中进行实例化的,
那么我们能不能自己写一个类继承Instrumentation并重写Instrumentation的newActivity方法,很高兴的是Instrumentation是个可见的,并且newActivity也是public的,这下太好了,
再看看用于检查组件是否被注册的方法checkStartActivityResult,可惜的方法是非public,不能被重写了,看来得换种思路:
为了让检查机制通过我们还是要在AndroidManifest.xml中注册一个Activity名叫TempActivity,但我们重写newActivity方法,在这里我们进行调换,把成
我们真实要启动的Activity如PluginActivity,我们试一下
比如在MainActivity中启动PluginActivity的时候这么做:
Intent intent = new Intent(MainActivity.this, TempActivity.class);
intent.putEXACT("IS_IN_PLUGIN", true);
intent.putEXACT("LAUNCH_ACTIVITY", "PluginActivity");
startActivity(intent);
来看看newActivity中如果把TempActivity转成PluginActivity
public class MyInstrumentation extends Instrumentation { public Activity newActivity(Class<?> clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException { Activity activity = getPluginActivity(intent); if (activity != null) { return activity; } return super.newActivity(clazz, context, token, application, intent, info, title, parent, id, lastNonConfigurationInstance); } public Activity newActivity(ClassLoader cl, String fromClassName, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { Activity activity = getPluginActivity(intent); if (activity != null) { return activity; } return super.newActivity(cl, fromClassName, intent); } private Activity getPluginActivity(Intent intent) { boolean isInPlugin = intent.getBooleanExtra("IS_PLUGIN", false); if (isInPlugin) { String activity = intent.getStringExtra("LAUNCH_ACTIVITY"); ClassLoader loader = ClassLoader.getSystemClassLoader(); DexClassLoader dexLoader = new DexClassLoader(getPluginPath(pluginPkgName), getDexDir(), null, loader.getParent()); Class c = dexLoader.loadClass("com.plugin.test.PluginActivity"); if (c != null) { activity = (Activity)c.newInstance(); if (activity != null) { initPluginResources(activity); return activity; } } } return null; } protected void initPluginResources(Activity activity){// 获取Activity的Resource资源 Resources hostResource = mContext.getResources();// 获取插件的Resource try { // 获得系统assetManager AssetManager assetManager = AssetManager.class.newInstance();// 将插件地址添加到资源地址 Method method_addAssetPath = AssetManager.class.getDeclaredMethod("addAssetPath", String.class); method_addAssetPath.setAccessible(true); method_addAssetPath.invoke(assetManager, getPluginPath(pluginPkgName)); // 获得新的完整的资源 Resources resources = new Resources(assetManager, hostResource.getDisplayMetrics(), hostResource.getConfiguration()); Field field_mResources = ContextThemeWrapper.class.getDeclaredField("mResources"); field_mResources.setAccessible(true); field_mResources.set(activity, resources); } catch (Exception e) {e.printStackTrace();} }}
那么我们如何把我们系统层的Instrumentation替换成我们的MyInstrumentation呢,这里就要使用反射机制,看看系统层在哪使用了Instrumentation对象实例我们知道ActivityThread中保存了Instrumentation的对象,但是我们如何拿到ActivityThread对象呢,还好它内部有一个currentActivityThread静态方法返回,我们可以从这入手,在Application的onCreate中添加以下代码
public void onCreate() {super.onCreate();class activityThreadCls = Class.forName("android.app.ActivityThread");// 获得ActivityThread#currentActivityThread()方法Method currentActivityThreadMethod = activityThreadCls.getDeclaredMethod("currentActivityThread");// 根据currentActivityThread方法获得ActivityThread对象Obj activityThread = currentActivityThreadMethod.invoke(ActivityThread);// 获得ActivityThread类中的Instrumentation字段Field instrumentationField = activityThread.getClass().getDeclaredField("mInstrumentation");instrumentationField.setAccessible(true);// 创建出一个新的InstrumentationMyInstrumentation instrumentation = new MyInstrumentation(context);// 用Instrumentation字段注入Sona的Instrumentation变量instrumentationField.set(obj_activityThread, instrumentation);}
这样一来我们就把ActivityThread中的mInstrumentation属性给替换成我们的了
0 0
- Android插件化开发原理
- 详述Android插件化原理
- android插件化开发
- Android插件化开发
- Android插件化开发
- Android 插件化开发
- Android插件化开发
- Android插件化开发
- android插件化开发
- Android插件化开发
- Android插件化开发
- Android 插件化开发
- 插件化开发系列之一---原理分析
- Mybatis插件开发原理
- android插件化-apkplug插件开发-07
- Android中微信抢红包插件原理解析和开发实现
- Android中微信抢红包插件原理解析和开发实现
- Android中微信抢红包插件原理解析和开发实现
- HTML常用标签
- 【源码剖析】MemoryPool —— 简单高效的内存池 allocator 实现
- Java异常类(Throwable)
- Oracle EBS 应用实例管理
- Volley学习
- Android插件化开发原理
- spring mvc 配合ajax进行表单提交(有文件上传)并且提醒用户提交成功
- 当你选择编程语言时你在选择什么
- run: read failed, socket might closed or timeout, read ret: -1
- Oracle Rac 部署详细过程
- 绑定本地Service和远程Service并调用其中方法
- PAT1010. 一元多项式求导 (25)
- 社会工程学攻击之看我如何用office文档欺骗用户
- linux操作笔记,windows连接云服务器