android跨进程加载布局(通过反射加载资源)

android中可以通过反射加载另一个进程的资源,可以通过AIDL传递资源包名和资源名称,通过包名和资源名称就可以加载资源来使用。下面介绍跨进程加载layout布局的流程。
服务端新建AIDL文件,只有addReflectionView和removeReflectionView添加和移除反射View的接口。

// IViewReflectionManager.aidl
package com.example.viewreflectiontest;

import android.os.Bundle;

interface IViewReflectionManager {

    void addReflectionView(in Bundle bundle);

    void removeReflectionView();
}

服务端通过Bundle获取客户端传入的包名和布局名称,然后通过反射资源id得到客户端的布局id,有了这个id就可以加载到布局View实例。

private final IViewReflectionManager mBinder = new IViewReflectionManager.Stub() {
        @Override
        public void addReflectionView(Bundle bundle) throws RemoteException {
            String packageName = bundle.getString("package", null);
            String layout = bundle.getString("layout", null);
            try {
                Context packageContext = createPackageContext(packageName,
                        Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
                Class<?> cls = packageContext.getClassLoader().loadClass(packageName + ".R"); // 获得目标apk的R类
                int layoutId = getResourceIdByName(cls, "layout", layout);
                mView = LayoutInflater.from(packageContext).inflate(layoutId, null);
                mUIHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (!mIsWindowAdd) {
                            mIsWindowAdd = true;
                            mWindowManager.addView(mView, mLayoutParams);
                        }
                    }
                });
            } catch (PackageManager.NameNotFoundException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void removeReflectionView() throws RemoteException {
            mUIHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (mIsWindowAdd) {
                        mIsWindowAdd = false;
                        mWindowManager.removeView(mView);
                    }
                }
            });
        }
    };

通过反射获取不同进程的资源文件方法getResourceIdByName如下:

    private int getResourceIdByName(Class<?> clazz, String className, String name) {
        int id = 0;
        try {

            Class<?>[] classes = clazz.getClasses(); // 获取R.java里的所有静态内部类
            Class<?> desireClass = null;

            for (Class<?> aClass : classes) {
                if (aClass.getName().split("\\$")[1].equals(className)) { // 查找指定的静态内部类
                    desireClass = aClass;
                    break;
                }
            }
            if (desireClass != null) {
                id = desireClass.getField(name).getInt(desireClass); // 从指定的静态内部类获得资源编号
            }
        } catch (IllegalArgumentException | SecurityException | IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();
        }
        return id;
    }

客户端绑定服务端,调用接口即可动态让服务端加载客户端的布局。

Intent intent = new Intent("com.example.viewreflectiontest.action");
        intent.setPackage("com.example.viewreflectiontest");
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        btnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mIViewReflectionManager != null) {
                    Bundle bundle = new Bundle();
                    bundle.putString("package", "com.example.myapplication");
                    bundle.putString("layout", "layout_reflection");
                    try {
                        mIViewReflectionManager.addReflectionView(bundle);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        btnRemove.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mIViewReflectionManager != null) {
                    try {
                        mIViewReflectionManager.removeReflectionView();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

需要注意赋予服务端悬浮窗的权限才可正常添加窗口。
最终效果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

言并肃

感谢大哥支持!您的鼓励是我动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值