成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Android 插件化原理學(xué)習(xí) —— Hook 機制之動態(tài)代理

gekylin / 3175人閱讀

摘要:什么樣的對象容易找到靜態(tài)變量和單例。在一個進程之內(nèi),靜態(tài)變量和單例變量是相對不容易發(fā)生變化的,因此非常容易定位,而普通的對象則要么無法標志,要么容易改變。

前言

為了實現(xiàn) App 的快速迭代更新,基于 H5 Hybrid 的解決方案有很多,由于 webview 本身的性能問題,也隨之出現(xiàn)了很多基于 JS 引擎實現(xiàn)的原生渲染的方案,例如 React Native、weex 等,而國內(nèi)一線大廠基本上主要還是 Android 插件化解決大部分的更新問題,對于部分是采用 webview 或者 React Native 這種方案,而對于 Android 插件化采用的技術(shù)對于 Android Framewrok 的理解要求很高,真正實現(xiàn)落地的方案都還是有難度,對于非 Android Native 開發(fā)的人員更是有技術(shù)門檻。插件化可以很好的解決 Android 運行的一些問題,本文站在學(xué)習(xí)者的角度去嘗試理解插件化到底解決了什么問題。

插件化框架

如下是主流的插件化框架之間的對比:

特性 DynamicLoadApk DynamicAPK Small DroidPlugin VirtualAPK
支持四大組件 只支持 Activity 只支持 Activity 只支持 Activity 全支持 全支持
無需在宿主 manifest 中預(yù)注冊 ×
插件可以依賴宿主 ×
支持 PendingIntent × × ×
Android 特性支持 大部分 大部分 大部分 幾乎全部 幾乎全部
兼容性適配 一般 一般 中等
插件構(gòu)建 部署 aapt Gradle 插件 Gradle 插件
代理模式

代理模式是為一個對象提供一個代用品或占位符,以便控制對它的訪問。使用代理可以屏蔽內(nèi)部實現(xiàn)細節(jié),后續(xù)內(nèi)部有變動對于外部調(diào)用者來說是封閉的,符合開放-封閉原則。用戶可以放心地請求代理,他只關(guān)心是否能得到想要的結(jié)果。在任何使用本體的地方都可以替換成使用代理,從而實現(xiàn)實現(xiàn)和調(diào)用松耦合。

不用代理模式:

使用代理模式:

靜態(tài)代理

例如我們有兩個接口:

// Subject1.java
public interface Subject1 {
  void method1();
  void method2();
}

// Subject2.java
public interface Subject2 {
  void method1();
  void method2();
  void method3();
}

我們分別實現(xiàn)這兩個接口:

// RealSubject1.java
public class RealSubject1 implements Subject1 {
  @Override
  public void method1() {
    Logger.i(RealSubject1.class, "我是RealSubject1的方法1");
  }

  @Override
  public void method2() {
    Logger.i(RealSubject1.class, "我是RealSubject1的方法2");
  }
}

// RealSubject2.java
public class RealSubject2 implements Subject2 {
  @Override
  public void method1() {
    Logger.i(RealSubject2.class, "我是RealSubject2的方法1");
  }

  @Override
  public void method2() {
    Logger.i(RealSubject2.class, "我是RealSubject2的方法2");
  }

  @Override
  public void method3() {
    Logger.i(RealSubject2.class, "我是RealSubject2的方法3");
  }
}

如果不使用代理模式,我們一般會直接實例化 RealSubject1 和 RealSubject2 類對象。使用代理,我們一般都需要建立一個代理類。在 Java 等語言中,代理和本體都需要顯式地實現(xiàn)同一個接口,一方面接口保證了它們會擁 有同樣的方法,另一方面,面向接口編程迎合依賴倒置原則,通過接口進行向上轉(zhuǎn)型,從而避開 編譯器的類型檢查,代理和本體將來可以被替換使用。

/**
 * 靜態(tài)代理類(為了保持行為的一致性,代理類和委托類通常會實現(xiàn)相同的接口)
 * ProxySubject1.java
 */
public class ProxySubject1 implements Subject1 {
  private Subject1 subject1;

  public ProxySubject1(Subject1 subject1) {
    this.subject1 = subject1;
  }

  @Override
  public void method1() {
    Logger.i(ProxySubject1.class, "我是代理,我會在執(zhí)行實體方法1之前先做一些預(yù)處理的工作");
    subject1.method1();
  }

  @Override
  public void method2() {
    Logger.i(ProxySubject1.class, "我是代理,我會在執(zhí)行實體方法2之前先做一些預(yù)處理的工作");
    subject1.method2();
  }
}

