Android P+通过反射调用系统API实现高级功能

通过反射调用系统API已经不算是什么新鲜事了,不过在Android P之后,Google对隐藏API的限制更加严格,不能再直接通过反射去调用系统API了,必须通过特定手段先打开隐藏API的限制,具体原理可以移步另一种绕过 Android P以上非公开API限制的办法,这里我们只讲实战用法。

1. 打开隐藏API

1.1 导入FreeReflection包

新建AS项目后,打开项目的settings.gradle,在repositories闭包中添加

maven { url 'https://jitpack.io' }

然后在具体module的build.gradle中的dependencies中加入以下依赖

implementation 'com.github.tiann:FreeReflection:3.1.0'

1.2 打开隐藏API

在moudle中添加一个继承自Application的类(有关Application的相关信息请自行查阅相关文档)并在AndroidManifest.xml中注册。
例:
新建的类

public class ShellApplication extends Application {
   ......
}

AndroidManifest.xml中注册

<application
        android:name=".ShellApplication"
        ......

然后需要重写Application类的attachBaseContext方法,并在这个方法中调用FreeReflection库打开隐藏API

// ignore other import
import me.weishu.reflection.Reflection;
public class ShellApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        Reflection.unseal(base);
    }
}

至此,隐藏API就打开了,我们就能够像之前一样使用反射了

2. 反射系统服务并调用相应方法

不同Android版本,系统服务的架构可能存在差别,需要根据具体版本进行处理,思路基本相同,这里以Android Q为例,反射ActivityTaskManager,注意ActivityTaskManager是在Android Q中加入的,低版本不适用。
在开始反射之前,我们需要先找到我们想反射的方法是属于哪一个系统服务里面的,思路比较简单,跟流程,这里我需要反射的是startActivityAndWait方法,这个方法是am命令带-W参数启动应用的实现,调用流程是Am->ActivityManagerService->ActivityTaskManagerService
但是我们知道,系统Service都是通过binder去调用的,这里ActivityTaskManagerSericeIActivityTaskManager进行调用的,并且由ActivityTaskManager进行代理,在ActivityTaskManager中使用单例模式保存了IActivityTaskManager的实例,并且提供了一个静态方法getService()用于获取该实例(其实Android其他的系统服务都在对应的xxxManager中提供了getService()方法去获取对应的实例),这就是我们着手的地方(反射不到实例就毫无用处)
代码如下:

        Class atmClazz = Class.forName("android.app.ActivityTaskManager");
        @SuppressLint("BlockedPrivateApi")
        Method methodGetService = atmClazz.getDeclaredMethod("getService");
        methodGetService.setAccessible(true);
        // atmObj即IActivityTaskManager
        Object atmObj = methodGetService.invoke(null);

获取到IActivityTaskManager之后就是反射对应的方法了,例如我需要反射startActivityAndWait方法,那么对应代码如下:

        Class singletonClazz = Class.forName("android.app.IActivityTaskManager");
        Class clazzIApplicationThread = Class.forName("android.app.IApplicationThread");
        Class clazzProfileInfo = Class.forName("android.app.ProfilerInfo");

        Method startMethod = singletonClazz.getDeclaredMethod("startActivityAndWait",
                clazzIApplicationThread,
                String.class,
                Intent.class,
                String.class,
                IBinder.class,
                String.class,
                int.class,
                int.class,
                clazzProfileInfo,
                Bundle.class,
                int.class
        );
        startMethod.setAccessible(true);
        
        startMethod.invoke(atmObj,
                null, // caller
                context.getPackageName(), // call package 这里context传入ApplicationContext即可
                intent, // intent -> ActivityManagerShellCommand -> MakeIntent
                // intent 可以通过context.getPackageManager().getLaunchIntentForPackage("com.xxx.xxx")获取
                null, // resolveType
                null, // resultInfo
                null, // resultWho
                0, // request code
                0, // flags
                null, // profile info
                null,
                0 // userId
        );
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值