【Android 插件化】Hook 插件化框架总结 ( 插件包管理 | Hook Activity 启动流程 | Hook 插件包资源加载 ) ★★★(二)

简介: 【Android 插件化】Hook 插件化框架总结 ( 插件包管理 | Hook Activity 启动流程 | Hook 插件包资源加载 ) ★★★(二)

3、宿主 Activity 界面


在该 Activity 界面中 , 主要用于跳转到插件 Activity 中 ;


package com.example.host;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "宿主应用 MainActivity onCreate");
        // 反射插件包中的 com.example.plugin.MainActivity
        Class<?> clazz = null;
        try {
            clazz = Class.forName("com.example.plugin.MainActivity");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Method method = null;
        try {
            method = clazz.getDeclaredMethod("log");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        try {
            // 执行 com.example.plugin.MainActivity 的 log 方法
            method.invoke(clazz.newInstance());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        // 设置按钮点击事件
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 启动插件包中的 Activity
                Intent pluginIntent = new Intent();
                pluginIntent.setComponent(new ComponentName("com.example.plugin",
                        "com.example.plugin.MainActivity"));
                pluginIntent.putExtra("isPlugin", true);
                startActivity(pluginIntent);
            }
        });
    }
}





三、插件化框架





1、反射工具类


使用反射工具类 , 能快速开发反射相关功能 ;


package kim.hsl.plugin;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
 * 封装反射相关逻辑的工具类
 * 该封装类会维持链式调用
 */
public class Reflector {
    /**
     * 反射的类型
     */
    private Class<?> mClass;
    /**
     * 反射针对的实例对象
     * 如获取 Object 某个字段的值
     */
    private Object mCaller;
    /**
     * 反射的字段
     */
    private Field mField;
    /**
     * 反射的方法
     */
    private Method mMethod;
    /**
     * 反射某个类的入口方法
     *
     * @param type 要反射的类
     * @return
     */
    public static Reflector on(Class<?> type) {
        Reflector reflector = new Reflector();
        reflector.mClass = type;
        return reflector;
    }
    /**
     * 反射某个类的入口方法
     *
     * @param className 要反射的类名
     * @return
     */
    public static Reflector on(String className) {
        try {
            return on(Class.forName(className));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 反射某个类的入口方法
     *
     * @param object 反射类对应的实例对象
     * @return
     */
    public static Reflector on(Object object) {
        return on(object.getClass()).with(object);
    }
    /**
     * 设置反射对应的实例对象
     *
     * @param object
     * @return
     */
    public Reflector with(Object object) {
        mCaller = object;
        return this;
    }
    /**
     * 创建 mClass 类型的实例对象
     * @param <T>
     * @return
     * @throws Exception
     */
    public <T> T newInstance() {
        try {
            return (T) mClass.newInstance();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        } catch (InstantiationException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 反射类中的某个字段
     *
     * @param name 要反射的字段名称
     * @return
     */
    public Reflector field(String name) {
        mField = findField(name);
        mField.setAccessible(true);
        return this;
    }
    /**
     * 查找字段名称
     *      首先在本类中查找
     *          如果找到直接返回字段
     *          如果在本类中没有找到 , 就去遍历它的父类 , 尝试在父类中查找该字段
     *              如果有父类 , 则在父类中查找
     *                  如果在父类中找到 , 返回该字段
     *                  如果在父类中没有找到 , 则返回空
     *              如果没有父类 , 返回空
     *
     * 尽量传具体的正确的类 , 不要传子类
     * @param fieldName
     * @return
     */
    private Field findField(String fieldName) {
        try {
            // 首先在本类中查找 , 如果找到直接返回字段
            return mClass.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            // 如果在本类中没有找到 , 就去遍历它的父类 , 尝试在父类中查找该字段
            for (Class<?> clazz = mClass; clazz != null; clazz = clazz.getSuperclass()) {
                try {
                    // 如果在父类中找到 , 返回该字段
                    return clazz.getDeclaredField(fieldName);
                } catch (NoSuchFieldException ex) {
                    // 如果在父类中没有找到 , 则返回空
                    return null;
                }
            }
            // 如果没有父类, 则返回空
            return null;
        }
    }
    /**
     * 获取 mCaller 对象中的 mField 属性值
     *
     * @return
     */
    public Object get() {
        try {
            return mField.get(mCaller);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 设置 mCaller 对象中的 mField 属性值
     *
     * @param value
     * @return 链式调用 , 返回 Reflector
     */
    public Reflector set(Object value) {
        try {
            mField.set(mCaller, value);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return this;
    }
    /**
     * 反射类中的某个方法
     *
     * @param name
     * @param args
     * @return
     */
    public Reflector method(String name, Class<?>... args) {
        mMethod = findMethod(name, args);
        mMethod.setAccessible(true);
        return this;
    }
    /**
     * 根据方法名 和 参数名称 , 查找 Method 方法
     *      首先在本类中查找
     *          如果找到直接返回字段
     *          如果在本类中没有找到 , 就去遍历它的父类 , 尝试在父类中查找该字段
     *              如果有父类 , 则在父类中查找
     *                  如果在父类中找到 , 返回该字段
     *                  如果在父类中没有找到 , 则返回空
     *              如果没有父类 , 返回空
     *
     * 尽量传具体的正确的类 , 不要传子类
     * @param name
     * @param args
     * @return
     */
    private Method findMethod(String name, Class<?>... args) {
        try {
            // 首先在本类中查找 , 如果找到直接返回方法
            return mClass.getDeclaredMethod(name, args);
        } catch (NoSuchMethodException e) {
            // 如果在本类中没有找到 , 就去遍历它的父类 , 尝试在父类中查找该方法
            for (Class<?> cls = mClass; cls != null; cls = cls.getSuperclass()) {
                try {
                    // 如果在父类中找到 , 返回该字段
                    return cls.getDeclaredMethod(name);
                } catch (NoSuchMethodException ex) {
                    // 如果在父类中没有找到 , 则返回空
                    return null;
                }
            }
            // 如果没有父类, 则返回空
            return null;
        }
    }
    /**
     * 调用 mCaller 的 mMethod 方法
     *
     * @param args
     * @param <T>
     * @return
     */
    public <T> T call(Object... args) {
        try {
            return (T) mMethod.invoke(mCaller, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            return null;
        }
    }
}


目录
相关文章
|
2月前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
83 6
|
2月前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
Android面试高频知识点(4) 详解Activity的启动流程
27 3
|
2月前
|
缓存 前端开发 Android开发
Android实战之如何截取Activity或者Fragment的内容?
本文首发于公众号“AntDream”,介绍了如何在Android中截取Activity或Fragment的屏幕内容并保存为图片。包括截取整个Activity、特定控件或区域的方法,以及处理包含RecyclerView的复杂情况。
19 3
|
2月前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
18 0
|
Android开发
【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )(三)
【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )(三)
110 0
|
Android开发
【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )(二)
【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )(二)
186 0
|
Java API Android开发
【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )(一)
【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )(一)
153 0
|
8天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
13天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
15天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。