插件hook android插件构建流程,选择性注入

This commit is contained in:
yummylau
2019-10-25 15:50:00 +08:00
parent 18677bfb93
commit 6ff12225e0
7 changed files with 405 additions and 316 deletions

View File

@@ -14,6 +14,9 @@ import org.gradle.api.Project
* ./gradlew --no-daemon :app:assemble -Dorg.gradle.debug=true
* ./gradlew --no-daemon [:library:assembleDebug, :libraryKotlin:assembleDebug, :debugModule:assembleDebug, :app:assembleDebug] -Dorg.gradle.debug=true
* 组件插件入口
* 插件统一在root模块配置收集所有配置信息在root评估之后统一初始化完成
* pin功能需要在android插件apply之前
* debug/sdk功能需要在android插件apply之后
* created by yummylau 2019/08/09
*/
class ComponentPlugin extends AbsPlugin implements Plugin<Project> {
@@ -28,47 +31,57 @@ class ComponentPlugin extends AbsPlugin implements Plugin<Project> {
if (project == project.rootProject) {
componentExtension = project.getExtensions().create(Constants.COMPONENT, ComponentExtension, project)
initExtension(componentExtension)
evaluate(project, true)
Runtimes.initRuntimeConfigurationOnEvaluate(project)
project.afterEvaluate {
afterEvaluate(project, true)
Runtimes.initRuntimeConfigurationAfterEvaluate(project, componentExtension)
Runtimes.hookAfterApplyingAndroidPlugin(project, this)
Runtimes.injectComponentPlugin(project)
}
project.gradle.projectsEvaluated {
afterAllEvaluate()
afterAllEvaluate(project)
}
} else {
evaluate(project, false)
evaluateBeforeAndroidPlugin(project)
project.afterEvaluate {
afterEvaluate(project, false)
afterEvaluateBeforeAndroidPlugin(project)
}
}
}
@Override
void evaluate(Project project, boolean isRoot) {
sdk.evaluate(project, isRoot)
debug.evaluate(project, isRoot)
pins.evaluate(project, isRoot)
}
@Override
void afterEvaluate(Project project, boolean isRoot) {
sdk.afterEvaluate(project, isRoot)
debug.afterEvaluate(project, isRoot)
pins.afterEvaluate(project, isRoot)
}
@Override
void initExtension(ComponentExtension componentExtension) {
this.componentExtension = componentExtension
sdk.initExtension(componentExtension)
debug.initExtension(componentExtension)
pins.initExtension(componentExtension)
}
@Override
void evaluateBeforeAndroidPlugin(Project project) {
pins.evaluateBeforeAndroidPlugin(project)
}
@Override
void afterAllEvaluate() {
sdk.afterAllEvaluate()
debug.afterAllEvaluate()
pins.afterAllEvaluate()
void afterEvaluateBeforeAndroidPlugin(Project project) {
pins.afterEvaluateBeforeAndroidPlugin(project)
}
@Override
void evaluateAfterAndroidPlugin(Project project) {
sdk.evaluateAfterAndroidPlugin(project)
debug.evaluateAfterAndroidPlugin(project)
}
@Override
void afterEvaluateAfterAndroidPlugin(Project project) {
sdk.afterEvaluateAfterAndroidPlugin(project)
debug.afterEvaluateAfterAndroidPlugin(project)
}
@Override
void afterAllEvaluate(Project root) {
sdk.afterAllEvaluate(root)
debug.afterAllEvaluate(root)
pins.afterAllEvaluate(root)
}
}

View File

@@ -1,17 +1,34 @@
package com.plugin.component
import com.android.build.gradle.AppExtension
import com.android.build.gradle.AppPlugin
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.LibraryPlugin
import com.android.build.gradle.TestedExtension
import com.plugin.component.extension.ComponentExtension
import com.plugin.component.extension.PublicationManager
import com.plugin.component.extension.module.PinInfo
import com.plugin.component.extension.module.ProjectInfo
import com.plugin.component.extension.option.debug.DebugDependenciesOption
import com.plugin.component.extension.option.pin.PinConfiguration
import com.plugin.component.extension.option.pin.PinOption
import com.plugin.component.extension.option.sdk.CompileOptions
import com.plugin.component.extension.option.debug.DebugConfiguration
import com.plugin.component.extension.option.sdk.PublicationDependenciesOption
import com.plugin.component.extension.option.sdk.PublicationOption
import com.plugin.component.extension.option.debug.DebugOption
import com.plugin.component.extension.option.sdk.SdkOption
import com.plugin.component.plugin.AbsPlugin
import com.plugin.component.transform.ComponentTransform
import com.plugin.component.transform.InjectCodeTransform
import com.plugin.component.transform.ScanCodeTransform
import com.plugin.component.utils.JarUtil
import com.plugin.component.utils.ProjectUtil
import com.plugin.component.utils.PublicationUtil
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.plugins.AppliedPlugin
class Runtimes {
@@ -33,7 +50,63 @@ class Runtimes {
public static File sSdkDir
public static File sImplDir
static initRuntimeConfiguration(Project root, ComponentExtension componentExtension) {
static initRuntimeConfigurationOnEvaluate(Project root) {
sSdkDir = new File(root.projectDir, Constants.SDK_DIR)
sImplDir = new File(root.projectDir, Constants.IMPL_DIR)
Logger.buildOutput("sdk目录 File[" + sSdkDir.name + "]")
Logger.buildOutput("impl目录 File[" + sSdkDir.name + "]")
if (!sSdkDir.exists()) {
sSdkDir.mkdirs()
Logger.buildOutput("create File[" + sSdkDir.name + "]")
}
if (!sImplDir.exists()) {
sImplDir.mkdirs()
Logger.buildOutput("create File[" + sImplDir.name + "]")
}
ProjectUtil.getTasks(root).each {
if (it == Constants.CLEAN) {
if (!sSdkDir.deleteDir()) {
throw new RuntimeException("unable to delete dir " + sSdkDir.absolutePath)
}
if (!sImplDir.deleteDir()) {
throw new RuntimeException("unable to delete dir " + sImplDir.absolutePath)
}
sSdkDir.mkdirs()
Logger.buildOutput("reset File[" + sSdkDir.name + "]")
sImplDir.mkdirs()
Logger.buildOutput("reset File[" + sImplDir.name + "]")
}
}
root.repositories {
flatDir {
dirs sSdkDir.absolutePath
Logger.buildOutput("flatDir Dir[" + sSdkDir.absolutePath + "]")
dirs sImplDir.absolutePath
Logger.buildOutput("flatDir Dir[" + sImplDir.absolutePath + "]")
}
}
Logger.buildOutput("读取 sdk/impl manifest 配置文件...")
PublicationManager.getInstance().loadManifest(root)
Logger.buildOutput("读取 component.gradle 信息...")
//todo sdk中依赖sdk需要特别区分预留后续逻辑
PublicationDependenciesOption.metaClass.component { String value ->
return Constants.COMPONENT_PRE + value
}
DebugDependenciesOption.metaClass.component { String value ->
return Constants.DEBUG_COMPONENT_PRE + value
}
}
static initRuntimeConfigurationAfterEvaluate(Project root, ComponentExtension componentExtension) {
sExtension = componentExtension
sDebugOption = sExtension.debugOption
sSdkOption = sExtension.sdkOption
@@ -63,8 +136,185 @@ class Runtimes {
}
}
}
Logger.buildOutput("")
Logger.buildOutput("=====> 处理 sdk/impl jar <=====")
List<String> topSort = PublicationManager.getInstance().dependencyGraph.topSort()
Collections.reverse(topSort)
topSort.each {
PublicationOption publication = PublicationManager.getInstance().publicationDependencies.get(it)
if (publication == null) {
return
}
Project childProject = root.findProject(publication.project)
PublicationUtil.filterPublicationDependencies(publication)
if (publication.version != null) {
JarUtil.handleMavenJar(childProject, publication)
} else {
JarUtil.handleLocalJar(childProject, publication)
}
PublicationManager.getInstance().hitPublication(publication)
}
Logger.buildOutput("=====> 处理 sdk/impl jar <=====")
Logger.buildOutput("")
//添加flat路径
root.allprojects.each {
if (it == root) return
if (!shouldApplyComponentPlugin(it)) return
Project childProject = it
Logger.buildOutput("")
Logger.buildOutput("=====> project[" + childProject.name + "]配置信息 <=====")
childProject.repositories {
flatDir {
dirs sSdkDir.absolutePath
Logger.buildOutput("add flatDir Dir[" + sSdkDir.absolutePath + "]")
dirs sImplDir.absolutePath
Logger.buildOutput("add flatDir Dir[" + sImplDir.absolutePath + "]")
}
}
}
}
static hookAfterApplyingAndroidPlugin(Project root, AbsPlugin... plugins) {
root.allprojects.each {
if (it == root) return
if (!shouldApplyComponentPlugin(it)) return
Project childProject = it
ProjectInfo projectInfo = new ProjectInfo(childProject)
addProjectInfo(childProject.name, projectInfo)
Logger.buildOutput("compileModuleName", projectInfo.compileModuleName)
Logger.buildOutput("projectName", projectInfo.name)
Logger.buildOutput("isDebugModule", projectInfo.isDebugModule())
Logger.buildOutput("taskNames", projectInfo.taskNames)
Logger.buildOutput("isSyncTask", projectInfo.isSync())
Logger.buildOutput("isAssemble", projectInfo.isAssemble)
Logger.buildOutput("isDebug", projectInfo.isDebug)
Logger.buildOutput("=====> project[" + childProject.name + "]配置信息 <=====")
Logger.buildOutput("")
//
// childProject.plugins.all {
// Class extensionClass
// if (it instanceof AppPlugin) {
// extensionClass = AppExtension
// } else if (it instanceof LibraryPlugin) {
// extensionClass = LibraryExtension
// } else {
// return
// }
// childProject.extensions.configure(extensionClass, new Action<? extends TestedExtension>() {
// @Override
// void execute(TestedExtension testedExtension) {
// if (plugins != null && plugins.size() > 0) {
// for (AbsPlugin absPlugin : plugins) {
// absPlugin.evaluateAfterAndroidPlugin(childProject)
// }
// }
// }
// })
// }
/**
* 代替上述注解逻辑
*/
childProject.plugins.whenObjectAdded {
if (it instanceof AppPlugin || it instanceof LibraryPlugin) {
if (plugins != null && plugins.size() > 0) {
for (AbsPlugin absPlugin : plugins) {
absPlugin.evaluateAfterAndroidPlugin(childProject)
}
}
if (it instanceof AppPlugin) {
if (projectInfo.isDebugModule() || projectInfo.isCompileModuleAndAssemble()) {
Logger.buildOutput("plugin is AppPlugin")
Logger.buildOutput("registerTransform", "ScanCodeTransform")
Logger.buildOutput("registerTransform", "InjectCodeTransform")
childProject.extensions.findByType(BaseExtension.class).registerTransform(new ComponentTransform(childProject))
// childProject.extensions.findByType(BaseExtension.class).registerTransform(new InjectCodeTransform(childProject))
}
}
childProject.dependencies {
Logger.buildOutput("add dependency: " + Constants.CORE_DEPENDENCY)
implementation Constants.CORE_DEPENDENCY
}
if (plugins != null && plugins.size() > 0) {
for (AbsPlugin absPlugin : plugins) {
absPlugin.afterEvaluateAfterAndroidPlugin(childProject)
}
}
}
}
}
}
/**
* 测试 AppPlugin/LibraryPlugin 时许
* t(evaluate) < t(configure) < t(whenObjectAdded) < t(withPlugin) < t(afterEvaluate)
* t越大约慢
* @param project
*/
static void timeCallerTest(Project project) {
project.plugins.all {
Class extensionClass
if (it instanceof AppPlugin) {
extensionClass = AppExtension
} else if (it instanceof LibraryPlugin) {
extensionClass = LibraryExtension
} else {
return
}
/**
* 在 evaluate 之后 afterEvaluate 之前调用 configure 最早
*/
project.extensions.configure(extensionClass, new Action<? extends TestedExtension>() {
@Override
void execute(TestedExtension testedExtension) {
Logger.buildOutput(project.name + "==>" + "test-configure")
}
})
}
/**
* 在 afterEvaluate 回调之前调用,在 configure 之后
*
*/
project.plugins.whenObjectAdded {
if (it instanceof AppPlugin || it in LibraryPlugin) {
Logger.buildOutput(project.name + "==>" + "test-whenObjectAdded")
}
}
/**
* 在 evaluate 之后 afterEvaluate 之前调用,比 configure 慢,最慢
*/
project.getPluginManager().withPlugin("com.android.library", new Action<AppliedPlugin>() {
@Override
void execute(AppliedPlugin appliedPlugin) {
Logger.buildOutput(project.name + "==>" + "test-withPlugin")
}
})
project.getPluginManager().withPlugin("com.android.application", new Action<AppliedPlugin>() {
@Override
void execute(AppliedPlugin appliedPlugin) {
Logger.buildOutput(project.name + "==>" + "test-withPlugin")
}
})
}
static void injectComponentPlugin(Project root) {
root.allprojects.each {
if (it == root) return
if (!shouldApplyComponentPlugin(it)) return
it.pluginManager.apply(Constants.PLUGIN_COMPONENT)
Logger.buildOutput(it.name + "apply ==>" + "com.android.component")
// timeCallerTest(it)
}
}
static Map<String, PinConfiguration> getPinConfigurations() {
return sPinConfigurations
}

View File

@@ -7,9 +7,13 @@ abstract class AbsPlugin {
abstract void initExtension(ComponentExtension componentExtension)
abstract void evaluate(Project project, boolean isRoot)
abstract void evaluateBeforeAndroidPlugin(Project project)
abstract void afterEvaluate(Project project, boolean isRoot)
abstract void afterEvaluateBeforeAndroidPlugin(Project project)
abstract void afterAllEvaluate()
abstract void evaluateAfterAndroidPlugin(Project project)
abstract void afterEvaluateAfterAndroidPlugin(Project project)
abstract void afterAllEvaluate(Project root)
}

View File

@@ -5,25 +5,38 @@ import org.gradle.api.Project
class BasePlugin extends AbsPlugin {
ComponentExtension componentExtension
@Override
void initExtension(ComponentExtension componentExtension) {
this.componentExtension = componentExtension
}
@Override
void evaluate(Project project, boolean isRoot) {
void evaluateBeforeAndroidPlugin(Project project) {
}
@Override
void afterEvaluate(Project project, boolean isRoot) {
void afterEvaluateBeforeAndroidPlugin(Project project) {
}
@Override
void afterAllEvaluate() {
void evaluateAfterAndroidPlugin(Project project) {
}
@Override
void afterEvaluateAfterAndroidPlugin(Project project) {
}
@Override
void afterAllEvaluate(Project root) {
}
}

View File

@@ -9,10 +9,9 @@ import org.gradle.api.Project
class DebugPlugin extends BasePlugin {
@Override
void afterEvaluate(Project project, boolean isRoot) {
void afterEvaluateAfterAndroidPlugin(Project project) {
ProjectInfo projectInfo = Runtimes.getProjectInfo(project.name)
//调整debugModule结构
if (ProjectUtil.isProjectSame(projectInfo.name, Runtimes.getDebugModuleName())) {
if (projectInfo != null && ProjectUtil.isProjectSame(projectInfo.name, Runtimes.getDebugModuleName())) {
Logger.buildOutput("")
Logger.buildOutput(" =====> project[" + projectInfo.name + "] is debugModel,modifying DebugSets <=====")
ProjectUtil.modifyDebugSets(projectInfo.project.rootProject, projectInfo)

View File

@@ -11,6 +11,7 @@ import com.plugin.component.Runtimes
import com.plugin.component.extension.module.PinInfo
import com.plugin.component.extension.option.pin.PinConfiguration
import com.plugin.component.utils.PinUtils
import com.plugin.component.utils.ProjectUtil
import org.gradle.BuildListener
import org.gradle.BuildResult
import org.gradle.api.Action
@@ -44,12 +45,8 @@ class PinPlugin extends BasePlugin {
return pinConfiguration != null
}
@Override
void evaluate(Project project, boolean isRoot) {
if (isRoot) {
return
}
void evaluateBeforeAndroidPlugin(Project project) {
this.project = project
pinConfiguration = Runtimes.getPinConfiguration(project.name)
@@ -154,59 +151,7 @@ class PinPlugin extends BasePlugin {
}
@Override
void afterEvaluate(Project project, boolean isRoot) {
if (isRoot) {
if (Runtimes.hasPinModule()) {
project.gradle.addBuildListener(new BuildListener() {
@Override
void buildStarted(Gradle gradle) {
}
@Override
void settingsEvaluated(Settings settings) {
}
@Override
void projectsLoaded(Gradle gradle) {
}
@Override
void projectsEvaluated(Gradle gradle) {
}
@Override
void buildFinished(BuildResult buildResult) {
// generate microModules.xml for PinInfo IDEA plugin.
def ideaFile = new File(buildResult.gradle.rootProject.rootDir, '.idea')
if (!ideaFile.exists()) return
def pininfos = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<modules>\n'
Map<String, PinConfiguration> allPins = Runtimes.getPinConfigurations()
Set<String> moduleNames = allPins.keySet()
for (String moduleName : moduleNames) {
PinConfiguration pins = allPins.get(moduleName)
def displayName = pins.name
pininfos += ' <module name=\"' + displayName.substring(displayName.indexOf("'") + 1, displayName.lastIndexOf("'")) + '\" path=\"' + it.projectDir.getCanonicalPath() + '\">\n'
pins.includePins.each {
PinInfo microModule = it.value
pininfos += ' <microModule name=\"' + microModule.name + '\" path=\"' + microModule.pinDir.getCanonicalPath() + '\" />\n'
}
pininfos += ' </module>\n'
}
pininfos += '</modules>'
def pins = new File(ideaFile, 'microModules.xml')
pins.write(pininfos, 'utf-8')
}
})
}
return
}
void afterEvaluateBeforeAndroidPlugin(Project project) {
if (!isSupportPins()) {
return
@@ -271,7 +216,7 @@ class PinPlugin extends BasePlugin {
PinUtils.generateAndroidManifest(project, pinConfiguration, startTaskState)
project.tasks.preBuild.doFirst {
clearOriginSourceSet()
PinUtils.clearOriginSourceSet(project, pinConfiguration.productFlavorInfo)
if (startTaskState == ASSEMBLE_OR_GENERATE) {
pinConfiguration.includePins.each {
PinInfo pin = it.value
@@ -288,6 +233,62 @@ class PinPlugin extends BasePlugin {
}
}
@Override
void afterAllEvaluate(Project root) {
if (Runtimes.hasPinModule()) {
root.gradle.addBuildListener(new BuildListener() {
@Override
void buildStarted(Gradle gradle) {
}
@Override
void settingsEvaluated(Settings settings) {
}
@Override
void projectsLoaded(Gradle gradle) {
}
@Override
void projectsEvaluated(Gradle gradle) {
}
@Override
void buildFinished(BuildResult buildResult) {
// generate microModules.xml for PinInfo IDEA plugin.
def ideaFile = new File(buildResult.gradle.rootProject.rootDir, '.idea')
if (!ideaFile.exists()) return
def pininfos = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<modules>\n'
Map<String, PinConfiguration> allPins = Runtimes.getPinConfigurations()
Set<String> moduleNames = allPins.keySet()
for (String moduleName : moduleNames) {
PinConfiguration pins = allPins.get(moduleName)
Project project = ProjectUtil.getProject(root, pins.name)
if (project != null) {
def displayName = project.displayName
pininfos += ' <module name=\"' + displayName.substring(displayName.indexOf("'") + 1, displayName.lastIndexOf("'")) + '\" path=\"' + project.projectDir.getCanonicalPath() + '\">\n'
pins.includePins.each {
PinInfo pin = it.value
pininfos += ' <pin name=\"' + pin.name + '\" path=\"' + pin.pinDir.getCanonicalPath() + '\" />\n'
}
pininfos += ' </module>\n'
}
}
pininfos += '</modules>'
def pins = new File(ideaFile, 'modulePins.xml')
pins.write(pininfos, 'utf-8')
}
})
}
}
void applyMicroModuleScript(Project project, PinInfo microModule) {
def pinBuild = new File(microModule.pinDir, 'build.gradle')

View File

@@ -1,247 +1,57 @@
package com.plugin.component.plugin
import com.android.build.gradle.AppExtension
import com.android.build.gradle.AppPlugin
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.LibraryPlugin
import com.android.build.gradle.TestedExtension
import com.plugin.component.Constants
import com.plugin.component.Logger
import com.plugin.component.Runtimes
import com.plugin.component.extension.PublicationManager
import com.plugin.component.extension.module.ProjectInfo
import com.plugin.component.extension.option.debug.DebugDependenciesOption
import com.plugin.component.extension.option.sdk.PublicationDependenciesOption
import com.plugin.component.extension.option.sdk.PublicationOption
import com.plugin.component.transform.ComponentTransform
import com.plugin.component.utils.JarUtil
import com.plugin.component.utils.ProjectUtil
import com.plugin.component.utils.PublicationUtil
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.plugins.AppliedPlugin
class SdkPlugin extends BasePlugin {
@Override
void evaluate(Project project, boolean isRoot) {
if (isRoot) {
Runtimes.sSdkDir = new File(project.projectDir, Constants.SDK_DIR)
Runtimes.sImplDir = new File(project.projectDir, Constants.IMPL_DIR)
Logger.buildOutput("sdk目录 File[" + Runtimes.sSdkDir.name + "]")
Logger.buildOutput("impl目录 File[" + Runtimes.sSdkDir.name + "]")
void evaluateAfterAndroidPlugin(Project project) {
ProjectInfo projectInfo = Runtimes.getProjectInfo(project.name)
if (!Runtimes.sSdkDir.exists()) {
Runtimes.sSdkDir.mkdirs()
Logger.buildOutput("create File[" + Runtimes.sSdkDir.name + "]")
//解析: component
//example component(':library')
//规则:
// 1. component 对象必须为实现 component 插件的project
// 2. component(<project>) project 逻辑上被划分为 impl / debug / sdk其中 sdk 通过 api 暴露给上层impl 直接打包
project.dependencies.metaClass.component { String value ->
return PublicationUtil.parseComponent(projectInfo, value)
}
//project 需要使用 api 依赖并暴露 sdk解决 project 被依赖的时候,依赖者可以引用到 project sdk
List<PublicationOption> publications = PublicationManager.getInstance().getPublicationByProject(project)
project.dependencies {
publications.each {
api PublicationUtil.getPublication(it)
}
}
if (!Runtimes.sImplDir.exists()) {
Runtimes.sImplDir.mkdirs()
Logger.buildOutput("create File[" + Runtimes.sImplDir.name + "]")
}
ProjectUtil.getTasks(project).each {
if (it == Constants.CLEAN) {
if (!Runtimes.sSdkDir.deleteDir()) {
throw new RuntimeException("unable to delete dir " + Runtimes.sSdkDir.absolutePath)
}
if (!Runtimes.sImplDir.deleteDir()) {
throw new RuntimeException("unable to delete dir " + Runtimes.sImplDir.absolutePath)
}
Runtimes.sSdkDir.mkdirs()
Logger.buildOutput("reset File[" + Runtimes.sSdkDir.name + "]")
Runtimes.sImplDir.mkdirs()
Logger.buildOutput("reset File[" + Runtimes.sImplDir.name + "]")
}
}
project.repositories {
flatDir {
dirs Runtimes.sSdkDir.absolutePath
Logger.buildOutput("flatDir Dir[" + Runtimes.sSdkDir.absolutePath + "]")
dirs Runtimes.sImplDir.absolutePath
Logger.buildOutput("flatDir Dir[" + Runtimes.sImplDir.absolutePath + "]")
}
}
Logger.buildOutput("读取 sdk/impl manifest 配置文件...")
PublicationManager.getInstance().loadManifest(project)
Logger.buildOutput("读取 component.gradle 信息...")
//todo sdk中依赖sdk需要特别区分预留后续逻辑
PublicationDependenciesOption.metaClass.component { String value ->
return Constants.COMPONENT_PRE + value
}
DebugDependenciesOption.metaClass.component { String value ->
return Constants.DEBUG_COMPONENT_PRE + value
}
} else {
ProjectInfo projectInfo = Runtimes.getProjectInfo(project.name)
//解析: component
//example component(':library')
//规则:
// 1. component 对象必须为实现 component 插件的project
// 2. component(<project>) project 逻辑上被划分为 impl / debug / sdk其中 sdk 通过 api 暴露给上层impl 直接打包
project.dependencies.metaClass.component { String value ->
return PublicationUtil.parseComponent(projectInfo, value)
}
//project 需要使用 api 依赖并暴露 sdk解决 project 被依赖的时候,依赖者可以引用到 project sdk
List<PublicationOption> publications = PublicationManager.getInstance().getPublicationByProject(project)
project.dependencies {
publications.each {
api PublicationUtil.getPublication(it)
}
}
/**
* Syncing Gradle will evaluate the build files by comparing the current files to the project state that Gradle and Android Studio maintain.
* If it finds any changes it will execute just those specific tasks.
*/
//project 需要依赖 sdk 中声明的依赖意味着同步的时候component.gradle 中 sdk { dependencies { <xxxxx> }} 内容需要同步迁移到 project
if (projectInfo.isSync()) {
Logger.buildOutput("Syncing gradle...")
publications.each {
PublicationUtil.addPublicationDependencies(projectInfo, it)
}
/**
* Syncing Gradle will evaluateAfterAndroidPlugin the build files by comparing the current files to the project state that Gradle and Android Studio maintain.
* If it finds any changes it will execute just those specific tasks.
*/
//project 需要依赖 sdk 中声明的依赖意味着同步的时候component.gradle 中 sdk { dependencies { <xxxxx> }} 内容需要同步迁移到 project
if (projectInfo.isSync()) {
Logger.buildOutput("Syncing gradle...")
publications.each {
PublicationUtil.addPublicationDependencies(projectInfo, it)
}
}
}
@Override
void afterEvaluate(Project project,boolean isRoot) {
if(isRoot){
Logger.buildOutput("")
Logger.buildOutput("=====> 处理 sdk/impl jar <=====")
List<String> topSort = PublicationManager.getInstance().dependencyGraph.topSort()
Collections.reverse(topSort)
topSort.each {
PublicationOption publication = PublicationManager.getInstance().publicationDependencies.get(it)
if (publication == null) {
return
}
Project childProject = project.findProject(publication.project)
PublicationUtil.filterPublicationDependencies(publication)
if (publication.version != null) {
JarUtil.handleMavenJar(childProject, publication)
} else {
JarUtil.handleLocalJar(childProject, publication)
}
PublicationManager.getInstance().hitPublication(publication)
}
Logger.buildOutput("=====> 处理 sdk/impl jar <=====")
Logger.buildOutput("")
void afterEvaluateAfterAndroidPlugin(Project project) {
ProjectInfo projectInfo = Runtimes.getProjectInfo(project.name)
ProjectUtil.modifySourceSets(projectInfo)
project.allprojects.each {
if (it == project) return
if (!Runtimes.shouldApplyComponentPlugin(it)) return
Project childProject = it
Logger.buildOutput("")
Logger.buildOutput("=====> project[" + childProject.name + "]配置信息 <=====")
ProjectInfo projectInfo = new ProjectInfo(childProject)
childProject.repositories {
flatDir {
dirs Runtimes.sSdkDir.absolutePath
Logger.buildOutput("add flatDir Dir[" + Runtimes.sSdkDir.absolutePath + "]")
dirs Runtimes.sImplDir.absolutePath
Logger.buildOutput("add flatDir Dir[" + Runtimes.sImplDir.absolutePath + "]")
}
}
Runtimes.addProjectInfo(childProject.name, projectInfo)
Logger.buildOutput("compileModuleName", projectInfo.compileModuleName)
Logger.buildOutput("projectName", projectInfo.name)
Logger.buildOutput("isDebugModule", projectInfo.isDebugModule())
Logger.buildOutput("taskNames", projectInfo.taskNames)
Logger.buildOutput("isSyncTask", projectInfo.isSync())
Logger.buildOutput("isAssemble", projectInfo.isAssemble)
Logger.buildOutput("isDebug", projectInfo.isDebug)
Logger.buildOutput("=====> project[" + childProject.name + "]配置信息 <=====")
Logger.buildOutput("")
childProject.plugins.all {
Class extensionClass
if (it instanceof AppPlugin) {
extensionClass = AppExtension
} else if (it instanceof LibraryPlugin) {
extensionClass = LibraryExtension
} else {
return
}
//plugin afterEvaluate 之后调用
childProject.extensions.configure(extensionClass, new Action<? extends TestedExtension>() {
@Override
void execute(TestedExtension testedExtension) {
Logger.buildOutput("")
}
})
}
/**
* plugin afterEvaluate 之后调用
*/
childProject.plugins.whenObjectAdded {
if (it instanceof AppPlugin || it instanceof LibraryPlugin) {
Logger.buildOutput("")
Logger.buildOutput("=====> project[" + childProject.name + "]注入插件 <=====")
Logger.buildOutput("project[" + childProject.name + "] whenObjectAdded(AppPlugin or LibraryPlugin)")
Logger.buildOutput("apply plugin: com.android.component")
childProject.pluginManager.apply(Constants.PLUGIN_COMPONENT)
childProject.dependencies {
Logger.buildOutput("add dependency: " + Constants.CORE_DEPENDENCY)
implementation Constants.CORE_DEPENDENCY
// implementation childProject.project(":component-core")
}
if (it instanceof AppPlugin) {
if (projectInfo.isDebugModule() || projectInfo.isCompileModuleAndAssemble()) {
Logger.buildOutput("plugin is AppPlugin")
Logger.buildOutput("registerTransform", "ScanCodeTransform")
Logger.buildOutput("registerTransform", "InjectCodeTransform")
childProject.extensions.findByType(BaseExtension.class).registerTransform(new ComponentTransform(childProject))
}
}
Logger.buildOutput("=====> project[" + childProject.name + "]注入插件 <=====")
Logger.buildOutput("")
}
}
/**
* 介于 evaluate 与 afterEvaluate 中间
*/
childProject.getPluginManager().withPlugin("com.android.library", new Action<AppliedPlugin>() {
@Override
void execute(AppliedPlugin appliedPlugin) {
Logger.buildOutput("")
}
})
childProject.getPluginManager().withPlugin("com.android.application", new Action<AppliedPlugin>() {
@Override
void execute(AppliedPlugin appliedPlugin) {
Logger.buildOutput("")
}
})
//评估之后after之前
childProject.getPluginManager().withPlugin("com.android.component", new Action<AppliedPlugin>() {
@Override
void execute(AppliedPlugin appliedPlugin) {
Logger.buildOutput("")
}
})
}
}else{
ProjectInfo projectInfo = Runtimes.getProjectInfo(project.name)
ProjectUtil.modifySourceSets(projectInfo)
//todo 发布
//todo 发布
// List<PublicationOption> publicationList = PublicationManager.getInstance().getPublicationByProject(project)
// List<PublicationOption> publicationPublishList = new ArrayList<>()
// publicationList.each {
@@ -261,12 +71,11 @@ class SdkPlugin extends BasePlugin {
// PublicationUtil.createPublishTask(project, it)
// }
// }
}
}
@Override
void afterAllEvaluate() {
void afterAllEvaluate(Project root) {
ProjectInfo compileProject = Runtimes.getCompileProjectWhenAssemble()
if (compileProject != null) {
Logger.buildOutput("")