Įsišaknijimas tinka ne visiems. Štai kaip galite gauti padidinto apvalkalo lygio leidimus programoje naudodami Shizuku biblioteką.
Yra daug priežasčių, kodėl paprastai jūsų programai suteikiamų leidimų gali nepakakti. Galbūt esate panašus į mane ir mėgstate kurti įsilaužėlių programas, kurios piktnaudžiauja „Android“ API. Kai kurios mano naudojamos API yra užrakintos naudojant specialius leidimus. Kartais tik apvalkalo vartotojas (ADB) arba sistema gali juos pasiekti. Tačiau yra sprendimas - Shizuku.
„Shizuku“ leidžia iškviesti sistemos API beveik tiesiogiai ir visiškai „Java“ arba „Kotlin“. Šis vadovas parodys, kaip įdiegti ir naudoti Shizuku.
Kas yra Shizuku?
Prieš pradedant naudoti Shizuku, gali būti naudinga žinoti, kas tai yra. Jei esate susipažinę su Magisk, tada Shizuku yra panašus. Tačiau užuot valdęs pagrindinę prieigą, jis valdo prieigą prie apvalkalo.
„Shizuku“ vykdo savo procesą su apvalkalo lygio leidimais. Kaip naudotojas suaktyvina šį procesą, priklauso nuo jo įrenginio, „Android“ versijos ir pasirinkimo. „Shizuku“ galima suaktyvinti per ADB, per įrenginyje esantį belaidį ADB (
„Android 11“ ir naujesnėse versijose), arba per root prieigą. Tada programos, įdiegiančios „Shizuku“, gali prašyti leidimo naudoti šį procesą padidintoms operacijoms atlikti.Kaina: Nemokama.
4.1.
Kodėl Shizuku?
Nors apvalkalo lygio prieiga prie sistemos neleidžia padaryti tiek, kiek šaknis, ji vis tiek suteikia daugiau prieigos nei įprasta programa. Be to, „Shizuku“ veikimo būdas leidžia naudoti „Android“ API beveik kaip įprasta. Jums nereikia pasikliauti apvalkalo komandomis (nors galite, jei norite).
Jei jūsų programai reikia specialių leidimų, kuriuos galima suteikti tik per ADB (arba su root), „Shizuku“ ir „Android 11“ puikiai susieja. Galite tiesiog naudoti „Shizuku“, kad suteiktumėte specialius leidimus visiškai įrenginyje.
Net naudojant įrenginius, kuriuose nėra „Android 11“, „Shizuku“ gali būti naudingas. Programėlė vartotojams pateikia instrukcijas ir scenarijus, todėl jums to nereikia.
Integracija
„Shizuku“ pridėjimas prie programos nėra pats paprasčiausias, bet ir nėra sunkus. Deja, kūrėjo dokumentacija nėra visiškai baigtas, bet šis straipsnis jums skirtas. Štai kaip integruoti Shizuku į savo programą.
Priklausomybės
Pirmasis žingsnis yra pridėti Shizuku priklausomybes. Savo modulio lygio build.gradle prie priklausomybių bloko pridėkite toliau nurodytus dalykus.
def shizuku_version = '11.0.3'
implementation "dev.rikka.shizuku: api:$shizuku_version"
implementation "dev.rikka.shizuku: provider:$shizuku_version"
Jei reikia, būtinai atnaujinkite versiją. 11.0.3 yra naujausias rašymo metu.
Teikėjas
Kad „Shizuku“ veiktų, prie programos aprašo turite pridėti teikėjo bloką. Atidarykite AndroidManifest.xml ir programos bloke pridėkite toliau pateiktą informaciją.
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" />
Leidimas
Autorizavimui „Shizuku“ naudoja vykdymo laiko leidimą. Netrukus pradėsime suteikti leidimą. Kol kas pridėkite jį prie AndroidManifest.xml aprašo bloke.
Dabar, kai visa tai pridėta, pagrindinė integracija atlikta. Leiskite Gradle sinchronizuoti projektą ir pereikite prie Naudojimo.
Naudojimas
Pasiekiamumo tikrinimas
Prieš pradėdami naudoti „Shizuku“, pakalbėkime apie tai, kaip įsitikinti, ar jį iš tikrųjų galima naudoti.
Prieš tikrindami, ar leidimas suteiktas, ir prieš skambindami API per Shizuku, galite įsitikinti, kad tie patikrinimai ir skambučiai bus sėkmingi, naudodami šį metodą:
Shizuku.pingBinder()
Jei „Shizuku“ yra įdiegtas ir paleistas, jis grįš tiesa. Priešingu atveju jis grįš klaidingas.
Leidimo suteikimas
Kadangi „Shizuku“ naudoja vykdymo laiko leidimą, jis turi būti suteiktas jūsų programai, kad galėtumėte ką nors padaryti naudodami apvalkalo prieigą. Taip pat yra dvi API versijos su skirtingais suteikimo būdais. Šiame skyriuje bus parodyta, kaip elgtis abiem atvejais.
Tikrinama
Prieš prašydami leidimo, geriausia patikrinti, ar jį jau turite. Jei tai padarysite, galite tęsti viską, ką jums reikia padaryti. Priešingu atveju prieš tęsdami turėsite pateikti užklausą.
Norėdami patikrinti, ar turite leidimą naudoti „Shizuku“, galite naudoti šiuos veiksmus. Šis kodas daro prielaidą, kad jį vykdote veikloje.
Kotlinas:
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;
}
Prašymas
Jei reikia prašyti leidimo naudoti „Shizuku“, štai kaip.
The SHIZUKU_CODE toliau naudojamas kintamasis turi būti sveikas skaičius su pastovia verte (statinis kintamasis).
Kotlinas:
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);
}
Norėdami klausytis rezultato, turėsite nepaisyti veiklos onRequestPermissionsResult() metodas. Taip pat reikės įgyvendinti Šizuku. OnRequestPermissionResultListener. Pavyzdyje, kurį parodysiu, daroma prielaida, kad jūsų veikla įgyvendina tą sąsają, tačiau, jei norite, galite ją įdiegti kintamajame.
Kotlinas:
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.
}
}
Naudojant API
Dabar, kai „Shizuku“ nustatytas ir suteikiami leidimai, galite pradėti skambinti API naudodami „Shizuku“. Procesas čia yra šiek tiek kitoks nei esate įpratę. Užuot skambinęs getSystemService()
ir mesti į kažką panašaus WindowManager
, vietoj jų turėsite naudoti vidines API (pvz., IWindowManager
).
„Shizuku“ apima „Android“ paslėpto API juodojo sąrašo apėjimą, todėl naudojant jį nereikės dėl to jaudintis. Vis dėlto, jei jums įdomu, kaip tai apeiti, peržiūrėkite mano ankstesnę mokymo programą.
Pateikiame trumpą pavyzdį (naudojant refleksiją), parodantį, kaip galite gauti pavyzdį IPackageManager
ir naudokite jį, kad suteiktumėte programai vykdymo laiko leidimą.
Kotlinas:
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);
Kitų API procesas yra panašus. Gaukite nuorodas į klasę ir jos „Stub“ poklasį. Gaukite nuorodą į asInterface
metodas Stub klasei. Gaukite nuorodas į norimus metodus iš pačios klasės. Tada iškvieskite asInterface
metodo nuoroda, kurią turite, pakeičiant "package"
aukščiau su bet kokia jums reikalinga paslauga. Tada tą atvejį galima perduoti metodų iškvietimams.
Pro patarimas: galite visiškai nenaudoti atspindžio, jei įdiegiate modifikuotą SDK. Peržiūrėkite anggrayudi „GitHub“ saugyklą modifikuotiems SDK ir diegimo instrukcijoms. Tai įdiegus, aukščiau pateiktas kodas (Kotlin) tampa daug paprastesnis.
val iPm = IPackageManager.Stub.asInterface(ShizukuBinderWrapper(SystemServiceHelper.getService("package"))))
iPm.grantRuntimePermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0)
Bet kurios AIDL pagrįstos API gali būti naudojamos naudojant šį metodą bet kurioje programos vietoje, jei veikia „Shizuku“ ir programa turi leidimą.
Vartotojo paslauga
Nors Binder metodas apima daugumą naudojimo atvejų, kartais gali prireikti API, kuri neturi tiesioginės Binder sąsajos. Tokiu atveju galite naudoti „Shizuku“ vartotojo aptarnavimo funkciją.
Šis metodas veikia panašiai kaip įprasta paslauga „Android“. Jūs jį „paleidžiate“, susisiekite su juo su ServiceConnection ir paleisite savo logiką paslaugų klasėje. Skirtumas yra tas, kad jūs nenaudojate „Android“ paslaugos, o bet kas paslaugos viduje veikia su ADB leidimais.
Dabar yra tam tikrų apribojimų. Vartotojo paslauga veikia visiškai atskiru procesu ir vartotoju, todėl negalite bendrauti su likusia programa, išskyrus savo AIDL atgalinius skambučius ir segtuvus. Kadangi ji taip pat neveikia tinkamai programos procese, kai kurie dalykai, pvz., „Android“ paslaugų susiejimas, gali neveikti tinkamai.
Tam taip pat reikalinga 10 ar naujesnė „Shizuku“ versija. Nors šiuo metu daugumoje programos šaltinių yra 11 versija, vis tiek turėtumėte įtraukti versijos patikrą, kuri bus įtraukta į pavyzdį.
AIDL apibrėžimas
Norėdami pradėti, turėsite sukurti naują AIDL failą. Tai galite padaryti „Android Studio“ dešiniuoju pelės mygtuku spustelėdami bet ką „Android“ failo rodinyje, užvesdami pelės žymeklį ant parinkties „Naujas“ ir pasirinkę parinktį „AIDL“. Įveskite failo pavadinimą (pvz., „IUserService“), o „Android Studio“ sukurs šablono failą.
Jei nesate susipažinę su AIDL veikimo principu, būtinai patikrinkite Google dokumentacija.
Pašalinkite šablono metodus iš AIDL ir pridėkite a destroy()
metodas su tinkamu Shizuku ID. Tai bus iškviesta, kai Shizuku užmuša naudotojo paslaugą, ir turėtų būti naudojama norint išvalyti visas nuorodas ar nuolatinę logiką.
AIDL pavyzdys:
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 įgyvendinimas
Kitas dalykas, kurį reikia padaryti, yra iš tikrųjų įgyvendinti 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);
}
}
Kotlinas:
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)
}
}
Aukščiau pateikti pavyzdžiai daro prielaidą, kad turite Android Hidden API SDK įdiegtas.
Paslaugos ryšio nustatymas
Dabar, kai vartotojo paslauga apibrėžta ir įdiegta, laikas ją nustatyti naudoti. Pirmas dalykas, kurį turėtumėte padaryti, yra apibrėžti ServiceConnection, kur norite su juo susisiekti (pvz., iš pagrindinės programos veiklos).
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;
}
}
Kotlinas:
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
kintamasis yra tai, ką naudosite bendraudami su naudotojo paslauga iš savo programos. Norėdami patikrinti, ar jį galima naudoti, tiesiog patikrinkite, ar jis nėra niekinis, ir tai pingBinder()
grįžta tiesa, kaip ir anksčiau pateiktame kodo pavyzdyje.
Vartotojo paslaugos argumentų kūrimas
Kad galėtumėte valdyti vartotojo paslaugą, turėsite apibrėžti kai kuriuos argumentus, kuriuos Shizuku naudotų ją paleidžiant ir sustabdant. Tai apima tokius dalykus kaip faktinis paslaugos klasės pavadinimo pasakymas Shizuku, proceso galūnės nurodymas, ar galima derinti, ar ne, ir kokia ji yra.
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);
Kotlinas:
private val serviceArgs = Shizuku.UserServiceArgs(
ComponentName(BuildConfig.APPLICATION_ID, UserService.class::java.getName()))
.processNameSuffix("user_service")
.debuggable(BuildCOnfig.DEBUG)
.version(BuildConfig.VERSION_CODE)
Vartotojo paslaugos paleidimas, sustabdymas ir susiejimas
Paleidimo ir surišimo bei sustabdymo ir atrišimo veiksmai yra suvienodinti Shizuku. Nėra atskirų pradžios ir susiejimo metodų arba sustabdymo ir atšaukimo metodų.
Štai kaip tai padaryti pradėti ir susieti Vartotojo paslauga.
Java:
if (Shizuku.getVersion >= 10) {
//This only works on Shizuku 10 or later.
Shizuku.bindUserService(serviceArgs, connection);
} else {
//Tell the user to upgrade Shizuku.
}
Kotlinas:
if (Shizuku.getVersion() >= 10) {
//This only works on Shizuku 10 or later.
Shizuku.bindUserService(serviceArgs, connection)
} else {
//Tell the user to upgrade Shizuku.
}
Štai kaip tai padaryti sustabdyti ir atrišti Vartotojo paslauga.
Java:
if (Shizuku.getVersion >= 10) {
Shizuku.unbindUserService(serviceArgs, connection, true);
}
Kotlinas:
if (Shizuku.getVersion >= 10) {
Shizuku.unbindUserService(serviceArgs, connection, true)
}
Vartotojo paslaugos iškvietimas
Paleidę Vartotojo paslaugą galite pradėti ja naudotis. Tiesiog patikrinkite, ar binder
kintamasis nėra nulis ir gali būti pinguojamas, tada iškvieskite metodą.
Java:
if (binder != null && binder.pingBinder()) {
binder.grantPermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0);
}
Kotlinas:
if (binder?.pingBinder() == true) {
binder?.grantPermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0)
}
Išvada
Jei atliksite visa tai, dabar turėtumėte turėti veikiančią Shizuku integraciją. Tiesiog nepamirškite pasakyti savo vartotojams, kad jie įdiegtų „Shizuku“ ir prieš bandydami jį naudoti tinkamai patikrinti, ar „Shizuku“ yra.