Shizuku API 使用教程
项目配置
要使用 Shizuku,首先需要在项目中完成基础配置。以下是关键步骤:
-
添加依赖:在项目级的
build.gradle.kts
中引入 Shizuku 的 API 和 Provider 库dependencies { implementation("dev.rikka.shizuku:provider:${latest_version}") implementation("dev.rikka.shizuku:api:${latest_version}") }
最新版本依赖可在Shizuku 官方仓库 查看
-
启用 AIDL:在刚刚的
build.gradle.kts
中在buildFeatures
开启 AIDL 支持android { ... buildFeatures { aidl = true // 启用 AIDL ... } ... }
-
配置 Manifest:添加 Shizuku Provider
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> ... <application ... > ... <provider android:name="rikka.shizuku.ShizukuProvider" android:authorities="${applicationId}.shizuku" android:enabled="true" android:exported="true" android:multiprocess="false" android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" /> </application> </manifest>
直接复制
provider
块即可
AIDL 的作用: AIDL(Android Interface Definition Language)是 Shizuku 的核心通信机制,用于定义客户端与特权进程之间的接口,进而通过特权进程代理运行代码。通过自定义 AIDL 文件,你可以灵活设计需要的功能。
定义 AIDL 接口
目录创建
app/
├── src/
│ ├── main/
│ │ ├── aidl/com/.../...
│ │ ├── java/com/.../...
│ │ ├── res/...
│ │ ├── AndroidManifest.xml
像这样创建一个和 java 资源同级、包名相同的文件夹并创建这些 AIDL 文件
核心接口设计
-
IUserService.aidl
:定义核心服务接口,如执行 Shell 命令、退出服务等。package com.niki.cmd; import com.niki.cmd.ExecResult; interface IUserService { // 销毁服务 void destroy() = 16777114; // 固定的方法编号, 由 Shizuku 规定 // 自定义方法 void exit() = 1; // 执行 shell 命令 ExecResult exec(String command) = 2; // 可以添加更多自定义方法, 最后要自己实现 }
-
ExecResult.aidl
(示例):自定义可序列化的数据结构,用于返回命令执行结果(如标准输出、错误输出和退出码)package com.niki.cmd; parcelable ExecResult { String stdout; String stderr; int exitCode; }
AIDL 使用注意
AIDL parcelable
编译出来的对应 java 类似乎不能直接调用有参构造函数,所以赋值操作可以这样写:
val result = ExecResult().apply {
stdout = ""
stderr = ""
exitCode = 0
}
这个示例通过AIDL接口,用shizuku
特权进程代理运行shell
命令
实现 UserService
UserService 的核心逻辑
UserService 是 AIDL 接口的具体实现,负责处理实际操作,你可以在接口定义任何操作,实现的时候没什么特别之处,只是这些代码运行在了更高权限的进程中,进而实现安装应用、修改系统设置等高级操作
以下是一个实现
package com.niki.cmd
import android.os.Build
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import kotlin.system.exitProcess
internal class UserService : IUserService.Stub() {
override fun destroy() = exitProcess(0)
override fun exit() = destroy()
override fun exec(command: String?): ExecResult {
var process: Process? = null
val stdoutSB = StringBuilder()
val stderrSB = StringBuilder()
val result = ExecResult().apply {
stdout = ""
stderr = ""
exitCode = 0
}
if (command == null || command.trim { it <= ' ' }.isEmpty()) {
result.apply {
stdout = ""
stderr = "Error: Empty command"
exitCode = -1
}
return result
}
try {
process = Runtime.getRuntime()
.exec(command.split("\\s+".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray())
val stdoutReader = BufferedReader(InputStreamReader(process.inputStream))
var line: String?
while ((stdoutReader.readLine().also { line = it }) != null) {
stdoutSB.append(line).append('\n')
}
stdoutReader.close()
val stderrReader = BufferedReader(InputStreamReader(process.errorStream))
while ((stderrReader.readLine().also { line = it }) != null) {
stderrSB.append(line).append('\n')
}
stderrReader.close()
result.apply {
stdout = stdoutSB.toString()
stderr = stderrSB.toString()
exitCode = process.waitFor()
}
} catch (e: SecurityException) {
result.apply {
stdout = ""
stderr = "Permission denied: ${e.message}"
exitCode = -2
}
} catch (e: IOException) {
result.apply {
stdout = ""
stderr = "IO error: ${e.message}"
exitCode = -3
}
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
result.apply {
stdout = ""
stderr = "Execution interrupted: ${e.message}"
exitCode = -4
}
} finally {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
process?.destroyForcibly()
}
return result
}
}
使用
Shizuku 的使用分为三个关键步骤:
- 权限请求:授予 Shizuku 权限,就是唤起 Shizuku 授权对话框来让用户同意授权的操作
- 服务绑定:通过 Shizuku 绑定我们写好的的 UserService,获取 AIDL 接口实例
- 大功告成:获得 AIDL 接口实例(
IUserService
)后我们可以直接调用我们实现的方法了
授权
private const val REQUEST_CODE_PERMISSION = 666 // 自行定义, 和 activity result那个类似
fun checkAndRequestPermission(callback: OnPermissionResultCallback) {
if (Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Shizuku 权限已授予")
callback.onResult(true, null)
return
}
if (Shizuku.shouldShowRequestPermissionRationale()) {
Log.e(TAG, "用户拒绝授权 Shizuku")
callback.onResult(false, "用户拒绝授权")
return
}
val listener = OnRequestPermissionResultListener { _, grantResult ->
Shizuku.removeRequestPermissionResultListener(listener)
val isGranted = grantResult == PackageManager.PERMISSION_GRANTED
Log.d(TAG, "Shizuku 授权结果: $isGranted")
callback.onResult(isGranted, if (isGranted) null else "授权失败")
}
Shizuku.addRequestPermissionResultListener(listener)
try {
Shizuku.requestPermission(REQUEST_CODE_PERMISSION)
} catch (e: Exception) {
Log.e(TAG, "授权失败", e)
Shizuku.removeRequestPermissionResultListener(listener)
callback.onResult(false, "授权异常: ${e.message}")
}
}
interface OnPermissionResultCallback {
fun onResult(isGranted: Boolean, errorMessage: String?)
}
绑定服务
在确保你有 Shizuku 权限后,进行服务绑定
private var userService: IUserService? = null
private var serviceConnection: ServiceConnection? = null
fun bind(context: Context, callback: OnBindResultCallback) {
if (userService != null) {
Log.d(TAG, "Shizuku service 已经连接")
callback.onResult(true, null, userService)
return
}
try {
val args = UserServiceArgs(ComponentName(context, UserService::class.java.name))
.daemon(true)
.processNameSuffix("${context.packageName}.shizuku.service")
.debuggable(true)
serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
userService = IUserService.Stub.asInterface(service)
Log.d(TAG, "Shizuku service 成功连接: ${name.className}")
callback.onResult(true, null, userService)
}
override fun onServiceDisconnected(name: ComponentName) {
userService = null
Log.d(TAG, "Shizuku service 断开: ${name.className}")
}
}
Shizuku.bindUserService(args, serviceConnection!!)
} catch (e: Exception) {
Log.e(TAG, "绑定失败", e)
callback.onResult(false, "绑定异常: ${e.message}", null)
}
}
fun unbind(context: Context) {
try {
if (serviceConnection != null) {
Shizuku.unbindUserService(
UserServiceArgs(ComponentName(context, UserService::class.java.name)),
serviceConnection!!,
true
)
}
} catch (e: Exception) {
Log.e(TAG, "解绑出错", e)
} finally {
userService = null
serviceConnection = null
Log.d(TAG, "Shizuku service 解绑")
}
}
interface OnBindResultCallback {
fun onResult(success: Boolean, errorMessage: String?, userService: IUserService?)
}
大功告成:现在直接使用即可
val execResult = userService.exec(command)
至此,就是基于 Shizuku 开发的教程
更高级的使用
感兴趣可以去了解一下ShizukuBinderWrapper
通过它可以将我们的应用所发起的对系统服务的Binder
调用路由到Shizuku的特权进程中执行,典型的应用场景有:
- 应用安装/卸载:通过
IPackageManager
进行应用的安装、卸载或权限管理, - 文件管理:访问
/Android/data
和/Android/obb
等受限目录,这些目录通常在Android 11及更高版本中对普通应用不可访问 - 系统设置修改:更改网络设置、Wi-Fi密码、传感器状态、私有DNS服务器等
- 日志读取:读取系统日志(Logcat)
- 其他系统控制:控制应用音量、冻结/禁用/隐藏/卸载Android应用、管理设备所有者权限等
以下是一个使用ShizukuBinderWrapper
的示例
private static final IPackageManager PACKAGE_MANAGER =
IPackageManager.Stub.asInterface(new ShizukuBinderWrapper(
SystemServiceHelper.getSystemService("package")));
public static void grantRuntimePermission(String packageName, String permissionName, int userId) {
try {
PACKAGE_MANAGER.grantRuntimePermission(packageName, permissionName, userId);
} catch (RemoteException e) {
// Handle exception
}
}
基于协程的优雅封装
这是一个基于 Kotlin 协程的 Android Shell 命令执行框架,支持 User、Shizuku 和 Root 三种权限的命令行调用,提供统一易用的挂起式 API,使用起来就像:
val shell: Shell = ShizukuShell(context)
if (shell.isAvailable()) {
val result = shell.exec("echo test", timeout = 20_000L)
println("标准输出: ${result.stdout}")
println("错误输出: ${result.stderr}")
println("退出码: ${result.exitCode}")
}
这是作者封装的包括 Shizuku 在内的 Shell 执行工具,使用非常简单,有关 AIDL、接口回调等复杂操作都封装起来了,也就是说,导个依赖就能调用 Shizuku API
喜欢的话请给我点个 Star,这对我很重要,谢谢