Jak zbudować Android SDK z dostępnymi ukrytymi i wewnętrznymi interfejsami API?

85

Chcę przebudować Android SDK (a raczej tylko android.jar), aby zawierał ukryte i wewnętrzne interfejsy API.

Nie mogłem znaleźć żadnej dokumentacji ani dyskusji, jak się do tego zabrać. Mam już skonfigurowane środowisko kompilacji Ubuntu CyanogenMod, które jest w stanie zbudować cm7.

Teraz czytałem, że make SDK zbuduje SDK, ale chcę zbudować SDK, który zawiera metody i pola, które są oznaczone jako ukryte za pomocą @hide. czy to możliwe?

To, co chcę zrobić, to wprowadzić zmiany w aplikacji, która korzysta z ukrytego API i aby ją przebudować, chciałbym użyć zmodyfikowanego SDK.

Thomas Hofmann
źródło
2
@Hidden po prostu ukrywa javadoc, wszystkie te metody są nadal dostępne
Blundell
12
@hide usuwa je z plików zajęć.
Thomas Hofmann
1
Powiązane: stackoverflow.com/questions/4951146/…
Blundell,
Wiem, że mógłbym użyć refleksji, ale chcę zmienić istniejącą aplikację, która używa ukrytego interfejsu API bez refelction i nie chcę zmieniać całego istniejącego kodu, aby używał refelction.
Thomas Hofmann
4
Myślę, że możesz usunąć @Hiddenetykietę API, do którego chcesz uzyskać dostęp, a następnie wykonać make update-apii make SDKzbudować własny SDK.
dreamtale

Odpowiedzi:

68

To jest to, co zawsze robię, aby używać ukrytego interfejsu API.

  1. Zbuduj repozytorium lub pobierz słoiki z https://sites.google.com/site/hippunosource/home/android/androidnohide-apiwo-shi-yongsuru-rifurekushonha-wei-shi-yong
  2. skopiuj out / target / common / obj / JAVA_LIBRARIES / framework_intermediates / classes.jar (lepiej zmienić nazwę na coś takiego jak framework_all.jar)
  3. Skonfiguruj ścieżkę kompilacji projektu -> biblioteki -> dodaj te zewnętrzne pliki JAR. W sekcji Order and Export przenieś ją w górę, a przed android.jar
Długie
źródło
Dla mnie to też zadziałało! teraz mogę zabrać się za właściwe zadanie, dzięki za to
CurlyPaul
IMHO, to jest najłatwiejsze i najszybsze.
Patrick Cho,
Czy nie ma sposobu, aby oznaczyć to jako właściwą odpowiedź?
Chris Browet
2
czy ta metoda działa na wszystkich urządzeniach, czy tylko na urządzeniu docelowym?
Hải Phong
Aby zdefiniować kolejność bibliotek w Android Studio, musisz zmienić .imlplik modułu i wprowadzić żądane biblioteki <orderEntry>przed Android SDK . Niestety ta technika nie jest trwała, ponieważ plik zostanie nadpisany po naciśnięciu przycisku synchronizacji gradle.
waqaslam
44

Zbadałem to trochę i mój wniosek jest prosty: nie da się tego zrobić bez dużej ilości pracy. Przeczytaj resztę tej odpowiedzi, aby uzyskać szczegółowe informacje na temat tego, co znalazłem.


android.jarw rzeczywistości składa się z „publicznego interfejsu API” programu framework.jari core.jarznajduje się w system/frameworks/urządzeniu. android.jarjest rodzajem tego, co nazwałbym nagłówkiem biblioteki Java, wszystkie implementacje w rzeczywistym kodzie bajtowym są po prostu a throw new RuntimeException("stub");, to pozwala na kompilację android.jar(np. w Eclipse), ale wykonanie musi być wykonane na urządzeniu lub emulatorze.

Publiczny interfejs API zestawu Android SDK jest definiowany przez klasy / metody / pola, które nie są poprzedzone @{hide}adnotacją javadoc. To znaczy wszystko, co nie jest opisane, jest zawarte w SDK.

