Rooting არ არის ყველასთვის. აი, როგორ შეგიძლიათ მიიღოთ ამაღლებული გარსის დონის ნებართვები თქვენს აპლიკაციაში Shizuku ბიბლიოთეკის გამოყენებით.
არსებობს მრავალი მიზეზი, რის გამოც თქვენს აპლიკაციას ჩვეულებრივ მინიჭებული ნებართვები შეიძლება არ იყოს საკმარისი. იქნებ თქვენც ჩემნაირი ხართ და გსიამოვნებთ ჰაკიური აპების შექმნით, რომლებიც ბოროტად იყენებენ Android API-ს. ზოგიერთი API, რომელსაც მე ვიყენებ, ჩაკეტილია სპეციალური ნებართვების მიღმა. ზოგჯერ მხოლოდ shell მომხმარებელს (ADB) ან სისტემას შეუძლია მათზე წვდომა. თუმცა გამოსავალი არსებობს - შიზუკუ.
Shizuku საშუალებას გაძლევთ დარეკოთ სისტემის API-ები თითქმის პირდაპირ და მთლიანად Java-ში ან Kotlin-ში. ეს სახელმძღვანელო გაჩვენებთ, თუ როგორ უნდა დანერგოთ და გამოიყენოთ Shizuku.
რა არის შიზუკუ?
სანამ Shizuku-ს გამოყენებას შევუდგებით, შეიძლება სასარგებლო იყოს იმის ცოდნა, თუ რა არის ეს. თუ იცნობთ მაგისკი, მაშინ შიზუკუ მსგავსია. მაგრამ root წვდომის მართვის ნაცვლად, ის მართავს ჭურვის წვდომას.
Shizuku მართავს საკუთარ პროცესს ჭურვის დონის ნებართვებით. როგორ ააქტიურებს მომხმარებელი ამ პროცესს, დამოკიდებულია მის მოწყობილობაზე, Android ვერსიაზე და არჩევანზე. Shizuku შეიძლება გააქტიურდეს ADB-ის მეშვეობით, მოწყობილობაზე უკაბელო ADB-ის მეშვეობით (
Android 11-ზე და შემდეგზე), ან root წვდომის საშუალებით. აპებს, რომლებიც ახორციელებენ Shizuku-ს, შეუძლიათ მოითხოვონ ნებართვა, გამოიყენონ ეს პროცესი ამაღლებული ოპერაციების შესასრულებლად.ფასი: უფასო.
4.1.
რატომ შიზუკუ?
მიუხედავად იმისა, რომ ჭურვის დონის წვდომა სისტემაში არ გაძლევს იმდენის გაკეთების საშუალებას ფესვი, ის მაინც გაძლევთ უფრო მეტ წვდომას, ვიდრე ჩვეულებრივი აპლიკაცია. გარდა ამისა, Shizuku-ს მუშაობის წესი საშუალებას გაძლევთ გამოიყენოთ Android API-ები თითქმის ჩვეულებრივად. თქვენ არ უნდა დაეყრდნოთ ჭურვის ბრძანებებს (თუმცა შეგიძლიათ, თუ გსურთ).
თუ თქვენს აპს ესაჭიროება სპეციალური ნებართვები, რომელთა მინიჭება შესაძლებელია მხოლოდ ADB-ის საშუალებით (ან root-ით), Shizuku და Android 11 ქმნიან შესანიშნავ დაწყვილებას. თქვენ შეგიძლიათ უბრალოდ გამოიყენოთ Shizuku სპეციალური ნებართვების მისაცემად მთლიანად მოწყობილობაზე.
იმ მოწყობილობებითაც კი, რომლებიც არ არის Android 11-ზე, Shizuku შეიძლება სასარგებლო იყოს. აპლიკაცია უზრუნველყოფს ინსტრუქციებს და სკრიპტებს მომხმარებლებისთვის, ასე რომ თქვენ არ გჭირდებათ.
ინტეგრაცია
Shizuku-ს თქვენს აპლიკაციაში დამატება არ არის უმარტივესი, მაგრამ არც რთული. სამწუხაროდ, დეველოპერის დოკუმენტაცია არ არის ზუსტად სრული, მაგრამ ეს სტატია გაშუქდა. აი, როგორ დააკავშიროთ Shizuku თქვენს აპლიკაციაში.
დამოკიდებულებები
პირველი ნაბიჯი არის შიზუკუს დამოკიდებულებების დამატება. თქვენი მოდულის დონის build.gradle-ში დაამატეთ შემდეგი დამოკიდებულებების ბლოკს.
def shizuku_version = '11.0.3'
implementation "dev.rikka.shizuku: api:$shizuku_version"
implementation "dev.rikka.shizuku: provider:$shizuku_version"
დარწმუნდით, რომ განაახლეთ ვერსია საჭიროების შემთხვევაში. 11.0.3 არის უახლესი წერის მომენტში.
პროვაიდერი
იმისათვის, რომ Shizuku-მ იმუშაოს, თქვენ უნდა დაამატოთ პროვაიდერის ბლოკი თქვენი აპლიკაციის მანიფესტში. გახსენით AndroidManifest.xml და დაამატეთ შემდეგი აპლიკაციის ბლოკში.
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" />
ნებართვა
ავტორიზაციისთვის, Shizuku იყენებს გაშვების ნებართვას. ამ ნებართვის გაცემას ცოტა ხანში შევუდგებით. ახლა დაამატეთ იგი AndroidManifest.xml-ს მანიფესტის ბლოკში.
ახლა, როდესაც ეს ყველაფერი დაემატა, ძირითადი ინტეგრაცია შესრულებულია. მიეცით Gradle-ს პროექტის სინქრონიზაციის საშუალება და განაგრძეთ გამოყენება.
გამოყენება
ხელმისაწვდომობის შემოწმება
სანამ Shizuku-ს გამოყენებას შევეხებით, მოდით ვისაუბროთ იმაზე, რომ დავრწმუნდეთ, რომ ის რეალურად ხელმისაწვდომია გამოსაყენებლად.
სანამ შეამოწმებთ, არის თუ არა ნებართვა მინიჭებული და API ზარების განხორციელებამდე Shizuku-ს მეშვეობით, შეგიძლიათ დარწმუნდეთ, რომ ეს შემოწმება და ზარები წარმატებული იქნება შემდეგი მეთოდით:
Shizuku.pingBinder()
თუ Shizuku დაინსტალირებულია და მუშაობს, ის დაბრუნდება მართალია. წინააღმდეგ შემთხვევაში, ის დაბრუნდება ყალბი.
ნებართვის გაცემა
ვინაიდან Shizuku იყენებს გაშვების ნებართვას, ის უნდა მიენიჭოს თქვენს აპს, სანამ რაიმეს გააკეთებთ ჭურვის წვდომით. ასევე მიმოქცევაშია ორი API ვერსია, მისი მინიჭების სხვადასხვა გზით. ეს განყოფილება გაჩვენებთ, თუ როგორ უნდა გაუმკლავდეთ ორივეს.
შემოწმება
სანამ ნებართვას მოითხოვთ, საუკეთესო რამ არის იმის შემოწმება, უკვე გაქვთ თუ არა იგი. თუ ამას აკეთებთ, შეგიძლიათ გააგრძელოთ ის, რაც გჭირდებათ. წინააღმდეგ შემთხვევაში, გაგრძელებამდე უნდა მოითხოვოთ.
იმის შესამოწმებლად, გაქვთ თუ არა შიზუკუს გამოყენების ნებართვა, შეგიძლიათ გამოიყენოთ შემდეგი. ეს კოდი ვარაუდობს, რომ თქვენ მას აწარმოებთ აქტივობის შიგნით.
კოტლინი:
val isGranted = if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
checkSelfPermission(ShizukuProvider.PERMISSION) == PackageManager.PERMISSION_GRANTED
} else {
Shizuku.checkSelfPermission() = PackageManager.PERMISSION_GRANTED
}
ჯავა:
boolean isGranted;
if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
isGranted = checkSelfPermission(ShizukuProvider.PERMISSION) == PackageManager.PERMISSION_GRANTED;
} else {
isGranted = Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED;
}
ითხოვს
თუ შიზუკუს გამოყენების ნებართვა გჭირდებათ, აი, როგორ.
The SHIZUKU_CODE ქვემოთ გამოყენებული ცვლადი უნდა იყოს მთელი რიცხვი სტაბილური მნიშვნელობით (სტატიკური ცვლადი).
კოტლინი:
if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
requestPermissions(arrayOf(ShizukuProvider.PERMISSION), SHIZUKU_CODE)
} else {
Shizuku.requestPermission(SHIZUKU_CODE)
}
ჯავა:
if (Shizuku.isPreV11() || Shizuku.getVersion() < 11) {
requestPermissions(newString[] { ShizukuProvider.PERMISSION }, SHIZUKU_CODE);
} else {
Shizuku.requestPermissions(SHIZUKU_CODE);
}
შედეგის მოსასმენად მოგიწევთ Activity-ის უგულებელყოფა onRequestPermissionsResult() მეთოდი. თქვენ ასევე დაგჭირდებათ განხორციელება შიზუკუ. OnRequestPermissionResultListener. მაგალითი, რომლის ჩვენებასაც ვაპირებ, ვარაუდობს, რომ თქვენი აქტივობა ახორციელებს ამ ინტერფეისს, მაგრამ თუ გსურთ, შეგიძლიათ მისი დანერგვა ცვლადში.
კოტლინი:
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.
}
}
ჯავა:
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-ების გამოყენება
ახლა, როდესაც Shizuku დაყენებულია და ნებართვები მინიჭებულია, შეგიძლიათ რეალურად დაიწყოთ API-ების გამოძახება Shizuku-ს გამოყენებით. აქ პროცესი ცოტათი განსხვავებულია, ვიდრე თქვენ შეიძლება იყოთ მიჩვეული. დარეკვის ნაცვლად getSystemService()
და კასტინგი რაღაცის მსგავსზე WindowManager
, ამის ნაცვლად თქვენ მოგიწევთ შიდა API-ების გამოყენება (მაგ. IWindowManager
).
Shizuku შეიცავს Android-ის დამალული API შავი სიის შემოვლით, ასე რომ თქვენ არ დაგჭირდებათ ამაზე ფიქრი მისი გამოყენებისას. თუ თქვენ გაინტერესებთ, როგორ ავუაროთ ამას თავად, შეამოწმეთ ჩემი წინა გაკვეთილი.
აქ არის სწრაფი მაგალითი (რეფლექსიის გამოყენებით), რომელიც გაჩვენებთ, თუ როგორ შეგიძლიათ მიიღოთ მაგალითი IPackageManager
და გამოიყენეთ იგი აპისთვის მუშაობის დროის ნებართვის მისაცემად.
კოტლინი:
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)
ჯავა:
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);
სხვა API-ების პროცესი მსგავსია. მიიღეთ მითითებები კლასისა და მისი Stub ქვეკლასისთვის. მიიღეთ მითითება asInterface
მეთოდი Stub კლასისთვის. მიიღეთ მითითებები თქვენთვის სასურველ მეთოდებზე თავად კლასიდან. შემდეგ, გამოიძახეთ asInterface
მეთოდის მითითება გაქვთ, ჩანაცვლება "package"
ზემოთ ნებისმიერი სერვისით რაც გჭირდებათ. შემდეგ ეს მაგალითი შეიძლება გადავიდეს მეთოდის გამოძახებისთვის.
პრო-წვერი: თქვენ შეგიძლიათ თავიდან აიცილოთ ასახვის გამოყენება, თუ თქვენ დააინსტალირებთ შეცვლილ SDK-ს. შეამოწმეთ anggrayudi-ის GitHub საცავი შეცვლილი SDK-ებისთვის და ინსტალაციის ინსტრუქციებისთვის. ამ დაყენებით, ზემოაღნიშნული კოდი (კოტლინში) სულ უფრო მარტივი ხდება.
val iPm = IPackageManager.Stub.asInterface(ShizukuBinderWrapper(SystemServiceHelper.getService("package"))))
iPm.grantRuntimePermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0)
ნებისმიერი AIDL-ზე დაფუძნებული API შეიძლება გამოყენებულ იქნას ამ მეთოდით თქვენი აპის ნებისმიერი ადგილიდან, სანამ Shizuku მუშაობს და თქვენს აპს აქვს ნებართვა.
მომხმარებლის სერვისი
მიუხედავად იმისა, რომ Binder მეთოდი მოიცავს გამოყენების შემთხვევების უმეტესობას, შეიძლება იყოს შემთხვევები, როდესაც გჭირდებათ API, რომელსაც არ აქვს პირდაპირი Binder ინტერფეისი. ამ შემთხვევაში, შეგიძლიათ გამოიყენოთ მომხმარებლის სერვისის ფუნქცია Shizuku-ში.
ეს მეთოდი მუშაობს ანდროიდის ჩვეულებრივი სერვისის მსგავსად. თქვენ "იწყებთ", დაუკავშირდებით მას ServiceConnection-ით და აწარმოებთ თქვენს ლოგიკას სერვისის კლასში. განსხვავება ისაა, რომ თქვენ არ იყენებთ Android-ის სერვისს და სერვისის შიგნით ყველაფერი მუშაობს ADB ნებართვით.
ახლა არის გარკვეული შეზღუდვები. მომხმარებლის სერვისი მუშაობს სრულიად განცალკევებულ პროცესში და მომხმარებელს, ასე რომ თქვენ არ შეგიძლიათ დაუკავშირდეთ თქვენს დანარჩენ აპს, გარდა თქვენი საკუთარი AIDL გამოხმაურებისა და ბაინდერების საშუალებით. იმის გამო, რომ ის ასევე არ მუშაობს აპლიკაციის სათანადო პროცესში, ზოგიერთი რამ, როგორიცაა Android სერვისების დაკავშირება, შეიძლება გამართულად არ იმუშაოს.
ეს ასევე მოითხოვს Shizuku ვერსია 10 ან უფრო გვიან. მიუხედავად იმისა, რომ აპის წყაროების უმეტესობას ამჟამად აქვს ვერსია 11, თქვენ მაინც უნდა შეიტანოთ ვერსიის შემოწმება, რომელიც ჩართული იქნება მაგალითში.
AIDL-ის განსაზღვრა
დასაწყებად, თქვენ უნდა შექმნათ ახალი AIDL ფაილი. ამის გაკეთება შეგიძლიათ Android Studio-ში, თუ დააწკაპუნეთ მაუსის მარჯვენა ღილაკით ნებისმიერზე Android ფაილის ხედში, გადაიტანთ „ახალ“ ოფციაზე და აირჩევთ „AIDL“ ოფციას. შეიყვანეთ ფაილის სახელი (მაგ., "IUserService") და Android Studio შექმნის შაბლონის ფაილს თქვენთვის.
თუ არ იცით როგორ მუშაობს AIDL-ები, აუცილებლად შეამოწმეთ Google-ის დოკუმენტაცია.
ამოიღეთ შაბლონის მეთოდები AIDL-დან და შემდეგ დაამატეთ a destroy()
მეთოდი Shizuku-სთვის შესაბამისი ID-ით. ეს გამოიძახება, როდესაც Shizuku კლავს მომხმარებლის სერვისს და უნდა იქნას გამოყენებული ნებისმიერი მითითების ან მიმდინარე ლოგიკის გასასუფთავებლად, რაც გაქვთ.
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-ის განხორციელება
შემდეგი რაც უნდა გააკეთოთ არის AIDL-ის რეალურად განხორციელება.
ჯავა:
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);
}
}
კოტლინი:
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)
}
}
ზემოთ მოყვანილი მაგალითები ვარაუდობენ, რომ თქვენ გაქვთ Android დამალული API დაინსტალირებულია SDK.
სერვისის კავშირის დაყენება
ახლა, როდესაც მომხმარებლის სერვისი განსაზღვრულია და დანერგილია, დროა მისი დაყენება გამოსაყენებლად. პირველი, რაც უნდა გააკეთოთ, არის განსაზღვროთ ServiceConnection, სადაც გსურთ მასთან კომუნიკაცია (მაგ., თქვენი აპის ძირითადი აქტივობიდან).
ჯავა:
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;
}
}
კოტლინი:
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
ცვლადი არის ის, რასაც გამოიყენებთ თქვენი აპიდან მომხმარებლის სერვისთან კომუნიკაციისთვის. იმის შესამოწმებლად, ხელმისაწვდომია თუ არა გამოსაყენებლად, უბრალოდ შეამოწმეთ, რომ ის არ არის null და ეს pingBinder()
ბრუნდება მართალია, ისევე როგორც ზემოთ მოცემული კოდის მაგალითში.
მომხმარებლის სერვისის არგუმენტების შექმნა
სანამ მომხმარებლის სერვისის მართვას შეძლებთ, თქვენ უნდა განსაზღვროთ რამდენიმე არგუმენტი, რომ Shizuku გამოიყენოს მისი გაშვებისა და შეჩერებისას. ეს მოიცავს ისეთ რაღაცეებს, როგორიცაა შიზუკუს სერვისის კლასის სახელის რეალურად თქმა, პროცესის სუფიქსის მითითება, გამართვადია თუ არა და რა ვერსიაა.
ჯავა:
privatefinal Shizuku.UserServiceArgs serviceArgs = new Shizuku.UserServiceArgs(
newComponentName(BuildConfig.APPLICATION_ID, UserService.class.getName()))
.processNameSuffix("user_service")
.debuggable(BuildConfig.DEBUG)
.version(BuildConfig.VERSION_CODE);
კოტლინი:
private val serviceArgs = Shizuku.UserServiceArgs(
ComponentName(BuildConfig.APPLICATION_ID, UserService.class::java.getName()))
.processNameSuffix("user_service")
.debuggable(BuildCOnfig.DEBUG)
.version(BuildConfig.VERSION_CODE)
მომხმარებლის სერვისის დაწყება, შეჩერება და დაკავშირება
შიზუკუში გაერთიანებულია დაწყების და შებოჭვის მოქმედებები და გაჩერების და გაუქმების მოქმედებები. არ არსებობს ცალ-ცალკე დაწყებისა და შებოჭვის მეთოდები ან გაჩერებისა და გაუქმების მეთოდები.
აი როგორ დაწყება და შებოჭვა მომხმარებლის სერვისი.
ჯავა:
if (Shizuku.getVersion >= 10) {
//This only works on Shizuku 10 or later.
Shizuku.bindUserService(serviceArgs, connection);
} else {
//Tell the user to upgrade Shizuku.
}
კოტლინი:
if (Shizuku.getVersion() >= 10) {
//This only works on Shizuku 10 or later.
Shizuku.bindUserService(serviceArgs, connection)
} else {
//Tell the user to upgrade Shizuku.
}
აი როგორ შეაჩერე და გაშალე მომხმარებლის სერვისი.
ჯავა:
if (Shizuku.getVersion >= 10) {
Shizuku.unbindUserService(serviceArgs, connection, true);
}
კოტლინი:
if (Shizuku.getVersion >= 10) {
Shizuku.unbindUserService(serviceArgs, connection, true)
}
მომხმარებლის სერვისის გამოძახება
მომხმარებლის სერვისის დაწყების შემდეგ, შეგიძლიათ დაიწყოთ მისი გამოყენება. უბრალოდ შეამოწმეთ თუ არა binder
ცვლადი არის არა null და pingable და შემდეგ გააკეთეთ თქვენი მეთოდის გამოძახება.
ჯავა:
if (binder != null && binder.pingBinder()) {
binder.grantPermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0);
}
კოტლინი:
if (binder?.pingBinder() == true) {
binder?.grantPermission("com.zacharee1.systemuituner", android.Manifest.permission.WRITE_SECURE_SETTINGS, 0)
}
დასკვნა
თუ თქვენ მიჰყევით ამ ყველაფერს, ახლა უნდა გქონდეთ სამუშაო Shizuku ინტეგრაცია. უბრალოდ დაიმახსოვრე, რომ უთხარი თქვენს მომხმარებლებს დააინსტალირონ Shizuku და სწორად შეამოწმონ, რომ Shizuku ხელმისაწვდომია, სანამ შეეცდებით მის გამოყენებას.