首页 > 其他分享 >Android插件化的一种方案

Android插件化的一种方案

时间:2024-05-25 16:57:03浏览次数:24  
标签:方案 插件 void intent Override Android null super public

思路:打开插件包里边的activity时 统一都用 一个ProxyActivity作为代理  

1、首先宿主APP提供ProxyActivity,当宿主需要打开插件包中的Activity时,一律是启动的ProxyActivity,

在启动ProxyActivity的intent中携带我们真正需要去打开的插件包中Activity的类全名。

public class ProxyActivity extends Activity {
    private IPluginActivity mPluginActivity;//用来接收插件包所有Activity的接口对象

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String className = getIntent().getStringExtra("className");
        try {
            Class activityClass = getClassLoader().loadClass(className);
            Constructor constructor = activityClass.getConstructor(new Class[]{});
            Object instance = constructor.newInstance(new Object[]{});
            mPluginActivity = (PluginBaseActivity) instance;
            mPluginActivity.onCreate(savedInstanceState);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        mPluginActivity.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mPluginActivity.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mPluginActivity.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
        mPluginActivity.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPluginActivity.onDestroy();
    }
}

  

在Activity中有很重要的两个回调方法:

@Override
    public ClassLoader getClassLoader() {
        return PluginManager.getInstance().getPluginBean().getDexClassLoader();
    }

    @Override
    public Resources getResources() {
        return PluginManager.getInstance().getPluginBean().getResources();
    }

  

  • getClassLoader返回的是ClassLoader 对象,Activity内部在使用反射new对象时,都会去使用这里返回的ClassLoader 来进行反射,所以我们ProxyActivity中需要提供的应该是当前加载插件包对应的ClassLoader 。
  • getResources返回的是Resources 对象,Activity内部在使用资源文件时,都会去使用这里返回的Resources 来获取资源,所以我们ProxyActivity中需要提供的应该是当前加载插件包对应的Resources 。
  我们宿主APP提供了一个ProxyActivity,我们打开插件包Activity其实都是打开的ProxyActivity,只不过ProxyActivity不做任何其他事情,只负责实例化插件包Activity,并且将ProxyActivity中的所有事  件驱动通知给插件包Activity,也就是ProxyActivity调用了插件包Activity中的代码来实现插件包要实现的功能。   获得classLoader和resource:
            File pluginFile;//插件包文件
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageArchiveInfo(pluginFile.getAbsolutePath(), PackageManager.GET_ACTIVITIES);

            File dexOutFile = context.getDir("dex", Context.MODE_PRIVATE);
            DexClassLoader dexClassLoader = new DexClassLoader(pluginFile.getAbsolutePath(), dexOutFile.getAbsolutePath()
                    , null, context.getClassLoader());

            AssetManager assetManager = AssetManager.class.newInstance();
            Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
            addAssetPath.invoke(assetManager, pluginFile.getAbsolutePath());
            Resources resources = new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());

  

PackageInfo 可以获取插件包manifest中所有注册了的组件信息,例如主Activity的全类名的获取为:

 
packageInfo.activities[0].name

  

下面是完整的

public abstract class PluginBaseActivity extends AppCompatActivity implements IPluginActivity {

    protected Activity that;//宿主Activity

    @Override
    public void attach(ProxyActivity proxyActivity) {
        if (that != null)
            throw new RuntimeException("Plugin's activity already has been attached!");
        this.that = proxyActivity;
        attachBaseContext(proxyActivity);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        if (that == null) {
            super.onCreate(savedInstanceState);
        }
    }

    @Override
    public void onStart() {
        if (that == null) {
            super.onStart();
        }
    }

    @Override
    public void onResume() {
        if (that == null) {
            super.onResume();
        }
    }

    @Override
    public void onPause() {
        if (that == null) {
            super.onPause();
        }
    }

    @Override
    public void onStop() {
        if (that == null) {
            super.onStop();
        }
    }

