上一次项目迭代中,接触到了插件化框架。

使用场景:我们的app需要集成某一直播app。即在不安装第三方直播app到手机的情况下,点击我们app内部的某一连接能跳转到直播app中,运行里面原有的所有功能。

原理:也就是通过插件化框架,把第三方直播app的apk文件包下载到手机本地,然后在我们的app中,使用插件化框架解压第三方app的代码到我们app的安装目录下,使用classloader加载字节码到另一个进程中,与我们的app进程进行通讯。或许不太对,是个大概的思路。总之,好处就是,不用强制安装第三方app到手机桌面上,可使用第三方app的大部分功能,下载时会一起卸载第三方app的所有文件。

360插件化框架DroidPlugin地址

下面开始集成步骤:

一、下载插件代码,把library以module的形式加入到项目中:

解压下载 的源码,复制..\DroidPlugin-master\project\Libraries\DroidPlugin目录到项目的根目录,如图:


在主工程的settings.gradle文件中添加DroidPlugin库,如图:


编译程序。


二、修改插件内部配置:

如果上一步编译不通过,很正常,可能有些地方需要修改。先说插件内部:


把图中这些lib统一一下名称,都改成libs吧。


还是刚才那个文件,改成你的包名。现在应该可以编译通过了。

将插件中DroidPlugin/AndroidManifest.xml中的所有provider对应的authorities修改成自己的,其实改成如下即可:

android:authorities="${authorityName}_P01"  , 使用${authorityName}变量,去取build.gradle中的值,便于迁移到其他项目中


并且修改PluginManager.STUB_AUTHORITY_NAME 为你的值:
PluginManager.STUB_AUTHORITY_NAME="com.example.droidplugin_stub"

如果发现程序中是这样的,就不用改了:

public static final String STUB_AUTHORITY_NAME = BuildConfig.AUTHORITY_NAME;


三、修改项目配置:

在自定义的application中相应的方法添加插件初始化代码:

