插件hook android插件构建流程,选择性注入
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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("")
|
||||
|
||||
Reference in New Issue
Block a user