android.jarjest zbudowany ze źródeł, w out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediatesktórych sam jest generowany przez narzędzie DroidDoc znajdujące się w build/tools/droiddoc.

DroidDoc to narzędzie (prawdopodobnie zaadaptowane z javadoc lub używające javadoc), które generuje rzeczywistą dokumentację Android SDK. Jako efekt uboczny i prawdopodobnie dlatego, że już analizuje cały javadoc, wypluwa również kody pośredniczące Androida, które są następnie kompilowane do tego, android.jarktóry jest dystrybuowany w SDK.

Aby uwzględnić ukryte elementy, możesz, jeśli chcesz uwzględnić tylko określone części, po prostu usuń @hideadnotację i przebuduj SDK.

Jeśli jednak chcesz uwzględnić wszystkie ukryte części, sprawy stają się znacznie bardziej skomplikowane. Możesz zmodyfikować DroidDoc (odpowiednie źródło jest w build/tools/droiddoc/src/Stubs.java) tak, aby nic nie było wykrywane jako ukryte. Jest to dość trywialne i próbowałem tego, jednak generowane wówczas kody pośredniczące w ogóle się nie kompilują.

Mój wniosek jest teraz taki, że jest to po prostu niewykonalne. Stopy wygenerowane po usunięciu części DroidDoc, która wykrywa ukryte adnotacje, są po prostu niekompilowalne i wymagałyby sporo pracy, aby je poprawnie skompilować.

Tak więc moja odpowiedź na Twoje pytania brzmi: Nie, nie da się tego zrobić bez dużego nakładu pracy. Przepraszam.


Dodatkowa uwaga na temat mkstubsnarzędzia. mkstubssą używane podczas budowania dodatku SDK , czyli dodatków, które można znaleźć w menedżerze Android SDK od dostawców, np. Samsunga udostępniającego dodatkowe API dla rzeczy specyficznych dla telefonów Samsung. mkstubsrobi to samo, co proces generowania kodów pośredniczących w DroidDoc, jednak nie używa @hideadnotacji, używa .defspliku opisującego, które pakiety / klasy / pola należy uwzględnić lub wykluczyć z dodatku SDK.

Jednak to wszystko nie ma znaczenia dla pytania, ponieważ kompilacja Android SDK nie korzysta z tego mkstubsnarzędzia. (Niestety.)

Bjarke Freund-Hansen
źródło
Też się obejrzałem. Oprócz Droiddoc w katalogu / development / tools / mkstubs znajduje się narzędzie o nazwie mkstubs. Zostaje wywołany podczas kompilacji i, o ile widziałem, zmodyfikuje pliki klas, usuwając z nich rzeczy. W build / core / jobs / sdk-addon.mk znajduje się następujący kod: define stub-addon-jar $ (wywołaj stub-addon-jar-file, $ (1)): $ (1) | mkstubs $ (info Stubbing pliku jar dodatku za pomocą $ (PRODUCT_SDK_ADDON_STUB_DEFS)) $ (ukryj) java -jar $ (wywołanie plików zainstalowanych modułów, mkstubs) $ (jeśli $ (ukryj) ,, - v) \ "$$ <" „$$ @” @ $ (PRODUCT_SDK_ADDON_STUB_DEFS) endef
Thomas Hofmann
Niestety nie przepadam za tym, ale też wygląda na to, że wszystko zależy od zmiennej o nazwie hide. Nie znalazłem jednak, czy to jest ustawione. Jeśli poszukasz $ (hide) w innych plikach kompilacji, zobaczysz, że wiele zależy od tej wartości. Wydaje się, że wpływa to również na sposób budowania bibliotek C.
Thomas Hofmann
@ThomasHofmann: Początkowo byłem zdezorientowany także przez narzędzie mkstubs. Nauczyłem się, że mkstubs jest używany tylko wtedy, gdy tworzysz dodatek SDK (sprzedającego), a nie tylko wtedy, gdy budujesz normalny zestaw SDK. Jednak mkstubs robi to samo, co DroidDoc, z wyjątkiem tego, że nie używa @hideadnotacji, a "po prostu" używa .defspliku opisującego, które pakiety / klasy / pola mają być zawarte w API dodatku.
Bjarke Freund-Hansen
2
@ThomasHofmann: O $(hide), mylisz się. $(hide)jest po prostu prefiksem w plikach makefile, który ukrywa linię poleceń wykonywanego programu, nic więcej, i jest używany prawie wszędzie. Nie ma to nic wspólnego z Android SDK ani @hideadnotacją w kodzie źródłowym.
Bjarke Freund-Hansen
jak mogę to sprawdzić powyżej ścieżka out / target / common / obj / JAVA_LIBRARIES / framework_intermediates / classes.jar
Bunny
31