@Override public void onCreate() {     super.onCreate();     //这里必须在super.onCreate方法之后,顺序不能变     PluginHelper.getInstance().applicationOnCreate(getBaseContext()); }    @Override protected void attachBaseContext(Context base) {     PluginHelper.getInstance().applicationAttachBaseContext(base);     super.attachBaseContext(base); }




差不多了。


四、功能代码(官网原话):

1、安装、更新插件,使用如下方法:


 int PluginManager.getInstance().installPackage(String filepath, int flags)
说明:安装插件到插件系统中,filepath为插件apk路径,flags可以设置为0,如果要更新插件,则设置为PackageManagerCompat.INSTALL_REPLACE_EXISTING返回值及其含义请参见PackageManagerCompat类中的相关字段。


2、卸载插件,使用如下方法:


 int PluginManager.getInstance().deletePackage(String packageName,int flags);
说明:从插件系统中卸载某个插件,packageName传插件包名即可,flags传0。


3、启动插件:启动插件的Activity、Service等都和你启动一个以及安装在系统中的app一样,使用系统提供的相关API即可。组件间通讯也是如此。


知道这么回事后,于是整理代码,干成一个工具类:

/** * @Author: duke * @DateTime: 2017-05-30 21:40 * @Description: 插件化安装工具类 */public class PluginUtils {    /**     * 启动插件     *     * @param activity     * @param packageName     */    public static void startActivity(Activity activity, String packageName) {        PackageManager pm = activity.getPackageManager();        Intent intent = pm.getLaunchIntentForPackage(packageName);        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        activity.startActivity(intent);    }    /**     * 删除apk     *     * @param activity     * @param packageName     */    public static void unInstallApk(Activity activity, String packageName) {        if (!PluginManager.getInstance().isConnected()) {            Toast.makeText(activity, "服务未连接", Toast.LENGTH_SHORT).show();        } else {            try {                PluginManager.getInstance().deletePackage(packageName, 0);                Toast.makeText(activity, "删除完成", Toast.LENGTH_SHORT).show();            } catch (RemoteException e) {                e.printStackTrace();            }        }    }    /**     * 应该在线程中安装,此方法仅供测试     *     * @param context     * @param apkPathAndName     * @param packageName     */    public static boolean installApk(Context context, String apkPathAndName, String packageName) {        if (!PluginManager.getInstance().isConnected()) {            //installTips(context,"插件服务正在初始化,请稍后再试。。。");            return false;        }        try {            if (PluginManager.getInstance().getPackageInfo(packageName, 0) != null) {                //installTips(context,"已经安装了,不能再安装");                return true;            } else {                //如果需要更新插件,则flag 设置为 PackageManagerCompat.INSTALL_REPLACE_EXISTING                //int returnCode = PluginManager.getInstance().installPackage(filepath, PackageManagerCompat.INSTALL_REPLACE_EXISTING);                int returnCode = PluginManager.getInstance().installPackage(apkPathAndName, 0);                if (returnCode == PluginManager.INSTALL_FAILED_NO_REQUESTEDPERMISSION) {                    //安装失败,文件请求的权限太多                    //installTips(context,"安装失败,文件请求的权限太多");                } else {                    //安装完成                    //installTips(context,"安装完成");                    return true;                }            }        } catch (Exception e) {            e.printStackTrace();        }        return false;    }}


五、具体场景使用:

剩下的就是实战了。在没有安装目标app的前提下,如果你想在你的app中,点击按钮跳转到目标app的某页面。


1、click事件跳转时,你的判断插件有没有安装。当然了,某次插件安装成功后,你得做标记了。判断是也就是拿这个标记判断了。工具类中提供检查插件包是否安装的方法。

2、如果没有安装,则启动子线程安装了。肯定,你的下载第三方包到手机存储的某个位置,不然怎么办。

boolean isInstall = PluginUtils.installApk(weakReference.get(), basePath + "/a.apk", packagename);
可能是耗时操作,需要异步。需要知道第三方app下载到的位置,需要知道第三方app的包名。需要私下协商告知的,不然两个公司怎么合作?

3、跳转进入第三方app:

@Override    public void onClick(View v) {        if (v.getId() == R.id.jumpBtn) {            PluginUtils.startActivity(PluginTestActivity.this, packagename);        }    }

/**     * 启动插件     *     * @param activity     * @param packageName     */    public static void startActivity(Activity activity, String packageName) {        PackageManager pm = activity.getPackageManager();        Intent intent = pm.getLaunchIntentForPackage(packageName);        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        activity.startActivity(intent);    }

必须知道第三方app的包名。还有,如果不是launch模式的intent的话,或者说启动的不是第三方app的启动页时,怎么办?

一样的,跟app内部跳转一样,或者给一个特定的action,或者知道第三方app某Activity的具体路径,即可跳转了。


最后,还有一个混淆配置,坑爹的货:

##----360插件-----------------------------------------keep class com.morgoo.droidplugin.**{*;}



没有上传真个项目,单独把配置好的插件部分上传了

下载地址:http://download.csdn.net/download/fesdgasdgasdg/9873964






更多相关文章

  1. Android插件化开发之OpenAtlas插件的安装与卸载、更新与回滚
  2. Android:Service生命周期方法与Service启动方式bindService与Star
  3. HP TouchPad 灵魂不死,Android(安卓)附身且带 APK 应用安装
  4. 电脑怎么安装安卓系统?安卓(Android)x86 4.4安装方法图文步骤
  5. Android(安卓):为你的启动页面SplashActivity 添加动画的几种方法
  6. 关于android创建快捷方式会启动两个应用的问题(二)
  7. Qt for Android(安卓)自定义启动页(解决启动页拉伸的问题)
  8. Android(安卓)App静默安装的解决方案
  9. [置顶] Ionic项目打包Android版本实战

随机推荐

  1. android涂鸦程序(在图像上绘制)
  2. MVPVM框架 Android(安卓)DataBinding(零
  3. Android(安卓)MP4视频录制(思路篇,无DEMO)
  4. Android(安卓)源码 图形系统之请求布局
  5. Android混淆、反编译以及反破解的简单回
  6. Flutter学习笔记 按返回键直接回到桌面,不
  7. Android开源SlidingMenu的使用
  8. android之文字处理
  9. 工程android配置windows7下cocos2d-x、an
  10. 应用内存优化之OnLowMemory&OnTrimMemory