pin初步逻辑
This commit is contained in:
@@ -21,12 +21,12 @@ class ComponentPlugin implements Plugin<Project>,BasePlugin{
|
||||
private BasePlugin sdk = new SdkPlugin()
|
||||
private BasePlugin debug = new DebugPlugin()
|
||||
private BasePlugin pins = new PinPlugin()
|
||||
private ComponentExtension componentExtension
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
|
||||
if (project == project.rootProject) {
|
||||
ComponentExtension componentExtension = project.getExtensions().create(Constants.COMPONENT, ComponentExtension, project)
|
||||
componentExtension = project.getExtensions().create(Constants.COMPONENT, ComponentExtension, project)
|
||||
initExtension(componentExtension)
|
||||
evaluateRoot(project)
|
||||
project.afterEvaluate {
|
||||
@@ -73,6 +73,7 @@ class ComponentPlugin implements Plugin<Project>,BasePlugin{
|
||||
|
||||
@Override
|
||||
void afterEvaluateRoot(Project root) {
|
||||
Runtimes.initRuntimeConfiguration(root, componentExtension)
|
||||
sdk.afterEvaluateRoot(root)
|
||||
debug.afterEvaluateRoot(root)
|
||||
pins.afterEvaluateRoot(root)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.plugin.component
|
||||
|
||||
import com.plugin.component.extension.ComponentExtension
|
||||
import com.plugin.component.extension.module.PinInfo
|
||||
import com.plugin.component.extension.module.ProjectInfo
|
||||
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
|
||||
@@ -20,6 +22,8 @@ class Runtimes {
|
||||
//模块信息
|
||||
private static Map<String, ProjectInfo> sProjectInfoMap = new HashMap<>()
|
||||
|
||||
private static Map<String, PinConfiguration> sPinConfigurations = new HashMap<>()
|
||||
|
||||
private static String sAndroidJarPath
|
||||
public static DebugOption sDebugOption
|
||||
public static SdkOption sSdkOption
|
||||
@@ -49,13 +53,35 @@ class Runtimes {
|
||||
Logger.buildOutput(componentExtension.debugOption.toString())
|
||||
Logger.buildOutput(" =====> component.gradle配置信息 <===== ")
|
||||
Logger.buildOutput("")
|
||||
|
||||
//初始化pins
|
||||
root.allprojects.each {
|
||||
for (PinConfiguration pinConfiguration : sPinOption.configurationList) {
|
||||
if (ProjectUtil.isProjectSame(it.name, pinConfiguration.name)) {
|
||||
sPinConfigurations.put(it.name, pinConfiguration)
|
||||
pinConfiguration.initMainPin(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static CompileOptions getCompileOption(){
|
||||
static Map<String, PinConfiguration> getPinConfigurations() {
|
||||
return sPinConfigurations
|
||||
}
|
||||
|
||||
static boolean hasPinModule() {
|
||||
return !sPinConfigurations.isEmpty()
|
||||
}
|
||||
|
||||
static PinConfiguration getPinConfiguration(String name) {
|
||||
return sPinConfigurations.get(name)
|
||||
}
|
||||
|
||||
static CompileOptions getCompileOption() {
|
||||
return sSdkOption.compileOption
|
||||
}
|
||||
|
||||
static getAndroidJarPath(){
|
||||
static getAndroidJarPath() {
|
||||
return sAndroidJarPath
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.plugin.component.check
|
||||
|
||||
import com.plugin.component.extension.module.MicroModule
|
||||
import com.plugin.component.extension.module.MicroModuleInfo
|
||||
import com.plugin.component.extension.module.PinInfo
|
||||
import com.plugin.component.extension.module.ProductFlavorInfo
|
||||
import com.plugin.component.extension.option.pin.PinConfiguration
|
||||
import org.gradle.api.GradleScriptException
|
||||
import org.gradle.api.Project
|
||||
import org.w3c.dom.Element
|
||||
@@ -11,7 +11,7 @@ import org.w3c.dom.NodeList
|
||||
class CodeChecker {
|
||||
|
||||
Project project
|
||||
MicroModuleInfo microModuleInfo
|
||||
PinConfiguration pinConfiguration
|
||||
ProductFlavorInfo productFlavorInfo
|
||||
|
||||
String buildType
|
||||
@@ -25,9 +25,9 @@ class CodeChecker {
|
||||
|
||||
Map<String, List<String>> microModulePackageNameMap
|
||||
|
||||
CodeChecker(Project project, MicroModuleInfo microModuleInfo, ProductFlavorInfo productFlavorInfo, String buildType, String productFlavor) {
|
||||
CodeChecker(Project project, PinConfiguration pinConfiguration, ProductFlavorInfo productFlavorInfo, String buildType, String productFlavor) {
|
||||
this.project = project
|
||||
this.microModuleInfo = microModuleInfo
|
||||
this.pinConfiguration = pinConfiguration
|
||||
this.productFlavorInfo = productFlavorInfo
|
||||
this.buildType = buildType
|
||||
this.productFlavor = productFlavor
|
||||
@@ -50,7 +50,7 @@ class CodeChecker {
|
||||
throw new GradleScriptException(errorMessage, null)
|
||||
}
|
||||
|
||||
def manifest = new File(microModuleInfo.mainMicroModule.microModuleDir, "src/main/AndroidManifest.xml")
|
||||
def manifest = new File(pinConfiguration.mainPin.pinDir, "src/main/AndroidManifest.xml")
|
||||
String packageName = Utils.getAndroidManifestPackageName(manifest)
|
||||
checkManifest.packageName = packageName
|
||||
saveModuleCheckManifest()
|
||||
@@ -105,7 +105,7 @@ class CodeChecker {
|
||||
def find = matcher.group()
|
||||
def name = find.substring(find.indexOf("/") + 1)
|
||||
def from = resourcesMap.get(name)
|
||||
if (from != null && microModuleName != from && !microModuleInfo.hasDependency(microModuleName, from)) {
|
||||
if (from != null && microModuleName != from && !pinConfiguration.hasDependency(microModuleName, from)) {
|
||||
List<Number> lines = textLines.findIndexValues { it.contains(find) }
|
||||
lines.each {
|
||||
def lineIndex = it.intValue()
|
||||
@@ -117,7 +117,7 @@ class CodeChecker {
|
||||
def message = absolutePath + ':' + (lineIndex + 1)
|
||||
if (!errorMessage.contains(message)) {
|
||||
message += lineSeparator
|
||||
message += "- cannot use [" + find + "] which from MicroModule '${from}'."
|
||||
message += "- cannot use [" + find + "] which from PinInfo '${from}'."
|
||||
message += lineSeparator
|
||||
errorMessage += message
|
||||
}
|
||||
@@ -157,14 +157,14 @@ class CodeChecker {
|
||||
List<File> getModifiedClassesList(List<String> sourceFolders) {
|
||||
Map<String, MicroModuleFile> lastModifiedClassesMap = checkManifest.getClassesMap()
|
||||
List<File> modifiedClassesList = new ArrayList<>()
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
pinConfiguration.includePins.each {
|
||||
PinInfo microModule = it.value
|
||||
sourceFolders.each {
|
||||
File javaDir = new File(microModule.microModuleDir, "/src/${it}/java")
|
||||
File javaDir = new File(microModule.pinDir, "/src/${it}/java")
|
||||
if (javaDir.exists()) {
|
||||
getModifiedJavaFile(javaDir, modifiedClassesList, lastModifiedClassesMap)
|
||||
}
|
||||
File kotlinDir = new File(microModule.microModuleDir, "/src/${it}/kotlin")
|
||||
File kotlinDir = new File(microModule.pinDir, "/src/${it}/kotlin")
|
||||
if (kotlinDir.exists()) {
|
||||
getModifiedJavaFile(kotlinDir, modifiedClassesList, lastModifiedClassesMap)
|
||||
}
|
||||
@@ -229,7 +229,7 @@ class CodeChecker {
|
||||
from = classesMap.get(name)
|
||||
}
|
||||
|
||||
if (from != null && microModuleName != from && !microModuleInfo.hasDependency(microModuleName, from)) {
|
||||
if (from != null && microModuleName != from && !pinConfiguration.hasDependency(microModuleName, from)) {
|
||||
List<Number> lines = textLines.findIndexValues { it.contains(find) }
|
||||
lines.each {
|
||||
def lineIndex = it.intValue()
|
||||
@@ -241,7 +241,7 @@ class CodeChecker {
|
||||
def message = absolutePath + ':' + (lineIndex + 1)
|
||||
if (!errorMessage.contains(message)) {
|
||||
message += lineSeparator
|
||||
message += "- cannot use [" + find + "] which from MicroModule '${from}'."
|
||||
message += "- cannot use [" + find + "] which from PinInfo '${from}'."
|
||||
message += lineSeparator
|
||||
errorMessage += message
|
||||
}
|
||||
@@ -307,13 +307,13 @@ class CodeChecker {
|
||||
|
||||
private String initMicroModulePackageName() {
|
||||
microModulePackageNameMap = new HashMap<>()
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
pinConfiguration.includePins.each {
|
||||
PinInfo microModule = it.value
|
||||
boolean find = false
|
||||
List<String> flavorList = productFlavorInfo.combinedProductFlavorsMap.get(productFlavor)
|
||||
if (flavorList != null && !flavorList.isEmpty()) {
|
||||
for (String flavor : flavorList) {
|
||||
File manifest = new File(microModule.microModuleDir, "/src/${flavor}/AndroidManifest.xml")
|
||||
File manifest = new File(microModule.pinDir, "/src/${flavor}/AndroidManifest.xml")
|
||||
if (manifest.exists()) {
|
||||
String packageName = Utils.getAndroidManifestPackageName(manifest)
|
||||
if (packageName != null && !packageName.isEmpty()) {
|
||||
@@ -331,7 +331,7 @@ class CodeChecker {
|
||||
}
|
||||
|
||||
if (!find) {
|
||||
File manifest = new File(microModule.microModuleDir, "/src/${buildType}/AndroidManifest.xml")
|
||||
File manifest = new File(microModule.pinDir, "/src/${buildType}/AndroidManifest.xml")
|
||||
if (manifest.exists()) {
|
||||
String packageName = Utils.getAndroidManifestPackageName(manifest)
|
||||
if (packageName != null && !packageName.isEmpty()) {
|
||||
@@ -347,7 +347,7 @@ class CodeChecker {
|
||||
}
|
||||
|
||||
if (!find) {
|
||||
File manifest = new File(microModule.microModuleDir, "/src/main/AndroidManifest.xml")
|
||||
File manifest = new File(microModule.pinDir, "/src/main/AndroidManifest.xml")
|
||||
if (manifest.exists()) {
|
||||
String packageName = Utils.getAndroidManifestPackageName(manifest)
|
||||
if (packageName != null && !packageName.isEmpty()) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.plugin.component.extension
|
||||
|
||||
import com.plugin.component.Runtimes
|
||||
import com.plugin.component.extension.option.pin.PinOption
|
||||
import com.plugin.component.extension.option.debug.DebugOption
|
||||
import com.plugin.component.extension.option.sdk.SdkOption
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package com.plugin.component.extension.module
|
||||
|
||||
import com.plugin.component.utils.PinUtils
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
|
||||
class MicroModuleInfo {
|
||||
|
||||
Project project
|
||||
MicroModule mainMicroModule
|
||||
Map<String, MicroModule> includeMicroModules
|
||||
Map<String, String> exportMicroModules
|
||||
|
||||
Digraph<String> dependencyGraph
|
||||
|
||||
MicroModuleInfo(Project project) {
|
||||
this.project = project
|
||||
this.includeMicroModules = new HashMap<>()
|
||||
this.exportMicroModules = new HashMap<>()
|
||||
dependencyGraph = new Digraph<String>()
|
||||
|
||||
MicroModule microModule = PinUtils.buildMicroModule(project, ':main')
|
||||
if (microModule != null) {
|
||||
setMainMicroModule(microModule)
|
||||
}
|
||||
}
|
||||
|
||||
void setMainMicroModule(MicroModule microModule) {
|
||||
if (microModule == null) {
|
||||
throw new GradleException("main MicroModule cannot be null.")
|
||||
}
|
||||
this.mainMicroModule = microModule
|
||||
addIncludeMicroModule(microModule)
|
||||
}
|
||||
|
||||
void addIncludeMicroModule(MicroModule microModule) {
|
||||
includeMicroModules.put(microModule.name, microModule)
|
||||
}
|
||||
|
||||
void addExportMicroModule(String name) {
|
||||
MicroModule microModule = PinUtils.buildMicroModule(project, name)
|
||||
if (microModule == null) {
|
||||
throw new GradleException("MicroModule with path '${name}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
exportMicroModules.put(name, null)
|
||||
}
|
||||
|
||||
MicroModule getMicroModule(String name) {
|
||||
return includeMicroModules.get(name)
|
||||
}
|
||||
|
||||
void setMicroModuleDependency(String target, String dependency) {
|
||||
MicroModule dependencyMicroModule = getMicroModule(dependency)
|
||||
if(dependencyMicroModule == null) {
|
||||
if(PinUtils.buildMicroModule(project, dependency) != null) {
|
||||
throw new GradleException("MicroModule '${target}' dependency MicroModle '${dependency}', but its not included.")
|
||||
} else {
|
||||
throw new GradleException("MicroModule with path '${path}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
}
|
||||
|
||||
dependencyGraph.add(target, dependency)
|
||||
if(!dependencyGraph.isDag()) {
|
||||
throw new GradleException("Circular dependency between MicroModule '${target}' and '${dependency}'.")
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasDependency(String target, String dependency) {
|
||||
Map<String, Integer> bfsDistance = dependencyGraph.bfsDistance(target)
|
||||
for(String key: bfsDistance.keySet()) {
|
||||
if(key == dependency) {
|
||||
return bfsDistance.get(key) != null
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
package com.plugin.component.extension.module
|
||||
|
||||
|
||||
class MicroModule {
|
||||
|
||||
class PinInfo {
|
||||
String name
|
||||
File microModuleDir
|
||||
|
||||
File pinDir
|
||||
boolean appliedScript
|
||||
|
||||
}
|
||||
@@ -4,6 +4,12 @@ import com.android.build.gradle.BaseExtension
|
||||
import com.plugin.component.utils.PinUtils
|
||||
import org.gradle.api.Project
|
||||
|
||||
/**
|
||||
* 记录变种信息
|
||||
* 参考 https://developer.android.com/studio/build/build-variants
|
||||
* 变体的产品根据 <product-flavor><Build-Type> 做命名方案
|
||||
* 如果还存在维度,则 <product-flavor><flavor-dimensions><Build-Type>
|
||||
*/
|
||||
class ProductFlavorInfo {
|
||||
|
||||
List<String> flavorDimensions
|
||||
@@ -18,27 +24,35 @@ class ProductFlavorInfo {
|
||||
ProductFlavorInfo(Project project) {
|
||||
BaseExtension extension = (BaseExtension) project.extensions.getByName("android")
|
||||
buildTypes = new ArrayList<>()
|
||||
|
||||
//获取build类型, 比如 debug,release
|
||||
if(extension.buildTypes != null) {
|
||||
extension.buildTypes.each {
|
||||
buildTypes.add(it.name)
|
||||
}
|
||||
}
|
||||
|
||||
//获取维度,比如 api mode
|
||||
flavorDimensions = extension.flavorDimensionList
|
||||
if (flavorDimensions == null) {
|
||||
flavorDimensions = new ArrayList<>()
|
||||
}
|
||||
|
||||
productFlavors = new ArrayList<>()
|
||||
flavorGroups = new ArrayList<>()
|
||||
for (int i = 0; i < flavorDimensions.size(); i++) {
|
||||
flavorGroups.add(new ArrayList<>())
|
||||
}
|
||||
|
||||
//获取变体,比如 minApi21{ dimension "api"} minApi24{ dimension "mode"}
|
||||
productFlavors = new ArrayList<>()
|
||||
extension.productFlavors.each {
|
||||
productFlavors.add(it.name)
|
||||
def position = flavorDimensions.indexOf(it.dimension)
|
||||
flavorGroups.get(position).add(it.name)
|
||||
}
|
||||
|
||||
|
||||
//过滤掉无效的维度
|
||||
List<List<String>> flavorGroupTemp = new ArrayList<>()
|
||||
flavorGroups.each {
|
||||
if (it.size() != 0) {
|
||||
@@ -47,7 +61,9 @@ class ProductFlavorInfo {
|
||||
}
|
||||
flavorGroups = flavorGroupTemp
|
||||
|
||||
//计算合并变体
|
||||
calculateFlavorCombination()
|
||||
|
||||
if (combinedProductFlavors.size() == extension.productFlavors.size()) {
|
||||
singleDimension = true
|
||||
}
|
||||
@@ -62,12 +78,12 @@ class ProductFlavorInfo {
|
||||
}
|
||||
|
||||
List<Integer> combination = new ArrayList<Integer>()
|
||||
int n = flavorGroups.size();
|
||||
int n = flavorGroups.size()
|
||||
for (int i = 0; i < n; i++) {
|
||||
combination.add(0);
|
||||
combination.add(0)
|
||||
}
|
||||
int i = 0;
|
||||
boolean isContinue = true;
|
||||
int i = 0
|
||||
boolean isContinue = true
|
||||
while (isContinue) {
|
||||
List<String> items = new ArrayList<>()
|
||||
String item = flavorGroups.get(0).get(combination.get(0))
|
||||
@@ -80,21 +96,22 @@ class ProductFlavorInfo {
|
||||
}
|
||||
combinedProductFlavors.add(combined)
|
||||
combinedProductFlavorsMap.put(combined, items)
|
||||
i++;
|
||||
combination.set(n - 1, i);
|
||||
i++
|
||||
//i赋值给n-1
|
||||
combination.set(n - 1, i)
|
||||
for (int j = n - 1; j >= 0; j--) {
|
||||
if (combination.get(j) >= flavorGroups.get(j).size()) {
|
||||
combination.set(j, 0);
|
||||
i = 0;
|
||||
combination.set(j, 0)
|
||||
i = 0
|
||||
if (j - 1 >= 0) {
|
||||
combination.set(j - 1, combination.get(j - 1) + 1);
|
||||
combination.set(j - 1, combination.get(j - 1) + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
isContinue = false;
|
||||
isContinue = false
|
||||
for (Integer integer : combination) {
|
||||
if (integer != 0) {
|
||||
isContinue = true;
|
||||
isContinue = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.plugin.component.extension.option.pin
|
||||
|
||||
import com.plugin.component.extension.module.MicroModule
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
|
||||
class DefaultMicroModuleExtension implements MicroModuleExtension {
|
||||
|
||||
Project project
|
||||
OnMicroModuleListener onMicroModuleListener
|
||||
|
||||
boolean codeCheckEnabled = true
|
||||
|
||||
DefaultMicroModuleExtension(Project project) {
|
||||
this.project = project
|
||||
}
|
||||
|
||||
@Override
|
||||
void codeCheckEnabled(boolean enabled) {
|
||||
this.codeCheckEnabled = enabled
|
||||
}
|
||||
|
||||
@Override
|
||||
void export(String... microModulePaths) {
|
||||
if(onMicroModuleListener == null) return
|
||||
|
||||
onMicroModuleListener.addExportMicroModule(microModulePaths)
|
||||
}
|
||||
|
||||
@Override
|
||||
void include(String... microModulePaths) {
|
||||
if(onMicroModuleListener == null) return
|
||||
|
||||
int size = microModulePaths.size()
|
||||
for (int i = 0; i < size; i++) {
|
||||
MicroModule microModule = Utils.buildMicroModule(project, microModulePaths[i])
|
||||
if (microModule == null) {
|
||||
throw new GradleException("MicroModule with path '${microModulePaths[i]}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
onMicroModuleListener.addIncludeMicroModule(microModule, false)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void includeMain(String microModulePath) {
|
||||
if(onMicroModuleListener == null) return
|
||||
|
||||
MicroModule microModule = Utils.buildMicroModule(project, microModulePath)
|
||||
if (microModule == null) {
|
||||
throw new GradleException("MicroModule with path '${microModulePath}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
onMicroModuleListener.addIncludeMicroModule(microModule, true)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.plugin.component.extension.option.pin
|
||||
|
||||
interface MicroModuleExtension {
|
||||
|
||||
void codeCheckEnabled(boolean disable)
|
||||
|
||||
void export(String... microModulePaths)
|
||||
|
||||
void includeMain(String microModulePath)
|
||||
|
||||
void include(String... microModulePaths)
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.plugin.component.extension.option.pin
|
||||
|
||||
import com.plugin.component.extension.module.MicroModule
|
||||
|
||||
|
||||
interface OnMicroModuleListener {
|
||||
|
||||
void addIncludeMicroModule(MicroModule microModule, boolean mainMicroModule)
|
||||
|
||||
void addExportMicroModule(String... microModulePaths)
|
||||
|
||||
}
|
||||
@@ -1,18 +1,122 @@
|
||||
package com.plugin.component.extension.option.pin
|
||||
import com.plugin.component.Logger
|
||||
|
||||
import com.plugin.component.extension.module.Digraph
|
||||
import com.plugin.component.extension.module.PinInfo
|
||||
import com.plugin.component.extension.module.ProductFlavorInfo
|
||||
import com.plugin.component.utils.PinUtils
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
|
||||
|
||||
class PinConfiguration {
|
||||
|
||||
String name
|
||||
boolean codeCheckEnabled = true
|
||||
Set<String> includePins = new HashSet<>()
|
||||
Set<String> include = new HashSet<>()
|
||||
Set<String> export = new HashSet<>()
|
||||
String mainPath
|
||||
|
||||
Project project
|
||||
PinInfo mainPin
|
||||
Map<String, PinInfo> includePins
|
||||
Map<String, String> exportPins
|
||||
Digraph<String> dependencyGraph
|
||||
ProductFlavorInfo productFlavorInfo
|
||||
|
||||
PinConfiguration(String name) {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
void initMainPin(Project project) {
|
||||
this.project = project
|
||||
this.includePins = new HashMap<>()
|
||||
this.exportPins = new HashMap<>()
|
||||
dependencyGraph = new Digraph<String>()
|
||||
PinInfo mainPin = PinUtils.buildPin(project, ':main')
|
||||
if (mainPin != null) {
|
||||
setMainPin(mainPin)
|
||||
}
|
||||
}
|
||||
|
||||
void initProductFlavor() {
|
||||
productFlavorInfo = new ProductFlavorInfo(project)
|
||||
PinUtils.clearOriginSourceSet(project, productFlavorInfo)
|
||||
|
||||
for (String include : include) {
|
||||
PinInfo pin = PinUtils.buildPin(project, include)
|
||||
if (microModule == null) {
|
||||
throw new GradleException("PinInfo with path '${include}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
addIncludePin(pin)
|
||||
PinUtils.addMicroModuleSourceSet(project, pin, productFlavorInfo)
|
||||
}
|
||||
|
||||
for (String export : export) {
|
||||
PinInfo pin = PinUtils.buildPin(project, export)
|
||||
if (pin == null) {
|
||||
throw new GradleException("PinInfo with path '${export}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
addExportPin(pin)
|
||||
PinUtils.addMicroModuleSourceSet(project, pin, productFlavorInfo)
|
||||
}
|
||||
|
||||
if (mainPath != null && !mainPath.isEmpty()) {
|
||||
PinInfo pin = PinUtils.buildPin(project, mainPath)
|
||||
setMainPin(pin)
|
||||
PinUtils.addMicroModuleSourceSet(project, pin, productFlavorInfo)
|
||||
}
|
||||
}
|
||||
|
||||
void setMainPin(PinInfo pin) {
|
||||
if (pin == null) {
|
||||
throw new GradleException("main PinInfo cannot be null.")
|
||||
}
|
||||
this.mainPin = pin
|
||||
addIncludePin(pin)
|
||||
}
|
||||
|
||||
void addIncludePin(PinInfo pin) {
|
||||
includePins.put(pin.name, pin)
|
||||
}
|
||||
|
||||
void addExportPin(String name) {
|
||||
PinInfo pin = PinUtils.buildPin(project, name)
|
||||
if (pin == null) {
|
||||
throw new GradleException("PinInfo with path '${name}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
exportPins.put(name, null)
|
||||
}
|
||||
|
||||
PinInfo getIncludePin(String name) {
|
||||
return includePins.get(name)
|
||||
}
|
||||
|
||||
void setPinDependency(String target, String name) {
|
||||
PinInfo pin = getIncludePin(name)
|
||||
if (pin == null) {
|
||||
if (PinUtils.buildPin(project, name) != null) {
|
||||
throw new GradleException("PinInfo '${target}' name MicroModle '${name}', but its not included.")
|
||||
} else {
|
||||
throw new GradleException("PinInfo with path '${path}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
}
|
||||
dependencyGraph.add(target, name)
|
||||
if (!dependencyGraph.isDag()) {
|
||||
throw new GradleException("Circular name between PinInfo '${target}' and '${name}'.")
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasDependency(String target, String name) {
|
||||
Map<String, Integer> bfsDistance = dependencyGraph.bfsDistance(target)
|
||||
for (String key : bfsDistance.keySet()) {
|
||||
if (key == name) {
|
||||
return bfsDistance.get(key) != null
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
void codeCheckEnabled(boolean enabled) {
|
||||
this.codeCheckEnabled = enabled
|
||||
}
|
||||
@@ -20,7 +124,7 @@ class PinConfiguration {
|
||||
void export(String... pinPaths) {
|
||||
int size = pinPaths.size()
|
||||
for (int i = 0; i < size; i++) {
|
||||
includePins.add(pinPaths[i])
|
||||
include.add(pinPaths[i])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
package com.plugin.component.extension.option.pin
|
||||
|
||||
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.util.ConfigureUtil
|
||||
|
||||
class PinOption {
|
||||
|
||||
Project project
|
||||
Project root
|
||||
List<PinConfiguration> configurationList = new ArrayList<>() //配置信息
|
||||
|
||||
PinOption(Project project) {
|
||||
this.project = project
|
||||
PinOption(Project root) {
|
||||
this.root = root
|
||||
}
|
||||
|
||||
void configuration(Closure closure) {
|
||||
NamedDomainObjectContainer<PinConfiguration> configurations = project.container(PinConfiguration)
|
||||
NamedDomainObjectContainer<PinConfiguration> configurations = root.container(PinConfiguration)
|
||||
ConfigureUtil.configure(closure, configurations)
|
||||
configurations.each {
|
||||
configurationList.add(it)
|
||||
@@ -25,13 +26,14 @@ class PinOption {
|
||||
String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder("\n")
|
||||
stringBuilder.append(" ------------------------------------------------------------------" + "\n")
|
||||
stringBuilder.append(" | configuration = [ " + "\n" )
|
||||
for(PinConfiguration configuration: configurationList){
|
||||
stringBuilder.append(" | name = " + configuration.name + ", codeCheckEnabled = " + configuration.codeCheckEnabled + ", mathPath = " + configuration.mainPath
|
||||
+ ", include = " + configuration.includePins.toString() + ", export = " + configuration.export.toString() + "\n" )
|
||||
stringBuilder.append(" | configuration = [ " + "\n")
|
||||
for (PinConfiguration configuration : configurationList) {
|
||||
stringBuilder.append(" | name = " + configuration.name + ", codeCheckEnabled = " + configuration.codeCheckEnabled + ", mathPath = " + configuration.mainPath
|
||||
+ ", include = " + configuration.include.toString() + ", export = " + configuration.export.toString() + "\n")
|
||||
}
|
||||
stringBuilder.append(" | ] " + "\n" )
|
||||
stringBuilder.append(" | ] " + "\n")
|
||||
stringBuilder.append(" ------------------------------------------------------------------" + "\n")
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,608 +0,0 @@
|
||||
package com.plugin.component.plugin
|
||||
|
||||
import com.android.build.gradle.*
|
||||
import com.android.build.gradle.api.BaseVariant
|
||||
import com.android.builder.model.ProductFlavor
|
||||
import com.android.manifmerger.ManifestMerger2
|
||||
import com.android.manifmerger.MergingReport
|
||||
import com.android.manifmerger.XmlDocument
|
||||
import com.android.utils.ILogger
|
||||
import com.plugin.component.check.CodeChecker
|
||||
import com.plugin.component.extension.module.MicroModule
|
||||
import com.plugin.component.extension.module.MicroModuleInfo
|
||||
import com.plugin.component.extension.module.ProductFlavorInfo
|
||||
import com.plugin.component.utils.PinUtils
|
||||
import com.plugin.component.extension.option.pin.DefaultMicroModuleExtension
|
||||
import com.plugin.component.extension.option.pin.OnMicroModuleListener
|
||||
import org.gradle.BuildListener
|
||||
import org.gradle.BuildResult
|
||||
import org.gradle.api.*
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.initialization.Settings
|
||||
import org.gradle.api.invocation.Gradle
|
||||
|
||||
class MicroModulePlugin implements Plugin<Project> {
|
||||
|
||||
private final static String NORMAL = 'normal'
|
||||
private final static String ASSEMBLE_OR_GENERATE = 'assemble_or_generate'
|
||||
|
||||
private final static String APPLY_NORMAL_MICRO_MODULE_SCRIPT = 'apply_normal_micro_module_script'
|
||||
private final static String APPLY_INCLUDE_MICRO_MODULE_SCRIPT = 'apply_include_micro_module_script'
|
||||
private final static String APPLY_EXPORT_MICRO_MODULE_SCRIPT = 'apply_export_micro_module_script'
|
||||
|
||||
Project project
|
||||
String startTaskState = NORMAL
|
||||
MicroModuleInfo microModuleInfo
|
||||
ProductFlavorInfo productFlavorInfo
|
||||
MicroModule currentMicroModule
|
||||
String applyScriptState
|
||||
boolean appliedLibraryPlugin
|
||||
boolean clearedOriginSourceSets
|
||||
|
||||
private final static BuildListener buildListener = 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 MicroModule IDEA plugin.
|
||||
def ideaFile = new File(buildResult.gradle.rootProject.rootDir, '.idea')
|
||||
if (!ideaFile.exists()) return
|
||||
|
||||
def microModuleInfo = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<modules>\n'
|
||||
buildResult.gradle.rootProject.allprojects.each {
|
||||
MicroModulePlugin microModulePlugin = it.plugins.findPlugin('micro-module')
|
||||
if (microModulePlugin == null) return
|
||||
|
||||
def displayName = it.displayName
|
||||
microModuleInfo += ' <module name=\"' + displayName.substring(displayName.indexOf("'") + 1, displayName.lastIndexOf("'")) + '\" path=\"' + it.projectDir.getCanonicalPath() + '\">\n'
|
||||
microModulePlugin.microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
microModuleInfo += ' <microModule name=\"' + microModule.name + '\" path=\"' + microModule.microModuleDir.getCanonicalPath() + '\" />\n'
|
||||
}
|
||||
microModuleInfo += ' </module>\n'
|
||||
}
|
||||
microModuleInfo += '</modules>'
|
||||
|
||||
def microModules = new File(ideaFile, 'microModules.xml')
|
||||
microModules.write(microModuleInfo, 'utf-8')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void apply(Project project) {
|
||||
this.project = project
|
||||
this.microModuleInfo = new MicroModuleInfo(project)
|
||||
|
||||
project.gradle.removeListener(buildListener)
|
||||
project.gradle.addBuildListener(buildListener)
|
||||
|
||||
if (project.gradle.getStartParameter().taskNames.size() == 0) {
|
||||
startTaskState = NORMAL
|
||||
} else {
|
||||
startTaskState = ASSEMBLE_OR_GENERATE
|
||||
}
|
||||
|
||||
if (startTaskState != NORMAL) {
|
||||
project.getConfigurations().whenObjectAdded {
|
||||
Configuration configuration = it
|
||||
configuration.dependencies.whenObjectAdded {
|
||||
if (applyScriptState == APPLY_INCLUDE_MICRO_MODULE_SCRIPT) {
|
||||
configuration.dependencies.remove(it)
|
||||
return
|
||||
} else if (applyScriptState == APPLY_NORMAL_MICRO_MODULE_SCRIPT
|
||||
|| applyScriptState == APPLY_EXPORT_MICRO_MODULE_SCRIPT) {
|
||||
return
|
||||
} else if (currentMicroModule == null && startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
return
|
||||
} else if (it.group != null && it.group.startsWith('com.android.tools')) {
|
||||
return
|
||||
}
|
||||
|
||||
configuration.dependencies.remove(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DefaultMicroModuleExtension microModuleExtension = project.extensions.create(MicroModuleExtension, 'microModule', DefaultMicroModuleExtension, project)
|
||||
microModuleExtension.onMicroModuleListener = new OnMicroModuleListener() {
|
||||
|
||||
@Override
|
||||
void addIncludeMicroModule(MicroModule microModule, boolean mainMicroModule) {
|
||||
if (mainMicroModule) {
|
||||
microModuleInfo.setMainMicroModule(microModule)
|
||||
} else {
|
||||
microModuleInfo.addIncludeMicroModule(microModule)
|
||||
}
|
||||
|
||||
if(!clearedOriginSourceSets) {
|
||||
productFlavorInfo = new ProductFlavorInfo(project)
|
||||
clearedOriginSourceSets = true
|
||||
clearOriginSourceSet()
|
||||
|
||||
if(microModuleInfo.mainMicroModule != null) {
|
||||
addMicroModuleSourceSet(microModuleInfo.mainMicroModule)
|
||||
}
|
||||
}
|
||||
|
||||
addMicroModuleSourceSet(microModule)
|
||||
}
|
||||
|
||||
@Override
|
||||
void addExportMicroModule(String... microModulePaths) {
|
||||
microModulePaths.each {
|
||||
microModuleInfo.addExportMicroModule(it)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
project.dependencies.metaClass.microModule { String path ->
|
||||
if (currentMicroModule == null || applyScriptState == APPLY_NORMAL_MICRO_MODULE_SCRIPT) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (applyScriptState == APPLY_INCLUDE_MICRO_MODULE_SCRIPT) {
|
||||
microModuleInfo.setMicroModuleDependency(currentMicroModule.name, path)
|
||||
return []
|
||||
}
|
||||
|
||||
MicroModule microModule = microModuleInfo.getMicroModule(path)
|
||||
|
||||
def result = []
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
addMicroModuleSourceSet(microModule)
|
||||
applyMicroModuleScript(microModule)
|
||||
microModule.appliedScript = true
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
project.plugins.all {
|
||||
Class extensionClass
|
||||
if (it instanceof AppPlugin) {
|
||||
extensionClass = AppExtension
|
||||
} else if (it instanceof LibraryPlugin) {
|
||||
extensionClass = LibraryExtension
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
project.extensions.configure(extensionClass, new Action<? extends TestedExtension>() {
|
||||
@Override
|
||||
void execute(TestedExtension testedExtension) {
|
||||
boolean isLibrary
|
||||
DomainObjectSet<BaseVariant> baseVariants
|
||||
if (testedExtension instanceof AppExtension) {
|
||||
AppExtension appExtension = (AppExtension) testedExtension
|
||||
baseVariants = appExtension.applicationVariants
|
||||
} else {
|
||||
LibraryExtension libraryExtension = (LibraryExtension) testedExtension
|
||||
baseVariants = libraryExtension.libraryVariants
|
||||
isLibrary = true
|
||||
}
|
||||
|
||||
baseVariants.all { BaseVariant variant ->
|
||||
if (microModuleExtension.codeCheckEnabled) {
|
||||
def taskNamePrefix = isLibrary ? 'package' : 'merge'
|
||||
List<String> sourceFolders = new ArrayList<>()
|
||||
sourceFolders.add('main')
|
||||
sourceFolders.add(variant.buildType.name)
|
||||
if (variant.productFlavors.size() > 0) {
|
||||
sourceFolders.add(variant.name)
|
||||
sourceFolders.add(variant.flavorName)
|
||||
for (ProductFlavor productFlavor : variant.productFlavors) {
|
||||
sourceFolders.add(productFlavor.name)
|
||||
}
|
||||
checkMicroModuleBoundary(taskNamePrefix, variant.buildType.name, variant.flavorName, sourceFolders)
|
||||
} else {
|
||||
checkMicroModuleBoundary(taskNamePrefix, variant.buildType.name, null, sourceFolders)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
microModuleExtension.onMicroModuleListener = null
|
||||
if (microModuleInfo.mainMicroModule == null) {
|
||||
throw new GradleException("the main MicroModule could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
|
||||
appliedLibraryPlugin = project.pluginManager.hasPlugin('com.android.library')
|
||||
|
||||
productFlavorInfo = new ProductFlavorInfo(project)
|
||||
|
||||
applyScriptState = APPLY_INCLUDE_MICRO_MODULE_SCRIPT
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
microModuleInfo.dependencyGraph.add(microModule.name)
|
||||
applyMicroModuleScript(microModule)
|
||||
}
|
||||
|
||||
clearOriginSourceSet()
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
applyScriptState = APPLY_EXPORT_MICRO_MODULE_SCRIPT
|
||||
boolean hasExportMainMicroModule = false
|
||||
boolean isEmpty = microModuleInfo.exportMicroModules.isEmpty()
|
||||
List<String> dependencySort = microModuleInfo.dependencyGraph.topSort()
|
||||
dependencySort.each {
|
||||
if (isEmpty || microModuleInfo.exportMicroModules.containsKey(it)) {
|
||||
MicroModule microModule = microModuleInfo.getMicroModule(it)
|
||||
if (microModule == null) {
|
||||
throw new GradleException("MicroModule with path '${it}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
|
||||
if (microModule == microModuleInfo.mainMicroModule) {
|
||||
hasExportMainMicroModule = true
|
||||
}
|
||||
|
||||
if (microModule.appliedScript) return
|
||||
|
||||
addMicroModuleSourceSet(microModule)
|
||||
applyMicroModuleScript(microModule)
|
||||
microModule.appliedScript = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasExportMainMicroModule) {
|
||||
throw new GradleException("the main MicroModule '${microModuleInfo.mainMicroModule.name}' is not in the export list.")
|
||||
}
|
||||
} else {
|
||||
applyScriptState = APPLY_NORMAL_MICRO_MODULE_SCRIPT
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
addMicroModuleSourceSet(microModule)
|
||||
applyMicroModuleScript(microModule)
|
||||
}
|
||||
}
|
||||
currentMicroModule = null
|
||||
|
||||
generateAndroidManifest()
|
||||
|
||||
project.tasks.preBuild.doFirst {
|
||||
clearOriginSourceSet()
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
if (microModule.appliedScript) {
|
||||
addMicroModuleSourceSet(microModule)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
addMicroModuleSourceSet(it.value)
|
||||
}
|
||||
}
|
||||
generateAndroidManifest()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def generateAndroidManifest() {
|
||||
if ((startTaskState == ASSEMBLE_OR_GENERATE || !microModuleInfo.exportMicroModules.isEmpty()) && isMainSourceSetEmpty()) {
|
||||
setMainSourceSetManifest()
|
||||
return
|
||||
}
|
||||
mergeAndroidManifest('main')
|
||||
|
||||
productFlavorInfo.buildTypes.each {
|
||||
mergeAndroidManifest(it)
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
mergeAndroidManifest(it)
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
mergeAndroidManifest(it)
|
||||
|
||||
def productFlavor = it
|
||||
productFlavorInfo.buildTypes.each {
|
||||
mergeAndroidManifest(productFlavor + PinUtils.upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
def androidTest = 'androidTest'
|
||||
mergeAndroidManifest(androidTest)
|
||||
mergeAndroidManifest(androidTest + 'Debug')
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
mergeAndroidManifest(androidTest + PinUtils.upperCase(it))
|
||||
}
|
||||
}
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
mergeAndroidManifest(androidTest + PinUtils.upperCase(it))
|
||||
mergeAndroidManifest(androidTest + PinUtils.upperCase(it) + 'Debug')
|
||||
}
|
||||
}
|
||||
|
||||
def mergeAndroidManifest(String variantName) {
|
||||
File mainManifestFile = new File(microModuleInfo.mainMicroModule.microModuleDir, "/src/${variantName}/AndroidManifest.xml")
|
||||
if (!mainManifestFile.exists()) return
|
||||
ManifestMerger2.MergeType mergeType = ManifestMerger2.MergeType.APPLICATION
|
||||
XmlDocument.Type documentType = XmlDocument.Type.MAIN
|
||||
def logger = new ILogger() {
|
||||
@Override
|
||||
void error(Throwable t, String msgFormat, Object... args) {
|
||||
println(msgFormat)
|
||||
}
|
||||
|
||||
@Override
|
||||
void warning(String msgFormat, Object... args) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void info(String msgFormat, Object... args) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void verbose(String msgFormat, Object... args) {
|
||||
|
||||
}
|
||||
}
|
||||
ManifestMerger2.Invoker invoker = new ManifestMerger2.Invoker(mainManifestFile, logger, mergeType, documentType)
|
||||
invoker.withFeatures(ManifestMerger2.Invoker.Feature.NO_PLACEHOLDER_REPLACEMENT)
|
||||
|
||||
microModuleInfo.includeMicroModules.each {
|
||||
MicroModule microModule = it.value
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE && !microModule.appliedScript) return
|
||||
if (microModule.name == microModuleInfo.mainMicroModule.name) return
|
||||
def microManifestFile = new File(microModule.microModuleDir, "/src/${variantName}/AndroidManifest.xml")
|
||||
if (microManifestFile.exists()) {
|
||||
invoker.addLibraryManifest(microManifestFile)
|
||||
}
|
||||
}
|
||||
|
||||
def mergingReport = invoker.merge()
|
||||
if (!mergingReport.result.success) {
|
||||
mergingReport.log(logger)
|
||||
throw new GradleException(mergingReport.reportString)
|
||||
}
|
||||
def moduleAndroidManifest = mergingReport.getMergedDocument(MergingReport.MergedManifestKind.MERGED)
|
||||
moduleAndroidManifest = new String(moduleAndroidManifest.getBytes('UTF-8'))
|
||||
|
||||
def saveDir = new File(project.projectDir, "build/microModule/merge-manifest/${variantName}")
|
||||
saveDir.mkdirs()
|
||||
def AndroidManifestFile = new File(saveDir, 'AndroidManifest.xml')
|
||||
AndroidManifestFile.createNewFile()
|
||||
AndroidManifestFile.write(moduleAndroidManifest)
|
||||
|
||||
def extensionContainer = project.getExtensions()
|
||||
BaseExtension android = extensionContainer.getByName('android')
|
||||
def obj = android.sourceSets.findByName(variantName)
|
||||
if (obj == null) {
|
||||
return
|
||||
}
|
||||
obj.manifest.srcFile project.projectDir.absolutePath + "/build/microModule/merge-manifest/${variantName}/AndroidManifest.xml"
|
||||
}
|
||||
|
||||
def addMicroModuleSourceSet(MicroModule microModule) {
|
||||
addVariantSourceSet(microModule, 'main')
|
||||
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(microModule, it)
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
addVariantSourceSet(microModule, it)
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
addVariantSourceSet(microModule, it)
|
||||
def flavorName = it
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(microModule, flavorName + PinUtils.upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
def testTypes = ['androidTest', 'test']
|
||||
testTypes.each {
|
||||
def testType = it
|
||||
addVariantSourceSet(microModule, testType)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(microModule, testType + PinUtils.upperCase(it))
|
||||
}
|
||||
} else {
|
||||
addVariantSourceSet(microModule, testType + 'Debug')
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
addVariantSourceSet(microModule, testType + PinUtils.upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
def productFlavorName = testType + PinUtils.upperCase(it)
|
||||
addVariantSourceSet(microModule, productFlavorName)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(microModule, productFlavorName + PinUtils.upperCase(it))
|
||||
}
|
||||
} else {
|
||||
addVariantSourceSet(microModule, productFlavorName + 'Debug')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def clearOriginSourceSet() {
|
||||
clearModuleSourceSet('main')
|
||||
|
||||
// buildTypes
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(it)
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
clearModuleSourceSet(it)
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
clearModuleSourceSet(it)
|
||||
def flavorName = it
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(flavorName + PinUtils.upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
def testTypes = ['androidTest', 'test']
|
||||
testTypes.each {
|
||||
def testType = it
|
||||
clearModuleSourceSet(testType)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(testType + PinUtils.upperCase(it))
|
||||
}
|
||||
} else {
|
||||
clearModuleSourceSet(testType + 'Debug')
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
clearModuleSourceSet(testType + PinUtils.upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
def productFlavorName = testType + PinUtils.upperCase(it)
|
||||
clearModuleSourceSet(productFlavorName)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(productFlavorName + PinUtils.upperCase(it))
|
||||
}
|
||||
} else {
|
||||
clearModuleSourceSet(productFlavorName + 'Debug')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def isMainSourceSetEmpty() {
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName('main')
|
||||
if (obj == null) {
|
||||
return true
|
||||
}
|
||||
return obj.java.srcDirs.size() == 0;
|
||||
}
|
||||
|
||||
def setMainSourceSetManifest() {
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName('main')
|
||||
if (obj == null) {
|
||||
obj = android.sourceSets.create('main')
|
||||
}
|
||||
File mainManifestFile = new File(microModuleInfo.mainMicroModule.microModuleDir, '/src/main/AndroidManifest.xml')
|
||||
obj.manifest.srcFile mainManifestFile
|
||||
}
|
||||
|
||||
def addVariantSourceSet(MicroModule microModule, def type) {
|
||||
def absolutePath = microModule.microModuleDir.absolutePath
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName(type)
|
||||
if (obj == null) {
|
||||
obj = android.sourceSets.create(type)
|
||||
}
|
||||
|
||||
obj.java.srcDir(absolutePath + "/src/${type}/java")
|
||||
obj.java.srcDir(absolutePath + "/src/${type}/kotlin")
|
||||
obj.res.srcDir(absolutePath + "/src/${type}/res")
|
||||
obj.jni.srcDir(absolutePath + "/src/${type}/jni")
|
||||
obj.jniLibs.srcDir(absolutePath + "/src/${type}/jniLibs")
|
||||
obj.aidl.srcDir(absolutePath + "/src/${type}/aidl")
|
||||
obj.assets.srcDir(absolutePath + "/src/${type}/assets")
|
||||
obj.shaders.srcDir(absolutePath + "/src/${type}/shaders")
|
||||
obj.resources.srcDir(absolutePath + "/src/${type}/resources")
|
||||
obj.renderscript.srcDir(absolutePath + "/src/${type}/rs")
|
||||
}
|
||||
|
||||
def clearModuleSourceSet(def type) {
|
||||
def srcDirs = []
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName(type)
|
||||
if (obj == null) {
|
||||
return
|
||||
}
|
||||
obj.java.srcDirs = srcDirs
|
||||
obj.res.srcDirs = srcDirs
|
||||
obj.jni.srcDirs = srcDirs
|
||||
obj.jniLibs.srcDirs = srcDirs
|
||||
obj.aidl.srcDirs = srcDirs
|
||||
obj.assets.srcDirs = srcDirs
|
||||
obj.shaders.srcDirs = srcDirs
|
||||
obj.resources.srcDirs = srcDirs
|
||||
obj.renderscript.srcDirs = srcDirs
|
||||
}
|
||||
|
||||
void applyMicroModuleScript(MicroModule microModule) {
|
||||
def microModuleBuild = new File(microModule.microModuleDir, 'build.gradle')
|
||||
if (microModuleBuild.exists()) {
|
||||
MicroModule tempMicroModule = currentMicroModule
|
||||
currentMicroModule = microModule
|
||||
project.apply from: microModuleBuild.absolutePath
|
||||
currentMicroModule = tempMicroModule
|
||||
}
|
||||
}
|
||||
|
||||
def checkMicroModuleBoundary(String taskPrefix, String buildType, String flavorName, List<String> sourceFolders) {
|
||||
CodeChecker codeChecker
|
||||
|
||||
def buildTypeFirstUp = PinUtils.upperCase(buildType)
|
||||
def productFlavorFirstUp = flavorName != null ? PinUtils.upperCase(flavorName) : ""
|
||||
|
||||
def mergeResourcesTaskName = taskPrefix + productFlavorFirstUp + buildTypeFirstUp + 'Resources'
|
||||
def packageResourcesTask = project.tasks.findByName(mergeResourcesTaskName)
|
||||
if (packageResourcesTask != null) {
|
||||
codeChecker = new CodeChecker(project, microModuleInfo, productFlavorInfo, buildType, flavorName)
|
||||
packageResourcesTask.doLast {
|
||||
codeChecker.checkResources(mergeResourcesTaskName, sourceFolders)
|
||||
}
|
||||
}
|
||||
|
||||
def compileJavaTaskName = "compile${productFlavorFirstUp}${buildTypeFirstUp}JavaWithJavac"
|
||||
def compileJavaTask = project.tasks.findByName(compileJavaTaskName)
|
||||
if (compileJavaTask != null) {
|
||||
compileJavaTask.doLast {
|
||||
if (codeChecker == null) {
|
||||
codeChecker = new CodeChecker(project, microModuleInfo, productFlavorInfo, buildType, flavorName)
|
||||
}
|
||||
codeChecker.checkClasses(mergeResourcesTaskName, sourceFolders)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,26 @@
|
||||
package com.plugin.component.plugin
|
||||
|
||||
import com.android.build.gradle.AppExtension
|
||||
import com.android.build.gradle.AppPlugin
|
||||
import com.android.build.gradle.LibraryExtension
|
||||
import com.android.build.gradle.LibraryPlugin
|
||||
import com.android.build.gradle.TestedExtension
|
||||
import com.android.build.gradle.api.BaseVariant
|
||||
import com.android.builder.model.ProductFlavor
|
||||
import com.plugin.component.Runtimes
|
||||
import com.plugin.component.extension.ComponentExtension
|
||||
import com.plugin.component.extension.module.PinInfo
|
||||
import com.plugin.component.extension.option.pin.PinConfiguration
|
||||
import com.plugin.component.utils.PinUtils
|
||||
import org.gradle.BuildListener
|
||||
import org.gradle.BuildResult
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.DomainObjectSet
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.initialization.Settings
|
||||
import org.gradle.api.invocation.Gradle
|
||||
|
||||
class PinPlugin implements BasePlugin {
|
||||
|
||||
@@ -12,19 +31,211 @@ class PinPlugin implements BasePlugin {
|
||||
private final static String APPLY_INCLUDE_MICRO_MODULE_SCRIPT = 'apply_include_micro_module_script'
|
||||
private final static String APPLY_EXPORT_MICRO_MODULE_SCRIPT = 'apply_export_micro_module_script'
|
||||
|
||||
String startTaskState = NORMAL
|
||||
|
||||
String applyScriptState
|
||||
boolean appliedLibraryPlugin
|
||||
|
||||
ComponentExtension componentExtension
|
||||
PinConfiguration pinConfiguration
|
||||
PinInfo currentPin
|
||||
Project project
|
||||
|
||||
|
||||
@Override
|
||||
void initExtension(ComponentExtension componentExtension) {
|
||||
this.componentExtension = componentExtension
|
||||
}
|
||||
|
||||
|
||||
boolean isSupportPins() {
|
||||
return pinConfiguration != null
|
||||
}
|
||||
|
||||
@Override
|
||||
void evaluateChild(Project child) {
|
||||
this.project = child
|
||||
pinConfiguration = Runtimes.getPinConfiguration(child.name)
|
||||
if (!isSupportPins()) {
|
||||
return
|
||||
}
|
||||
|
||||
//是否是sync
|
||||
if (project.gradle.getStartParameter().taskNames.size() == 0) {
|
||||
startTaskState = NORMAL
|
||||
} else {
|
||||
startTaskState = ASSEMBLE_OR_GENERATE
|
||||
}
|
||||
|
||||
//非sync情况下,在configuration添加的时候
|
||||
if (startTaskState != NORMAL) {
|
||||
project.getConfigurations().whenObjectAdded {
|
||||
Configuration configuration = it
|
||||
configuration.dependencies.whenObjectAdded {
|
||||
if (applyScriptState == APPLY_INCLUDE_MICRO_MODULE_SCRIPT) {
|
||||
configuration.dependencies.remove(it)
|
||||
return
|
||||
} else if (applyScriptState == APPLY_NORMAL_MICRO_MODULE_SCRIPT
|
||||
|| applyScriptState == APPLY_EXPORT_MICRO_MODULE_SCRIPT) {
|
||||
return
|
||||
} else if (currentPin == null && startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
return
|
||||
} else if (it.group != null && it.group.startsWith('com.android.tools')) {
|
||||
return
|
||||
}
|
||||
|
||||
configuration.dependencies.remove(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.dependencies.metaClass.microModule { String path ->
|
||||
if (currentPin == null || applyScriptState == APPLY_NORMAL_MICRO_MODULE_SCRIPT) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (applyScriptState == APPLY_INCLUDE_MICRO_MODULE_SCRIPT) {
|
||||
pinConfiguration.setPinDependency(currentPin.name, path)
|
||||
return []
|
||||
}
|
||||
|
||||
PinInfo microModule = pinConfiguration.getIncludePin(path)
|
||||
|
||||
def result = []
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
PinUtils.addMicroModuleSourceSet(project, microModule, pinConfiguration.productFlavorInfo)
|
||||
PinUtils.applyMicroModuleScript(child, microModule, currentPin)
|
||||
microModule.appliedScript = true
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
project.plugins.all {
|
||||
Class extensionClass
|
||||
if (it instanceof AppPlugin) {
|
||||
extensionClass = AppExtension
|
||||
} else if (it instanceof LibraryPlugin) {
|
||||
extensionClass = LibraryExtension
|
||||
} else {
|
||||
return
|
||||
}
|
||||
project.extensions.configure(extensionClass, new Action<? extends TestedExtension>() {
|
||||
@Override
|
||||
void execute(TestedExtension testedExtension) {
|
||||
boolean isLibrary
|
||||
DomainObjectSet<BaseVariant> baseVariants
|
||||
if (testedExtension instanceof AppExtension) {
|
||||
AppExtension appExtension = (AppExtension) testedExtension
|
||||
baseVariants = appExtension.applicationVariants
|
||||
} else {
|
||||
LibraryExtension libraryExtension = (LibraryExtension) testedExtension
|
||||
baseVariants = libraryExtension.libraryVariants
|
||||
isLibrary = true
|
||||
}
|
||||
|
||||
baseVariants.all { BaseVariant variant ->
|
||||
if (pinConfiguration.codeCheckEnabled) {
|
||||
def taskNamePrefix = isLibrary ? 'package' : 'merge'
|
||||
List<String> sourceFolders = new ArrayList<>()
|
||||
sourceFolders.add('main')
|
||||
sourceFolders.add(variant.buildType.name)
|
||||
if (variant.productFlavors.size() > 0) {
|
||||
sourceFolders.add(variant.name)
|
||||
sourceFolders.add(variant.flavorName)
|
||||
for (ProductFlavor productFlavor : variant.productFlavors) {
|
||||
sourceFolders.add(productFlavor.name)
|
||||
}
|
||||
PinUtils.checkMicroModuleBoundary(child, pinConfiguration, taskNamePrefix, variant.buildType.name, variant.flavorName, sourceFolders)
|
||||
} else {
|
||||
PinUtils.checkMicroModuleBoundary(child, pinConfiguration, taskNamePrefix, variant.buildType.name, null, sourceFolders)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void afterEvaluateChild(Project child) {
|
||||
if (!isSupportPins()) {
|
||||
return
|
||||
}
|
||||
|
||||
pinConfiguration.initProductFlavor()
|
||||
|
||||
if (pinConfiguration.mainPin == null) {
|
||||
throw new GradleException("the main PinInfo could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
|
||||
appliedLibraryPlugin = project.pluginManager.hasPlugin('com.android.library')
|
||||
applyScriptState = APPLY_INCLUDE_MICRO_MODULE_SCRIPT
|
||||
pinConfiguration.includePins.each {
|
||||
PinInfo microModule = it.value
|
||||
pinConfiguration.dependencyGraph.add(microModule.name)
|
||||
applyMicroModuleScript(child, microModule)
|
||||
}
|
||||
|
||||
//清除所有 srouceSet 信息
|
||||
PinUtils.clearOriginSourceSet(child, pinConfiguration.productFlavorInfo)
|
||||
|
||||
//如果非 sync
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
//读取所有 export 配置
|
||||
applyScriptState = APPLY_EXPORT_MICRO_MODULE_SCRIPT
|
||||
boolean hasExportMainMicroModule = false
|
||||
boolean isEmpty = pinConfiguration.exportPins.isEmpty()
|
||||
List<String> dependencySort = pinConfiguration.dependencyGraph.topSort()
|
||||
dependencySort.each {
|
||||
if (isEmpty || pinConfiguration.exportPins.containsKey(it)) {
|
||||
PinInfo microModule = pinConfiguration.getIncludePin(it)
|
||||
if (microModule == null) {
|
||||
throw new GradleException("PinInfo with path '${it}' could not be found in ${project.getDisplayName()}.")
|
||||
}
|
||||
|
||||
if (microModule == pinConfiguration.mainPin) {
|
||||
hasExportMainMicroModule = true
|
||||
}
|
||||
|
||||
if (microModule.appliedScript) return
|
||||
|
||||
PinUtils.addMicroModuleSourceSet(project, microModule, pinConfiguration.productFlavorInfo)
|
||||
applyMicroModuleScript(child, microModule)
|
||||
microModule.appliedScript = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasExportMainMicroModule) {
|
||||
throw new GradleException("the main PinInfo '${pinConfiguration.mainPin.name}' is not in the export list.")
|
||||
}
|
||||
} else {
|
||||
applyScriptState = APPLY_NORMAL_MICRO_MODULE_SCRIPT
|
||||
pinConfiguration.includePins.each {
|
||||
PinInfo microModule = it.value
|
||||
PinUtils.addMicroModuleSourceSet(project, microModule, pinConfiguration.productFlavorInfo)
|
||||
applyMicroModuleScript(child, microModule)
|
||||
}
|
||||
}
|
||||
currentPin = null
|
||||
|
||||
PinUtils.generateAndroidManifest(project, pinConfiguration, startTaskState)
|
||||
|
||||
project.tasks.preBuild.doFirst {
|
||||
clearOriginSourceSet()
|
||||
if (startTaskState == ASSEMBLE_OR_GENERATE) {
|
||||
pinConfiguration.includePins.each {
|
||||
PinInfo pin = it.value
|
||||
if (pin.appliedScript) {
|
||||
PinUtils.addMicroModuleSourceSet(project, pin, pinConfiguration.productFlavorInfo)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pinConfiguration.includePins.each {
|
||||
PinUtils.addMicroModuleSourceSet(project, it.value, pinConfiguration.productFlavorInfo)
|
||||
}
|
||||
}
|
||||
PinUtils.generateAndroidManifest(project, pinConfiguration, startTaskState)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -34,11 +245,68 @@ class PinPlugin implements BasePlugin {
|
||||
|
||||
@Override
|
||||
void afterEvaluateRoot(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)
|
||||
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')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void afterAllEvaluate() {
|
||||
}
|
||||
|
||||
void applyMicroModuleScript(Project project, PinInfo microModule) {
|
||||
def pinBuild = new File(microModule.pinDir, 'build.gradle')
|
||||
if (pinBuild.exists()) {
|
||||
PinInfo tempMicroModule = currentPin
|
||||
currentPin = microModule
|
||||
project.apply from: pinBuild.absolutePath
|
||||
currentPin = tempMicroModule
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,8 +151,6 @@ class SdkPlugin implements BasePlugin{
|
||||
|
||||
@Override
|
||||
void afterEvaluateRoot(Project root) {
|
||||
Runtimes.initRuntimeConfiguration(root, mComponentExtension)
|
||||
|
||||
Logger.buildOutput("")
|
||||
Logger.buildOutput("=====> 处理 sdk/impl jar <=====")
|
||||
List<String> topSort = PublicationManager.getInstance().dependencyGraph.topSort()
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
package com.plugin.component.utils
|
||||
|
||||
import com.plugin.component.extension.module.MicroModule
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import com.android.manifmerger.ManifestMerger2
|
||||
import com.android.manifmerger.MergingReport
|
||||
import com.android.manifmerger.XmlDocument
|
||||
import com.android.utils.ILogger
|
||||
import com.plugin.component.check.CodeChecker
|
||||
import com.plugin.component.extension.module.PinInfo
|
||||
import com.plugin.component.extension.module.ProductFlavorInfo
|
||||
import com.plugin.component.extension.option.pin.PinConfiguration
|
||||
import com.plugin.component.plugin.PinPlugin
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@@ -16,6 +26,303 @@ class PinUtils {
|
||||
return String.valueOf(ch)
|
||||
}
|
||||
|
||||
static void generateAndroidManifest(Project project, PinConfiguration pinConfiguration, String startTaskState) {
|
||||
if ((startTaskState == PinPlugin.ASSEMBLE_OR_GENERATE || !pinConfiguration.exportPins.isEmpty()) && isMainSourceSetEmpty(project)) {
|
||||
setMainSourceSetManifest()
|
||||
return
|
||||
}
|
||||
mergeAndroidManifest(project, 'main', pinConfiguration, startTaskState)
|
||||
|
||||
pinConfiguration.productFlavorInfo.buildTypes.each {
|
||||
mergeAndroidManifest(project, it, pinConfiguration, startTaskState)
|
||||
}
|
||||
|
||||
if (!pinConfiguration.productFlavorInfo.singleDimension) {
|
||||
pinConfiguration.productFlavorInfo.productFlavors.each {
|
||||
mergeAndroidManifest(project, it, pinConfiguration, startTaskState)
|
||||
}
|
||||
}
|
||||
|
||||
pinConfiguration.productFlavorInfo.combinedProductFlavors.each {
|
||||
mergeAndroidManifest(project, it, pinConfiguration, startTaskState)
|
||||
|
||||
def productFlavor = it
|
||||
pinConfiguration.productFlavorInfo.buildTypes.each {
|
||||
mergeAndroidManifest(project, productFlavor + upperCase(it), pinConfiguration, startTaskState)
|
||||
}
|
||||
}
|
||||
|
||||
def androidTest = 'androidTest'
|
||||
mergeAndroidManifest(project, androidTest, pinConfiguration, startTaskState)
|
||||
mergeAndroidManifest(project, androidTest + 'Debug', pinConfiguration, startTaskState)
|
||||
if (!pinConfiguration.productFlavorInfo.singleDimension) {
|
||||
pinConfiguration.productFlavorInfo.productFlavors.each {
|
||||
mergeAndroidManifest(project, androidTest + upperCase(it), pinConfiguration, startTaskState)
|
||||
}
|
||||
}
|
||||
pinConfiguration.productFlavorInfo.combinedProductFlavors.each {
|
||||
mergeAndroidManifest(androidTest + Utils.upperCase(it), pinConfiguration, startTaskState)
|
||||
mergeAndroidManifest(androidTest + Utils.upperCase(it) + 'Debug', pinConfiguration, startTaskState)
|
||||
}
|
||||
}
|
||||
|
||||
static void mergeAndroidManifest(Project project, String variantName, PinConfiguration pinConfiguration, String startTaskState) {
|
||||
File mainManifestFile = new File(pinConfiguration.mainPin.pinDir, "/src/${variantName}/AndroidManifest.xml")
|
||||
if (!mainManifestFile.exists()) return
|
||||
ManifestMerger2.MergeType mergeType = ManifestMerger2.MergeType.APPLICATION
|
||||
XmlDocument.Type documentType = XmlDocument.Type.MAIN
|
||||
def logger = new ILogger() {
|
||||
@Override
|
||||
void error(Throwable t, String msgFormat, Object... args) {
|
||||
println(msgFormat)
|
||||
}
|
||||
|
||||
@Override
|
||||
void warning(String msgFormat, Object... args) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void info(String msgFormat, Object... args) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void verbose(String msgFormat, Object... args) {
|
||||
|
||||
}
|
||||
}
|
||||
ManifestMerger2.Invoker invoker = new ManifestMerger2.Invoker(mainManifestFile, logger, mergeType, documentType)
|
||||
invoker.withFeatures(ManifestMerger2.Invoker.Feature.NO_PLACEHOLDER_REPLACEMENT)
|
||||
|
||||
pinConfiguration.includePins.each {
|
||||
PinInfo pin = it.value
|
||||
if (startTaskState == PinPlugin.ASSEMBLE_OR_GENERATE && !pin.appliedScript) return
|
||||
if (pin.name == pinConfiguration.mainPin.name) return
|
||||
def pinManifestFile = new File(pin.pinDir, "/src/${variantName}/AndroidManifest.xml")
|
||||
if (pinManifestFile.exists()) {
|
||||
invoker.addLibraryManifest(pinManifestFile)
|
||||
}
|
||||
}
|
||||
|
||||
def mergingReport = invoker.merge()
|
||||
if (!mergingReport.result.success) {
|
||||
mergingReport.log(logger)
|
||||
throw new GradleException(mergingReport.reportString)
|
||||
}
|
||||
def moduleAndroidManifest = mergingReport.getMergedDocument(MergingReport.MergedManifestKind.MERGED)
|
||||
moduleAndroidManifest = new String(moduleAndroidManifest.getBytes('UTF-8'))
|
||||
|
||||
def saveDir = new File(project.projectDir, "build/pin/merge-manifest/${variantName}")
|
||||
saveDir.mkdirs()
|
||||
def AndroidManifestFile = new File(saveDir, 'AndroidManifest.xml')
|
||||
AndroidManifestFile.createNewFile()
|
||||
AndroidManifestFile.write(moduleAndroidManifest)
|
||||
|
||||
def extensionContainer = project.getExtensions()
|
||||
BaseExtension android = extensionContainer.getByName('android')
|
||||
def obj = android.sourceSets.findByName(variantName)
|
||||
if (obj == null) {
|
||||
return
|
||||
}
|
||||
obj.manifest.srcFile project.projectDir.absolutePath + "/build/pin/merge-manifest/${variantName}/AndroidManifest.xml"
|
||||
}
|
||||
|
||||
static void addMicroModuleSourceSet(Project project, PinInfo pin, ProductFlavorInfo productFlavorInfo) {
|
||||
addVariantSourceSet(project, pin, 'main')
|
||||
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(project, pin, it)
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
addVariantSourceSet(project, pin, it)
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
addVariantSourceSet(project, pin, it)
|
||||
def flavorName = it
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(project, pin, flavorName + upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
def testTypes = ['androidTest', 'test']
|
||||
testTypes.each {
|
||||
def testType = it
|
||||
addVariantSourceSet(project, pin, testType)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(project, pin, testType + upperCase(it))
|
||||
}
|
||||
} else {
|
||||
addVariantSourceSet(project, pin, testType + 'Debug')
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
addVariantSourceSet(project, pin, testType + upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
def productFlavorName = testType + upperCase(it)
|
||||
addVariantSourceSet(project, pin, productFlavorName)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
addVariantSourceSet(project, pin, productFlavorName + upperCase(it))
|
||||
}
|
||||
} else {
|
||||
addVariantSourceSet(project, pin, productFlavorName + 'Debug')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clearOriginSourceSet(Project project, ProductFlavorInfo productFlavorInfo) {
|
||||
clearModuleSourceSet(project, 'main')
|
||||
|
||||
// buildTypes
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(project, it)
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
clearModuleSourceSet(project, it)
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
clearModuleSourceSet(project, it)
|
||||
def flavorName = it
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(project, flavorName + upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
def testTypes = ['androidTest', 'test']
|
||||
testTypes.each {
|
||||
def testType = it
|
||||
clearModuleSourceSet(project, testType)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(project, testType + upperCase(it))
|
||||
}
|
||||
} else {
|
||||
clearModuleSourceSet(project, testType + 'Debug')
|
||||
}
|
||||
|
||||
if (!productFlavorInfo.singleDimension) {
|
||||
productFlavorInfo.productFlavors.each {
|
||||
clearModuleSourceSet(project, testType + upperCase(it))
|
||||
}
|
||||
}
|
||||
|
||||
productFlavorInfo.combinedProductFlavors.each {
|
||||
def productFlavorName = testType + upperCase(it)
|
||||
clearModuleSourceSet(project, productFlavorName)
|
||||
|
||||
if (testType == 'test') {
|
||||
productFlavorInfo.buildTypes.each {
|
||||
clearModuleSourceSet(project, productFlavorName + upperCase(it))
|
||||
}
|
||||
} else {
|
||||
clearModuleSourceSet(project, productFlavorName + 'Debug')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isMainSourceSetEmpty(Project project) {
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName('main')
|
||||
if (obj == null) {
|
||||
return true
|
||||
}
|
||||
return obj.java.srcDirs.size() == 0
|
||||
}
|
||||
|
||||
static setMainSourceSetManifest(Project project, String dir) {
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName('main')
|
||||
if (obj == null) {
|
||||
obj = android.sourceSets.create('main')
|
||||
}
|
||||
File mainManifestFile = new File(dir, '/src/main/AndroidManifest.xml')
|
||||
obj.manifest.srcFile mainManifestFile
|
||||
}
|
||||
|
||||
static clearModuleSourceSet(Project project, def type) {
|
||||
def srcDirs = []
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName(type)
|
||||
if (obj == null) {
|
||||
return
|
||||
}
|
||||
obj.java.srcDirs = srcDirs
|
||||
obj.res.srcDirs = srcDirs
|
||||
obj.jni.srcDirs = srcDirs
|
||||
obj.jniLibs.srcDirs = srcDirs
|
||||
obj.aidl.srcDirs = srcDirs
|
||||
obj.assets.srcDirs = srcDirs
|
||||
obj.shaders.srcDirs = srcDirs
|
||||
obj.resources.srcDirs = srcDirs
|
||||
obj.renderscript.srcDirs = srcDirs
|
||||
}
|
||||
|
||||
static addVariantSourceSet(Project project, PinInfo microModule, def type) {
|
||||
def absolutePath = microModule.pinDir.absolutePath
|
||||
BaseExtension android = project.extensions.getByName('android')
|
||||
def obj = android.sourceSets.findByName(type)
|
||||
if (obj == null) {
|
||||
obj = android.sourceSets.create(type)
|
||||
}
|
||||
obj.java.srcDir(absolutePath + "/src/${type}/java")
|
||||
obj.java.srcDir(absolutePath + "/src/${type}/kotlin")
|
||||
obj.res.srcDir(absolutePath + "/src/${type}/res")
|
||||
obj.jni.srcDir(absolutePath + "/src/${type}/jni")
|
||||
obj.jniLibs.srcDir(absolutePath + "/src/${type}/jniLibs")
|
||||
obj.aidl.srcDir(absolutePath + "/src/${type}/aidl")
|
||||
obj.assets.srcDir(absolutePath + "/src/${type}/assets")
|
||||
obj.shaders.srcDir(absolutePath + "/src/${type}/shaders")
|
||||
obj.resources.srcDir(absolutePath + "/src/${type}/resources")
|
||||
obj.renderscript.srcDir(absolutePath + "/src/${type}/rs")
|
||||
}
|
||||
|
||||
|
||||
static void checkMicroModuleBoundary(Project project, PinConfiguration pinConfiguration, String taskPrefix, String buildType, String flavorName, List<String> sourceFolders) {
|
||||
CodeChecker codeChecker
|
||||
|
||||
def buildTypeFirstUp = upperCase(buildType)
|
||||
def productFlavorFirstUp = flavorName != null ? upperCase(flavorName) : ""
|
||||
|
||||
def mergeResourcesTaskName = taskPrefix + productFlavorFirstUp + buildTypeFirstUp + 'Resources'
|
||||
def packageResourcesTask = project.tasks.findByName(mergeResourcesTaskName)
|
||||
if (packageResourcesTask != null) {
|
||||
codeChecker = new CodeChecker(project, pinConfiguration, pinConfiguration.productFlavorInfo, buildType, flavorName)
|
||||
packageResourcesTask.doLast {
|
||||
codeChecker.checkResources(mergeResourcesTaskName, sourceFolders)
|
||||
}
|
||||
}
|
||||
|
||||
def compileJavaTaskName = "compile${productFlavorFirstUp}${buildTypeFirstUp}JavaWithJavac"
|
||||
def compileJavaTask = project.tasks.findByName(compileJavaTaskName)
|
||||
if (compileJavaTask != null) {
|
||||
compileJavaTask.doLast {
|
||||
if (codeChecker == null) {
|
||||
codeChecker = new CodeChecker(project, pinConfiguration, pinConfiguration.productFlavorInfo, buildType, flavorName)
|
||||
}
|
||||
codeChecker.checkClasses(mergeResourcesTaskName, sourceFolders)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String getAndroidManifestPackageName(File androidManifest) {
|
||||
def builderFactory = DocumentBuilderFactory.newInstance()
|
||||
builderFactory.setNamespaceAware(true)
|
||||
@@ -23,7 +330,13 @@ class PinUtils {
|
||||
return manifestXml.getAttribute("package")
|
||||
}
|
||||
|
||||
static MicroModule buildMicroModule(Project project, String microModulePath) {
|
||||
/**
|
||||
* 构建pin工程
|
||||
* @param project
|
||||
* @param microModulePath
|
||||
* @return
|
||||
*/
|
||||
static PinInfo buildPin(Project project, String microModulePath) {
|
||||
String[] pathElements = removeTrailingColon(microModulePath).split(":")
|
||||
int pathElementsLen = pathElements.size()
|
||||
File parentMicroModuleDir = project.projectDir
|
||||
@@ -40,12 +353,17 @@ class PinUtils {
|
||||
if (!microModuleDir.exists()) {
|
||||
return null
|
||||
}
|
||||
MicroModule microModule = new MicroModule()
|
||||
PinInfo microModule = new PinInfo()
|
||||
microModule.name = microModuleName
|
||||
microModule.microModuleDir = microModuleDir
|
||||
microModule.pinDir = microModuleDir
|
||||
return microModule
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除冒号
|
||||
* @param microModulePath
|
||||
* @return
|
||||
*/
|
||||
private static String removeTrailingColon(String microModulePath) {
|
||||
return microModulePath.startsWith(":") ? microModulePath.substring(1) : microModulePath
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.plugin.component.utils
|
||||
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class Utils {
|
||||
|
||||
|
||||
//
|
||||
// /**
|
||||
// * 自动添加依赖,只在运行assemble任务的才会添加依赖,因此在开发期间组件之间是完全感知不到的,这是做到完全隔离的关键
|
||||
// * 支持两种语法:module或者groupId:artifactId:version(@aar),前者之间引用module工程,后者使用maven中已经发布的aar
|
||||
// *
|
||||
// * @param assembleTask
|
||||
// * @param project
|
||||
// */
|
||||
// static void compileComponents(@Nonnull Project project, @Nonnull AssembleTask assembleTask) {
|
||||
// String components;
|
||||
// if (assembleTask.isDebug) {
|
||||
// components = (String) project.getProperties().get("debugCompileComponent");
|
||||
// } else {
|
||||
// components = (String) project.getProperties().get("releaseCompileComponent");
|
||||
// }
|
||||
//
|
||||
// if (components == null || components.length() == 0) {
|
||||
// System.out.println("there is no add dependencies ");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// String[] compileComponents = components.split(",");
|
||||
// if (compileComponents == null || compileComponents.length == 0) {
|
||||
// System.out.println("there is no add dependencies ");
|
||||
// return;
|
||||
// }
|
||||
// for (String str : compileComponents) {
|
||||
// System.out.println("comp is " + str);
|
||||
// str = str.trim();
|
||||
// if (str.startsWith(":")) {
|
||||
// str = str.substring(1);
|
||||
// }
|
||||
// if (isMavenArtifact(str)) {
|
||||
// /**
|
||||
// * 示例语法:groupId:artifactId:version(@aar)
|
||||
// * compileComponent=com.luojilab.reader:readercomponent:1.0.0
|
||||
// * 注意,前提是已经将组件aar文件发布到maven上,并配置了相应的repositories
|
||||
// */
|
||||
// project.getDependencies().add("implementation", str);
|
||||
// System.out.println("add dependencies lib : " + str);
|
||||
// } else {
|
||||
// /**
|
||||
// * 示例语法:module
|
||||
// * compileComponent=readercomponent,sharecomponent
|
||||
// */
|
||||
// project.getDependencies().add("implementation", project.project(':' + str));
|
||||
// System.out.println("add dependencies project : " + str);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 是否是maven 坐标
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static boolean isMavenArtifact(String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return Pattern.matches("\\S+(\\.\\S+)+:\\S+(:\\S+)?(@\\S+)?", str);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,7 @@ component {
|
||||
exclude 'libraryWithoutPlugin','component-core'
|
||||
|
||||
// 上述 语句等价于下面语句
|
||||
include ':app','library','libraryKotlin','debugModule'
|
||||
// include ':app','library','libraryKotlin','debugModule'
|
||||
|
||||
|
||||
sdk {
|
||||
@@ -46,14 +46,12 @@ component {
|
||||
}
|
||||
|
||||
pin {
|
||||
|
||||
configuration {
|
||||
'library' {
|
||||
'pins' {
|
||||
codeCheckEnabled true
|
||||
include ':p_base'
|
||||
include ':p_common'
|
||||
include ':p_home'
|
||||
|
||||
export ':main', ':p_home'
|
||||
export ':p_common'
|
||||
}
|
||||
|
||||
1
pins/.gitignore
vendored
Normal file
1
pins/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
36
pins/build.gradle
Normal file
36
pins/build.gradle
Normal file
@@ -0,0 +1,36 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.2"
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles 'consumer-rules.pro'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.1.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
}
|
||||
0
pins/consumer-rules.pro
Normal file
0
pins/consumer-rules.pro
Normal file
3
pins/main/build.gradle
Normal file
3
pins/main/build.gradle
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'main/libs', include: ['*.jar'])
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.plugin.pin
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.plugin.pin.test", appContext.packageName)
|
||||
}
|
||||
}
|
||||
2
pins/main/src/main/AndroidManifest.xml
Normal file
2
pins/main/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.plugin.pin" />
|
||||
3
pins/main/src/main/res/values/strings.xml
Normal file
3
pins/main/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Pins</string>
|
||||
</resources>
|
||||
17
pins/main/src/test/java/com/plugin/pin/ExampleUnitTest.kt
Normal file
17
pins/main/src/test/java/com/plugin/pin/ExampleUnitTest.kt
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.plugin.pin
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
3
pins/p_base/build.gradle
Normal file
3
pins/p_base/build.gradle
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies {
|
||||
|
||||
}
|
||||
2
pins/p_base/src/main/AndroidManifest.xml
Normal file
2
pins/p_base/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.plugin.pin.base" />
|
||||
@@ -0,0 +1,2 @@
|
||||
class Base {
|
||||
}
|
||||
3
pins/p_common/build.gradle
Normal file
3
pins/p_common/build.gradle
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies {
|
||||
|
||||
}
|
||||
2
pins/p_common/src/main/AndroidManifest.xml
Normal file
2
pins/p_common/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.plugin.pin.common" />
|
||||
@@ -0,0 +1,2 @@
|
||||
class Common {
|
||||
}
|
||||
3
pins/p_home/build.gradle
Normal file
3
pins/p_home/build.gradle
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies {
|
||||
|
||||
}
|
||||
2
pins/p_home/src/main/AndroidManifest.xml
Normal file
2
pins/p_home/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.plugin.pin.home" />
|
||||
@@ -0,0 +1,2 @@
|
||||
class Home {
|
||||
}
|
||||
21
pins/proguard-rules.pro
vendored
Normal file
21
pins/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -7,6 +7,6 @@
|
||||
//调试插件
|
||||
includeBuild './component-plugin'
|
||||
//
|
||||
include ':app'
|
||||
include ':app', ':pins'
|
||||
include ':debugModule'
|
||||
include ':library', ':libraryKotlin', ':libraryWithoutPlugin'
|
||||
|
||||
Reference in New Issue
Block a user