安装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);
执行命令
在app
级gradle
文件中添加如下配置
android {
buildFeatures {
buildConfig true // 开启BuildConfig类的生成
aidl true // 启用aidl
}
}
在main
包下添加aidl
目录,其与java
、src
目录同级,在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吧