Replugin 源码分析------replugin-host-gradle插件源码分析
Posted Wastrel_xyz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Replugin 源码分析------replugin-host-gradle插件源码分析相关的知识,希望对你有一定的参考价值。
前言
Replugin
是360开源的一个插件化框架,源码地址:https://github.com/Qihoo360/RePlugin,属于一种占坑类的插件化方案,整个框架分为四部分:宿主编译插件、插件工程编译插件、宿主依赖库、插件依赖库。今天分享的是宿主编译插件源码,该插件的作用是在编译时将四大组件的坑位预置进宿主程序中,并生成内置插件的配置信息。
一、源码结构
很显然标准的
gradle
插件工程,编码语言为groovy
,编译工具为gradle
,本文不讨论gradle
插件工程相关知识,本文只分析该插件在宿主编译时做了哪些工作。
二、源码分析
从replugin-host-gradle.properties
文件可以看到整个plugin
的入口在类com.qihoo360.replugin.gradle.host.Replugin
中,首先就从这个文件开始入手吧。
源码路径:com.qihoo360.replugin.gradle.host.Replugin.groovy
/**整个插件的调用入口方法*/
@Override
public void apply(Project project)
this.project = project
/* Extensions */
//创建extensions,然后再bulid.gradle文件里就可以,修改RepluginConfig里的默认配置了。
project.extensions.create(AppConstant.USER_CONFIG, RepluginConfig)
/*app工程才会执行,Library项目直接过滤了*/
if (project.plugins.hasPlugin(AppPlugin))
def android = project.extensions.getByType(AppExtension)
android.applicationVariants.all variant ->
addShowPluginTask(variant)
//获取用户bulid.gradle文件里的配置
if (config == null)
config = project.extensions.getByName(AppConstant.USER_CONFIG)
checkUserConfig(config)
def generateBuildConfigTask = VariantCompat.getGenerateBuildConfigTask(variant)
def appID = generateBuildConfigTask.appPackageName
def newManifest = ComponentsGenerator.generateComponent(appID, config)
println "$TAG countTask=$config.countTask"
def variantData = variant.variantData
def scope = variantData.scope
//host generate task
def generateHostConfigTaskName = scope.getTaskName(AppConstant.TASK_GENERATE, "HostConfig")
def generateHostConfigTask = project.task(generateHostConfigTaskName)
//生成RePluginHostConfig.java
generateHostConfigTask.doLast
FileCreators.createHostConfig(project, variant, config)
generateHostConfigTask.group = AppConstant.TASKS_GROUP
//depends on build config task
if (generateBuildConfigTask)
generateHostConfigTask.dependsOn generateBuildConfigTask
generateBuildConfigTask.finalizedBy generateHostConfigTask
//json generate task
def generateBuiltinJsonTaskName = scope.getTaskName(AppConstant.TASK_GENERATE, "BuiltinJson")
def generateBuiltinJsonTask = project.task(generateBuiltinJsonTaskName)
//plugins-builtin.json
generateBuiltinJsonTask.doLast
FileCreators.createBuiltinJson(project, variant, config)
generateBuiltinJsonTask.group = AppConstant.TASKS_GROUP
//depends on mergeAssets Task
def mergeAssetsTask = VariantCompat.getMergeAssetsTask(variant)
if (mergeAssetsTask)
generateBuiltinJsonTask.dependsOn mergeAssetsTask
mergeAssetsTask.finalizedBy generateBuiltinJsonTask
variant.outputs.each output ->
VariantCompat.getProcessManifestTask(output).doLast
println "$AppConstant.TAG processManifest: $it.outputs.files"
it.outputs.files.each File file ->
updateManifest(file, newManifest)
上面代码出现多次使用了一个工具类VariantCompat
,该类是做gradle
版本兼容的,主要目的是从Android Gradle Task
里获取对应的task
,例如方法VariantCompat.getGenerateBuildConfigTask(variant)
就是获取generateBuildConfigTask
的,可以在Android Studio中打开gradle任务视图,根据不同的variant
即可获取到不同的任务。
生成坑位代码
/**
* 动态生成插件化框架中需要的组件
*
* @param applicationID 宿主的 applicationID
* @param config 用户配置
* @return String 插件化框架中需要的组件
*/
def newManifest = ComponentsGenerator.generateComponent(appID, config)
//生成结果
// <provider android:name='com.qihoo360.replugin.component.process.ProcessPitProviderPersist' android:authorities='com.qihoo360.replugin.sample.host.loader.p.main' android:exported='false' android:process=':GuardService' />
// ...
// <activity android:name='com.qihoo360.replugin.sample.host.loader.a.ActivityN1NRTS0' android:configChanges='keyboard|keyboardHidden|orientation|screenSize' android:exported='false' android:screenOrientation='portrait' android:theme='@android:style/Theme.Translucent.NoTitleBar'/>
//...
// <service android:name='com.qihoo360.replugin.component.service.server.PluginPitServiceP2' android:process=':p2' android:exported='false' />
//...
该方法通过gradle
文件中的配置坑位个数来生成四大组件的预置坑位,生成代码很简单,就是for循环生成xml文件。有兴趣可以点进去看,源码路径:com.qihoo360.replugin.gradle.host.handlemanifest.ComponentsGenerator.groovy
生成内置插件json配置
源码位置:com.qihoo360.replugin.gradle.host.creator.impl.json.PluginBuiltinJsonCreator#getFileContent;
//查找插件文件并抽取信息,如果没有就直接返回null
File pluginDirFile = new File(fileDir?.getAbsolutePath() + File.separator + config.pluginDir)
//遍历assets/plugins下的所有插件。
new File(fileDir.getAbsolutePath() + File.separator + config.pluginDir)
.traverse(type: FileType.FILES, nameFilter: ~/.*\\$config.pluginFilePostfix/)
PluginInfoParser parser = null
try
//利用开源库解析插件APK的版本号等Meta信息。
parser = new PluginInfoParser(it.absoluteFile, config)
catch (Exception e)
if (config.enablePluginFileIllegalStopBuild)
throw new Exception(e)
if (null != parser)
pluginInfos << parser.pluginInfo
//插件为0个
if (pluginInfos.isEmpty())
return null
//构建插件们的json信息
def jsonOutput = new JsonOutput()
String pluginInfosJson = jsonOutput.toJson(pluginInfos)
//格式化打印插件们的json信息
return pluginInfosJson
从代码中看到,此处直接从assets里扫描并生成内置插件的json
信息。这里解析插件apk
文件用到了一个开源库net.dongliu:apk-parser:2.2.0
,https://github.com/hsiafan/apk-parser,有兴趣可以关注一下。
更新到Manifest文件中
直接上代码吧,没有任何难度,就是简单的替换,找到所有的AndroidManifest.xml
把生产的坑位append
上去。
def updateManifest(def file, def newManifest)
// 除了目录和AndroidManifest.xml之外,还可能会包含manifest-merger-debug-report.txt等不相干的文件,过滤它
if (file == null || !file.exists() || newManifest == null) return
if (file.isDirectory())
println "$AppConstant.TAG updateManifest: $file"
file.listFiles().each
updateManifest(it, newManifest)
else if (file.name.equalsIgnoreCase("AndroidManifest.xml"))
appendManifest(file, newManifest)
def appendManifest(def file, def content)
if (file == null || !file.exists()) return
println "$AppConstant.TAG appendManifest: $file"
def updatedContent = file.getText("UTF-8").replaceAll("</application>", content + "</application>")
file.write(updatedContent, 'UTF-8')
总结
看完源码后,Replugin
宿主的gradle
插件没有干什么高大上的活,都是一些配置生成的体力活。理论上来讲对编译性能影响也不大,耗时多得地方可能就在扫描内置插件的任务上了。但是Replugin
生成了非常多得坑位,接入之后,最终的AndroidManifest.xml
会多出200多个坑位,但这两百多个坑位是没有对应的类文件的,后续阅读宿主程序源码后再行分析。整体来看Replugin
在编译器对宿主的入侵是很小的。
以上是关于Replugin 源码分析------replugin-host-gradle插件源码分析的主要内容,如果未能解决你的问题,请参考以下文章
Replugin 源码分析------replugin-host-gradle插件源码分析
Replugin 源码分析------replugin-host-gradle插件源码分析
唯一插件化Replugin源码及原理深度剖析--唯一Hook点原理
唯一插件化Replugin源码及原理深度剖析--唯一Hook点原理