როგორ ავუაროთ ფარული API შავ სიას Android 9+-ზე

Google-მა Android 9-ში შემოიღო შეზღუდვები, რომლებზეც API-ებზე წვდომა შეუძლიათ დეველოპერებს. აქ მოცემულია, თუ როგორ უნდა გადალახოთ ეს ფარული API შეზღუდვები.

2018 წელს Google-მა გამოუშვა Android Pie. ინტერფეისის ცვლილებებსა და ახალ ფუნქციებს შორის, ასევე იყო გარკვეული ცვლილებები დეველოპერის მხრიდან. ეს ცვლილებები მოიცავდა ახალ API-ებს, არსებული API-ების შეცდომების გამოსწორებას და ასევე ფარული API-ებზე წვდომის შეზღუდვები.

თუმცა, საბედნიეროდ, ამ შეზღუდვების თავიდან აცილების გზები არსებობს. სანამ შევეხები, თუ როგორ უნდა ავიცილოთ შეზღუდვების გვერდის ავლით, ცოტათი უნდა აგიხსნათ რა არის ფარული API-ები, რატომ შეიზღუდა ისინი თავიდან და რატომ შეიძლება გინდოდეთ მათზე წვდომა.

დამალული API არის API-ები Android-ში, რომლებსაც აპების დეველოპერები ჩვეულებრივ ვერ ხედავენ. თუ გადახედავთ AOSP-ის კოდს, დაინახავთ კლასების, ცვლადების და მეთოდების მთელ ჯგუფს, რომლებსაც აქვთ @hide ანოტაცია მათ ზემოთ კომენტარების ბლოკში.

ეს ანოტაცია ავალებს ნებისმიერ ინსტრუმენტს, რომელსაც Google გამოიყენებს SDK-ის შედგენისას, გამორიცხოს მის ქვეშ მყოფი ელემენტი. ეს SDK შემდეგ ნაწილდება დეველოპერებზე Android Studio-დან გადმოწერილი SDK-ების შიგნით. თუ არ იყენებთ შეცვლილ SDK-ს, Android Studio იფიქრებს, რომ რომელიმე ფარული ელემენტი უბრალოდ არ არსებობს. თუ თქვენ ცდილობთ გამოიყენოთ ერთი პირდაპირ, ის გამოჩნდება წითლად და უარს იტყვის კომპილაციაზე.

არსებობს მრავალი მიზეზი, რის გამოც API შეიძლება დამალული იყოს. ზოგიერთი ნივთი განკუთვნილია მხოლოდ შიდა ან სისტემური აპებისთვის გამოსაყენებლად და არ იმუშავებს, თუ გამოიყენება მესამე მხარის აპის მიერ. სხვები არის ექსპერიმენტული ან არასტაბილური და შესაძლოა წაიშალოს ან შეიცვალოს მომავალში. ზოგიერთი კი უბრალოდ API-ებია, გუგლს უბრალოდ არ სურს გაატაროს ნორმალური გაუქმების ციკლი, თუ ისინი ოდესმე წაიშლება.

მიუხედავად იმისა, რომ სტანდარტულ Android SDK-ს აქვს ა ბევრი მასში, ზოგჯერ ეს არ არის საკმარისი. ზოგჯერ არის რაღაც, რისი გაკეთებაც გსურთ, რომელიც უკვე არსებობს Android-ში, მაგრამ უბრალოდ არ არის საჯაროდ გამოვლენილი.

მაგალითად, მე ვაკეთებ ბევრ აპლიკაციას, მათ შორის SystemUI ტიუნერი და ჩაკეტილი ეკრანის ვიჯეტები, გამოიყენეთ სხვადასხვა ფარული API-ების სიმრავლე. SystemUI Tuner-ს სჭირდება წვდომა ზოგიერთზე, რათა სწორად თვალყური ადევნოს, შეცვალოს და გადატვირთოს პარამეტრები. Lockscreen Widgets იყენებს ზოგიერთს მის ქვეშ არსებული ფონის საჩვენებლად, სხვა საკითხებთან ერთად.

დეველოპერების უმეტესობას არ სჭირდება ფარული API-ებზე წვდომა, მაგრამ ზოგჯერ ისინი შეიძლება საკმაოდ სასარგებლო იყოს.

Android 9-ის (Pie) გამოშვებით Google-მა შემოიტანა ფარული API შავი სია. ყველა ფარული API არ იყო ჩართული და იყო სხვადასხვა დონის სიები. თეთრ სიაში დამალულ API-ებზე წვდომა ნებისმიერს შეეძლო. ღია ნაცრისფერ სიაში დამალულ API-ებზე წვდომა ნებისმიერ აპს შეუძლია, მაგრამ შესაძლოა მიუწვდომელი იყოს Android-ის მომავალ ვერსიებში. მუქ-ნაცრისფერ სიაში ნებისმიერზე წვდომა შეიძლებოდა მხოლოდ აპებისთვის, რომლებიც მიზნად ისახავს API დონეებს Pie-მდე (ანუ API დონემდე 28). აპლიკაციებს, რომლებიც მიზნად ისახავს Pie-ს და მოგვიანებით, აკრძალული იქნება წვდომა. დაბოლოს, შავ სიაში დამალულ API-ებზე წვდომა არ შეიძლებოდა არასისტემური (ან არათეთრ სიაში) აპისთვის, მიუხედავად სამიზნე API-ისა.

