<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          滴滴開源的Android 字節(jié)碼編輯插件!

          共 7920字,需瀏覽 16分鐘

           ·

          2020-08-07 21:54

          DroidAssist

          DroidAssist?是一個(gè)輕量級的 Android 字節(jié)碼編輯插件,基于?Javassist?對字節(jié)碼操作,根據(jù) xml 配置處理 class 文件,以達(dá)到對 class 文件進(jìn)行動(dòng)態(tài)修改的效果。和其他 AOP 方案不同,DroidAssist 提供了一種更加輕量,簡單易用,無侵入,可配置化的字節(jié)碼操作方式,你不需要 Java 字節(jié)碼的相關(guān)知識,只需要在 Xml 插件配置中添加簡單的 Java 代碼即可實(shí)現(xiàn)類似 AOP 的功能,同時(shí)不需要引入其他額外的依賴。

          功能

          • 替換:把指定位置代碼替換為指定代碼

          • 插入:在指定位置的前后插入指定代碼

          • 環(huán)繞:在指定位置環(huán)繞插入指定代碼

          • 增強(qiáng)

            • TryCatch?對指定代碼添加 try catch 代碼

            • Timing?對指定代碼添加耗時(shí)統(tǒng)計(jì)代碼

          特點(diǎn)

          • 靈活的配置化方式,使得一個(gè)配置就可以處理項(xiàng)目中所有的 class 文件。

          • 豐富的字節(jié)碼處理功能,針對 Android 移動(dòng)端的特點(diǎn)提供了例如代碼替換,添加 try catch,方法耗時(shí)等功能。

          • 簡單易用,只需要依賴一個(gè)插件,處理過程以及處理后的代碼中也不需要添加額外的依賴。

          • 處理速度較快,只占用較少的編譯時(shí)間。

          開發(fā)文檔

          DroidAssist 配置文件

          DroidAssist 將掃描工程中的每一個(gè)單獨(dú)的 class 以及 jar 中的 class, 并對 class 與配置文件中的規(guī)則進(jìn)行匹配,如果有規(guī)則能夠匹配到 class,則根據(jù) DroidAssist 配置對此 class 進(jìn)行字節(jié)碼修改。DroidAssist 配置是一個(gè) xml 文件,根節(jié)點(diǎn)是?DroidAssist?, 根節(jié)點(diǎn)下包含?Global?,?Insert?,?Around?,?Replace?,?Enhance?代碼操作配置,完整的 DroidAssist 配置文件格式如下:



          ????
          ????
          ????????...
          ????


          ????
          ????
          ????????...
          ????


          ????
          ????
          ????????...
          ????


          ????
          ????
          ????????...
          ????


          ????
          ????
          ????????...
          ????


          為了方便編寫配置文件,在 IDE 中能自動(dòng)提示,請將根目錄下 DTD文件 拷貝到配置文件第二行。

          配置分類:

          • Insert:代碼插入類

          • Replace:代碼替換類

          • Around:代碼環(huán)繞類

          • Enhance:代碼增強(qiáng)類

          Source 和 Target

          Insert、Replace、Around、Enhance 類型代碼操作配置中均需要包含?Source?和?Target?元素:例:


          ????
          ????????
          ????????????int?android.util.Log.d(java.lang.String,java.lang.String)
          ????????
          ????????
          ????????????$_=?com.didichuxing.tools.test.LogUtils.log($$);
          ????????

          ????


          Source 的值?int android.util.Log.d(java.lang.String,java.lang.String)?表示需要匹配方法調(diào)用?android.util.Log.d( )?Target 的值?$_= com.didichuxing.tools.test.LogUtils.log($$);表示將調(diào)用?android.util.Log.d( )?方法調(diào)用的代碼替換為?com.didichuxing.tools.test.LogUtils.log( )

          Source

          表示需要進(jìn)行修改的代碼位置,用以精確匹配代碼位置,Source 按照代碼位置類型可以分為方法、構(gòu)造方法、字段、靜態(tài)初始化塊:

          1. 方法

          Source 表示方法時(shí),格式為?returnType className.methodName(argType1,argType2)?:

          ??int?android.util.Log.d(java.lang.String,java.lang.String)?
          2. 構(gòu)造方法

          Source 表示方法時(shí),格式為?new className(argType1,argType2)?或者?className.new(argType1,argType2)

          ??new?com.didichuxing.tools.test.ExampleSpec(int)?

          ??com.didichuxing.tools.test.ExampleSpec.new(int)?
          3. 字段

          Source 表示字段時(shí),格式為?fieldType className.fieldName?:

          ??int?com.didichuxing.tools.test.ExampleSpec.id?
          4. 靜態(tài)初始化塊

          Source 表示靜態(tài)初始化塊時(shí),格式為?className?:

          ??com.didichuxing.tools.test.ExampleSpec?

          注意:

          1. Source 的范圍為本類和在子類有效(構(gòu)造方法和靜態(tài)初始化塊除外),方法和字段如果在子類中可見,則也會(huì)被匹配,如果不需要匹配子類只匹配當(dāng)前配置類,可在標(biāo)簽中添加?extend?屬性:extend = "false"

          2. Source 中所有的 class 均需要配置全限定名。

          3. Source 中 class 如果是內(nèi)部類,需要使用分隔符?$?和外部類隔開,如?com.didichuxing.tools.test.ExampleSpec$Inner。

          Target

          需要修改成的目標(biāo)代碼,該值接受一個(gè) Java 表達(dá)式或者以大括號{}包圍的代碼塊。如果表達(dá)式是一個(gè)單獨(dú)的表達(dá)式,需要以分號;結(jié)尾。

          例:

          java.lang.System.out.println("BeforeMethodCall");

          或:

          {System.out.println("Hello");?System.out.println("World");}

          注意:

          1. 如果 Source 的表達(dá)式中?returnType?為非?void?類型時(shí), Target 中表達(dá)式必須 要包含?$_=?以保存返回值,否則可能會(huì)出現(xiàn)錯(cuò)誤。

          擴(kuò)展變量

          基于 Javassist 的支持,可以在 Target 中使用語言擴(kuò)展,$?開頭的標(biāo)識符有特殊的含義:

          符號含義scope
          $0,$1,$2?..this?和方法的參數(shù)runtime
          $args方法參數(shù)數(shù)組,類型為?Object[]runtime
          $$所有實(shí)參, 例如 m($$) 等價(jià)于 m($1,$2,…)runtime
          $proceed表示原始的方法、構(gòu)造方法、字段調(diào)用runtime
          $cflow(...)cflow 變量runtime
          $r返回結(jié)果的類型,用于強(qiáng)制類型轉(zhuǎn)換runtime
          $w包裝器類型,用于強(qiáng)制類型轉(zhuǎn)換runtime
          $_返回值runtime
          $sig參數(shù)類型數(shù)組,類型為?java.lang.Class[]runtime
          $type返回值類型,類型為?java.lang.Classruntime
          $class表示當(dāng)前正在修改的類,類型為?java.lang.Classcompile
          $line表示當(dāng)前正在修改的行號,類型為?intcompile
          $name表示當(dāng)前正在方法或字段名,類型為?java.lang.Stringcompile
          $file表示當(dāng)前正在修改的文件名,類型為?java.lang.Stringcompile
          1. Target 中對于?java.lang?包中的類可以直接使用,不用添加包名。

          2. Around 類型配置中?Target?分解為?TargetBefore?和?TargetAfter

          3. Scope 為?compile?類型的擴(kuò)展在編譯后將直接替換成結(jié)果值,runtime?類型的擴(kuò)展只在運(yùn)行期有效。

          類過濾器 Filter

          默認(rèn)情況下 DroidAssist 將掃描工程中的每一個(gè) class 并進(jìn)行匹配和處理,為了加快處理速度以及排除某些不需要處理的類,可以使用類過濾器 Filter 配置將不需要處理的類排除。Filter 配置中包含:

          • Include:需要處理的類,支持通配符匹配和精確匹配

          • Exclude:不需要處理的類,支持通配符匹配和精確匹配

          每個(gè) Filter 中可以包含多個(gè) Include、Exclude 配置,支持通配符匹配,class 被匹配的條件是類名可以被 Include 規(guī)則匹配但是不能被 Exclude 匹配,即?(Include & !Exclude)?。

          例:


          ????
          ????????
          ????????????int?android.util.Log.d(java.lang.String,java.lang.String)
          ????????
          ????????
          ????????????com.didichuxing.tools.test.LogUtils.log($$);
          ????????

          ????

          ????
          ????????*
          ????????com.didichuxing.tools.test.Utils
          ????????android.*
          ????????com.android.*
          ????


          該配置中的 Filter 中 有1個(gè) Include 配置,值?*?表示將處理所有的 class,有 3 個(gè) Exclude 配置表示將不處理com.didichuxing.tools.test.Utils?類,以及類名匹配?android.*?和?com.android.*?的類。

          1. 每一個(gè)代碼操作配置規(guī)則下都可以添加 Filter 配置(可選)

          2. Global 配置中可以包含 Filter,當(dāng) Filter 出現(xiàn)在 Global 配置中時(shí),對所有的代碼操作配置都生效。

          Global 配置

          Global 配置可以包含類過濾器 Filter:


          ????
          ????????*
          ????????android.*
          ????????com.android.*
          ????


          Replace 配置

          Replace 類型代碼操作配置的作用是將指定代碼替換成目標(biāo)代碼,包含以下配置:

          • MethodCall?方法調(diào)用

          • MethodExecution?方法體執(zhí)行

          • ConstructorCall?構(gòu)造方法調(diào)用

          • ConstructorExecution?構(gòu)造方法體執(zhí)行

          • InitializerExecution?靜態(tài)代碼初始化塊執(zhí)行

          • FieldRead?字段讀取

          • FieldWrite?字段賦值

          Call 表示方法或者構(gòu)造方法被其他代碼調(diào)用,Execution 代表方法、構(gòu)造方法或者靜態(tài)初始化代碼塊的方法體本身。

          例:


          ????
          ????????
          ????????????int?android.util.Log.d(java.lang.String,java.lang.String)
          ????????
          ????????
          ????????????$_=?com.didichuxing.tools.test.LogUtils.log($$);
          ????????

          ????

          ????
          ????????new?com.didichuxing.tools.test.ExampleSpec(int)
          ????????{$_=?com.didichuxing.tools.test.ExampleSpec.getInstance();}
          ????


          Insert 配置

          Insert 類型代碼操作配置的作用是將指定代碼之前或之后插入目標(biāo)代碼,包含以下配置:

          • BeforeMethodCall?方法調(diào)用之前

          • AfterMethodCall?方法調(diào)用之后

          • BeforeMethodExecution?方法體執(zhí)行之前

          • AfterMethodExecution?方法體執(zhí)行之后

          • BeforeConstructorCall?構(gòu)造方法體調(diào)用之前

          • AfterConstructorCall?構(gòu)造方法體調(diào)用之后

          • BeforeConstructorExecution?構(gòu)造方法體執(zhí)行之前

          • AfterConstructorExecution?構(gòu)造方法體執(zhí)行之前

          • BeforeInitializerExecution?靜態(tài)代碼初始化塊執(zhí)行之前

          • AfterInitializerExecution?靜態(tài)代碼初始化塊執(zhí)行之前

          • BeforeFieldRead?字段讀取之前

          • AfterFieldRead?字段讀取之后

          • BeforeFieldWrite?字段賦值之前

          • AfterFieldWrite?字段賦值之后

          例:


          ????
          ????????void?com.didichuxing.tools.test.ExampleSpec.run()
          ????????{java.lang.System.out.println("BeforeMethodCall");}
          ????


          ????
          ????????new?com.didichuxing.tools.test.ExampleSpec()
          ????????java.lang.System.out.println("AfterConstructorExecution");
          ????


          Around 配置

          Around 類型代碼操作配置的作用是將指定代碼前后環(huán)繞插入目標(biāo)代碼,包含以下配置:

          • MethodCall?方法調(diào)用環(huán)繞插入代碼

          • MethodExecution?方法體執(zhí)行環(huán)繞插入代碼

          • ConstructorCall?構(gòu)造方法調(diào)用環(huán)繞插入代碼

          • ConstructorExecution?構(gòu)造方法體執(zhí)行環(huán)繞插入代碼

          • InitializerExecution?靜態(tài)代碼初始化塊執(zhí)行環(huán)繞插入代碼

          • FieldRead?字段讀取環(huán)繞插入代碼

          • FieldWrite?字段賦值環(huán)繞插入代碼

          在 Around 類型配置中 Target 配置分解為?TargetBefore?和?TargetAfter,分別表示 Source 代碼之前和之后插入的代碼,在?TargetBefore?中聲明的變量,在?TargetAfter?可以直接使用。

          例:


          ????
          ????????
          ????????????void?com.didichuxing.tools.test.ExampleSpec.call()
          ????????
          ????????
          ????????????java.lang.System.out.println("around?before?MethodCall");
          ????????

          ????????
          ????????????java.lang.System.out.println("around?after?MethodCall");
          ????????

          ????


          Enhance 配置

          Enhance 類型代碼操作配置的作用是加入增強(qiáng)性代碼,可以對 Source 代碼添加?TryCatch?方法和?Timing?耗時(shí)統(tǒng)計(jì)方法 :

          TryCatch

          TryCatch 類型配置可以對 Source 代碼添加?try{...} catch(...){...}代碼,包含以下配置:

          • TryCatchMethodCall?方法調(diào)用添加 Try Catch 代碼

          • TryCatchMethodExecution?方法體執(zhí)行添加 Try Catch 代碼

          • TryCatchConstructorCall?構(gòu)造方法調(diào)用添加 Try Catch 代碼

          • TryCatchConstructorExecution?構(gòu)造方法體執(zhí)行添加 Try Catch 代碼

          • TryCatchInitializerExecution?靜態(tài)代碼初始化塊執(zhí)行添加 Try Catch 代碼

          Exception

          TryCatch 配置默認(rèn)將捕獲?java.lang.Exception?類型異常,如果需要捕獲其他異常,需要添加?Exception?配置,聲明需要捕獲的異常,在 Target 表達(dá)式中可以使用?$e?擴(kuò)展變量接收捕獲的異常對象。

          例:


          ????
          ????????void?android.content.Context.startActivity(android.content.Intent)
          ????
          ????
          ????????android.content.ActivityNotFoundException
          ????

          ????
          ????????android.util.Log.d("test",?"startActivity?error",?$e);
          ????


          Timing

          Timing 類型配置可以對 Source 代碼添加耗時(shí)統(tǒng)計(jì)代碼,包含以下配置:

          • TimingMethodCall?方法調(diào)用添加耗時(shí)統(tǒng)計(jì)代碼

          • TimingMethodExecution?方法體執(zhí)行耗時(shí)統(tǒng)計(jì)代碼

          • TimingConstructorCall?構(gòu)造方法調(diào)用耗時(shí)統(tǒng)計(jì)代碼

          • TimingConstructorExecution?構(gòu)造方法體執(zhí)行耗時(shí)統(tǒng)計(jì)代碼

          • TimingInitializerExecution?靜態(tài)代碼初始化塊執(zhí)行耗時(shí)統(tǒng)計(jì)代碼

          Timing 類型配置會(huì)自動(dòng)在 Source 代碼前后添加耗時(shí)計(jì)算代碼,并將耗時(shí)毫秒值保存到?$time?擴(kuò)展變量中,可以在 Target 配置中直接使用該擴(kuò)展變量。例:


          ????void?com.didichuxing.tools.test.ExampleSpec.timing()
          ????
          ????????android.util.Log.d("test",?"time?cost=?"+?$time);
          ????


          $time?擴(kuò)展變量為?long?型,單位為毫秒,如果需要獲取耗時(shí)的微秒值,可以使用?$nanotime?擴(kuò)展變量。

          Q & A

          1. DroidAssist 可以實(shí)現(xiàn)什么功能?

          DroidAssist 提供了一套輕量級的字節(jié)碼操作方案,可以輕易實(shí)現(xiàn)諸如代碼替換,代碼插入等功能,滴滴出行APP 目前利用DroidAssist 實(shí)現(xiàn)了日志輸出替換,系統(tǒng) SharedPreferences 替換,SharedPreferences commit 替換 apply,Dialog show 保護(hù),獲取 deviceId 接口替換,getPackageInfo 接口替換,getSystemService 接口替換,startActivity 保護(hù),匿名線程重命名,線程池創(chuàng)建監(jiān)控,主線程卡頓監(jiān)控,文件夾創(chuàng)建監(jiān)控,Activity 生命周期耗時(shí)統(tǒng)計(jì),APP啟動(dòng)耗時(shí)統(tǒng)計(jì)等功能。

          2. DroidAssist 和 AspectJ 有什么區(qū)別?

          DroidAssist 采用配置化方案,編寫相關(guān)配置就可以實(shí)現(xiàn) AOP 的功能,可以完全不用修改 Java 代碼,DroidAssist 使用比較簡單,不需要復(fù)雜的注解配置,DroidAssist 可以比較方便的實(shí)現(xiàn) AspectJ 不容易實(shí)現(xiàn)的代碼替換功能。

          項(xiàng)目地址

          github地址:https://github.com/didi/DroidAssist



          ? 開發(fā)者全社區(qū)?

          5T技術(shù)資源大放送!包括但不限于:Android,Python,Java,大數(shù)據(jù),人工智能,AI等等。關(guān)注公眾號后回復(fù)「2T」,即可免費(fèi)獲?。?/span>!
          瀏覽 40
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久国产乱子伦精品免费女,网站 | 18禁免费观看网站 | 人人插人人搞 | 黄 色 视 中日本 | 91xx在线 |