Android-Plugin-Framework集成开发

Android-Plugin-Framework集成开发

  • 项目地址:https://github.com/limpoxe/Android-Plugin-Framework
  • 若想要了解插件实现原理,请见项目地址的说明,本文档只是教如何使用APF框架进行插件开发。

插件开发简易流程

宿主程序

  1. 引入并编译PluginCore核心库

    • 位置:项目根目录:
      Android-Plugin-Framework集成开发_第1张图片
  2. Application配置。若项目中定义过Application就继承插件的,若没有就定义库中的

    • 项目中未定义application,AndroidManifest.xml中Application字段如下:
      Android-Plugin-Framework集成开发_第2张图片
  3. 检查PluginCore库中的AndroidManifest.xml文件的activity,service等配置(具体配置文件中有说明)
  4. 资源id分配问题,解决和插件资源id冲突,此处参照PluginMain项目中的代码
    • 拷贝Android-Plugin-Framework-master\PluginMain\public.xml文件到宿主应用(:app)根目录(和build.gradle同级)
    • 拷贝下面代码到build.gradle下
tasks.whenTaskAdded { task -> if (task.name.startsWith("merge") && task.name.endsWith("Resources")) {
        task.doLast {
            copy {
                from(project.getProjectDir()) {
                    include 'public.xml'
                }
                String dirName = task.name.replace("merge", "").replace("Resources", "");
                //这里最好再增加一个buildType判断,而不是写死Debug和Release两种
                if (dirName.equals("Debug") || dirName.equals("Release")) {
                    into("${project.buildDir}/intermediates/res/merged/" + dirName.toLowerCase() + "/values/")
                } else if (dirName.endsWith("Debug")) {
                    into("${project.buildDir}/intermediates/res/merged/" + dirName.replace("Debug", "") + "/debug/values/")
                } else if (dirName.endsWith("Release")) {
                    into("${project.buildDir}/intermediates/res/merged/" + dirName.replace("Release", "") + "/release/values/")
                }
            }
        }
        //task.enabled = false
    }
if (task.name.startsWith("process") && task.name.endsWith("Resources")) {

        task.doLast {
            copy {
                String name = task.name.replace("process", "").replace("Resources", "");
                //这里最好再增加一个buildType判断,而不是写死Debug和Release两种
                if (name.equals("Debug") || name.equals("Release")) {
                    name = "resources-" + name.toLowerCase() + ".ap_";
                } else if (name.endsWith("Debug")) {
                    name = "resources-" + name.replace("Debug", "") + "-debug.ap_";
                } else if (name.endsWith("Release")) {
                    name = "resources-" + name.replace("Release", "") + "-release.ap_";
                }

                from("${project.buildDir}/intermediates/res/") {
                    include name
                }
                if (task.name.endsWith("DebugResources")) {
                    into("${project.buildDir}/outputs/")
                    rename { String fileName -> 'resources-debug.ap_'
                    }
                } else if (task.name.endsWith("ReleaseResources")) {
                    into("${project.buildDir}/outputs/")
                    rename { String fileName -> 'resources-release.ap_'
                    }
                }
            }
        }

        //task.enabled = false
    }
}

注意:拷贝完成后,请删除build文件夹,然后重新编译。ps:直接rebuild会报错。若编译时还报错,请注释掉这段代码(此时R文件资源分区已分区),这个bug给作者提过,说是脚本有错,但我不知道如何修改。

  1. 初始化插件(未安装的apk文件) //注意读写权限
    • 在需要初始化插件时,调用下面代码,参数为插件的绝对路径 PluginLoader.installPlugin(Environment.getExternalStorageDirectory().getAbsolutePath()+"/app-debug.apk");
  2. 使用插件:
        // 根据插件包名(pluginId)查询插件
        PluginDescriptor pluginDescriptor = PluginLoader.getPluginDescriptorByPluginId("com.example.testfacejar");

        // 得到插件中所有的activity
        HashMap<String, PluginActivityInfo> activityInfos = pluginDescriptor.getActivityInfos();
        for (final Map.Entry<String,PluginActivityInfo> entry: activityInfos.entrySet()) {
               Intent intent = new Intent();
                // 通过类名,启动activity,宿主可以通过intent和插件通信
               intent.setClassName(MainActivity.this, entry.getKey());
               intent.putExtra("testParam", "testParam");
               startActivity(intent);
        }

使用service,receiver同理。

宿主注意事项

  1. 更新插件,需在应用启动时(旧的插件没有运行)
  2. 插件权限,需由宿主程序声明
  3. 发布版本时,请将PluginCode中的LogUtil类的isDebug字段修改为false

宿主程序给插件一个统一的平台支持,起到管理,安装,打开插件等功能。具体的管理策略由服务器插件模块下发指令,宿主执行。宿主只负责根据指令启动对应的插件,不对插件内部做干预。

插件程序

插件程序在开发中,无特别的注意事项,和普通开发方式几乎一致。不过在研究APF框架时也发现了以下特别注意事项:

  1. 在插件中调用getPackageName方法返回的是宿主的包名,不是插件包名。插件包名请用BuildConfig.APPLICATION_ID获取。
  2. 对于插件和宿主共享依赖jar包,常见的如Gson。那么插件在编译的时候就不用编译到插件中去,需要使用provided方式依赖。,以gson.jar依赖为例,在bulid.gradle中配置:
    dependencies {
    compile files(‘libs/AudienceNetwork.jar’)
    provided files(‘libs/gson-2.5.jar’)
    }
  3. 插件Activity切换动画不支持使用插件自己的资源。
  4. 插件activity不支持透明
  5. 不支持插件申请权限,权限必须预埋到宿主中。
  6. 插件的SharedPreferences和DataBase与宿主隔离,不通用
  7. layout.xml中的view不能使用android:onclick=”“方式
  8. 资源名称不能重复,比如常见的activity_main.xml。

插件测试通过的功能

  1. activity、service、receiver

你可能感兴趣的:(android,插件)