Shizuku开发——通过Shizuku使app拥有shell权限

安装Shizuku

该方案通过Shizuku给自己的软件授予adb shell权限,但前提是Shizuku必须拥有adb shell权限,具体可以参考

Shizuku用户手册:
https://shizuku.rikka.app/zh-hans/guide/setup/

演示APP开源地址:
https://github.com/xxinPro/AdbShellUtils
演示APP下载地址:
https://lxx6.lanzouq.com/i5Hxp22szuwf

引入依赖

可以选择引入maven central中的远程依赖

    def shizuku_version = "13.1.5"
    implementation "dev.rikka.shizuku:api:$shizuku_version"
    implementation "dev.rikka.shizuku:provider:$shizuku_version"

亦或者引入Shizuku-API中对应的模块

    implementation project(':api')
    implementation project(':provider')

添加支持

在清单文件中加入如下代码

<provider
    android:name="rikka.shizuku.ShizukuProvider"
    android:authorities="${applicationId}.shizuku"
    android:multiprocess="false"
    android:enabled="true"
    android:exported="true"
    android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />

进行完这一步,已经可以发现在Shizuku的应用管理中出现了目标app

判断权限

判断当前app是否拥有shizuku中的adb shell权限

/**
 * 判断是否拥有shizuku adb shell权限
 */
private boolean checkPermission() {
    return Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED;
}

动态申请权限

动态申请Shizuku adb shell权限

    private void requestShizukuPermission() {
        boolean checked = checkPermission();
        if (checked) {
            Toast.makeText(this, "已拥有权限", Toast.LENGTH_SHORT).show();
            return;
        }

        if (Shizuku.isPreV11()) {
            Toast.makeText(this, "当前shizuku版本不支持动态申请", Toast.LENGTH_SHORT).show();
            return;
        }

        // 动态申请权限
        Shizuku.requestPermission(MainActivity.PERMISSION_CODE);
    }

Shizuku授权监听

    private final Shizuku.OnRequestPermissionResultListener onRequestPermissionResultListener = new Shizuku.OnRequestPermissionResultListener() {
        @Override
        public void onRequestPermissionResult(int requestCode, int grantResult) {
            boolean granted = grantResult == PackageManager.PERMISSION_GRANTED;
            if (granted) {
                Toast.makeText(MainActivity.this, "授权成功", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "授权失败", Toast.LENGTH_SHORT).show();
            }
        }
    };

授权监听需要手动添加

// 添加权限申请监听
Shizuku.addRequestPermissionResultListener(onRequestPermissionResultListener);

Activity销毁时移除授权监听

// 移除权限申请监听
Shizuku.removeRequestPermissionResultListener(onRequestPermissionResultListener);

Shizuku状态监听

Shiziku服务被启动时会调用该监听,例如app运行期间,通过电脑abd命令启动Shizuku服务,将会立即调用该监听;此外,在app启动时倘若Shiziku服务处于启动状态,也会调用该监听

// Shiziku服务启动时调用该监听
Shizuku.addBinderReceivedListenerSticky(onBinderReceivedListener);

private final Shizuku.OnBinderReceivedListener onBinderReceivedListener = new Shizuku.OnBinderReceivedListener() {
    @Override
    public void onBinderReceived() {
        Toast.makeText(MainActivity.this, "Shizuku服务启动", Toast.LENGTH_SHORT).show();
    }
};

Shiziku服务被终止时调用该监听,若app运行期间,Shizuku服务异常终止或手动停止,将会立即调用该监听

// Shiziku服务终止时调用该监听
Shizuku.addBinderDeadListener(onBinderDeadListener);

private final Shizuku.OnBinderDeadListener onBinderDeadListener = new Shizuku.OnBinderDeadListener() {
    @Override
    public void onBinderDead() {
        Toast.makeText(MainActivity.this, "Shizuku服务终止", Toast.LENGTH_SHORT).show();
    }
};

Activity销毁时移除监听

Shizuku.removeBinderReceivedListener(onBinderReceivedListener);
Shizuku.removeBinderDeadListener(onBinderDeadListener);

执行命令

appgradle文件中添加如下配置

android {
    buildFeatures {
        buildConfig true    // 开启BuildConfig类的生成
        aidl true           // 启用aidl
    }
}

main包下添加aidl目录,其与javasrc目录同级,在aidl目录的指定包下创建IUserService.aidl

package xyz.xxin.adbshellutils;

interface IUserService {

    /**
     * Shizuku服务端定义的销毁方法
     */
    void destroy() = 16777114;

    /**
     * 自定义的退出方法
     */
    void exit() = 1;

    /**
     * 执行命令
     */
    String exec(String command) = 2;
}

java目录的指定包下创建UserService.java,该服务继承IUserService.Stub,无需在app清单文件中注册

public class UserService extends IUserService.Stub {

    @Override
    public void destroy() throws RemoteException {
    }

    @Override
    public void exit() throws RemoteException {
    }

    @Override
    public String exec(String command) throws RemoteException {
    }
}

UserService.java中实现IUserService.aidl中的方法

public class UserService extends IUserService.Stub {

    @Override
    public void destroy() throws RemoteException {
        System.exit(0);
    }

    @Override
    public void exit() throws RemoteException {
        destroy();
    }

    @Override
    public String exec(String command) throws RemoteException {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            // 执行shell命令
            Process process = Runtime.getRuntime().exec(command);
            // 读取执行结果
            InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line).append("\n");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return stringBuilder.toString();
    }
}

绑定服务

Shizuku.bindUserService(userServiceArgs, serviceConnection);

// 指定服务的各项参数
private final Shizuku.UserServiceArgs userServiceArgs =
        new Shizuku.UserServiceArgs(new ComponentName(BuildConfig.APPLICATION_ID, UserService.class.getName()))
                .daemon(false)
                .processNameSuffix("adb_service")
                .debuggable(BuildConfig.DEBUG)
                .version(BuildConfig.VERSION_CODE);

// 建立服务连接通道
private final ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        Toast.makeText(MainActivity.this, "服务连接成功", Toast.LENGTH_SHORT).show();

        if (iBinder != null && iBinder.pingBinder()) {
            IUserService iUserService = IUserService.Stub.asInterface(iBinder);
            try {
                // 执行shell命令
                iUserService.exec("ls");
            } catch (RemoteException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        Toast.makeText(MainActivity.this, "服务连接断开", Toast.LENGTH_SHORT).show();
    }
};

解绑服务

Shizuku.unbindUserService(userServiceArgs, serviceConnection, true);

演示项目

演示APP开源地址:
https://github.com/xxinPro/AdbShellUtils
演示APP下载地址:
https://lxx6.lanzouq.com/i5Hxp22szuwf
提取码:0000

Shizuku开源地址:
https://github.com/RikkaApps/Shizuku

Shizuku开发指南:
https://github.com/RikkaApps/Shizuku-API

aidl参考:
Android 接口定义语言 (AIDL)
跟着例子,来整一遍AIDL吧

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值