Android 10-მა შეცვალა სიების ორგანიზება და ოდნავ გაამარტივა ისინი, მაგრამ იდეა იგივე დარჩა. ზოგიერთ ფარულ API-ზე წვდომა შეიძლებოდა აპებისთვის, ხოლო სხვები დაბლოკილი იყო. Android 11 გააძლიერა დაშვების ამოცნობა რომ დაბლოკოს შემოვლითი გზა გამოიყენება ტორტისთვის და 10.

Android-ის ყველა ვერსიაში, ნებისმიერ დროს, როცა მესამე მხარის აპლიკაცია შეეცდება წვდომას შავ სიაში შეყვანილ ფარულ API-ზე, Android გამოუშვებს შესაბამის შეცდომას „არ მოიძებნა“.

რეალურად არსებობს რამდენიმე გზა, რომ გადალახოთ ფარული API შავი სია. თქვენი საჭიროებიდან გამომდინარე, შეგიძლიათ აირჩიოთ ის, რომელიც მუშაობს Android-ის ყველა ვერსიისთვის, რომლებიც მუშაობენ მხოლოდ Android 9 და 10-ზე, რომლებიც იყენებენ მშობლიურ C++ კოდს და რომლებიც სრულად დაფუძნებულია Java-ზე. ADB-ის გამოყენებით მხოლოდ განვითარების გამოსავალიც კი არსებობს.

ADB გამოსავალი

თუ თქვენს მოწყობილობაზე მუშაობს Android Pie, გაუშვით შემდეგი ორი ADB ბრძანება, რათა ჩართოთ ფარული API წვდომა.

adb shell settings put global hidden_api_policy_pre_p_apps 1
adb shell settings put global hidden_api_policy_p_apps 1

თუ თქვენს მოწყობილობას აქვს Android 10 ან უფრო ახალი ვერსია, გაუშვით შემდეგი ADB ბრძანება, რათა ჩართოთ ფარული API წვდომა.

adb shell settings put global hidden_api_policy 1

ნაგულისხმევი ქცევის დასაბრუნებლად, უბრალოდ შეცვალეთ put თან delete და ამოიღეთ 1.

ცხადია, ეს ბრძანებები არ არის ზუსტად გამოსადეგი საწარმოო აპისთვის. პირადად შემიძლია გითხრათ, რომ მომხმარებლების სწორად ინსტრუქციები ADB-ის გამოყენების შესახებ წარმოუდგენლად რთულია. მაგრამ ისინი შეიძლება სასარგებლო იყოს, თუ გჭირდებათ ძველი აპლიკაციის განახლება ახალი შეზღუდვების შესასრულებლად.

მშობლიური/JNI გამოსავალი

არსებობს ორი გზა, რომლითაც შეგიძლიათ გვერდის ავლით ფარული API შავი სიის გამოყენებით JNI თქვენს Android აპში. ერთი მუშაობს Android 9 და 10-ზე, ხოლო მეორე მუშაობს Android 9 და უფრო გვიან.

Android 9 და 10

თუ უკვე გაქვთ თქვენი აპლიკაციის მშობლიური ნაწილი, ამის განხორციელება ადვილი იქნება. უბრალოდ გამოიყენეთ JNI_OnLoad() ფუნქცია.

სტატიკური ხელოვნება:: Runtime* Runtime = nullptr;

extern "C"jint JNI_OnLoad(JavaVM *vm, void *reserved){
...
runtime = reinterpret_cast<: javavmext>(vm)->GetRuntime();
runtime->SetHiddenApiEnforcementPolicy(art:: hiddenapi:: EnforcementPolicy:: kNoChecks);
...
}

გაითვალისწინეთ, რომ ეს მეთოდი მუშაობს მხოლოდ Android 9 და 10-ზე.

Android 9 და მოგვიანებით

Android-ის ნებისმიერი ვერსიისთვის, თქვენ გაქვთ არჩევანი ორი ბიბლიოთეკიდან, რომ გადალახოთ ფარული API შეზღუდვა: FreeReflection და RestrictionBypass.

ორივე არის მარტივი განხორციელება და გამოყენება.

FreeReflection-ის განსახორციელებლად, დაამატეთ დამოკიდებულება თქვენი მოდულის დონის build.gradle-ს.

implementation 'me.weishu: free_reflection: 3.0.1'

შემდეგ გადააჭარბეთ attachBaseContext() თქვენს აპლიკაციის კლასში.

@Override
protectedvoidattachBaseContext(Context base){
super.attachBaseContext(base);
Reflection.unseal(base);
}

თუ არ გაქვთ აპლიკაციის კლასი, შეგიძლიათ მარტივად დაამატოთ იგი. შექმენით ახალი კლასი, რომელიც ვრცელდება Application და შემდეგ მიუთითეთ თქვენს AndroidManifest.xml-ში.