Mogliśmy zrekonstruować pliki * .jar z platformy Android.

Najpierw podłącz ADB do swojego urządzenia. Następnie uruchomić:

adb pull /system/framework/core.jar .
adb pull /system/framework/framework.jar .

core.jarZawierać standardowe biblioteki Java ( java.*) i framework.jarzawierają biblioteki Androida (android.* ). Nie można tego jeszcze używać, ponieważ rzeczywiste pliki są w formacie DEX, a nie w formacie JAR.

Moglibyśmy przekonwertować te * .jary w formacie DEX na prawdziwe pliki JAR przy użyciu narzędzi takich jak dex2jar :

dex2jar core.jar
dex2jar framework.jar

Następnie ściągnij te słoiki za pomocą „Dodaj zewnętrzne pliki JAR ...” (zakładając, że używasz Eclipse ADT)

  • kliknij prawym przyciskiem myszy Project → Properties → Java Build Path → Libraries → Add External JARs... → (Wybierz core-dex2jar.jariz framework-dex2jar.jargóry).

Umożliwi to korzystanie z wewnętrznego i niektórych interfejsów API Java 7. (Wygenerowany plik APK, o ile widzę, nie zawiera żadnego rzeczywistego kodu z plików JAR).

kennytm
źródło
Dziękuję bardzo, próbowałem wielu różnych sposobów, tylko twoje metody działają na mnie.
SalutonMondo
7
Należy zauważyć, że ta metoda nadal działa z systemami ICS i nowszymi, ale wymaga trochę więcej żonglowania. Odpowiednie pliki są /system/framework/core.odex, /system/framework/framework.odexi prawdopodobnie więcej. Można je deodexed ( java -jar baksmali-2.0.3.jar -d system.framework -x system.framework/core.odex -o core) i reodexed ( java -jar smali-2.0.3.jar -x -o core.dex core), a dopiero potem dex2jar core.dexwykonuje swoje zadanie.
Alex Cohn,
nie można znaleźć core.jar w marshmallow
mehmet6parmak
masz jakiś pomysł na jądro i framework na Androida p?
Prabhakaran
jak mogę to sprawdzić powyżej ścieżka out / target / common / obj / JAVA_LIBRARIES / framework_intermediates / classes.jar
Bunny
17

W przypadku Lollipopa przepływ jest nieco inny:

  1. Pobierz /system/framework/arm/boot.oat z urządzenia Lollipop

  2. Użyj 'java -jar oat2dex.jar boot boot.oat”

  3. Otrzymasz dwa foldery: dex i odex. Przejdź do dex i utwórz 'java -jar dex2jar.jar framework.dex”
  4. Zmień nazwę wynikowego pliku framework.jar na .zip, wyodrębnij i znajdź potrzebne klasy
  5. Przejdź do [sdk_path] / platform / [target_platform] i wyodrębnij plik android.jar (najpierw zmień jego nazwę na zip).
  6. Skopiuj pliki z wyodrębnionej platformy do wyodrębnionego pliku android.jar. Następnie skompresuj do zip i zmień nazwę na .jar :)

ps: prawdopodobnie musisz powtórzyć kroki 4-6 dla 'framework_classes2.dex'