使用代理后我們對 RealSubject1 的操作換成對 ProxySubject1 對象的操作,如下:

ProxySubject1 proxySubject1 = new ProxySubject1(new RealSubject1());
proxySubject1.method1();
proxySubject1.method2();

結(jié)果:
[ProxySubject1] : 我是代理,我會在執(zhí)行實體方法1之前先做一些預(yù)處理的工作
[RealSubject1] : 我是RealSubject1的方法1
[ProxySubject1] : 我是代理,我會在執(zhí)行實體方法2之前先做一些預(yù)處理的工作
[RealSubject1] : 我是RealSubject1的方法2
[ProxySubject2] : 我是代理,我會在執(zhí)行實體方法1之前先做一些預(yù)處理的工作
[RealSubject2] : 我是RealSubject2的方法1
[ProxySubject2] : 我是代理,我會在執(zhí)行實體方法2之前先做一些預(yù)處理的工作
[RealSubject2] : 我是RealSubject2的方法2

顯然當我們想代理 RealSubject2 按照這種方式我們?nèi)匀恍枰⒁粋€類去處理,這也是靜態(tài)代理的局限性。如果寫一個代理類就能對上面兩個都能代理就好了,動態(tài)代理就解決了這個問題。

動態(tài)代理

在 java 的動態(tài)代理機制中,有兩個重要的類或接口,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class),這一個類和接口是實現(xiàn)我們動態(tài)代理所必須用到的。

動態(tài)代理的步驟:

寫一個 InvocationHandler 的實現(xiàn)類,并實現(xiàn) invoke 方法,return method.invoke(...);。

/**
  * @param proxy 指代我們所代理的那個真實對象
  * @param method 指代的是我們所要調(diào)用真實對象的某個方法的Method對象
  * @param args 指代的是調(diào)用真實對象某個方法時接受的參數(shù)
  */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

每一個動態(tài)代理類都必須要實現(xiàn) InvocationHandler 這個接口,并且每個代理類的實例都關(guān)聯(lián)到了一個 handler,當我們通過代理對象調(diào)用一個方法的時候,這個方法的調(diào)用就會被轉(zhuǎn)發(fā)為由 InvocationHandler 這個接口的 invoke 方法來進行調(diào)用。

使用 Proxy 類的 newProxyInstance 方法生成一個代理對象。例如: 生成 Subject1 的代理對象,注意第三個參數(shù)中要將一個實體對象傳入。

/**
  * @param loader 一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載
  * @param interfaces 一個Interface對象的數(shù)組,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它,那么這個代理對象就宣稱實現(xiàn)了該接口(多態(tài)),這樣我就能調(diào)用這組接口中的方法了
  * @param h 一個InvocationHandler對象,表示的是當我這個動態(tài)代理對象在調(diào)用方法的時候,會關(guān)聯(lián)到哪一個InvocationHandler對象上
  */
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) throws IllegalArgumentException

例如:

Proxy.newProxyInstance(
  Subject1.class.getClassLoader(),
  new Class[] {Subject1.class},
  new DynamicProxyHandler(new RealSubject1())
);

Proxy 這個類的作用就是用來動態(tài)創(chuàng)建一個代理對象的類,它提供了許多的方法,但是我們用的最多的就是 newProxyInstance 這個方法。

使用動態(tài)代理完成上述靜態(tài)代理中的功能:

public class DynamicProxyHandler implements InvocationHandler {
  private Object object;

  public DynamicProxyHandler(Object object) {
    this.object = object;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Logger.i(DynamicProxyHandler.class, "我正在動態(tài)代理[" + object.getClass().getSimpleName() + "]的[" + method.getName() + "]方法");
    return method.invoke(object, args);
  }

  /**
    * 調(diào)用Proxy.newProxyInstance即可生成一個代理對象
    *
    * @param object
    * @return
    */
  public static Object newProxyInstance(Object object) {
    // 傳入被代理對象的classloader實現(xiàn)的接口, 還有DynamicProxyHandler的對象即可。
    return Proxy.newProxyInstance(object.getClass().getClassLoader(),
      object.getClass().getInterfaces(),
      new DynamicProxyHandler(object));
  }
}

動態(tài)代理調(diào)用如下:

Subject1 dynamicProxyHandler1 = (Subject1) DynamicProxyHandler.newProxyInstance(new RealSubject1());
dynamicProxyHandler1.method1();
dynamicProxyHandler1.method2();
初識 Hook 機制

