如何开发一个可扩展性的应用?

前言

现需要开发一个应用,我们暂且叫它系统诊断应用,它的设计目标是:“提供一个平台,可以实现各个SDK的功能,具有可扩展性。

分析

  • 提供一个平台,实现各个SDK的功能:

这个到还挺容易,通过接入各个SDK,调用它们提供的接口,即可实现各自功能。

  • 具有可扩展性:

这个就比较麻烦了,当然,按照常规的做法,我们可以每增加一个SDK,然后在应用中增加对SDK接口的调用即可,但是,这样就使得应用不具有可扩展性了。那我们是否可以做到如下方式:“每增加一个SDK,无需增加额外代码调用,只需要在某处配置下就可以,使应用具有可扩展性。

经验告诉我们,答案当然是肯定的,可以做到。接下来就需要看看具体的实现。

架构设计

目标:每增加一个SDK,无需增加额外代码调用,只需要在某处配置下就可以,使应用具有可扩展性。

设计思想:

1)要想“每增加一个SDK,无需增加额外代码调用”,这就需要采用面向接口编程的方式,各SDK实现相同的接口,系统诊断应用调用统一的接口。

public interface IDiagnoseInterface {

    String init();

    void addDiagnoseAndRepairListener(IDiagnoseListener diagnoseListener);

    void startDiagnoseAndRepair(String diagnoseMode);

    String release();

}

2)“只需要在某处配置下就可以,使应用具有可扩展性”,既然系统诊断应用调用统一的接口,那么如何区分调用到的是哪个SDK的接口呢?——这就需要通过读取配置的方式去区分。本文的重点之一就来了——如何通过配置去区分各个SDK?

有如下三种方法可参考:

  • 各SDK通过manifest文件的meta-data方式(待进一步研究)
  • 各SDK自定义XML文件配置(可行)
  • 系统诊断应用通过寻找实现了固定接口的类(可行)

(1)通过manifest文件的meta-data方式

    <application>
        <meta-data
            android:name="com.tcl.systemdiagnose.sdk"
            android:value="com.tcl.aisdk.AIDiagnoseSdkImpl"/>
    </application>
  • 每个SDK的manifst文件中,定义一个meta-data,使用相同的name、不同的value;
  • 系统诊断应用通过获取各个SDK的不同value值,以区分不同SDK;
  • 系统诊断应用,通过类的全路径(value值)加载并初始化类(Class.foeName(value);),构造类的实例然后向上转型为接口,调用通用方法即可。
try {
    ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
    String value = appInfo.metaData.getString("com.tcl.systemdiagnose.sdk");
    IDiagnoseInterface diagnoseInterface = (IDiagnoseInterface)Class.forName(value).getConstructor().newInstance();
    diagnoseInterface.init();
 } catch (Exception e) {
     e.printStackTrace();
 }

问题:

由于各个SDK是直接依赖到系统诊断应用中的,各个SDK的manifest会合并到系统诊断应用中,合并的时候就出现问题了——每个SDK的manifst文件中,有相同的name的meta-data,会编译不通过或者会覆盖,只能保存一个。

目前这种方式我还没有找到可以解决此冲突的办法,就暂时不能用以区分各个SDK。

(2)各SDK自定义XML文件配置

这种方式可以弥补manifst文件相同name的meta-data冲突问题,不同点在于:不依赖manifest,自定义XML文件,并自己解析。

此方案是常规方案,就不在此赘述了。

(3)系统诊断应用通过寻找实现了固定接口的类

这是本文的重点之二。

前文的设计思想中提到:各SDK实现相同的接口。我们要区分各个SDK,就可以通过寻找各个SDK实现相同接口的类。但这里还有个问题需要思考——如何获取各个SDK实现相同接口的类?

下面提供一种方式,前提——需要传各个SDK的包名,去区分想要获取,哪一个SDK实现相同接口的类。

        List<Class> implementClassByInterface =                 
        ClassUtils.getImplementClassByInterface(IDiagnoseInterface.class, context, packageName);
        for (int i = 0; i < implementClassByInterface.size(); i++) {
            Log.d(TAG, "获取到的类名:" + implementClassByInterface.get(i).getName());
            try {
                IDiagnoseInterface diagnoseInterface = (IDiagnoseInterface) implementClassByInterface.get(i).getConstructor().newInstance();
                diagnoseInterface.init();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    public static List<Class> getImplementClassByInterface(Class c, Context context, String packageName) {
        Log.d(TAG, "getImplementClassByInterface:packageName = " + packageName);
        List<Class> classList = new ArrayList<>();
        try {
            // 通过DexFile查找当前的APK中可执行文件。
            DexFile dexFile = new DexFile(context.getPackageCodePath());
            // 获取dexFile中的元素。这里包含了所有可执行的类名,该类名是包名+类名的方式。
            Enumeration<String> enumeration = dexFile.entries();
            while (enumeration.hasMoreElements()) {
                String className = enumeration.nextElement();
                if (className.contains(packageName)) { // 在当前所有可执行的类里面,查找包含有该包名的所有类
                    Class<?> aClass = Class.forName(className);
                    // class1.isAssignableFrom(class2) => 判定此 Class1 对象所表示的类或接口与指定的 Class2 参数
                    // 所表示的类或接口是否相同,或是否是其超类或超接口。如果是则返回 true;否则返回 false。
                    if (c.isAssignableFrom(aClass) && !c.equals(aClass)) { // 如果是同一个接口,且不是本身的情况下,add类。
                        classList.add(aClass);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return classList;
    }

3)针对前面两步到的分解,核心思想我已经表达出来了,具体的实现逻辑可以参考下面接口类图及其描述:

 

接口类图的详细过程描述如下:

  • 系统诊断应用SystemDiagnose APK以aar的方式提供Interface SDK,包含IDiagnoseInterface接口和IDiagnoseListener接口;
  • Network SDK和AI SDK依赖Interface SDK并实现IDiagnoseInterface接口,但不需要将其打包进自己的SDK,并以aar的方式提供其SDK;
  • SystemDiagnose APK依赖Interface SD和Network SDK、AI SDK,实现IDiagnoseListener接口,然后通过Network SDK或AI SDK的包名找到它们实现IDiagnoseInterface接口的类,最后通过调用IDiagnoseInterface的方法实现诊断的功能。
发布了55 篇原创文章 · 获赞 61 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Agg_bin/article/details/103432641
今日推荐