<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 自定義 gradle 插件 ### 推薦閱讀 [Gradle自定義插件以及發布方法](https://www.jianshu.com/p/d1d7fd48ff0b) ### 簡介 自定義插件基于源碼放置可以分為3種: 1. Build script:源碼放置在模塊內的?build.gradle?中 2. buildSrc project:源碼放置在?rootProjectDir/buildSrc/src/main/groovy目錄內(也就是工程根目錄下創建 buildSrc 目錄) 3. Standalone project:使用單獨的一個工程/模塊創建我們的?[Gradle](https://gradle.org/guides/)?插件,這種方法會構建和發表一個JAR文件,可以提供給多工程構建和其他開發者共同使用 ### 實踐 ~~~ public class SimpleGradlePlugin implements Plugin<Project> { void apply(Project project) { note() //create an extension object:Whyn,so others can config via Whyn project.extensions.create("simpleGradle", SimpleGradleExtension) project.task('simpleGradle'){ group = "test" description = "gradle Standalone project demo,shares everywhere" doLast{ println '**************************************' println "$project.simpleGradle.description" println '**************************************' } } } private void note(){ println '------------------------' println 'apply StandAlonePlugin' println '------------------------' } } class SimpleGradleExtension { String description = 'default description' } ~~~ ## Transform ### 推薦閱讀 [官網](http://tools.android.com/tech-docs/new-build-system/transform-api) [Gradle自定義插件以及發布方法](https://www.jianshu.com/p/d1d7fd48ff0b) ### 簡介 Gradle Transform是Android官方提供給開發者在項目構建階段即由class到dex轉換期間修改class文件的一套api ![](https://img.kancloud.cn/15/b4/15b4aace81af312b66ce4b3ac5028f44_900x1090.png) 每個Transform其實都是一個gradle task,Android編譯器中的TaskManager將每個Transform串連起來,第一個Transform接收來自javac編譯的結果,以及已經拉取到在本地的第三方依賴(jar. aar),還有resource資源,注意,這里的resource并非android項目中的res資源,而是asset目錄下的資源。這些編譯的中間產物,在Transform組成的鏈條上流動,每個Transform節點可以對class進行處理再傳遞給下一個Transform。我們常見的混淆,Desugar等邏輯,它們的實現如今都是封裝在一個個Transform中,而我們自定義的Transform,會插入到這個Transform鏈條的最前面。 ![](https://img.kancloud.cn/39/e3/39e3a5eb43adacef93fcd888687fd457_1020x634.png) ### 實踐 #### 1 引入下面這個依賴 ~~~ compile 'com.android.tools.build:transform-api:1.5.0' ~~~ #### 2 自定義的Transform ~~~ //Transform 就是把輸入的 .class 文件轉變成目標字節碼文件。 public class AutoTransform extends Transform { Project project public AutoTransform(Project project) { this.project = project } @Override String getName() { return "AutoTrack" } @Override Set<QualifiedContent.ContentType> getInputTypes() { // 要處理的數據類型 // TransformManager.CONTENT_CLASS 編譯后的字節碼,有可能是jar也有可能是目錄 // TransformManager.CONTENT_RESOURCES 標準java資源 return TransformManager.CONTENT_CLASS } @Override Set<? super QualifiedContent.Scope> getScopes() { // 作用域 // Scope.PROJECT 只處理當前項目 // Scope.SUB_PROJECTS 只處理子項目 // Scope.PROJECT_LOCAL_DEPS 只處理當前項目本地依賴 jar aar // Scope.SUB_PROJECTS_LOCAL_DEPS 只處理子項目本地依賴 jar aar // Scope.EXTERNAL_LIBRARIES 只處理外部的依賴 return TransformManager.SCOPE_FULL_PROJECT } @Override boolean isIncremental() { // 是否增量構建? return true } // TransformInput 是指這些輸入文件的抽象。它包括兩部分: // 1)DirectoryInput 集合 // 是指以源碼方式參與項目編譯的所有目錄結構及其目錄下 的源碼文件。 // 2)JarInput 集合 // 是指以 jar 包方式參與項目編譯的所有本地 jar 包和遠程 jar 包。 // // TransformOutputProvider是指 Transform 的輸出,通過它可以獲取輸出路徑。 @Override void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException { Collection<TransformInput> inputs = transformInvocation.inputs TransformOutputProvider outputProvider = transformInvocation.outputProvider printlnJarAndDir(inputs) inputs.each { TransformInput input -> input.directoryInputs.each { DirectoryInput directoryInput -> handleDirectoryInput(directoryInput, outputProvider) } input.jarInputs.each { JarInput jarInput -> //處理jarInputs handleJarInputs(jarInput, outputProvider) } } } } ~~~ #### 3 自定義的Transform ~~~ class SimpleTransformPlugin implements Plugin<Project> { void apply(Project project) { def android = project.extensions.getByType(AppExtension) android.registerTransform(new AutoTransform(project)) } } ~~~ ## ASM ### 推薦閱讀 [官網](https://asm.ow2.io/) [一起玩轉Android項目中的字節碼](http://quinnchen.cn/2018/09/13/2018-09-13-asm-transform/) [Android】函數插樁(Gradle + ASM)](https://www.jianshu.com/p/16ed4d233fd1) ### 原理和簡介 JVM平臺上,處理字節碼的框架最常見的就三個,ASM,Javasist,AspectJ。最推薦選擇ASM,因為使用它可以更底層地處理字節碼的每條命令,處理速度、內存占用,也優于其他兩個框架。 ASM處理涉及三個類 ClassReader、ClassWriter、ClassVisitor ~~~ static void handleDirectoryInput(DirectoryInput directoryInput, TransformOutputProvider outputProvider, MethodIdFactory factory) { //是否是目錄 if (directoryInput.file.isDirectory()) { //列出目錄所有文件(包含子文件夾,子文件夾內文件) directoryInput.file.eachFileRecurse { File file -> def name = file.name if (name.endsWith(".class") && !name.startsWith("R\$") && !"R.class".equals(name) && !"BuildConfig.class".equals(name) && !name.contains("Manifest") ) { // ClassReader負責讀取class字節碼 ClassReader classReader = new ClassReader(file.bytes) ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS) //代理自己的ClassVisitor ClassVisitor cv = new MethodStatClassVisitor(classWriter, factory) //真正觸發這個邏輯就是通過ClassWriter的accept方式。 classReader.accept(cv, ClassReader.EXPAND_FRAMES) //我們通過ClassWriter的toByteArray(),將從ClassReader傳遞到ClassWriter的字節碼導出,寫入新的文件即可 byte[] code = classWriter.toByteArray() FileOutputStream fos = new FileOutputStream( file.parentFile.absolutePath + File.separator + name) fos.write(code) fos.close() } } } //處理完輸入文件之后,要把輸出給下一個任務 def dest = outputProvider.getContentLocation(directoryInput.name, directoryInput.contentTypes, directoryInput.scopes, Format.DIRECTORY) FileUtils.copyDirectory(directoryInput.file, dest) } ~~~ ClassReader負責讀取class字節碼,將字節碼的每個細節按順序通過接口的方式,傳遞給然后ClassReader通過一個ClassVisitor接口,將字節碼的每個細節按順序通過接口的方式,傳遞給ClassVisitor(你會發現ClassVisitor中有多個visitXXXX接口),這個過程就像ClassReader帶著ClassVisitor游覽了class字節碼的每一個指令。 ClassWriter我們可以看它源碼,其實就是一個ClassVisitor的實現。 ClassWriter的toByteArray(),將從ClassReader傳遞到ClassWriter的字節碼導出,寫入新的文件即可。這就完成了class文件的復制 ![](https://img.kancloud.cn/3b/a0/3ba0ea6fcd0b0a0eb9cd5291549a29b3_900x524.png) ![](https://img.kancloud.cn/f0/21/f02130f5864a1a117a276d451058973d_900x524.png) 自定義 ## 應用案例
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看