Cara Meningkatkan Izin Aplikasi menggunakan perpustakaan Shizuku

click fraud protection

Rooting bukan untuk semua orang. Inilah cara Anda bisa mendapatkan izin tingkat shell yang lebih tinggi di aplikasi Anda menggunakan perpustakaan Shizuku.

Ada banyak alasan mengapa izin yang biasanya diberikan pada aplikasi Anda mungkin tidak cukup. Mungkin Anda seperti saya dan senang membuat aplikasi hacky yang menyalahgunakan API Android. Beberapa API yang saya gunakan terkunci di balik izin khusus. Terkadang hanya pengguna shell (ADB) atau sistem yang dapat mengaksesnya. Namun ada solusinya — Shizuku.

Shizuku memungkinkan Anda memanggil API sistem hampir secara langsung, dan seluruhnya di Java atau Kotlin. Panduan ini akan menunjukkan cara menerapkan dan menggunakan Shizuku.

Apa itu Shizuku?

Sebelum kita mulai menggunakan Shizuku, mungkin ada gunanya mengetahui apa sebenarnya itu. Jika Anda sudah familiar dengan Magisk, maka Shizuku serupa. Namun alih-alih mengelola akses root, ia mengelola akses shell.

Shizuku menjalankan prosesnya sendiri dengan izin tingkat shell. Cara pengguna mengaktifkan proses tersebut bergantung pada perangkat, versi Android, dan pilihannya. Shizuku dapat diaktifkan melalui ADB, melalui ADB nirkabel di perangkat (

di Android 11 dan lebih baru), atau melalui akses root. Aplikasi yang mengimplementasikan Shizuku kemudian dapat meminta izin untuk menggunakan proses tersebut guna melakukan operasi yang lebih tinggi.

ShizukuPengembang: Xingchen & Rikka

Harga: Gratis.

4.1.

Unduh

Kenapa Shizuku?

Meskipun akses tingkat shell ke sistem tidak memungkinkan Anda melakukan sebanyak itu akar, aplikasi ini tetap memberi Anda lebih banyak akses dibandingkan aplikasi biasa. Selain itu, cara kerja Shizuku memungkinkan Anda menggunakan API Android hampir seperti biasa. Anda tidak harus bergantung pada perintah shell (walaupun bisa jika Anda mau).

Jika aplikasi Anda memerlukan izin khusus yang hanya dapat diberikan melalui ADB (atau dengan root), Shizuku dan Android 11 merupakan pasangan yang hebat. Anda cukup menggunakan Shizuku untuk memberikan izin khusus sepenuhnya pada perangkat.

Bahkan dengan perangkat yang tidak menjalankan Android 11, Shizuku dapat berguna. Aplikasi ini menyediakan instruksi dan skrip untuk pengguna sehingga Anda tidak perlu melakukannya.

Integrasi

Menambahkan Shizuku ke aplikasi Anda bukanlah hal yang paling sederhana, namun juga tidak sulit. Sayangnya dokumentasi pengembang belum sepenuhnya lengkap, namun artikel ini telah membantu Anda. Berikut cara mengintegrasikan Shizuku ke dalam aplikasi Anda.

Ketergantungan

Langkah pertama adalah menambahkan dependensi Shizuku. Di build.gradle tingkat modul Anda, tambahkan kode berikut ke blok dependencies.

def shizuku_version = '11.0.3'

implementation "dev.rikka.shizuku: api:$shizuku_version"
implementation "dev.rikka.shizuku: provider:$shizuku_version"

Pastikan untuk memperbarui versi jika diperlukan. 11.0.3 adalah yang terbaru pada saat penulisan.

Pemberi

Agar Shizuku berfungsi, Anda perlu menambahkan blok penyedia ke manifes aplikasi Anda. Buka AndroidManifest.xml dan tambahkan yang berikut ini di dalam blok aplikasi.

 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" />

Izin

