android app_process 反射实现广播

背景

因为Scrcpy 目前版本不支持输入法,自己的协同工具为了方便自己使用,增加直接在windows用输入法,而不是直接Keycode方式,这样子体验好很多。

使用输入法

我这里直接用了网上开源 ADBKeyBoard 解决 不能支持uncode编码问题(因为adb input 不支持unicode,如果直接反射也是不可以使用的【这样子中文就有很大问题】),但这个实现用广播,原来scrcpy没有反射广播,于是我看 adb shell am broadcast -a 对应在android cmd 里面目录代码,看他用了broadcastIntent 方法

反射 Android12 broadcastIntent

public void sendBroadcast(Intent intent){
        //IntentReceiver receiver = new IntentReceiver();

        try {
            Class cls = Class.forName("android.app.IApplicationThread");
            //   public int broadcastIntent(IApplicationThread caller,
            //2352            Intent intent, String resolvedType,  IIntentReceiver resultTo,
            //2353            int resultCode, String resultData, Bundle map,
            //2354            String requiredPermission, int appOp, boolean serialized,
            //2355            boolean sticky, int userId)
            Method method = manager.getClass().getMethod("broadcastIntent",cls, Intent.class, String.class, IIntentReceiver.class, int.class, String.class,
                    Bundle.class, String[].class, int.class, Bundle.class,boolean.class, boolean.class, int.class);

            Object objString = method.invoke(manager, null,intent, null, null, 0, null, null, null, -1, null, true, false, android.os.Process.myUid()/100000);
            Ln.i("调用完成:" + objString.toString() );
        } catch (ClassNotFoundException e) {
            Ln.e("notfound" + e.toString());
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            Ln.e("InvocationTargetException" + e.toString());
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            Ln.e("NoSuchMethodException" + e.toString());
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            Ln.e("IllegalAccessException" + e.toString());
            e.printStackTrace();
        }
        //manager.getClass().getMethod()
        /*this.broadcastIntent(null, intent, null, null, 0, null, null, null, true, false,
                Binder.getOrigCallingUser());*/
        //receiver.waitForFinish();
    }

这个参数挺多的,不能版本参数不一样,所以要看android的源代码,这样子我在windows 启动SDL 输入法
响应input

        if (event.type == SDL_TEXTINPUT) {
            HandleInput(event); //直接发送网络请求到android里面,然后调用反射发送广播
            continue;
        }

这样子就是简单实现app_process 反射广播

难点

  1. 一开始不不知道怎么弄,所以要看adb 里面发送广播的实现,scrcpy 实现本质也是看android adb源代码,所以协同工具本质就是自己实现一个adb在 app_process,同时app_process 启动进程使用shell权限,所以能反射一些高级命令,模拟点击就是具有adb权限,如果apk 具备这样子权限,那么也可以直接反射调用点击命令。
  2. 参数好多,如果不熟练很容易反射报错。今天我实现反射shellCommand 命令(高版本android 实现命令新代码),实例化带一个参数报错,结果我传入null,默认转换空参数数组,导致实例化失败。。
  3. 不同android版本反射参数有区别,我这里只是反射自己用的,所以要注意。

补充

后面可以说一下Scrcpy 开发思路,同时重点说一下服务怎么反射