Android 自定义Gradle插件(七):关于多渠道打包

语言: CN / TW / HK

公司的SDK项目原来主要是面向Google Play,最近接到了新需求,需要接入两个新的SDK,分别针对韩国和印度,出包时需要有独立的applicationId,并且不同的包要配置不同的依赖项。

这个需求用Android Studio的多渠道配置即可实现,直接在Android Studio中配置的话需要接入方添加,所以我们仍然是在gradle插件中来实现。

实现思路: 1. 根据接入方的包名从后台获取配置文件。 2. 根据配置文件来配置渠道参数,例如applicationId。 3. 根据执行的打包Task来动态添加依赖项。

获取接入方的包名

项目在之前的需求中其实已经实现了获取接入方的包名功能。接入方的包名来自于AppExtension,代码如下:

``` class MyPlugin implements Plugin {

@Override
public void apply(Project project) {
    def appExtension = project.extensions.findByType(AppExtension.class)

    project.afterEvaluate {
        def applicationId = appExtension.defaultConfig.applicationId
    }
}

} ```

但是多渠道配置productFlavors需要在gradle编译完之前就配置好,所以在project.afterEvaluate中再获取到applicationId就无法达成我们的目的,即根据配置文件来配置多渠道信息。

所以applicationId就需要从接入方的项目中直接传入到插件。因此,我想到了通过创建extensions来配置参数,代码如下:

``` Class DiyExtension{ String originalApplicationId }

class MyPlugin implements Plugin {

@Override
public void apply(Project project) {
    def diyExtension = project.extensions.create("DiyExtension", DiyExtension)

    project.afterEvaluate {
        def applicationId = diyExtension.originalApplicationId
    }
}

}

//在build.gradle中添加 DiyExtension{ originalApplicationId "com.test.applicationid" }

`` 然而这种方式其实和AppExtension一样,都需要在project.afterEvaluate`中才能获取到值。

最终决定通过读取文件的方式来实现,即给接入方一个plugin-config.json文件,放到项目的app目录下,然后我们在插件中通过读取这个文件来获取applicationId,代码如下:

``` plugin-config.json 文件内容 { "original_application_id": "com.test.applicationid" }

//读取文件类 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 {

@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
}

} ```

多渠道配置

最总多渠道的配置代码如下:

``` class MyPlugin implements Plugin {

def config = null
def isKoreaTask = false
def isIndiaTask = false

@Override
public void apply(Project project) {

    def appExtension = project.extensions.findByType(AppExtension.class)

    //判断当前执行的task是哪个渠道
    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){
        //根据配置文件配置多渠道
        if(config.korea.isEnable()||config.india.isEnable()){
            //必须配置dimension否则编译会报错
            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 {
        //添加不同的依赖
        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")
    }
}

} ```

生成了多渠道之后可以选择相应的build variant,如下图:

企业微信截图_16483495453293.png