Untuk otorisasi, Shizuku menggunakan izin runtime. Kami akan memberikan izin itu sebentar lagi. Untuk saat ini, tambahkan ke AndroidManifest.xml di dalam blok manifes.

Sekarang setelah semuanya ditambahkan, integrasi dasar telah selesai. Biarkan Gradle melakukan sinkronisasi proyek, dan lanjutkan ke Penggunaan.


Penggunaan

Memeriksa ketersediaan

Sebelum membahas cara menggunakan Shizuku, mari kita bahas tentang memastikan Shizuku benar-benar tersedia untuk digunakan.

Sebelum memeriksa apakah izin diberikan, dan sebelum melakukan panggilan API melalui Shizuku, Anda dapat memastikan pemeriksaan dan panggilan tersebut akan berhasil dengan metode berikut:

Shizuku.pingBinder()

Jika Shizuku diinstal dan dijalankan, ini akan kembali BENAR. Jika tidak, itu akan menghasilkan nilai salah.

Pemberian Izin

Karena Shizuku menggunakan izin runtime, izin tersebut harus diberikan kepada aplikasi Anda sebelum Anda dapat melakukan apa pun dengan akses shell. Ada juga dua versi API yang beredar, dengan cara pemberiannya berbeda. Bagian ini akan menunjukkan cara menangani keduanya.

Memeriksa

Sebelum Anda meminta izin, hal terbaik yang harus dilakukan adalah memeriksa apakah Anda sudah memilikinya. Jika ya, Anda dapat melanjutkan apa pun yang perlu Anda lakukan. Jika tidak, Anda harus memintanya sebelum melanjutkan.

Untuk memeriksa apakah Anda memiliki izin menggunakan Shizuku, Anda dapat menggunakan yang berikut ini. Kode ini mengasumsikan Anda menjalankannya di dalam suatu Aktivitas.

Kotlin:

val isGranted = if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
checkSelfPermission(ShizukuProvider.PERMISSION) == PackageManager.PERMISSION_GRANTED
} else {
Shizuku.checkSelfPermission() = PackageManager.PERMISSION_GRANTED
}

Jawa:

boolean isGranted;
if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
isGranted = checkSelfPermission(ShizukuProvider.PERMISSION) == PackageManager.PERMISSION_GRANTED;
} else {
isGranted = Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED;
}

Meminta

Jika Anda perlu meminta izin untuk menggunakan Shizuku, berikut caranya.

Itu SHIZUKU_CODE Variabel yang digunakan di bawah ini harus berupa bilangan bulat dengan nilai tetap (variabel statis).

Kotlin:

if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
requestPermissions(arrayOf(ShizukuProvider.PERMISSION), SHIZUKU_CODE)
} else {
Shizuku.requestPermission(SHIZUKU_CODE)
}

Jawa:

if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
requestPermissions(newString[] { ShizukuProvider.PERMISSION }, SHIZUKU_CODE);
} else {
Shizuku.requestPermissions(SHIZUKU_CODE);
}

Untuk mendengarkan hasilnya, Anda harus mengganti Activity padaRequestPermissionsResult() metode. Anda juga harus menerapkannya Shizuku. OnRequestPermissionResultListener. Contoh yang akan saya tunjukkan mengasumsikan Aktivitas Anda mengimplementasikan antarmuka tersebut, namun Anda dapat mengimplementasikannya dalam variabel jika Anda mau.

Kotlin:

classExampleActivity : AppCompatActivity, Shizuku.OnRequestPermissionResultListener {
...

override void onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
permissions.forEachIndexed { index, permission ->
if (permission == ShizukuProvider.PERMISSION) {
onRequestPermissionResult(requestCode, grantResults[index])
}
}
}

override voidonRequestPermissionResult(requestCode: Int, grantResult: Int){
val isGranted = grantResult == PackageManager.PERMISSION_GRANTED
//Dostuff based on the result.

}
}

Jawa:

