最近需要实现在android上开发插件,下面把一个简单例子分享一下...

首先我们需要创建两个工程,一个是主程序,一个是插件工程

1.首先在主程序中定义一个接口.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.mutour.testplugin;
import android.content.Context;
import android.view.View;
public interface Plugin {
    public void load();
     
    public void create(Context context, View view);
     
    public void create(View view);
     
    public void show();
     
    public void hide();
     
    public View getView();
}

2.接着在主程序中创建一个layout

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
    <LinearLayout
        android:id="@+id/LinearLayoutContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical" >
    </LinearLayout>
</LinearLayout>

3.然后把主程序中的interface Plugin打包成jar.

主程序工程右键,Export, 选择Java-JAR file,(注意保存的路径), 一路的next

只选择Plugin.java.

4.把生成的jar文件放到插件工程中

5.在插件工程中写一个layout文件R.layout.activity_number_plugin,随便放点什么控件

6.在插件工程中写插件类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.mutour.testplugin.plugin;
import com.mutour.testplugin.Plugin;
import com.mutour.testplugin.plugin.R;
import android.content.Context;
import android.view.View;
import android.widget.LinearLayout;
public class NumberPlugin implements Plugin {
    private static final String TAG = "NumberPlugin";
    private Context mContext;
    private View mView;
    private View viewNumber;
    /**
     * 必须有一个无参构造函数,否则无法用newInstance()获取句柄
     */
    public NumberPlugin() {
    }
    public void setContext(Context context) {
        mContext = context;
    }
    public NumberPlugin(Context context) {
        this();
        mContext = context;
    }
    @Override
    public void load() {
    }
    @Override
    public void show() {
        ((LinearLayout) mView).addView(viewNumber);
    }
    @Override
    public void hide() {
        if (mView != null)
            ((LinearLayout) mView).removeAllViews();
    }
    @Override
    public void create(View view) {
        mView = view;
        viewNumber = View.inflate(mContext, R.layout.activity_number_plugin,
                null);
    }
    @Override
    public void create(Context context, View view) {
        mContext = context;
        this.create(view);
    }
    @Override
    public View getView() {
        return viewNumber;
    }
}

7.编译工程,把bin目录中的classes.dex文件放入手机的sd卡里.本文中放在sd卡根目录中