上述我們對一個方法的調(diào)用采用了動態(tài)代理的辦法,如果我們自己創(chuàng)建代理對象,然后把原始對象替換為我們的代理對象,那么就可以在這個代理對象為所欲為了,修改參數(shù),替換返回值,我們稱之為 Hook。下面我們 Hook 掉 startActivity 這個方法,使得每次調(diào)用這個方法之前輸出一條日志;當然,這個輸入日志有點點弱,只是為了展示原理;只要你想,你想可以替換參數(shù),攔截這個 startActivity 過程,使得調(diào)用它導(dǎo)致啟動某個別的 Activity,指鹿為馬!

首先我們得找到被 Hook 的對象,我稱之為 Hook 點;什么樣的對象比較好 Hook 呢?自然是容易找到的對象。什么樣的對象容易找到?靜態(tài)變量和單例。在一個進程之內(nèi),靜態(tài)變量和單例變量是相對不容易發(fā)生變化的,因此非常容易定位,而普通的對象則要么無法標志,要么容易改變。我們根據(jù)這個原則找到所謂的 Hook 點。

對于 startActivity 過程有兩種方式:Context.startActivity 和 Activity.startActivity。這里暫不分析其中的區(qū)別,以 Activity.startActivity 為例說明整個過程的調(diào)用棧。

Activity 中的 startActivity 最終都是由 startActivityForResult 來實現(xiàn)的。

Activity#startActivityForResult:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
  // 一般的 Activity 其 mParent 為 null,mParent 常用在 ActivityGroup 中,ActivityGroup 已廢棄
  if (mParent == null) {
      options = transferSpringboardActivityOptions(options);
      // 這里會啟動新的Activity,核心功能都在 mMainThread.getApplicationThread() 中完成
      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) {
          mStartedActivity = true;
      }
      cancelInputsAndStartExitTransition(options);
  } 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);
      }
  }
}

可以發(fā)現(xiàn),真正打開 activity 的實現(xiàn)在 Instrumentation 的 execStartActivity 方法中。

Instrumentation#execStartActivity:

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    // 核心功能在這個whoThread中完成,其內(nèi)部scheduleLaunchActivity方法用于完成activity的打開
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    Uri referrer = target != null ? target.onProvideReferrer() : null;
    if (referrer != null) {
        intent.putExtra(Intent.EXTRA_REFERRER, referrer);
    }
    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i=0; i= 0 ? am.getResult() : null;
                    }
                    break;
                }
            }
        }
    }
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        // 這里才是真正打開 Activity 的地方,核心功能在 whoThread 中完成。
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        // 這個方法是專門拋異常的,它會對結(jié)果進行檢查,如果無法打開activity,
            // 則拋出諸如ActivityNotFoundException類似的各種異常
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

如果我們想深入了解 Activity 啟動過程我們需要接著 Android 源碼看下去,但是對于本文中我們初步了解 Hook 機制足以。

我們的目的是替換掉系統(tǒng)默認邏輯,對于 Activity#startActivityForResult 的方法里面核心邏輯就是 mInstrumentation 屬性的 execStartActivity 方法,而這里的 mInstrumentation 屬性在 Activity 類中恰好是一個單例,在 Activity 類的 attach 方法里面被賦值,我們可以在 attach 之后使用反射機制對 mInstrumentation 屬性進行重新賦值。attach() 方法調(diào)用完成后,就自然而然的調(diào)用了 Activity 的 onCreate() 方法了。

我們需要修改 mInstrumentation 這個字段為我們的代理對象,我們使用靜態(tài)代理實現(xiàn)這個代理對象。這里我們使用 EvilInstrumentation 作為代理對象。

public class EvilInstrumentation extends Instrumentation {
    private Instrumentation instrumentation;

