Rooting ei ole kaikille. Näin voit saada korotettuja shell-tason käyttöoikeuksia sovelluksellesi Shizuku-kirjaston avulla.
On monia syitä, miksi sovelluksellesi normaalisti myönnetyt käyttöoikeudet eivät välttämättä riitä. Ehkä olet kuin minä ja nautit Android-sovellusliittymää väärinkäyttävien hakkeroitujen sovellusten luomisesta. Jotkut käyttämistäni sovellusliittymistä on lukittu erityisten lupien taakse. Joskus vain shell-käyttäjä (ADB) tai järjestelmä voi käyttää niitä. Ratkaisu on kuitenkin olemassa - Shizuku.
Shizukun avulla voit kutsua järjestelmäsovellusliittymiä lähes suoraan ja kokonaan Java- tai Kotlin-kielillä. Tämä opas näyttää, kuinka Shizuku otetaan käyttöön ja käytetään.
Mikä on Shizuku?
Ennen kuin aloitamme Shizukun käytön, saattaa olla hyödyllistä tietää, mikä se tarkalleen on. Jos olet perehtynyt Magisk, niin Shizuku on samanlainen. Pääkäyttäjän oikeuksien hallinnan sijaan se hallitsee komentotulkin käyttöä.
Shizuku suorittaa omaa prosessiaan shell-tason käyttöoikeuksilla. Kuinka käyttäjä aktivoi prosessin, riippuu hänen laitteestaan, Android-versiostaan ja valinnastaan. Shizuku voidaan aktivoida ADB: n kautta, laitteen langattoman ADB: n kautta (
Android 11:ssä ja uudemmissa), tai pääkäyttäjän oikeuksilla. Shizukun toteuttavat sovellukset voivat sitten pyytää lupaa käyttää tätä prosessia korkeampien toimintojen suorittamiseen.Hinta: Ilmainen.
4.1.
Miksi Shizuku?
Vaikka shell-tason pääsy järjestelmään ei anna sinun tehdä niin paljon kuin juuri, se antaa sinulle silti enemmän pääsyä kuin tavallinen sovellus. Tämän lisäksi Shizukun toimintatapa antaa sinun käyttää Android-sovellusliittymiä melkein normaalisti. Sinun ei tarvitse luottaa komentotulkkikomentoihin (vaikka voit, jos haluat).
Jos sovelluksesi tarvitsee erityislupia, jotka voidaan myöntää vain ADB: n kautta (tai rootin kautta), Shizuku ja Android 11 muodostavat loistavan pariliitoksen. Voit vain käyttää Shizukua erityisten lupien myöntämiseen kokonaan laitteella.
Shizuku voi olla hyödyllinen myös laitteissa, joissa ei ole Android 11 -käyttöjärjestelmää. Sovellus tarjoaa käyttäjille ohjeita ja komentosarjoja, joten sinun ei tarvitse.
Liittäminen
Shizukun lisääminen sovellukseesi ei ole yksinkertaisinta, mutta ei myöskään vaikeaa. Valitettavasti kehittäjän dokumentaatio ei ole aivan täydellinen, mutta tämä artikkeli kattaa sinut. Näin voit integroida Shizukun sovellukseesi.
Riippuvuudet
Ensimmäinen askel on lisätä Shizuku-riippuvuudet. Lisää moduulitason build.gradle-tiedostossa seuraava riippuvuuslohkoon.
def shizuku_version = '11.0.3'
implementation "dev.rikka.shizuku: api:$shizuku_version"
implementation "dev.rikka.shizuku: provider:$shizuku_version"
Muista päivittää versio tarvittaessa. 11.0.3 on viimeisin kirjoitushetkellä.
Palveluntarjoaja
Jotta Shizuku toimisi, sinun on lisättävä palveluntarjoajan esto sovelluksesi luetteloon. Avaa AndroidManifest.xml ja lisää seuraavat tiedot sovelluslohkoon.
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" />
Lupa
Valtuutukseen Shizuku käyttää ajonaikaista lupaa. Aloitamme tämän luvan myöntämisen hetken kuluttua. Lisää se toistaiseksi luettelon sisällä olevaan AndroidManifest.xml-tiedostoon.
Nyt kun tämä kaikki on lisätty, perusintegrointi on tehty. Anna Gradlen tehdä projektin synkronointi ja jatka Käyttöön.
Käyttö
Tarkastetaan saatavuutta
Ennen kuin siirryt Shizukun käyttöön, puhutaanpa sen varmistamisesta, että se on todella käytettävissä.
Ennen kuin tarkistat, onko lupa myönnetty, ja ennen kuin teet API-kutsuja Shizukun kautta, voit varmistaa, että kyseiset tarkastukset ja kutsut onnistuvat seuraavalla tavalla:
Shizuku.pingBinder()
Jos Shizuku on asennettu ja käynnissä, tämä palautuu totta. Muuten se palauttaa epätosi.
Luvan myöntäminen
Koska Shizuku käyttää ajonaikaista lupaa, se on myönnettävä sovelluksellesi ennen kuin voit tehdä mitään shell-käyttöoikeuksilla. Liikkeellä on myös kaksi API-versiota, joilla on erilaisia myöntämistapoja. Tämä osio näyttää, kuinka käsitellä molempia.
Tarkistetaan
Ennen kuin pyydät luvan, on parasta tarkistaa, onko sinulla jo se. Jos teet niin, voit jatkaa mitä tahansa tarvitset. Muussa tapauksessa sinun on pyydettävä se ennen kuin jatkat.
Voit tarkistaa, onko sinulla lupa käyttää Shizukua, käyttämällä seuraavaa. Tämä koodi olettaa, että käytät sitä toiminnon sisällä.
Kotlin:
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;
}
Pyydetään
Jos sinun on pyydettävä lupa käyttää Shizukua, toimi näin.
The SHIZUKU_CODE alla käytettävän muuttujan tulee olla kokonaisluku, jolla on tasainen arvo (staattinen muuttuja).
Kotlin:
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);
}
Jotta voit kuunnella tulosta, sinun on ohitettava toiminnot onRequestPermissionsResult() menetelmä. Sinun on myös pantava täytäntöön Shizuku. OnRequestPermissionResultListener. Esittämässäni esimerkissä oletetaan, että toimintosi toteuttaa kyseisen käyttöliittymän, mutta voit toteuttaa sen muuttujassa, jos haluat.
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.
}
}
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.
}
}
API: iden käyttö
Nyt kun Shizuku on määritetty ja luvat myönnetty, voit alkaa todella kutsua API: ita Shizukun avulla. Tässä prosessi on hieman erilainen kuin mihin olet tottunut. Soittamisen sijaan getSystemService()
ja heittää johonkin vastaavaan WindowManager
, sinun on käytettävä sisäisiä sovellusliittymiä näille sen sijaan (esim. IWindowManager
).
Shizuku sisältää ohituksen Androidin piilotetun API: n mustalle listalle, joten sinun ei tarvitse huolehtia siitä, kun käytät sitä. Jos olet kuitenkin utelias, kuinka voit ohittaa sen itse, katso edellinen opetusohjelmani.
Tässä on nopea esimerkki (käyttämällä heijastusta), joka näyttää, kuinka voit saada esimerkin IPackageManager
ja käytä sitä sovellukselle suoritusajan luvan myöntämiseen.
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)
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);
Muiden sovellusliittymien prosessi on samanlainen. Hanki viittaukset luokkaan ja sen Stub-alaluokkaan. Hanki viittaus asInterface
menetelmä Stub-luokassa. Hanki itse luokasta viittaukset haluamiisi menetelmiin. Kutsu sitten asInterface
menetelmäviittaus sinulla on, korvaamalla "package"
edellä mitä palveluja tarvitset. Tämä ilmentymä voidaan sitten välittää menetelmäkutsuja varten.
Pro-vinkki: Voit välttää heijastuksen käyttämisen kokonaan, jos asennat muokatun SDK: n. Tutustu anggraudun GitHub-tietovarastoon muokatuille SDK: ille ja asennusohjeille. Kun tämä on asennettu, yllä oleva koodi (Kotlinissa) muuttuu paljon yksinkertaisemmiksi.
val iPm = IPackageManager.Stub.asInterface(ShizukuBinderWrapper(SystemServiceHelper.getService("package"))))
iPm.grantRuntimePermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0)
Mitä tahansa AIDL-pohjaisia sovellusliittymiä voidaan käyttää tällä menetelmällä missä tahansa sovelluksessasi, kunhan Shizuku on käynnissä ja sovelluksellasi on käyttöoikeus.
Käyttäjäpalvelu
Vaikka Binder-menetelmä kattaa useimmat käyttötapaukset, saattaa joskus olla, että tarvitset API: n, jolla ei ole suoraa Binder-käyttöliittymää. Siinä tapauksessa voit käyttää Shizukun User Service -ominaisuutta.
Tämä menetelmä toimii samalla tavalla kuin tavallinen palvelu Androidissa. "Käynnistät" sen, kommunikoit sitoutumalla siihen ServiceConnectionin avulla ja käytät logiikkaasi palveluluokassa. Erona on, että et käytä Androidin palvelua, ja kaikki palvelun sisällä toimii ADB-luvalla.
Nyt on joitain rajoituksia. Käyttäjäpalvelu toimii täysin erillisessä prosessissa ja käyttäjässä, joten et voi olla vuorovaikutuksessa muun sovelluksesi kanssa muutoin kuin omien AIDL-soittojen ja sidosten kautta. Koska se ei myöskään toimi asianmukaisessa sovellusprosessissa, jotkin asiat, kuten Android-palveluiden sitominen, eivät välttämättä toimi oikein.
Tämä vaatii myös Shizukun version 10 tai uudemman. Vaikka useimmissa sovelluksen lähteissä on tällä hetkellä versio 11, sinun tulee silti sisällyttää version tarkistus, joka sisällytetään esimerkkiin.
AIDL: n määrittely
Aloita luomalla uusi AIDL-tiedosto. Voit tehdä tämän Android Studiossa napsauttamalla hiiren kakkospainikkeella mitä tahansa Android-tiedostonäkymässä, viemällä hiiren "Uusi"-vaihtoehdon päälle ja valitsemalla "AIDL"-vaihtoehdon. Anna tiedoston nimi (esim. "IUserService"), ja Android Studio luo mallitiedoston puolestasi.
Jos et ole perehtynyt AIDL: ien toimintaan, muista tarkistaa se Googlen dokumentaatio.
Poista mallimenetelmät AIDL: stä ja lisää sitten a destroy()
menetelmä oikealla tunnuksella Shizukulle. Tätä kutsutaan, kun Shizuku tappaa käyttäjäpalvelun, ja sitä tulisi käyttää mahdollisten viittausten tai jatkuvan logiikan puhdistamiseen.
Esimerkki 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.
}
AIDL: n toteuttaminen
Seuraava asia on todella toteuttaa 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);
}
}
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)
}
}
Yllä olevissa esimerkeissä oletetaan, että sinulla on Android Hidden API SDK asennettuna.
Palveluyhteyden määrittäminen
Nyt kun käyttäjäpalvelu on määritelty ja otettu käyttöön, on aika ottaa se käyttöön. Ensimmäinen asia, joka sinun tulee tehdä, on määrittää ServiceConnection, jossa haluat kommunikoida sen kanssa (esim. sovelluksesi päätoiminnosta).
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;
}
}
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;
}
}
The binder
muuttuja on se, mitä käytät kommunikoidaksesi käyttäjäpalvelun kanssa sovelluksestasi. Tarkistaaksesi, onko se käytettävissä, tarkista vain, että se ei ole tyhjä pingBinder()
palaa totta, aivan kuten yllä olevassa koodiesimerkissä.
Luodaan User Service -argumentteja
Ennen kuin voit hallita käyttäjäpalvelua, sinun on määritettävä joitain argumentteja, joita Shizuku käyttää sen käynnistämisessä ja pysäyttämisessä. Näitä ovat esimerkiksi palvelun luokan nimen kertominen Shizukulle, prosessin jälkiliitteen määrittäminen, onko se virheenkorjattavissa ja mikä versio se on.
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);
Kotlin:
private val serviceArgs = Shizuku.UserServiceArgs(
ComponentName(BuildConfig.APPLICATION_ID, UserService.class::java.getName()))
.processNameSuffix("user_service")
.debuggable(BuildCOnfig.DEBUG)
.version(BuildConfig.VERSION_CODE)
Käyttäjäpalvelun käynnistäminen, pysäyttäminen ja sitominen
Aloitus- ja sitomistoiminnot sekä lopetus- ja sidontatoiminnot ovat yhtenäisiä Shizukussa. Ei ole olemassa erillisiä aloitus- ja sidontamenetelmiä tai lopetus- ja sidontamenetelmiä.
Näin aloittaa ja sitoa Käyttäjäpalveluun.
Java:
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.
}
Näin pysäyttää ja irrottaa Käyttäjäpalveluun.
Java:
if (Shizuku.getVersion >= 10) {
Shizuku.unbindUserService(serviceArgs, connection, true);
}
Kotlin:
if (Shizuku.getVersion >= 10) {
Shizuku.unbindUserService(serviceArgs, connection, true)
}
Käyttäjäpalvelun kutsuminen
Kun käyttäjäpalvelu on käynnistetty, voit aloittaa sen käytön. Tarkista vain, onko binder
muuttuja on ei-nolla ja pingattavissa, ja soita sitten menetelmäkutsu.
Java:
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)
}
Johtopäätös
Jos seurasit kaikkea tätä, sinulla pitäisi nyt olla toimiva Shizuku-integraatio. Muista vain pyytää käyttäjiäsi asentamaan Shizuku ja tarkistaa kunnolla, että Shizuku on saatavilla ennen kuin yrität käyttää sitä.