The company’s SDK project used to be mainly for Google Play, but recently received a new demand to access two new SDKS, one for South Korea and one for India. The package needs to have independent applicationId and different packages need to configure different dependencies.
This requirement can be implemented with the multi-channel configuration of Android Studio. If you configure it directly in Android Studio, you need to add it to the access party. Therefore, we still implement it in gradle plug-in.
Implementation idea:
- Obtain the configuration file from the background based on the package name of the access party.
- Configure channel parameters based on configuration files, for example
applicationId
. - Dynamically add dependencies based on the packaged Task executed.
Obtain the package name of the access party
In fact, the project has realized the function of obtaining the package name of the access party in the previous requirements. The package name of the access party comes from AppExtension and the code is as follows:
class MyPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
def appExtension = project.extensions.findByType(AppExtension.class)
project.afterEvaluate {
def applicationId = appExtension.defaultConfig.applicationId
}
}
}
Copy the code
ProductFlavors needs to be configured before Gradle is finished compiling, so getting applicationId in Project. AfterEvaluate doesn’t make it possible to configure multiple options based on the configuration file.
So the applicationId needs to be passed directly into the plug-in from the access side’s project. Therefore, I came up with the idea to configure the parameters by creating extensions as follows:
Class DiyExtension{ String originalApplicationId } class MyPlugin implements Plugin<Project> { @Override public void apply(Project project) { def diyExtension = project.extensions.create("DiyExtension", DiyExtension) project. AfterEvaluate {def applicationId = DiyExtension. OriginalApplicationId}}} / / in the build. Gradle added DiyExtension{ originalApplicationId "com.test.applicationid" }Copy the code
However, this approach, like AppExtension, requires obtaining the value in project.afterevaluate.
Json file to the app directory of the project. Then we read this file in the plug-in to obtain the applicationId, as follows:
Plugin-config. json file contents {"original_application_id": Public class FileUtils {public static String readFileFromAppFolder(File parentFile, String fileName) { File readFile = new File(parentFile, fileName); if (readFile.exists()) { StringBuilder config = new StringBuilder(); FileInputStream fileInputStream = null; InputStreamReader inputStreamReader = null; BufferedReader reader = null; try { fileInputStream = new FileInputStream(readFile); inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8); reader = new BufferedReader(inputStreamReader); String configContent; while ((configContent = reader.readLine()) ! = null) { config.append(configContent); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (reader ! = null) { reader.close(); } if (inputStreamReader ! = null) { inputStreamReader.close(); } if (fileInputStream ! = null) { fileInputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } return config.toString(); } return ""; } } class MyPlugin implements Plugin<Project> { @Override public void apply(Project project) { def pluginConfigStr = FileUtils.readFileFromAppFolder(project.projectDir, "plugin-config.json") PluginConfig pluginConfig = new Gson().fromJson(pluginConfigStr, new TypeToken<PluginConfig>() { }.getType()) def originalApplicationId = pluginConfig.original_application_id } }Copy the code
Multi-channel configuration
The maximum multi-channel configuration code is as follows:
class MyPlugin implements Plugin<Project> { def config = null def isKoreaTask = false def isIndiaTask = false @Override public void apply(Project project) { def appExtension = project.extensions.findByType(AppExtension.class) / / determine the currently executing task which channels are checkTask (project) def pluginConfigStr = FileUtils. ReadFileFromAppFolder (project. ProjectDir, "plugin-config.json") PluginConfig pluginConfig = new Gson().fromJson(pluginConfigStr, new TypeToken<PluginConfig>() { }.getType()) def originalApplicationId = pluginConfig.original_application_id GetPluginConfigFromNet (originalApplicationId) if(config! = null) {/ / according to the configuration file configuration multi-channel if (config. Chesapeake. IsEnable () | | config. India. IsEnable ()) {/ / must be configured dimension or the compiler complains appExtension.getFlavorDimensionList().add("country") appExtension.productFlavors.register("original", { dimension "country" }) if (config.korea.isEnable()) { appExtension.productFlavors.register("Korea", { dimension "country" applicationId config.korea.application_id }) } if (config.india.isEnable()) { appExtension.productFlavors.register("India", {dimension "country" applicationId config.india.application_id})}} project.afterevaluate {// Add different dependencies project.dependencies { if(isKoreaTask){ implementation("korea lib") } if(isIndiaTask){ implementation("india lib") } } } } static void getPluginConfigFromNet(String packageName) { def url = "https://downloadpath/" + packageName + "/config.json" def okHttpClient = new OkHttpClient.Builder().build(); def request = new Request.Builder() .url(url) .build(); def call = client.newCall(request); try { Response response = call.execute(); if(response.isSuccessful()){ if (response.body() ! = null) { def responseBodyString = responseBody.string() config = gson.fromJson(responseBodyString, new TypeToken<SdkConfig>() { }.getType()) } } response.close(); } catch (IOException | JsonIOException | JsonSyntaxException e) { e.printStackTrace(); } } private static boolean checkTask(Project project) { project.gradle.getStartParameter().getTaskNames().each { isKoreaTask = it.contains("korea") isIndiaTask = it.contains("india") } } }Copy the code
After generating multiple channels, you can select the corresponding Build Variant as shown below: