Dhizuku API 接入指南
因为Dhizuku-API仓库没有也不打算提供样例代码,想要接入Dhizuku API的开发者必须参考现有的开源项目和Dhizuku API的源代码,而很多项目的结构复杂,需要花大量的时间才能了解。所以我写了一个Dhizuku API接入指南。
本指南适合:会使用DevicePolicyManager API,想接入Dhizuku API的开发者。
添加依赖
io.github.iamr0s:Dhizuku-API
最新版本请前往Maven central查看。
初始化
Dhizuku.init(context)
如果返回false,说明Dhizuku未安装或未激活,不要继续。
根据你的需要,选择Activity context或Application context。Dhizuku API提供了一个无需Context的Dhizuku.init(),不建议使用。
请求权限
if (Dhizuku.isPermissionGranted()) {
// 权限已授予,下一步
} else {
Dhizuku.requestPermission(object : DhizukuRequestPermissionListener() {
override fun onRequestPermission(grantResult: Int) {
if (grantResult == PackageManager.PERMISSION_GRANTED) {
// 用户授予了权限,下一步
} else {
// 用户拒绝了请求
}
}
})
}
使用API
Binder wrapper
适用于DevicePolicyManager, PackageManager等系统服务
创建IDevicePolicyManager接口
创建文件YOUR_PROJECT/app/src/main/java/android/app/admin/IDevicePolicyManager.java
package android.app.admin;
import android.content.ComponentName;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import androidx.annotation.Keep;
@Keep
public interface IDevicePolicyManager extends IInterface {
@Keep
abstract class Stub extends Binder implements IDevicePolicyManager {
public static IDevicePolicyManager asInterface(IBinder obj) {
throw new UnsupportedOperationException();
}
}
}
如果你构建app时不启用shrink,你可以去掉@Keep注解。
绕过隐藏API限制
添加HiddenApiBypass依赖: org.lsposed.hiddenapibypass:hiddenapibypass,最新版本请前往Maven central查看。
建议在Application.onCreate()中调用此函数。
HiddenApiBypass.setHiddenApiExemptions("")
如果不绕过限制,在下一步的getDeclaredField("mService")时会抛出异常。
获取DevicePolicyManager
fun binderWrapperDevicePolicyManager(appContext: Context): DevicePolicyManager? {
try {
val context = appContext.createPackageContext(Dhizuku.getOwnerComponent().packageName, Context.CONTEXT_IGNORE_SECURITY)
val manager = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val field = manager.javaClass.getDeclaredField("mService")
field.isAccessible = true
val oldInterface = field[manager] as IDevicePolicyManager
if (oldInterface is DhizukuBinderWrapper) return manager
val oldBinder = oldInterface.asBinder()
val newBinder = Dhizuku.binderWrapper(oldBinder)
val newInterface = IDevicePolicyManager.Stub.asInterface(newBinder)
field[manager] = newInterface
return manager
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
调用DPM API
val dpm = binderWrapperDevicePolicyManager(context)
val component = Dhizuku.getOwnerComponent()
dpm.setApplicationHidden(component, "com.example.app", true) // 将com.example.app隐藏
User Service
Dhizuku的User service和Shizuku的User service十分接近。了解Shizuku API将会对你使用Dhizuku的User service有帮助。
启用AIDL
在app级的build.gradle.kts中启用AIDL
android {
buildFeatures {
aidl = true
}
}
创建AIDL文件
创建文件YOUR_PROJECT/app/src/main/aidl/com/example/app/IDhizukuUserService.aidl
package com.example.app;
interface IDhizukuUserService {
void testFunction();
}
构建app,会生成对应的java interface。
创建ActivityThread
创建文件YOUR_PROJECT/app/src/main/java/android/app/ActivityThread.java
package android.app;
public class ActivityThread {
public static ActivityThread currentActivityThread() {
throw new RuntimeException("STUB");
}
public Application getApplication() {
throw new RuntimeException("STUB");
}
}
实现IDhizukuUserService
package com.example.app
class MyDhizukuUserService: IDhizukuUserService.Stub() {
override fun testFunction() {
val context = ActivityThread.currentActivityThread().application
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
dpm.lockNow()
}
}
定义ServiceConnection
class MyDhizukuServiceConnection: ServiceConnection {
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
val service = IDhizukuUserService.Stub.asInterface(binder)
service.testFunction()
}
override fun onServiceDisconnected(name: ComponentName?) {
println("Disconnected")
}
}
绑定服务
Dhizuku.bindUserService(
DhizukuUserServiceArgs(ComponentName(context, MyDhizukuUserService::class.java)), MyDhizukuServiceConnection()
)
Delegated scopes
一旦获取Delegated scope权限,无需在调用API时和Dhizuku进行IPC,稳定,但功能有限,只支持DevicePolicyManager的部分API。
Dhizuku.setDelegatedScopes(arrayOf(DevicePolicyManager.DELEGATION_PACKAGE_ACCESS))
DevicePolicyManager类中定义了所有Delegated scopes,以DevicePolicyManager.DELEGATION_开头,详情请见Android developers上的API参考。