publicclassExampleActivityextendsAppCompatActivityimplementsShizuku.OnRequestPermissionResultListener{
...

@Override
publicvoidonRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){
for (int i = 0; i < permissions.length; i++) {
String permission = permissions[i];
int result = grantResults[i];

if (permission.equals(ShizukuProvider.PERMISSION) {
onRequestPermissionResult(requestCode, result);
}
}
}

@Override
publicvoidonRequestPermissionResult(int requestCode, int grantResult){
boolean isGranted = grantResult == PackageManager.PERMISSION_GRANTED;
//Dostuff based on the result.
}
}

Menggunakan API

Sekarang Shizuku sudah diatur dan izin diberikan, Anda dapat mulai memanggil API menggunakan Shizuku. Prosesnya di sini sedikit berbeda dari biasanya. Daripada menelepon getSystemService() dan casting ke sesuatu seperti WindowManager, Anda harus menggunakan API internal untuk ini (mis., IWindowManager).

Shizuku menyertakan bypass untuk daftar hitam API tersembunyi Android, jadi Anda tidak perlu khawatir tentang hal itu saat menggunakannya. Jika Anda penasaran bagaimana cara melewatinya sendiri, lihat tutorial saya sebelumnya.

Berikut ini contoh singkat (menggunakan refleksi) yang menunjukkan kepada Anda bagaimana Anda bisa mendapatkan sebuah instance IPackageManager dan menggunakannya untuk memberikan izin runtime pada aplikasi.

Kotlin:

val iPmClass = Class.forName("android.content.pm.IPackageManager")
val iPmStub = Class.forName("android.content.pm.IPackageManager\$Stub")
val asInterfaceMethod = iPmStub.getMethod("asInterface", IBinder::class.java)
val grantRuntimePermissionMethod = iPmClass.getMethod("grantRuntimePermission", String:: class.java /* package name */, String:: class.java /* permission name */, Int:: class.java /* user ID */)