    public EvilInstrumentation(Instrumentation instrumentation) {
        this.instrumentation = instrumentation;
    }

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {

        StringBuilder sb = new StringBuilder();
        sb.append("who = [").append(who).append("], ")
        .append("contextThread = [").append(contextThread).append("], ")
        .append("token = [").append(token).append("], ")
        .append("target = [").append(target).append("], ")
        .append("intent = [").append(intent).append("], ")
        .append("requestCode = [").append(requestCode).append("], ")
        .append("options = [").append(options).append("]");;
        Logger.i(EvilInstrumentation.class, "執(zhí)行了startActivity, 參數(shù)如下: " + sb.toString());

        try {
            Method execStartActivity = Instrumentation.class.getDeclaredMethod(
                    "execStartActivity",
                    Context.class,
                    IBinder.class,
                    IBinder.class,
                    Activity.class,
                    Intent.class,
                    int.class,
                    Bundle.class);
            return (ActivityResult) execStartActivity.invoke(instrumentation, who, contextThread, token, target, intent, requestCode, options);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

采用反射直接修改 Activity 中的 mInstrumentation 屬性,從而實現(xiàn)偷梁換柱——用代理對象替換原始對象。

// 拿到原始的 mInstrumentation字段
Field mInstrumentationField = Activity.class.getDeclaredField("mInstrumentation");
mInstrumentationField.setAccessible(true);

// 創(chuàng)建代理對象
Instrumentation originalInstrumentation = (Instrumentation) mInstrumentationField.get(activity);
mInstrumentationField.set(activity, new EvilInstrumentation(originalInstrumentation));

這段 Hook 的邏輯放在 Activity 的 onCreate 里面即可生效。

對于 Context 類的 startActivity 方法的 Hook 實現(xiàn)可以參考 weishu 大神的 Android 插件化原理解析——Hook 機制之動態(tài)代理,本文也是基于 weishu 大神的文章在學(xué)習(xí)過程記錄的內(nèi)容。

Activity 啟動過程

上述例子中我們只是完成了一個最基礎(chǔ)的 Hook 功能,然而大部分插件化框架提供了十分豐富的功能,例如:插件化支持首先要解決的一點就是插件里的 Activity 并未在宿主程序的 AndroidMainfest.xml 注冊。常規(guī)方法肯定無法直接啟動插件的 Activity,這個時候就需要去了解 Activity 的啟動流程。

完整的流程如下:

注: 可以在 http://androidxref.com/ 在線查看 Android 源碼。

上圖列出的是啟動一個 Activity 的主要過程,具體步驟如下:

Activity 調(diào)用 startActivity,實際會調(diào)用 Instrumentation 類的 execStartActivity 方法,Instrumentation 是系統(tǒng)用來監(jiān)控 Activity 運行的一個類,Activity 的整個生命周期都有它的影子。

通過跨進程的 Binder 調(diào)用,進入到 ActivityManagerService 中,其內(nèi)部會處理 Activity 棧。之后又通過跨進程調(diào)用進入到需要調(diào)用的 Activity 所在的進程中。

ApplicationThread 是一個 Binder 對象,其運行在 Binder 線程池中,內(nèi)部包含一個 H 類,該類繼承于類 Handler。ApplicationThread 將啟動需要調(diào)用的 Activity 的信息通過 H 對象發(fā)送給主線程。

主線程拿到需要調(diào)用的 Activity 的信息后,調(diào)用 Instrumentation 類的 newActivity 方法,其內(nèi)通過 ClassLoader 創(chuàng)建 Activity 實例。

下面介紹如何通過 hook 的方式啟動插件中的 Activity,需要解決以下兩個問題:

插件中的 Activity 沒有在 AndroidManifest 中注冊,如何繞過檢測。

如何構(gòu)造 Activity 實例,同步生命周期。

我們這里使用最簡單的一種實現(xiàn)方式:先在 Manifest 中預(yù)埋 StubActivity,啟動時 hook 上圖第 1 步,將 Intent 替換成 StubActivity。

// StubActivity.java
public class StubActivity extends Activity {
    public static final String TARGET_COMPONENT = "TARGET_COMPONENT";
}

我們上面在 EvilInstrumentation 類里面實現(xiàn)了 execStartActivity 方法,現(xiàn)在我們在這里再加一些額外的邏輯。

public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
    Intent intent, int requestCode, Bundle options) {

    StringBuilder sb = new StringBuilder();
    sb.append("who = [").append(who).append("], ")
    .append("contextThread = [").append(contextThread).append("], ")
    .append("token = [").append(token).append("], ")
    .append("target = [").append(target).append("], ")
    .append("intent = [").append(intent).append("], ")
    .append("requestCode = [").append(requestCode).append("], ")
    .append("options = [").append(options).append("]");;
    Logger.i(EvilInstrumentation.class, "執(zhí)行了startActivity, 參數(shù)如下: " + sb.toString());

    // 在此處先將 intent 原本的 Component 保存起來, 然后創(chuàng)建一個新的 intent。
    // 使用 StubActivity 并替換掉原本的 Activity, 以達通過 AMS 驗證的目的,然后等 AMS 驗證通過后再將其還原。
    Intent replaceIntent = new Intent(target, StubActivity.class);
    replaceIntent.putExtra(StubActivity.TARGET_COMPONENT, intent);
    intent = replaceIntent;

    try {
        Method execStartActivity = Instrumentation.class.getDeclaredMethod(
                "execStartActivity",
                Context.class,
                IBinder.class,
                IBinder.class,
                Activity.class,
                Intent.class,
                int.class,
                Bundle.class);
        return (ActivityResult) execStartActivity.invoke(instrumentation, who, contextThread, token, target, intent, requestCode, options);
    } catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

通過這種"移花接木"的方式繞過 AMS 驗證,但是這里我們并沒有完成對我們原本需要真正打開的 Activity 的創(chuàng)建。這里我們需要監(jiān)聽 Activity 的創(chuàng)建過程,然后在適當?shù)倪m合將原本需要打開的 Activity 還原回來。

在 ActivityThread 類中有一個重要的消息處理的方法 sendMessage。

2644    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
2645        if (DEBUG_MESSAGES) Slog.v(
2646            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
2647            + ": " + arg1 + " / " + obj);
2648        Message msg = Message.obtain();
2649        msg.what = what;
2650        msg.obj = obj;
2651        msg.arg1 = arg1;
2652        msg.arg2 = arg2;
2653        if (async) {
2654            msg.setAsynchronous(true);
2655        }
2656        mH.sendMessage(msg);
2657    }

最終都會落實到 mH.sendMessage(msg); 的調(diào)用,繼續(xù)追蹤這個 mH 對象,我們會發(fā)現(xiàn)是 H 對象的實例化對象。

final H mH = new H();
    private class H extends Handler {
        public void handleMessage(Message msg) {
1585            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
1586            switch (msg.what) {
1587                case LAUNCH_ACTIVITY: {
1588                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
1589                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
1590
1591                    r.packageInfo = getPackageInfoNoCheck(
1592                            r.activityInfo.applicationInfo, r.compatInfo);
1593                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
1594                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1595                } break;
        ...
        }
    }

我們知道 Handler 消息機制用于同進程的線程間通信, Handler 是工作線程向 UI 主線程發(fā)送消息,工作線程通過 mHandler 向其成員變量 MessageQueue 中添加新 Message,主線程一直處于 loop() 方法內(nèi),當收到新的 Message 時按照一定規(guī)則分發(fā)給相應(yīng)的 handleMessage() 方法來處理。

類似于對上述 mInstrumentation 實例化對象 hook 一樣,這里我們可以對 mH 對象進行 hook。

/**
 * 將替換的activity在此時還原回來
 */
public static void doHandlerHook() {
    try {
        Class activityThreadClass = Class.forName("android.app.ActivityThread");
        Method currentActivityThread = activityThreadClass.getDeclaredMethod("currentActivityThread");
        Object activityThread = currentActivityThread.invoke(null);

        Field mHField = activityThreadClass.getDeclaredField("mH");
        mHField.setAccessible(true);
        Handler mH = (Handler) mHField.get(activityThread);

        Field mCallbackField = Handler.class.getDeclaredField("mCallback");
        mCallbackField.setAccessible(true);
        mCallbackField.set(mH, new ActivityThreadHandlerCallback(mH));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

對于 Handler.Callback 的 hook 實現(xiàn)如下:

public class ActivityThreadHandlerCallback implements Handler.Callback {
    private Handler mBaseHandler;

    public ActivityThreadHandlerCallback(Handler mBaseHandler) {
        this.mBaseHandler = mBaseHandler;
    }

    @Override
    public boolean handleMessage(Message msg) {
        Logger.i(ActivityThreadHandlerCallback.class, "接受到消息了msg:" + msg);

        if (msg.what == 100) {
            try {
                Object obj = msg.obj;
                Field intentField = obj.getClass().getDeclaredField("intent");
                intentField.setAccessible(true);
                Intent intent = (Intent) intentField.get(obj);

                Intent targetIntent = intent.getParcelableExtra(StubActivity.TARGET_COMPONENT);
                intent.setComponent(targetIntent.getComponent());
                Log.e("intentField", targetIntent.toString());
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        mBaseHandler.handleMessage(msg);
        return true;
    }
}

我們設(shè)置在 handleMessage 里面還原我們最開始替換的 Activity,至此我們就實現(xiàn)了對于 startActivity 的完整 hook,但是這個過程中仍然存在很多問題,我們需要進一步去深入探索才能去理解和更好實現(xiàn)插件化框架的內(nèi)容。

學(xué)習(xí)案例

本文學(xué)習(xí)案例地址:android-plugin-framework

參考

Android 博客周刊專題之#插件化開發(fā)#

VirtualAPK Wiki

DroidPlugin Wiki

understand-plugin-framework

Android 插件化原理解析——Hook 機制之動態(tài)代理

Android 源碼分析-Activity 的啟動過程

APP 的啟動過程

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/71647.html

相關(guān)文章

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<