    @Override
    public void onDestroy() {
        if (that == null) {
            super.onDestroy();
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        if (that == null) {
            super.onSaveInstanceState(outState);
        }
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        if (that == null) {
            super.onRestoreInstanceState(savedInstanceState);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (that == null) {
            return super.onTouchEvent(event);
        }
        return false;
    }

    @Override
    public void onBackPressed() {
        if (that == null) {
            super.onBackPressed();
        }
    }

    @Override
    public void setContentView(View view) {
        if (that == null) {
            super.setContentView(view);
        } else {
            that.setContentView(view);
        }
    }

    @Override
    public void setContentView(int layoutResID) {
        if (that == null) {
            super.setContentView(layoutResID);
        } else {
            that.setContentView(layoutResID);
        }
    }

    @Override
    public void startActivity(Intent intent) {
        if (that == null) {
            super.startActivity(intent);
        } else {//篡改intent打开页面为proxyActivity
            intent.putExtra("className", intent.getComponent().getClassName());
            intent.setClassName(intent.getComponent().getPackageName(), ProxyActivity.class.getName());
            that.startActivity(intent);
        }
    }

    @Override
    public ComponentName startService(Intent intent) {
        if (that == null) {
            return super.startService(intent);
        } else {
            intent.putExtra("className", intent.getComponent().getClassName());
            intent.setClassName(intent.getComponent().getPackageName(), ProxyService.class.getName());
            return that.startService(intent);
        }
    }

    @Override
    public View findViewById(int id) {
        if (that == null) {
            return super.findViewById(id);
        } else {
            return that.findViewById(id);
        }
    }


    @Override
    public Intent getIntent() {
        if (that == null) {
            return super.getIntent();
        } else {
            return that.getIntent();
        }
    }


    @Override
    public Window getWindow() {
        if (that == null) {
            return super.getWindow();
        } else {
            return that.getWindow();
        }
    }

    @Override
    public WindowManager getWindowManager() {
        if (that == null) {
            return super.getWindowManager();
        } else {
            return that.getWindowManager();
        }
    }
}

  

public interface IPluginActivity {
    void attach(ProxyActivity proxyActivity);

    void onCreate(@Nullable Bundle savedInstanceState);

    void onStart();


    void onResume();

    void onPause();

    void onStop();

    void onDestroy();

    void onSaveInstanceState(Bundle outState);

    void onRestoreInstanceState(Bundle savedInstanceState);

    boolean onTouchEvent(MotionEvent event);

    void onBackPressed();

    void setContentView(View view);

    void setContentView(int layoutResID);

    void startActivity(Intent intent);

    ComponentName startService(Intent intent);

    View findViewById(int id);


    Intent getIntent();


    Window getWindow();

    WindowManager getWindowManager();
}

  以上步骤实则每次新打开的插件里的页面其实都是ProxyActivity 做的代理

   

标签:方案,插件,void,intent,Override,Android,null,super,public
From: https://www.cnblogs.com/bimingcong/p/18212602

相关文章

  • Android14音频进阶之AAOS之CarAudioService如何衔接AudioControl服务(七十四)
    简介:CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!优质专栏:Audio工程师进阶系列【原创干货持续更新中……】......
  • Android11 系统修改 AOSP输入法的默认输入键盘布局
    系统自带的输入法源码在packages\inputmethods\目录,像谷歌输入法和谷歌拼音输入法的源码都是在这里!系统的默认输入法,修改掉其系统的语言,输入法键盘布局也会改变!因为系统中的Android键盘(AOSP)有个语言设置选项,里面默认的是“使用系统语言”,现在客户要求关闭默认“使用系统语言......
  • Android编译命令
    AOSP原生单编命令(所有安卓衍生项目都支持)Settings模块单编:cdLINUX/androidsourcebuild/envsetup.sh//orlunch然后自己选择编译项lunch#mmm比mm编译速度快mmmpackages/app/Settingsormmpackages/app/SettingsormakeSettings代码编译编译指令解释m......
  • AP5192 DC-DC降压恒流三路RGB单亮 LED车灯方案
    1,资料来源:深圳市世微半导体有限公司2,产品描述AP5192是一款PWM工作模式,高效率、外围简单、内置功率MOS管,适用于4.5-100V输入的高精度降压LED恒流驱动芯片。电流1.5A。AP5192可实现线性调光和PWM调光,线性调光脚有效电压范围0.55-2.6V.AP5192工作频率可以通过RT外部电阻编程......
  • AP5127 DC-DC降压恒流IC 输入12-24 输出9V 2A LED车灯方案
    AP5127是一款PWM工作模式,高效率、外围简单、内置功率管,适用于12-100V输入的高精度降压LED恒流驱动芯片。输出功率可达25W,电流2.5A。AP5127可实现全亮/半亮功能切换,通过MODE切换:全亮/半亮/循环模式。AP5127工作频率固定在140KHZ,同时内置抖频电路,可以降低对其......
  • 世微 AP5191 降压恒流LED车灯 12-80V 9V5A电源驱动方案
    AP5191是一款PWM工作模式,高效率、外围简单、内置功率MOS管,适用于4.5-150V输入的高精度降压LED恒流驱动芯片。输出功率150W,电流6A。AP5191可实现线性调光和PWM调光,线性调光脚有效电压范围0.55-2.6V.AP5191工作频率可以通过RT外部电阻编程来设定,同时内置抖频电路,可以降低......
  • Android+SQLiteOpenHelper实现登录记住密码小案例
    实现自动登录,在数据库中存 注册的账号信息packagecom.example.databases_text;importandroid.content.Context;importandroid.content.SharedPreferences;importandroid.os.Bundle;importandroid.text.TextUtils;importandroid.util.Log;importandroid.view.Vi......
  • 抄表系统厂家:创新技术与解决方案的引领者
    1.技术创新:智能化抄表系统的兴起随着时代的发展,传统式手动抄水表方法已慢慢被智能化抄表系统所替代。抄表系统厂家在这一领域扮演了重要角色,她们产品研发智能抄表系统运用物联网技术、大数据和云计算等先进技术,完成了远程控制智能抄表,大大的提高了效率并降低了人为失误。这类......
  • 基于STM32四轴飞行器电路方案设计
    **单片机设计介绍,基于STM32四轴飞行器电路方案设计文章目录一概要二、功能设计设计思路三、软件设计原理图五、程序六、文章目录一概要  基于STM32的四轴飞行器电路方案设计概要如下:一、引言本设计采用STM32作为核心处理器,结合现代电子技术和传感器技......
  • 视频号直播间自动回复评论插件-循环发送话术-视频号直播机器人
    在使用视频号直播的时候,我们可以登录到视频号直播中控台,利用我开发的插件实现自动回复评论和循环发送评论原理:MutationObserver机制MouseEvent事件和dispatchEvent使用方法:开启直播后,登录到视频号直播后台https://channels.weixin.qq.com/platform/live/home开启插件:点击......