val iPmInstance = asInterfaceMethod.invoke(null, ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package")))

grantRuntimePermissionMethod.invoke(iPmInstance, "com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0)

Jawa:

Class< ?>> iPmClass = Class.forName("android.content.pm.IPackageManager");
Class< ?>> iPmStub = Class.forName("android.content.pm.IPackageManager$Stub");
Method asInterfaceMethod = iPmStub.getMethod("asInterface", IBinder.class);
Method grantRuntimePermissionMethod = iPmClass.getMethod("grantRuntimePermission", String.class, String.class, int.class);

val iPmInstance = asInterfaceMethod.invoke(null, new ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package")));

grantRuntimePermissionMethod.invoke(iPmInstance, "com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0);

Proses untuk API lainnya serupa. Dapatkan referensi ke kelas dan subkelas Stub-nya. Dapatkan referensi ke asInterface metode untuk kelas Stub. Dapatkan referensi metode yang Anda inginkan dari kelas itu sendiri. Kemudian, aktifkan asInterface referensi metode yang Anda miliki, ganti "package" di atas dengan layanan apa pun yang Anda butuhkan. Contoh tersebut kemudian dapat diteruskan untuk pemanggilan metode.

Kiat profesional: Anda dapat menghindari penggunaan refleksi sama sekali jika Anda memasang SDK yang dimodifikasi. Lihat repositori GitHub Angrayudi untuk SDK yang dimodifikasi dan petunjuk pemasangan. Dengan menginstal ini, kode di atas (di Kotlin) menjadi jauh lebih sederhana.

val iPm = IPackageManager.Stub.asInterface(ShizukuBinderWrapper(SystemServiceHelper.getService("package"))))
iPm.grantRuntimePermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0)

API berbasis AIDL apa pun dapat digunakan dengan metode ini dari mana saja di aplikasi Anda, selama Shizuku berjalan dan aplikasi Anda memiliki izin.

Layanan Pengguna

Meskipun metode Binder mencakup sebagian besar kasus penggunaan, mungkin ada saatnya Anda memerlukan API yang tidak memiliki antarmuka Binder langsung. Dalam hal ini, Anda dapat menggunakan fitur Layanan Pengguna di Shizuku.

Metode ini bekerja mirip dengan Layanan normal di Android. Anda "memulainya", berkomunikasi dengan mengikatnya menggunakan ServiceConnection, dan menjalankan logika Anda di kelas layanan. Perbedaannya adalah Anda tidak menggunakan Layanan Android, dan apa pun di dalam layanan tersebut berjalan dengan izin ADB.

Sekarang ada beberapa keterbatasan. Layanan Pengguna berjalan dalam proses dan pengguna yang benar-benar terpisah, sehingga Anda tidak dapat berinteraksi dengan seluruh aplikasi Anda kecuali melalui callback dan Binder AIDL Anda sendiri. Karena ini juga tidak berjalan dalam proses aplikasi yang tepat, beberapa hal seperti Layanan Android yang mengikat mungkin tidak berfungsi dengan benar.

Ini juga memerlukan Shizuku versi 10 atau lebih baru. Meskipun sebagian besar sumber aplikasi saat ini memiliki versi 11, Anda tetap harus menyertakan pemeriksaan versi, yang akan disertakan dalam contoh.

Mendefinisikan AIDL

Untuk memulai, Anda perlu membuat file AIDL baru. Anda dapat melakukan ini di Android Studio dengan mengeklik kanan apa pun di tampilan file Android, mengarahkan kursor ke opsi "Baru", dan memilih opsi "AIDL". Masukkan nama file (misalnya, "IUserService"), dan Android Studio akan membuatkan file template untuk Anda.

Jika Anda belum memahami cara kerja AIDL, pastikan untuk memeriksanya dokumentasi Google.

Hapus metode templat dari AIDL lalu tambahkan a destroy() metode dengan ID yang tepat untuk Shizuku. Ini akan dipanggil ketika Shizuku mematikan Layanan Pengguna, dan harus digunakan untuk membersihkan referensi atau logika berkelanjutan yang Anda miliki.

Contoh AIDL:

packagetk.zwander.shizukudemo;

interfaceIUserService{
voiddestroy()= 16777114;

void grantPermission(String packageName, String permission, int userId) = 1; //You can specify your own method IDs in the AIDL. Check out the documentation for more details on this.
}

Menerapkan AIDL

Hal berikutnya yang harus dilakukan adalah menerapkan AIDL.

Jawa:

publicclassUserServiceextendsIUserService.Stub{
//Make sure to include an empty constructor.
publicUserService(){
}

@Override
publicvoiddestroy(){
//Shizuku wants the service to be killed. Clean up and then exit.
System.exit(0);
}

@Override
publicvoidgrantPermission(String packageName, String permission, int userId){
//No need to use ShizukuBinderWrapper.
IPackageManager.Stub.asInterface(SystemServiceHelper.getService("package")).grantRuntimePermission(packageName, permission, userId);
}
}

Kotlin:

classUserService : IUserService.Stub {
//Include an empty constructor.
constructor() {
}

override fun destroy(){
//Shizuku wants the service to be killed. Clean up and exit.
System.exit(0)
}

override fun grantPermission(packageName: String, permission: String, userId: Int) {
//No need for ShizukuBinderWrapper.
IPackageManager.Stub.asInterface(SystemServiceHelper.getService("package")).grantRuntimePermission(packageName, permission, userId)
}
}

Contoh di atas mengasumsikan Anda memiliki API Tersembunyi Android SDK diinstal.

Menyiapkan Koneksi Layanan

Sekarang Layanan Pengguna telah ditentukan dan diimplementasikan, sekarang saatnya menyiapkannya untuk digunakan. Hal pertama yang harus Anda lakukan adalah menentukan ServiceConnection tempat Anda ingin berkomunikasi dengannya (misalnya, dari Aktivitas utama di aplikasi Anda).

Jawa:

private IUserService binder = null;

privatefinal ServiceConnection connection = new ServiceConnection() {
@Override
publicvoidonServiceConnected(ComponentName componentName, IBinder binder){
if (binder != null && binder.pingBinder()) {
binder = IUserService.Stub.asInterface(binder);
}
}

@Override
publicvoidonServiceDisconnected(ComponentName componentName){
binder = null;
}
}

Kotlin:

privatevar binder: IUserService? = null

private val connection = object: ServiceConnection {
override fun onServiceConnected(componentName: ComponentName, binder: IBinder?){
if (binder != null && binder.pingBinder()) {
binder = IUserService.Stub.asInterface(binder)
}
}

override fun onServiceDisconnected(componentName: ComponentName){
binder = null;
}
}

Itu binder variabel adalah apa yang akan Anda gunakan untuk berkomunikasi dengan Layanan Pengguna dari aplikasi Anda. Untuk memeriksa apakah itu tersedia untuk digunakan, cukup periksa apakah itu bukan null dan itu pingBinder() kembali BENAR, seperti pada contoh kode di atas.

Membuat argumen Layanan Pengguna

Sebelum Anda dapat mengontrol Layanan Pengguna, Anda perlu menentukan beberapa argumen yang akan digunakan Shizuku saat memulai dan menghentikannya. Hal ini mencakup hal-hal seperti memberi tahu Shizuku nama kelas layanan, menentukan akhiran proses, dapat di-debug atau tidak, dan versinya.

Jawa:

privatefinal Shizuku.UserServiceArgs serviceArgs = new Shizuku.UserServiceArgs(
newComponentName(BuildConfig.APPLICATION_ID, UserService.class.getName()))
.processNameSuffix("user_service")
.debuggable(BuildConfig.DEBUG)
.version(BuildConfig.VERSION_CODE);

Kotlin:

private val serviceArgs = Shizuku.UserServiceArgs(
ComponentName(BuildConfig.APPLICATION_ID, UserService.class::java.getName()))
.processNameSuffix("user_service")
.debuggable(BuildCOnfig.DEBUG)
.version(BuildConfig.VERSION_CODE)

Memulai, Menghentikan, dan Mengikat Layanan Pengguna

Tindakan memulai dan mengikat serta tindakan menghentikan dan melepaskan ikatan disatukan di Shizuku. Tidak ada metode mulai dan ikat yang terpisah, atau metode berhenti dan lepas ikatan.

Berikut caranya mulai dan ikat Layanan Pengguna.

Jawa:

if (Shizuku.getVersion >= 10) {
//This only works on Shizuku 10 or later.
Shizuku.bindUserService(serviceArgs, connection);
} else {
//Tell the user to upgrade Shizuku.
}

Kotlin:

if (Shizuku.getVersion() >= 10) {
//This only works on Shizuku 10 or later.
Shizuku.bindUserService(serviceArgs, connection)
} else {
//Tell the user to upgrade Shizuku.
}

Berikut caranya berhenti dan lepaskan ikatannya Layanan Pengguna.

Jawa:

if (Shizuku.getVersion >= 10) {
Shizuku.unbindUserService(serviceArgs, connection, true);
}

Kotlin:

if (Shizuku.getVersion >= 10) {
Shizuku.unbindUserService(serviceArgs, connection, true)
}

Memanggil Layanan Pengguna

Setelah Layanan Pengguna dimulai, Anda dapat mulai menggunakannya. Cukup periksa apakah binder variabel non-null dan dapat di-ping, lalu lakukan pemanggilan metode Anda.

Jawa:

if (binder != null && binder.pingBinder()) {
binder.grantPermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0);
}

Kotlin:

if (binder?.pingBinder() == true) {
binder?.grantPermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0)
}

Kesimpulan

Jika Anda mengikuti semua itu, Anda sekarang akan memiliki integrasi Shizuku yang berfungsi. Ingatlah untuk memberi tahu pengguna Anda untuk menginstal Shizuku, dan memeriksa dengan benar apakah Shizuku tersedia sebelum mencoba menggunakannya.