zboczeniec
źródło
W kroku 3 nie mogę znaleźć pliku dex2jar.jar pod tym linkiem ... Próbowałem wielu rzeczy i nie mogę tego rozgryźć. Czy jest gdzieś do tego link? Czy znajduje się w moim Android SDK? Nie mogę tego znaleźć.
Dwebtron
Tak, trafia do projektu na githubie i może to ja, ale nie mogę znaleźć ŻADNEGO pliku kończącego się na „.jar” ...
Dwebtron
1
zobacz sekcję „wydania”
dewiacyjny
2
Wygląda więc na to, że ostatnie wersje dex2jar zmieniły format pobierania. Po prostu rozpakuj plik i zamiast 'java -jar ...' po prostu uruchom skrypt 'd2j-dex2jar.sh' lub 'd2j-dex2jar.bat', w zależności od twojej platformy, bezpośrednio w pliku framework.dex
CalumMcCall
1
Skopiowałem oba pliki jar do android.jar, teraz Android Studio informuje mnie o błędzie: Błąd wykonania zadania „: app: processDebugResources”. > com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process „command” D: \ Program \ Android \ android-sdk \ build-tools \ 19.1.0 \ aapt.exe ” 'zakończył się niezerową wartością wyjścia 1
wutzebaer
16

Możesz pobrać zmodyfikowane android.jardo użycia jako ukryte API z tego repozytorium . Postępuj zgodnie z instrukcjami.

Anggrayudi H
źródło
4
Ta odpowiedź zasługuje na więcej głosów, ponieważ jest to najprostsze rozwiązanie. Ludzie, jeśli szukasz rozwiązania - wiedz, że inne osoby już to zrobiły i umieściły rozwiązanie tego repozytorium github. Użyj go i ciesz się! ))
Mixaz
1
Podczas korzystania z android.jar dla API 28 pojawia się błąd dotyczący robolectric. Zgłoszono problem github.com/anggrayudi/android-hidden-api/issues/62 i dziękuję za twój słoik @Anggrayudi
Prabhakaran
zrobiłem to samo dla Androida 10, nie działa dla mnie, raczej pobrałem od innego dostawcy github.com/aeab13/android-jar-with-hidden-api . udało mi się uzyskać dostęp do klasy hdmi-cec i ją zbudować, ale kody nadal są mylące. code link android.googlesource.com/platform/frameworks/base/+/4e90fcd/…
babbin tandukar
15

DroidCon 2011

Tutaj Erik Hellman z Sony Ericson wyjaśnia, jak uzyskać dostęp do ukrytych interfejsów API systemu Android:

http://vimeo.com/30180393 (Hmm link nie wydaje się działać).

Przejdź do strony internetowej DroidCon Dzień 2 przewiń w dół do sekcji Używanie ukrytych interfejsów API 10:15 i możesz ją tam obejrzeć.

Linki umierają!

Znalazłem ten: http://skillsmatter.com/podcast/os-mobile-server/hidden-api nie wiem, jak długo to będzie działać

Oficjalne interfejsy API w Android SDK są zwykle wystarczające dla większości zwykłych aplikacji. Czasami jednak zdarzają się sytuacje, w których programista potrzebuje dostępu do wewnętrznych usług systemowych, interfejsów API i zasobów, które nie są publikowane w oficjalnych interfejsach API. Na szczęście te interfejsy API są nadal dostępne dzięki sprytnym sztuczkom i często mogą być przydatne podczas opracowywania nowego i innowacyjnego rozwiązania na Androidzie. Podczas tej sesji dowiesz się, jak uzyskać dostęp do tych ukrytych i chronionych interfejsów API i jak z nich korzystać, a także dowiedzieć się, jakie są ograniczenia ich użytkowania, a także kilka wskazówek i sztuczek, jak z nich korzystać w bezpieczny i kontrolowany sposób na urządzeniach wielu dostawców i wersjach Androida. Widzowie zobaczą kilka zaawansowanych wersji demonstracyjnych, których normalnie nie można zrobić z systemem Android. Spodziewaj się dość zaawansowanej sesji z wieloma wglądami w wewnętrzne elementy platformy Android.

