Gradle插件开发
公司主营业务:成都网站建设、网站建设、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联建站是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联建站推出海拉尔免费做网站回馈大家。
Gradle插件是使用Groovy进行开发的,而Groovy其实是可以兼容Java的。Android Studio其实除了开发Android App外,完全可以胜任开发Gradle插件这一工作,下面来讲讲具体如何开发。
首先,新建一个Android项目。
之后,新建一个Android Module项目,类型选择Android Library。
将新建的Module中除了build.gradle文件外的其余文件全都删除,然后删除build.gradle文件中的所有内容。
在新建的module中新建文件夹src,接着在src文件目录下新建main文件夹,在main目录下新建groovy目录,这时候groovy文件夹会被Android识别为groovy源码目录。除了在main目录下新建groovy目录外,你还要在main目录下新建resources目录,同理resources目录会被自动识别为资源文件夹。在groovy目录下新建项目包名,就像Java包名那样。resources目录下新建文件夹META-INF,META-INF文件夹下新建gradle-plugins文件夹。这样,就完成了gradle 插件的项目的整体搭建,之后就是小细节了。目前,项目的结构是这样的。
打开Module下的build.gradle文件,输入
apply plugin: 'groovy'
apply plugin: 'maven'
dependencies {
compile gradleApi()
compile localGroovy()
}
repositories {
mavenCentral()
}12345678910111234567891011
下面我们在包名下新建一个文件,命名为PluginImpl.groovy,注意有groovy后缀,然后在里面输入,注意包名替换为你自己的包名。
package cn.edu.zafu.gradle
import org.gradle.api.Plugin
import org.gradle.api.Project
public class PluginImpl implements PluginProject {
void apply(Project project) {
project.task('testTask') {
println "Hello gradle plugin"
}
}
}123456789101112123456789101112
然后在resources/META-INF/gradle-plugins目录下新建一个properties文件,注意该文件的命名就是你只有使用插件的名字,这里命名为plugin.test.properties,在里面输入
implementation-class=cn.edu.zafu.gradle.PluginImpl11
注意包名需要替换为你自己的包名。
这样就完成了最简单的一个gradle插件,里面有一个叫testTask的Task,执行该task后会输出一段文字,就像当初我们输出HelloWorld一样。
android studio常用插件,可极大简化开发,增强开发效率。
1、ButterKnife Zelezny
ButterKnife 注解生成器,使用起来非常简单方便,使用ButterKnife的有福了!
2、SelectorChapek
设计师给我们提供好了各种资源,每个按钮都要写一个selector是不是很麻烦?这么这个插件就为解决这个问题而生,你只需要做的是告诉设计师们按照规范命名就好了,其他一键搞定。按照不同状态(normal、pressed)的标准命名后,右键文件树Generate
Android Selectors见inmite/android-selector-chapek · GitHub。
3、GsonFormat
现在大多数服务端api都以json数据格式返回,而客户端需要根据api接口生成相应的实体类,这个插件把这个过程自动化了,赶紧使用起来吧。
4、Android Parcelable Code Generator
Android中的序列化有两种方式,分别是实现Serializable接口和Parcelable接口,但在Android中是推荐使用Parcelable,只不过我们这种方式要比Serializable方式要繁琐,那么有了这个插件一切就ok了。
5、LeakCanary
使用Android Studio开发Gradle插件的步骤:
1 创建Gradle Module
AndroidStudio中是没有新建类似Gradle Plugin这样的选项的,那我们如何在AndroidStudio中编写Gradle插件,并打包出来呢?
(1) 首先,你得新建一个Android Project
(2) 然后再新建一个Module,这个Module用于开发Gradle插件,同样,Module里面没有gradle plugin给你选,但是我们只是需要一个“容器”来容纳我们写的插件,因此,你可以随便选择一个Module类型(如PhoneTablet Module或Android Librarty),因为接下来一步我们是将里面的大部分内容删除,所以选择哪个类型的Module不重要。
(3) 将Module里面的内容删除,只保留build.gradle文件和src/main目录。
由于gradle是基于groovy,因此,我们开发的gradle插件相当于一个groovy项目。所以需要在main目录下新建groovy目录
(4) groovy又是基于Java,因此,接下来创建groovy的过程跟创建java很类似。在groovy新建包名,如:com.hc.plugin,然后在该包下新建groovy文件,通过new-file-MyPlugin.groovy来新建名为MyPlugin的groovy文件。
(5) 为了让我们的groovy类申明为gradle的插件,新建的groovy需要实现org.gradle.api.Plugin接口。如下所示:
package com.hc.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
public class MyPlugin implements Pluginproject {/project
void apply(Project project) {
System.out.println("========================");
System.out.println("hello gradle plugin!");
System.out.println("========================");
}
}
因为我本人对groovy也不是特别熟悉,所以我尽可能的用Java语言,使用System.out.println而不是用groovy的pintln "",我们的代码里面啥也没做,就打印信息。
(6) 现在,我们已经定义好了自己的gradle插件类,接下来就是告诉gradle,哪一个是我们自定义的插件类,因此,需要在main目录下新建resources目录,然后在resources目录里面再新建META-INF目录,再在META-INF里面新建gradle-plugins目录。最后在gradle-plugins目录里面新建properties文件,注意这个文件的命名,你可以随意取名,但是后面使用这个插件的时候,会用到这个名字。比如,你取名为com.hc.gradle.properties,而在其他build.gradle文件中使用自定义的插件时候则需写成:
apply plugin: 'com.hc.gradle'
然后在com.hc.gradle.properties文件里面指明你自定义的类
implementation-class=com.hc.plugin.MyPlugin
现在,你的目录应该如下:
(7) 因为我们要用到groovy以及后面打包要用到maven,所以在我们自定义的Module下的build.gradle需要添加如下代码:
apply plugin: 'groovy'
apply plugin: 'maven'
dependencies {
compile gradleApi()
compile localGroovy()
}
repositories {
mavenCentral()
}
2 打包到本地Maven
前面我们已经自定义好了插件,接下来就是要打包到Maven库里面去了,你可以选择打包到本地,或者是远程服务器中。在我们自定义Module目录下的build.gradle添加如下代码:
group='com.hc.plugin'
version='1.0.0'
uploadArchives {
repositories {
mavenDeployer {
repository(url: uri('D:/repos'))
}
}
}
其中,group和version后面会用到,我们后面再讲。虽然我们已经定义好了打包地址以及打包相关配置,但是还需要我们让这个打包task执行。点击AndroidStudio右侧的gradle工具,如下图所示:
可以看到有uploadArchives这个Task,双击uploadArchives就会执行打包上传啦!执行完成后,去我们的Maven本地仓库查看一下:
其中,com/hc/plugin这几层目录是由我们的group指定,myplugin是模块的名称,1.0.0是版本号(version指定)。
原理:实现原理上都选择尽量少的hook,通过在manifest上预埋一些组件实现四大组件的插件化。其中Small更形成了一个跨平台、组件化的框架。
VirtulApp:
能够完全模拟app的运行环境,能够实现免安装应用和双开技术。
Atlas:
阿里出品,号称是一个容器化框架,结合了组件化和热更新技术。
Android中有两种类加载器,DexClassLoader和PathClassLoader,它们都继承于BaseDexClassLoader。
两者的区别:DexClassLoader多了一个optimizedDirectory的路径参数,这个目录必须是内部存储路径,用于缓存系统创建的Dex文件。
所以我们可以使用DexClassLoader去加载外部Apk中的类。
ClassLoader调用loadClass方法加载类采用了双亲委托机制来避免重复加载类。
首先,ClassLoader会查看自身已经加载的类中是否已经存在此类,如不存在,然后,则会使用父类来加载此类,如不能成功加载,则会使用自身重载于BaseDexClassLoader的findClass()方法来加载此类。
DexClass的DexPathList在DexClass的构造器中生成,findClass()方法则是从DexPathList下面找出对应的DexFile,循环DexElements,通过dexElement.dexFile取出对应的DexFile,再通过DexFile.loadClassBinaryName()加载对应的类。
作用:使用插件DexClassLoader加载出需要的类。
通过每一个插件的DexClassLoader加载出自身所需要的类,当每一个插件需要加载相同的类库时,可采用该类库的不同版本来使用。
通过把每一个插件的pathList(DexFile)合并到主app的DexClassLoader上,来使各个插件和主app直接能够相互调用类和方法,并且各个插件中相同的功能可以抽取出来作为一个Common插件供其它插件使用。
插件调用主工程
在ClassLoader构造时指定主工程的DexClassLoader为父加载器即可直接调用主工程中的类和方法。
主工程调用插件
如果是多DexClassLoader的情况,则需要通过插件的DexClassLoader加载对应的类并反射调用其方法。此种情况,主工程一般会在一个统一的地方对访问插件中的类和方法做一些访问权限的管理及配置。
如果是单DexClassLoader的情况,则可以直接调用插件中的类和方法。但是当多个插件引用的库的版本不同时,会出现错误,因此,建议采用Gradle版本依赖管理统一处理主工程及各个插件的库依赖。
Android通过Resource来加载资源,只要有插件apk,就可以使用assertManager.addAssertPath(apkPath)的方式来生成assertManager,再使用其new出对应的Resource对象即可。
注意:由于AssertManager并不是Public,所以需要通过反射的方式去调用它。并且由于一些Rom对Resource的处理,所以,需要兼容处理。
有2种处理方式:
产生的原因:由于主工程和各个插件引用的Resource id重复产生的冲突。
解决思路:Android中的资源在系统中是以8位16进制0XPPTTRRRR的方式存在,其中PP即是资源区分的区域(Android系统只用它来区分系统资源和应用资源),只要让每一个插件的PP段取不同的值即可解决资源id冲突的问题。
具体解决方式:
1.修改aapt源码,编译期修改PP段。
2.修改Resource的arsc文件,其中的每一条都包含了资源id和映射路径。
Activity的处理最为复杂,有两种处理方式:
1.ProxyActivity的方式。
2.预埋StubActivity,hook系统启动Activity的过程。
原理:VirtualAPK通过替换了系统的Instrumentation,hook了Activity的启动和创建,省去了手动管理插件Activity生命周期的繁琐,让插件Activity像正常的Activity一样被系统管理,并且插件Activity在开发时和常规一样,即能独立运行又能作为插件被主工程调用。
Android插件化方向主要有2个方向:
Android 插件化
android-postfix-plugin可根据后缀快速完成代码,这个属于拓展吧,系统已经有这些功能,如sout、notnull等,这个插件在原有的基础上增添了一些新的功
AndroidAccessors快速生成get和set方法的插件,其实系统的也有类似功能,这个更快。
Lifecycle-Sorter
可以根据Activity或者fragment的生命周期对其生命周期方法位置进行先后排序, 快捷键Ctrl + alt + K
JsonOnlineViewer
可实现直接在android studio中调试接口数据,可以选择请求类型,自定义请求头及请求体,json数据格式化后展示
CodeGlance
可用于快速定位代码,类似于Sublime编辑器右侧定位视图
idea-android-studio-plugin
IntelliJ IDEA / Android Studio plugin with some tools and usability improvements
folding-plugin
可以给资源文件分组,并且不移动文件,也不会创建文件夹:Android File Grouping Plugin
Android Drawable Importer
为了适应所有Android屏幕的大小和密度,每个Android项目都会包含drawable文件夹。任何具备Android开发经验的开发人员都知道,为了支持所有的屏幕尺寸,你必须给每个屏幕类型导入不同的画板。Android Drawable Importer插件能让这项工作变得更容易。它可以减少导入缩放图像到Android项目所需的工作量。Android Drawable Importer添加了一个在不同分辨率导入画板或缩放指定图像到定义分辨率的选项。这个插件加速了开发人员的画板工作。
Android ButterKnife Zelezny
用于在活动、片段和适配器中,从所选的XML布局文件生成ButterKnife注入。该插件提供了生成XML对象注入的最快方式。
Android Holo Colors Generator
开发Android应用程序需要伟大的设计和布局。Android Holo Colors Generator则是定制符合喜好的Android应用程序的最简单方法。Android Holo Colors Generator是一个允许你为你的应用程序随心所欲地创建Android布局组件的插件。此插件会生成所有必要的可在项目中使用的相关的XML画板和样式资源。
Android Parcelable code generator
生成实现了Parcelable接口的代码的插件。在你的类中,按下alt + insert键弹出插入代码的上下文菜单,你会看到在下面有一个Parcelable,如下所示。选择它之后,就会在你的类当中插入实现了Parcelable接口的代码。从此不用再手动写Parcelable代码
AndroidCodeGenerator
可以生成ViewHolder和findView方法的代码。尤其是在Adapter实现类的getView当中很有用。
Android Layout ID Converter
生成findView代码的使用方法。
SelectorChapek for Android
生成Selector的插件。你需要在drawable文件夹中右键,在弹出的菜单中选择Generate Android Selectors,如下所示,它就会根据你的几个drawable文件夹里的资源的命名,帮你生成Selector代码。当然,你的资源文件需要根据约定的后缀来命名。比如按下状态为_pressed,正常状态为_normal,不可用状态为_disable,等等
genymotion-gradle-plugin
不同于图形化的genymotion插件,这个允许你通过脚本来配置,创建device。
sdk-manager-plugin
SDK管理插件,自动检测更新并下载。
otto-intellij-pluginotto事件导航工具。
dagger-intellij-plugin
dagger可视化辅助工具。
eventbus-intellij-plugin
eventbus导航插件
eventbus3-intellij-plugin
eventbus导航插件
strings-xml-tools
管理Android工程中字符串国际化的插件
gradle-packer-plugin
Android多渠道打包工具。
gradle-retrolambda
在java 6 7中使用 lambda表达式的插件。
lint-cleaner-plugin
移除Android中无用资源。
dexcount-gradle-plugin方法数计算,对于较大应用避免方法爆棚很有用。
android-unit-test
添加Android单元测试。
robolectric-gradle-plugin
Robolectric测试辅助工具。
GradleDependenciesHelperPlugin
maven gradle 依赖支持自动补全。idea-markdownmarkdown插件
详细教程
插件化开发和组件化开发略有不用,插件化开发时将整个app拆分成很多模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk(组件化的每个模块是个lib),最终打包的时候将宿主apk和插件apk分开或者联合打包。
开源的插件化框架
Qihoo360/DroidPlugin
CtripMobile/DynamicAPK
mmin18/AndroidDynamicLoader
singwhatiwanna/dynamic-load-apk
houkx/android-pluginmgr
bunnyblue/ACDD
wequick/Small
……
目前开源的这几个框架有宿主和插件分离的也有融合在一起的,每个框架的详细介绍和demo在github里都可以查看到。插件化demo运行起来比较简单,但是真正将它用到实际项目中还是要考虑很多小细节的,目前我也正处于研究阶段。