8.编写主程序调用插件dex文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.mutour.testplugin;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.mutour.testplugin.plugin.QwertyPlugin;
import dalvik.system.DexClassLoader;
import android.os.Bundle;
import android.os.Environment;
import android.annotation.SuppressLint;
import android.app.ActionBar.LayoutParams;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
@SuppressLint("NewApi")
public class MainActivity extends Activity {
    Plugin mPlugin;
    private LinearLayout mLinearLayoutContainer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mLinearLayoutContainer = (LinearLayout) findViewById(R.id.LinearLayoutContainer);
        String filepath = Environment.getExternalStorageDirectory().toString()
                + File.separator + "classes.dex";
        DexClassLoader cl = new DexClassLoader(filepath, MainActivity.this
                .getDir("dex", 0).getAbsolutePath(), null, getClassLoader());
        Class libProviderClazz = null;
        Plugin plugin = null;
        try {
            Context pluginContext = createPackageContext(
                    "com.mutour.testplugin.plugin",
                    Context.CONTEXT_IGNORE_SECURITY);
            libProviderClazz = cl.loadClass("com.mutour.testplugin.plugin"
                    + ".NumberPlugin");
            plugin = (Plugin) libProviderClazz.newInstance();
            if (plugin != null) {
                switchPlugin(pluginContext, plugin);
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    private void switchPlugin(Context context, Plugin plugin) {
        if (mPlugin != null) {
            mPlugin.hide();
        }
        plugin.load();
        plugin.create(context, mLinearLayoutContainer);
        plugin.show();
        mPlugin = plugin;
    }
}

大功告成..............

其中有几个需要注意的地方

1..需要先获取dex的路径,使用DexClassLoader加载这个dex,然后使用包名和类名获取Class,然后使用newInstance获取句柄,把类型转换成Plugin

2.必须使用下面的方法获取插件包的Context,否则无法获取到插件包里的layout或其他资源

?
1
2
3
Context pluginContext = createPackageContext(
                    "com.mutour.testplugin.plugin",
                    Context.CONTEXT_IGNORE_SECURITY);

........................................................................................................................................

下面连接是该主程序和插件程序的代码..TestPlugin.rar是主程序 NumberPlugin.rar是插件程序

本方法是使用的dex方式,也可以使用apk方式安装插件.....

Android 实现简单的插件化模块化相关推荐

  1. android 程序开发的插件化

    本文为 博客园 黑暗伯爵 原创,转载请注明  http://hangxin1940.cnblogs.com 原文地址:android 程序开发的插件化 模块化方法 之一 框架已经放出: android ...

  2. Android 基于注解IOC组件化/模块化的架构实践

    当前参与的项目历史也很久远,第一行代码据说是写于2014年的某一天,那时Android用的ide还是Eclipse.那时Android还没有很好的架构指导(mvp.mvvm).那时Android最新的 ...

  3. Android 手写实现插件化换肤框架 兼容Android10 Android11

    目录 一.收集所有需要换肤的view及相关属性 二.统一为所有Activity设置工厂(兼容Android9以上) 三.加载皮肤包资源 四.处理支持库或者自定义view的换肤 五.处理状态栏换肤 六. ...

  4. Android热修复及插件化原理

    1.前言 热修复一直是这几年来很热门的话题,主流方案大致有两种,一种是微信Tinker的dex文件替换,另一种是阿里的Native层的方法替换.这里重点介绍Tinker的大致原理. 2.类加载机制 介 ...

  5. Android 热修复、插件化、双开基本原理

    最近几年,安卓热门技术中,有关热修复.插件化.双开等等技术应用的比较广泛.本文从最简单直接的一个例子入手,分析其中的技术原理和构建思路.有3个相关的基本知识点,java中的反射.设计模式中的代理模式. ...

  6. android开发模式之插件化开发

    一.简介 插件化开发是将整个app拆分成很多模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk(组件化的每个模块是个lib),最终打包的时候将宿主apk和插件apk分开或者联合打包.由宿主A ...

  7. android 插件化 模块化开发(apkplug)

    经过几个月断断续续的摸索开发,终于有了apkplug的第一个版本,将大部分的业余时间都用于研发这个东东说实话感觉挺累的,不过努力总算没有白费,目前插件平台功能基本还令我满意.在这里写下一个开发demo ...

  8. Android实战】DroidPlugin插件化应用分析

    简介 DroidPlugin 是360手机助手在Android系统上实现的一种新的插件机制:它可以在无需安装.修改的情况下运行APK文件,此机制对改进大型APP的架构,实现多团队协作开发具有一定的好处 ...

  9. Android插件化:从入门到放弃

    喜欢 | 作者 包建强 发布于 2016年7月14日. 估计阅读时间: 1 分钟 | 道AI风控.Serverless架构.EB级存储引擎,尽在ArchSummit!讨论 分享到:微博微信Facebo ...

最新文章

  1. 【译】 WebSocket 协议第十一章——IANA 注意事项(IANA Considerations)
  2. Google-Analytics 学习与思考
  3. android设置控件形状,Android控件自定义形状
  4. 【linux命令总结】——后续用到的内容持续补充和更新
  5. Spark: Structured + hive(Jdbc方式)卡死
  6. layui弹窗自适应变大_layui弹窗宽度固定高度自适应界面
  7. MATLAB学习笔记——数组
  8. oa系统源码 python_区块链技术基于springboot的办公oa系统实现源代码
  9. 【接力题典1800记录】定积分
  10. 电脑快捷方式变白原因及解决方法——血的教训呜呜呜
  11. Window系列 (一) — WindowManager 详解
  12. Qt 实现PC端网易云音乐界面
  13. Ubuntu grub recuse 修复方法
  14. 福寿园首席员工系列报道:一雕一琢 人生定格
  15. matlab中figure的坐标轴label、title、xticklabel的旋转
  16. mysql语句更新顺序_MySQL的Update语句Set顺序问题
  17. 微信小程序预览 word、excel、ppt、pdf 等文件
  18. ground truth解释
  19. 《精妙的IT》免费公开课
  20. uml通信图画法_UML通信图参考.ppt

热门文章

  1. 【Kotlin】Kotlin 自定义组件 ( 自定义 View | 自定义 SurfaceView )
  2. 【C++ 语言】Visual Studio 配置 FFMPEG 开发环境 ( VS2019 CMake 环境安装 | 下载 FFMPEG 开发包 | 配置 FFMPEG )
  3. 【Android 系统开发】Android JNI 之 JNIEnv 解析
  4. 什么样的对象会进入老年代
  5. IDEA----破解
  6. BZOJ3261 最大异或和 解题报告(可持久化Trie树)
  7. PC问题-该虚拟机似乎正在使用中
  8. JSP/SERVLET(5)——JSP页面单选按钮操作
  9. 使用beanUtils操纵bean的属性
  10. ROS学习(十二):ROS URDF-model_state