Blundell
źródło
1
To ciekawe, ale niestety nie odpowiada na moje pytanie. Prosiłem o sposób na rzeczywistą przebudowę SDK z dołączonymi ukrytymi elementami.
Thomas Hofmann
Wygląda na to, że znalazłem inny sposób na osiągnięcie tego, czego chcę. Opiszę to jutro.
Thomas Hofmann
Dowiedziałem się, że jeśli chcesz skompilować źródło projektu, które wykorzystuje ukryte API w ADT, możesz wykonać następujące czynności: 1) Utwórz projekt Android dla źródła. 2) Usuń kontener ścieżki klas Androida ze ścieżki kompilacji 3) Zdefiniuj bibliotekę użytkownika (zaznacz także pole wyboru biblioteki systemowej), która zawiera pliki JAR z kompilacji ASOP ROM, np. Cm7). To, których plików JAR używasz, zależy od tego, do czego chcesz się odwołać. Framework-directates prawdopodobnie będą tego częścią.
Thomas Hofmann
4) Po zbudowaniu projektu klasy biblioteki użytkownika nie zostaną uwzględnione w tworzonym APK. Ukryty interfejs API jest widoczny i wszystko się dobrze skompiluje.
Thomas Hofmann
@Blundell: Czy możesz zaktualizować linki… one nie żyją!
zombie
12

Spójrz na to :

Ostatecznym celem tych artykułów jest zapewnienie programistom możliwości wewnętrznych i ukrytych interfejsów API bez używania refleksji. Jeśli wykonasz wszystkie kroki opisane w kilku następnych częściach, będziesz mógł używać wewnętrznych i ukrytych interfejsów API, tak jakby były publicznymi otwartymi interfejsami API. Nie będzie potrzeby refleksji.

Ale jeśli używasz tych niepublicznych interfejsów API, powinieneś mieć świadomość, że Twoja aplikacja jest narażona na duże ryzyko. Zasadniczo nie ma gwarancji, że interfejsy API nie zostaną zerwane przy następnej aktualizacji systemu operacyjnego Android. Nie ma nawet gwarancji spójnego działania urządzeń różnych dostawców. Jesteś całkowicie sam.

Istnieją trzy scenariusze, które warto zastosować:

  1. Włącz zarówno wewnętrzne, jak i ukryte interfejsy API (scenariusz A)
  2. Włącz tylko ukryte API (scenariusz B)
  3. Włącz tylko wewnętrzny interfejs API (scenariusz C)

Scenariusz A jest sumą B i C. Scenariusz B jest najłatwiejszy (nie wymaga modyfikacji wtyczki eclipse ADT).

Scenariusz A : przeczytaj części 1 , 2 , 3 , 4 , 5

Scenariusz B : przeczytaj części 1 , 2 , 3 , 5

Scenariusz C : przeczytaj części 1 , 2 , 3 , 4 , 5

Zorb
źródło
3
Przeczytałem już ten wpis na blogu. Wspomina o tym: „1) Android to projekt typu open source. Możemy pobrać kod źródłowy i dostosować system kompilacji, aby nie wykluczał wewnętrznych i ukrytych klas z android.jar. To trudna droga”. Niestety nie wchodzi w szczegóły.
Thomas Hofmann
3
Idź do ostatniej części posta na blogu ( devmaze.wordpress.com/2011/01/19/… ), tam jest link ( github.com/inazaruk/android-sdk/tree/master/platforms ) do wstępnie zbudowanego Androida Interfejsy API ze wszystkimi ukrytymi i wewnętrznymi interfejsami API.
Bob
1
Podane linki niedostępne, wymagają zgody autora
SHAHS
jak mogę sprawdzić powyższą ścieżkę out / target / common / obj / JAVA_LIBRARIES / framework_intermediates / classes.jar
Bunny
1

Kiedyś napisałem kilka skryptów Groovy do wyodrębniania plików java z kasy repozytorium ze strony http://source.android.com/ a następnie kompilowania ich bez konieczności posiadania pełnego zestawu narzędzi do kompilacji wszystkich źródeł Androida, w tym potrzebnych innych kroków ( pakowanie, generowanie zasobów itp.).

