Sakņošana nav piemērota visiem. Lūk, kā savā lietotnē varat iegūt paaugstināta čaulas līmeņa atļaujas, izmantojot Shizuku bibliotēku.
Ir daudz iemeslu, kāpēc jūsu lietotnei parasti piešķirtās atļaujas var nebūt pietiekamas. Varbūt jūs esat tāds pats kā es, un jums patīk radīt hacky progr, kas ļaunprātīgi izmanto Android API. Dažas no manis izmantotajām API ir bloķētas ar īpašām atļaujām. Dažreiz tiem var piekļūt tikai čaulas lietotājs (ADB) vai sistēma. Tomēr ir risinājums - Shizuku.
Shizuku ļauj izsaukt sistēmas API gandrīz tieši un pilnībā Java vai Kotlin. Šī rokasgrāmata parādīs, kā ieviest un lietot Shizuku.
Kas ir Šizuku?
Pirms sākam lietot Shizuku, varētu būt noderīgi zināt, kas tieši tas ir. Ja esat iepazinies ar Magisk, tad Šizuku ir līdzīgs. Bet tā vietā, lai pārvaldītu root piekļuvi, tā pārvalda čaulas piekļuvi.
Shizuku vada savu procesu ar čaulas līmeņa atļaujām. Tas, kā lietotājs aktivizē šo procesu, ir atkarīgs no ierīces, Android versijas un izvēles. Shizuku var aktivizēt, izmantojot ADB, izmantojot ierīcē esošo bezvadu ADB (
operētājsistēmā Android 11 un jaunākās versijās), vai izmantojot root piekļuvi. Pēc tam lietotnes, kas ievieš Shizuku, var pieprasīt atļauju izmantot šo procesu, lai veiktu paaugstinātas darbības.Cena: bezmaksas.
4.1.
Kāpēc Šizuku?
Lai gan čaulas līmeņa piekļuve sistēmai neļauj jums paveikt tik daudz kā sakne, tas joprojām sniedz jums lielāku piekļuvi nekā parastā lietotne. Turklāt Shizuku darbības veids ļauj izmantot Android API gandrīz kā parasti. Jums nav jāpaļaujas uz čaulas komandām (lai gan varat, ja vēlaties).
Ja jūsu lietotnei ir nepieciešamas īpašas atļaujas, kuras var piešķirt tikai caur ADB (vai ar root), Shizuku un Android 11 ir lieliski savienojami pārī. Varat vienkārši izmantot Shizuku, lai pilnībā piešķirtu īpašas atļaujas ierīcē.
Pat ar ierīcēm, kurās nav operētājsistēmas Android 11, Shizuku var būt noderīgs. Lietojumprogramma lietotājiem nodrošina instrukcijas un skriptus, lai jums tas nebūtu jādara.
Integrācija
Shizuku pievienošana savai lietotnei nav vienkāršākā, taču arī tā nav grūta. Diemžēl, izstrādātāja dokumentācija nav gluži pilnīgs, taču šajā rakstā jūs to aplūkojat. Lūk, kā integrēt Shizuku savā lietotnē.
Atkarības
Pirmais solis ir Shizuku atkarību pievienošana. Savā moduļa līmeņa failā build.gradle atkarību blokam pievienojiet tālāk norādīto.
def shizuku_version = '11.0.3'
implementation "dev.rikka.shizuku: api:$shizuku_version"
implementation "dev.rikka.shizuku: provider:$shizuku_version"
Ja nepieciešams, noteikti atjauniniet versiju. 11.0.3 ir jaunākā versija rakstīšanas laikā.
Pakalpojumu sniedzējs
Lai Shizuku darbotos, lietotnes manifestam ir jāpievieno pakalpojumu sniedzēja bloks. Atveriet AndroidManifest.xml un lietojumprogrammu blokā pievienojiet tālāk norādīto.
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" />
Atļauja
Autorizācijai Shizuku izmanto izpildlaika atļauju. Pēc brīža mēs sāksim piešķirt šo atļauju. Pagaidām pievienojiet to failam AndroidManifest.xml manifesta blokā.
Tagad, kad tas viss ir pievienots, pamata integrācija ir pabeigta. Ļaujiet Gradle veikt projekta sinhronizāciju un pārejiet uz sadaļu Lietošana.
Lietošana
Pieejamības pārbaude
Pirms iedziļināties Shizuku lietošanā, parunāsim par to, vai tas tiešām ir pieejams lietošanai.
Pirms pārbaudāt, vai atļauja ir piešķirta, un pirms API izsaukumu veikšanas, izmantojot Shizuku, varat pārliecināties, vai šīs pārbaudes un zvani izdosies, izmantojot šādu metodi:
Shizuku.pingBinder()
Ja Shizuku ir instalēts un darbojas, tas atgriezīsies taisnība. Pretējā gadījumā tas atgriezīsies nepatiesi.
Atļaujas piešķiršana
Tā kā Shizuku izmanto izpildlaika atļauju, tā ir jāpiešķir jūsu lietotnei, lai varētu kaut ko darīt ar čaulas piekļuvi. Apritē ir arī divas API versijas ar dažādiem piešķiršanas veidiem. Šajā sadaļā tiks parādīts, kā rīkoties ar abiem.
Pārbauda
Pirms atļaujas pieprasīšanas vislabāk ir pārbaudīt, vai jums tā jau ir. Ja jūs to darāt, varat turpināt darīt visu, kas jums jādara. Pretējā gadījumā jums tas būs jāpieprasa, pirms turpināt.
Lai pārbaudītu, vai jums ir atļauja izmantot Shizuku, varat izmantot tālāk norādīto. Šis kods tiek pieņemts, ka jūs to palaižat darbības ietvaros.
Kotlins:
val isGranted = if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
checkSelfPermission(ShizukuProvider.PERMISSION) == PackageManager.PERMISSION_GRANTED
} else {
Shizuku.checkSelfPermission() = PackageManager.PERMISSION_GRANTED
}
Java:
boolean isGranted;
if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
isGranted = checkSelfPermission(ShizukuProvider.PERMISSION) == PackageManager.PERMISSION_GRANTED;
} else {
isGranted = Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED;
}
Pieprasot
Ja jums ir jāpieprasa atļauja izmantot Shizuku, rīkojieties šādi.
The SHIZUKU_CODE Tālāk izmantotajam mainīgajam ir jābūt veselam skaitlim ar nemainīgu vērtību (statiskais mainīgais).
Kotlins:
if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
requestPermissions(arrayOf(ShizukuProvider.PERMISSION), SHIZUKU_CODE)
} else {
Shizuku.requestPermission(SHIZUKU_CODE)
}
Java:
if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
requestPermissions(newString[] { ShizukuProvider.PERMISSION }, SHIZUKU_CODE);
} else {
Shizuku.requestPermissions(SHIZUKU_CODE);
}
Lai noklausītos rezultātu, jums ir jāignorē Activity's onRequestPermissionsResult() metodi. Jums būs arī jāīsteno Šizuku. OnRequestPermissionResultListener. Piemērā, ko es parādīšu, tiek pieņemts, ka jūsu darbība ievieš šo saskarni, taču, ja vēlaties, varat to ieviest mainīgajā.
Kotlins:
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.
}
}
Java:
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.
}
}
Izmantojot API
Tagad, kad Shizuku ir iestatīts un atļaujas ir piešķirtas, jūs varat sākt faktiski izsaukt API, izmantojot Shizuku. Šeit notiekošais process ir nedaudz atšķirīgs, nekā jūs, iespējams, esat pieradis. Tā vietā, lai piezvanītu getSystemService()
un apraide uz kaut ko līdzīgu WindowManager
, tā vietā jums būs jāizmanto iekšējās API (piemēram, IWindowManager
).
Shizuku ietver apvedceļu Android slēptajam API melnajam sarakstam, tāpēc, izmantojot to, jums par to nebūs jāuztraucas. Ja vēlaties pats to apiet, skatiet manu iepriekšējo pamācību.
Šeit ir īss piemērs (izmantojot pārdomas), kas parāda, kā iegūt piemēru IPackageManager
un izmantojiet to, lai piešķirtu lietotnei izpildlaika atļauju.
Kotlins:
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)
Java:
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);
Citu API process ir līdzīgs. Iegūstiet atsauces uz klasi un tās apakšklasi. Iegūstiet atsauci uz asInterface
metode Stub klasei. Iegūstiet no pašas klases atsauces uz nepieciešamajām metodēm. Pēc tam izsauciet asInterface
metodes atsauce jums ir, aizstājot "package"
augstāk ar jebkuru pakalpojumu, kas jums nepieciešams. Pēc tam šo gadījumu var nodot metodes izsaukšanai.
Pro-padoms: Ja instalējat modificētu SDK, varat izvairīties no pārdomu izmantošanas. Apskatiet anggrayudi GitHub repozitoriju modificētajiem SDK un instalēšanas instrukcijām. Kad tas ir instalēts, iepriekš minētais kods (Kotlinā) kļūst daudz vienkāršāks.
val iPm = IPackageManager.Stub.asInterface(ShizukuBinderWrapper(SystemServiceHelper.getService("package"))))
iPm.grantRuntimePermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0)
Jebkuru uz AIDL balstītu API var izmantot ar šo metodi no jebkuras vietas jūsu lietotnē, ja vien darbojas Shizuku un jūsu lietotnei ir atļauja.
Lietotāja pakalpojums
Lai gan Binder metode aptver lielāko daļu lietošanas gadījumu, var būt gadījumi, kad jums ir nepieciešama API, kurai nav tiešas Binder saskarnes. Tādā gadījumā Shizuku varat izmantot User Service funkciju.
Šī metode darbojas līdzīgi kā parastais pakalpojums operētājsistēmā Android. Jūs to "startējat", sazināties, piesaistot to ar ServiceConnection, un palaižat savu loģiku pakalpojumu klasē. Atšķirība ir tāda, ka jūs neizmantojat Android pakalpojumu, un viss pakalpojumā darbojas ar ADB atļaujām.
Tagad ir daži ierobežojumi. Lietotāja pakalpojums darbojas pilnīgi atsevišķā procesā un lietotājam, tāpēc jūs nevarat mijiedarboties ar pārējo savu lietotni, izņemot savus AIDL atzvanus un saistītājus. Tā kā tas arī nedarbojas pareizi lietotnes procesā, dažas lietas, piemēram, Android pakalpojumu saistīšana, var nedarboties pareizi.
Tam nepieciešama arī Shizuku versija 10 vai jaunāka versija. Lai gan lielākajai daļai lietotnes avotu pašlaik ir versija 11, jums joprojām ir jāiekļauj versijas pārbaude, kas tiks iekļauta piemērā.
AIDL definēšana
Lai sāktu, jums būs jāizveido jauns AIDL fails. To var izdarīt programmā Android Studio, ar peles labo pogu noklikšķinot uz jebkura Android faila skatā, virzot kursoru virs opcijas "Jauns" un izvēloties opciju "AIDL". Ievadiet faila nosaukumu (piem., "IUserService"), un Android Studio izveidos veidnes failu.
Ja neesat pazīstams ar AIDL darbību, noteikti pārbaudiet Google dokumentācija.
Noņemiet veidņu metodes no AIDL un pēc tam pievienojiet a destroy()
metode ar pareizu Šizuku ID. Tas tiks izsaukts, kad Shizuku nogalinās lietotāja pakalpojumu, un tas ir jāizmanto, lai notīrītu visas jūsu atsauces vai pastāvīgo loģiku.
AIDL piemērs:
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.
}
AIDL ieviešana
Nākamā lieta, kas jādara, ir faktiski ieviest AIDL.
Java:
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);
}
}
Kotlins:
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)
}
}
Iepriekš minētajos piemēros tiek pieņemts, ka jums ir Android slēptā API SDK ir instalēts.
Pakalpojuma savienojuma iestatīšana
Tagad, kad lietotāja pakalpojums ir definēts un ieviests, ir pienācis laiks to iestatīt lietošanai. Pirmā lieta, kas jums jādara, ir definēt ServiceConnection, kur vēlaties ar to sazināties (piemēram, no savas lietotnes galvenās darbības).
Java:
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;
}
}
Kotlins:
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;
}
}
The binder
mainīgais ir tas, ko izmantosit, lai no savas lietotnes sazinātos ar lietotāja pakalpojumu. Lai pārbaudītu, vai tas ir pieejams lietošanai, vienkārši pārbaudiet, vai tas nav nulle un tas pingBinder()
atgriežas taisnība, tāpat kā iepriekš minētajā koda piemērā.
User Service argumentu izveide
Lai varētu kontrolēt lietotāja pakalpojumu, jums ir jādefinē daži argumenti, ko Shizuku izmantot, startējot un apturot to. Tie ietver tādas lietas kā faktiska pakalpojuma klases nosaukuma paziņošana Shizuku, procesa sufiksa norādīšana, neatkarīgi no tā, vai tas ir atkļūdojams un kāda tā versija ir.
Java:
privatefinal Shizuku.UserServiceArgs serviceArgs = new Shizuku.UserServiceArgs(
newComponentName(BuildConfig.APPLICATION_ID, UserService.class.getName()))
.processNameSuffix("user_service")
.debuggable(BuildConfig.DEBUG)
.version(BuildConfig.VERSION_CODE);
Kotlins:
private val serviceArgs = Shizuku.UserServiceArgs(
ComponentName(BuildConfig.APPLICATION_ID, UserService.class::java.getName()))
.processNameSuffix("user_service")
.debuggable(BuildCOnfig.DEBUG)
.version(BuildConfig.VERSION_CODE)
Lietotāja pakalpojuma palaišana, apturēšana un saistīšana
Sākšanas un saistīšanas darbības un apturēšanas un atsaistīšanas darbības ir apvienotas Šizuku. Nav atsevišķu sākuma un saistīšanas metožu vai apturēšanas un atsaistīšanas metožu.
Lūk, kā to izdarīt sākt un saistīt lietotāja pakalpojumu.
Java:
if (Shizuku.getVersion >= 10) {
//This only works on Shizuku 10 or later.
Shizuku.bindUserService(serviceArgs, connection);
} else {
//Tell the user to upgrade Shizuku.
}
Kotlins:
if (Shizuku.getVersion() >= 10) {
//This only works on Shizuku 10 or later.
Shizuku.bindUserService(serviceArgs, connection)
} else {
//Tell the user to upgrade Shizuku.
}
Lūk, kā to izdarīt apturēt un atsaistīt lietotāja pakalpojumu.
Java:
if (Shizuku.getVersion >= 10) {
Shizuku.unbindUserService(serviceArgs, connection, true);
}
Kotlins:
if (Shizuku.getVersion >= 10) {
Shizuku.unbindUserService(serviceArgs, connection, true)
}
Lietotāja pakalpojuma izsaukšana
Kad lietotāja pakalpojums ir palaists, varat sākt to lietot. Vienkārši pārbaudiet, vai binder
mainīgais nav nulle un ir pingējams, un pēc tam veiciet metodes izsaukumu.
Java:
if (binder != null && binder.pingBinder()) {
binder.grantPermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0);
}
Kotlins:
if (binder?.pingBinder() == true) {
binder?.grantPermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0)
}
Secinājums
Ja sekojāt tam visam, jums tagad vajadzētu būt funkcionējošai Shizuku integrācijai. Vienkārši neaizmirstiet pastāstīt lietotājiem, ka viņi instalē Shizuku, un pareizi pārbaudiet, vai Shizuku ir pieejams, pirms mēģināt to izmantot.