მაგალითი:

publicclassAppextendsApplication{
...
@Override
protectedvoidattachBaseContext(Context base){
super.attachBaseContext(base);

Reflection.unseal(base);
}
}

<manifest>
...
...
name=".App">
...
application>
manifest>

RestrictionBypass-ის განსახორციელებლად, დაამატეთ JitPack საცავი თქვენი პროექტის დონის build.gradle-ს.

allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}

შემდეგ დაამატეთ დამოკიდებულება თქვენი მოდულის დონის build.gradle-ს.

implementation 'com.github.ChickenHook: RestrictionBypass: 2.2'

და ეს არის ის. ეს ბიბლიოთეკა ავტომატურად ხსნის შავი სიის შეზღუდვებს.

ჯავის გამოსავალი

მიუხედავად იმისა, რომ JNI გადაწყვეტილებები ეფექტურია, არის შემთხვევები, როდესაც შეიძლება არ მოგინდეთ მშობლიური კოდის გამოყენება. თუ თქვენ უკვე არ აკეთებთ რაღაცებს C++-ში, მას შეუძლია თქვენს აპლიკაციას დაუმატოს არასაჭირო ზომა, პლატფორმის შეზღუდვებთან ერთად. საბედნიეროდ, არსებობს ფარული API შავი სიის გვერდის ავლით მხოლოდ ჯავის გამოყენებით.

Android 9 და 10

Android 9-სა და 10-ში შეგიძლიათ გამოიყენოთ ის, რასაც შეიძლება ეწოდოს ორმაგი ასახვა ან მეტარეფლექსია ფარული API შავი სიის გვერდის ავლით. იმის გამო, რომ სისტემა მხოლოდ ამოწმებს, თუ რას ურეკავენ მესამე მხარის აპები, ორმაგი ასახვა ატყუებს მას, რომ სისტემა ახორციელებს ფარული API ზარებს.

ეს ხრიკი შეიძლება გამოყენებულ იქნას მეთოდის გამოსაძახებლად, რათა თქვენს აპს ფარული API გამონაკლისები მისცეთ, მართებულად დასახელებული setHiddenApiExemptions(). უბრალოდ დაამატეთ შემდეგი კოდი სადღაც თქვენი აპის სასიცოცხლო ციკლის დასაწყისში (როგორიცაა აპლიკაციის onCreate() მეთოდი), და ის გაუმკლავდება შავი სიის გვერდის ავლით.

Method forName = Class.class.getDeclaredMethod("forName", String.class);
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);

Class vmRuntimeClass = (Class) forName.invoke(null, "dalvik.system.VMRuntime");
Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", newClass[] { String[].class} );

Object vmRuntime = getRuntime.invoke(null);
setHiddenApiExemptions.invoke(vmRuntime, newString[][] { newString[] { "L" } });

თუ თქვენი აპი თავსებადია Android-ის 9-ზე დაბალ ვერსიებთან, არ დაგავიწყდეთ ეს ვერსიის შემოწმებაში.

Android 9 და მოგვიანებით

ფარული API შავი სიის გვერდის ავლით Android 9-ზე და ნებისმიერ გვიანდელ ვერსიაზე, შეგიძლიათ გამოიყენოთ LSPosed-ის ბიბლიოთეკა. ეს ბიბლიოთეკა იყენებს Java-ს არაუსაფრთხო API-ს, ამიტომ ნაკლებად სავარაუდოა, რომ ის ოდესმე გაფუჭდეს.

მის განსახორციელებლად, უბრალოდ დაამატეთ დამოკიდებულება თქვენი მოდულის დონის build.gradle-ს.

implementation 'org.lsposed.hiddenapibypass: hiddenapibypass: 2.0'

შემდეგ გამოიყენეთ იგი შავი სიის გვერდის ავლით.

HiddenApiBypass.addHiddenApiExemptions("L");

თუ თქვენი აპი თავსებადია Android-ის 9-ზე დაბალ ვერსიებთან, არ დაგავიწყდეთ ეს ვერსიის შემოწმებაში.

დასკვნა და მეტი ინფორმაცია

Android-ზე ფარული API შავი სიის გვერდის ავლით უამრავი ვარიანტია, არ აქვს მნიშვნელობა რომელ პლატფორმის ვერსიას ამიზნებთ ან იყენებთ. თუ გაინტერესებთ მეტი გაიგოთ, თუ როგორ მუშაობს ეს მეთოდები და ბიბლიოთეკები, აუცილებლად გადახედეთ შემდეგ ბმულებს.

  • ჩემი Stack Overflow კითხვა-პასუხი.
  • LSposed's Hidden API Bypass ბიბლიოთეკა GitHub-ზე.
  • ChickenHook's RestrictionBypass ბიბლიოთეკა GitHub-ზე.
  • tiann's FreeReflection ბიბლიოთეკა GitHub-ზე.
  • Google-ის დოკუმენტაცია ფარული API შავ სიაში.