Można je znaleźć tutaj:

https://github.com/thoutbeckers/CollectAndroid

Ale na pewno będzie to wymagało aktualizacji dla czegokolwiek po Gingerbread, głównie poprzez ustawienie właściwych katalogów w "rootdirs" w pliku konfiguracyjnym (CollectConfig.groovy).

W tamtym czasie regularnie używałem tego do programowania z wszystkimi dostępnymi ukrytymi API i źródłami (również problematycznymi w tym czasie).

Jak wspomniano w innym miejscu, com / android / internal / ** nadal będzie ukryty w ostatnich wersjach ADT z powodu zastosowanej reguły dostępu.

thoutbeckers
źródło
jak mogę sprawdzić powyższą ścieżkę out / target / common / obj / JAVA_LIBRARIES / framework_intermediates / classes.jar
Bunny
Zarchiwizowałem to repozytorium od czasu ostatniej aktualizacji dla Gingerbread . Niestety, będziesz musiał znaleźć inne podejście.
thoutbeckers
1

Odpowiedź Longa działała dla mnie, ale nadal brakowało mi niektórych zajęć, których potrzebowałem, w szczególności android.provider.Telephony. Udało mi się to dodać tak:

  1. Wyodrębnij plik framework.jar

    mkdir /tmp/framework
    cp framework.jar /tmp
    cd /tmp/framework
    jar xvf ../framework.jar
    mv android classes
    
  2. Zbuduj repozytorium Androida, które utworzy katalog out / target / common / obj / JAVA_LIBRARIES

  3. Dowiedz się, gdzie są brakujące klasy

    $ cd /path/to/out/target/common/obj/JAVA_LIBRARIES
    $ find . | grep "/Telephony.class"
    ./telephony-common_intermediates/classes/android/provider/Telephony.class
    ./android_stubs_current_intermediates/classes/android/provider/Telephony.class
    
  4. Dodaj nowe klasy i odbuduj plik JAR struktury

    cd /tmp/framework
    cp -r /path/to/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes .
    cp -r /path/to/out/target/common/obj/JAVA_LIBRARIES/telephony-common_intermediates/classes .
    cd classes
    jar cvf ../framework.jar .
    

Lub możesz po prostu być leniwy i dołączyć wszystkie klasy do jednego gigantycznego pliku jar:

cd /tmp/framework
cp -r /path/to/out/target/common/obj/JAVA_LIBRARIES/*/classes .
cd classes
jar cvf ../framework.jar .
bmaupin
źródło
out / target / common / obj / JAVA_LIBRARIES jak znaleźć tę ścieżkę?
Bunny
@Bunny Zaktualizowałem moją odpowiedź o więcej szczegółów. Ale wydaje się, że odpowiedź tutaj może być łatwiejsza: stackoverflow.com/a/32626155/399105
bmaupin
dziękuję za twoją odpowiedź @bmaupin .. czy możesz mi pomóc, jak mogę znaleźć tę ścieżkę out / target / common / obj / JAVA_LIBRARIES, aby uzyskać jar framework ... naprawdę utknąłem ... nie jestem w stanie znaleźć tej ścieżki lub brakuje czegoś ... poprowadź
Bunny
0

Nie mogę komentować, ale jest to w zasadzie komentarz do @ KennyTM's ( https://stackoverflow.com/a/13550030/2923406 doskonałej odpowiedzi ):

Jeśli napotkasz następujący błąd w Eclipse:

The type com.android.internal.util.Predicate cannot be resolved. It is indirectly referenced from required .class   files

(to znaczy, android.internal. * nie jest dostępny)

Wtedy jednym możliwym rozwiązaniem jest zastosowanie tej samej metody dla /system/framework/framework2.jar. Używając emulatora Androida dla SDK19 mam ten dodatkowy słoik. Na moim HTC One jest nawet plik framework3.jar.

Rolf
źródło
jak mogę sprawdzić powyższą ścieżkę out / target / common / obj / JAVA_LIBRARIES / framework_intermediates / classes.jar
Bunny