• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Android 热修复使用Gradle Plugin1.5改造Nuwa插件

Android 热修复使用Gradle Plugin1.5改造Nuwa插件

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了android nuwa,android nuwa热修复,nuwa成长记,王者荣耀nuwa视频,nuwa成长记2等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Android 热修复使用Gradle Plugin1.5改造Nuwa插件


随着谷歌的Gradle插件版本的不断升级,Gradle插件现在最新的已经到了2.1.0-beta1,对应的依赖为com.android.tools.build:gradle:2.0.0-beta6,而Nuwa当时出来的时候,Gradle插件还只是1.2.3版本,对应的依赖为com.android.tools.build:gradle:1.2.3,当时的Nuwa是根据有无preDex这个Task进行hook做不同的逻辑处理,而随着Gradle插件版本的不断增加,谷歌增加了一个新的接口可以用于处理我们的字节码注入的需求。这个接口最早出现在1.5.0-beta1中,官方的描述如下,不想看英文的直接略过看翻译。

Starting with 1.5.0-beta1, the Gradle plugin includes a Transform API allowing 3rd party plugins to manipulate compiled class files before they are converted to dex files.
(The API existed in 1.4.0-beta2 but it's been completely revamped in 1.5.0-beta1)

The goal of this API is to simplify injecting custom class manipulations without having to deal with tasks, and to offer more flexibility on what is manipulated. The internal code processing (jacoco, progard, multi-dex) have all moved to this new mechanism already in 1.5.0-beta1.
Note: this applies only to the javac/dx code path. Jack does not use this API at the moment.

The API doc is here.

To insert a transform into a build, you simply create a new class implementing one of the Transform interfaces, and register it with android.registerTransform(theTransform) or android.registerTransform(theTransform, dependencies).

Important notes:
The Dex class is gone. You cannot access it anymore through the variant API (the getter is still there for now but will throw an exception)
Transform can only be registered globally which applies them to all the variants. We'll improve this shortly.
There's no way to control ordering of the transforms.
We're looking for feedback on the API. Please file bugs or email us on our adt-dev mailing list.

从1.5开始,gradle插件包含了一个叫Transform的API,这个API允许第三方插件在class文件转为为dex文件前操作编译好的class文件,这个API的目标就是简化class文件的自定义的操作而不用对Task进行处理,并且可以更加灵活地进行操作。我们如何注入一个Transform呢,很简单,实现Transform抽象类中的方法,使用下面的两个方法之一进行注入即可。

android.registerTransform(theTransform) 

android.registerTransform(theTransform, dependencies)

那么我们就可以在这个函数中操作之前1.2.3版本中的Nuwa Gradle做的一切事情。在这之前,你最好通读下面三篇文章

如何使用Android Studio开发Gradle插件 Android 热修复Nuwa的原理及Gradle插件源码解析 深入理解Android之Gradle

现在,新建一个gradle插件项目,如何新建请阅读上面的第一篇文章,这个插件项目中有两个module,一个为app,用于测试插件,一个是插件module,姑且叫hotpatch,用于编写插件。

将你的gradle plugin版本切到1.5

classpath 'com.android.tools.build:gradle:1.5.0'

然后将gralde wrapper版本改为2.10

distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip

现在编译运行一下项目下的app module,看下gradle控制台输出的是什么。

这里写图片描述

可以看到,的确没有preDex这个Task,反倒是多了很多transform开头的Task,那么这些Task是怎么来的呢。在gradle plugin的源码中有一个叫TransformManager的类,这个类管理着所有的Transform的子类,里面有一个方法叫getTaskNamePrefix,在这个方法中就是获得Task的前缀,以transform开头,之后拼接ContentType,这个ContentType代表着这个Transform的输入文件的类型,类型主要有两种,一种是Classes,另一种是Resources,ContentType之间使用And连接,拼接完成后加上With,之后紧跟的就是这个Transform的Name,name在getName()方法中重写返回即可。代码如下:

@NonNull
    private static String getTaskNamePrefix(@NonNull Transform transform) {
        StringBuilder sb = new StringBuilder(100);
        sb.append("transform");

        Iterator iterator = transform.getInputTypes().iterator();
        // there's always at least one
        sb.append(capitalize(iterator.next().name().toLowerCase(Locale.getDefault())));
        while (iterator.hasNext()) {
            sb.append("And").append(capitalize(
                    iterator.next().name().toLowerCase(Locale.getDefault())));
        }

        sb.append("With").append(capitalize(transform.getName())).append("For");

        return sb.toString();
    }

ContentType是一个接口,有一个默认的枚举类的实现类,里面定义了两种文件,一种是class文件,另一种就是资源文件。

interface ContentType {
        /**
         * Content type name, readable by humans.
         * @return the string content type name
         */
        String name();

        /**
         * A unique value for a content type.
         */
        int getValue();
    }

    /**
     * The type of of the content.
     */
    enum DefaultContentType implements ContentType {
        /**
         * The content is compiled Java code. This can be in a Jar file or in a folder. If
         * in a folder, it is expected to in sub-folders matching package names.
         */
        CLASSES(0x01),

        /**
         * The content is standard Java resources.
         */
        RESOURCES(0x02);

        private final int value;

        DefaultContentType(int value) {
            this.value = value;
        }

        @Override
        public int getValue() {
            return value;
        }
    }

说到ContentType,顺便把另一个枚举类带掉,叫Scope,翻译过来就是作用域,关于详细的内容,请看下面的注释。

enum Scope {
        /** Only the project content */
        PROJECT(0x01),
        /** Only the project's local dependencies (local jars) */
        PROJECT_LOCAL_DEPS(0x02),
        /** Only the sub-projects. */
        SUB_PROJECTS(0x04),
        /** Only the sub-projects's local dependencies (local jars). */
        SUB_PROJECTS_LOCAL_DEPS(0x08),
        /** Only the external libraries */
        EXTERNAL_LIBRARIES(0x10),
        /** Code that is being tested by the current variant, including dependencies */
        TESTED_CODE(0x20),
        /** Local or remote dependencies that are provided-only */
        PROVIDED_ONLY(0x40);

        private final int value;

        Scope(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

ContentType和Scope,一起组成输出产物的目录结构。可以看到下图transforms下有很多莫名其妙的目录,比如1000,1f,main,3,等等,这些目录可不是随机产生的,而是根据上面的两个值产生的。

这里写图片描述

举个例子,上面的文件夹中有个proguard的目录,这个目录是ProGuardTransform产生的,在源码中可以找到其实现了getName方法,返回了proguard。这个getName()方法返回的值就创建了proguard这个目录。

public String getName() {
  return "proguard";
}

然后再看这个Transform的输入文件类型

public Set getInputTypes() {
  return TransformManager.CONTENT_JARS;
}

TransformManager.CONTENT_JARS是什么鬼呢,跟进去一目了然

public static final Set CONTENT_JARS = ImmutableSet.of(CLASSES, RESOURCES);

因此Proguard这个Transform有两种输入文件,一种是class文件(含jar),另一种是资源文件,这个Task是做混淆用的,class文件就是ProGuardTransform依赖的上一个Transform的输出产物,而资源文件可以是混淆时使用的配置文件。

因此根据上

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 聊聊Android 热修复Nuwa有哪些坑
  • Android 热修复使用Gradle Plugin1.5改造Nuwa插件
  • Android 热修复原理及Gradle插件源码解析(以Nuwa为例)

相关文章

  • 2017-05-26JSON解析,json在线解析
  • 2017-05-26使用Eclipse开发Android源码
  • 2017-05-26二维码Zxing&Zbar,zxing
  • 2017-05-26Android触摸事件(一)-AbsTouchEventHandle
  • 2017-05-26Android窗口机制分析与UI管理系统,androidui
  • 2017-05-26Atitit.android js 的键盘按键检测Back键Home键和Menu键事件,atitit.androidmenu
  • 2017-05-26Android Studio发布应用
  • 2017-05-26Android--控件属性汇总
  • 2017-05-26如何处理 android 方法总数超过 65536 . the number of method references in a .dex file exceed 64k,android.dex
  • 2017-05-26安卓开源项目周报0117,安卓开源项目0117

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • Android中使用SDcard进行文件的读取,androidsdcard
    • Android 手机卫士--参照文档编写选择器,android选择器
    • 张高兴的 Xamarin.Android 学习笔记:(四)常用控件,android常用控件
    • android:Activity启动模式之singleTop
    • Android sdk content loader 0%,androidsdk
    • NDK中使用pthread多线程中自己写的一个BUG,ndkpthread
    • Android合并两个APP的具体做法(掌握)
    • android实现文字渐变效果和歌词进度的效果
    • android 和Ubuntu 同步使用Xmind
    • 7.5.4 WebView文件下载

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有