2015-08-09 19 views
7

Un sacco di API interne in Android sono contrassegnate con @hide. Cosa fa esattamente ?Che cosa fa esattamente l'annotazione @hide di Android?

Another answer dice che nasconde solo i metodi da Javadoc, ma che è possibile utilizzare la riflessione per accedervi.

Non ha senso, tuttavia, se sono nascosti solo da Javadoc, sicuramente non avrà bisogno di una riflessione per accedervi. In effetti, ho scoperto che non lo faccio. Posso ancora chiamare alcuni metodi @hide (forse solo quelli statici?) E l'app viene compilata e funziona bene per quanto posso dire. Ottengo solo un errore di pelucchi:

Cannot resolve method

Si noti che il codice di cui sopra compila ancora bene.

Non mi interessa la possibilità che l'API venga modificata, quindi sono felice di utilizzare l'API privata, ma qualcuno può spiegare questo comportamento? Inoltre, se esiste un modo per disattivare la lanugine caso per caso, sarebbe utile.

risposta

15

What exactly does this do?

E controlla ciò che è nel android.jar che si sta compilando contro.

Quando hai, ad esempio, compileSdkVersion 19 nel tuo file build.gradle, quello che sta realmente accadendo è che $ANDROID_SDK/platforms/android-19/android.jar viene aggiunto al tuo classpath di compilazione.

Quel JAR viene creato come parte della compilazione di Android stesso. Le classi del framework Android vengono analizzate e ne viene creata una copia. Questa copia:

  • strisce fuori tutte le classi, metodi, campi, ecc contrassegnati con @hide

  • Ha implementazioni stub di tutti i metodi che rimangono (letteralmente throw new RuntimeException("Stub!"), l'ultima volta che ho guardato)

  • mantiene il commenti JavaDoc per tutto ciò che rimane

i JavaDocs sono b fuori da questo albero dei sorgenti (ecco perché i JavaDocs non mostrano metodi nascosti), e l'edizione SDK del JAR framework è compilata da questo albero dei sorgenti.

but that you can use reflection to access them

Quello è perché, in fase di esecuzione , il vera quadro JAR è nel classpath runtime, compilato fuori della vera fonte per le classi del framework. Contiene tutto ciò che è stato contrassegnato con @hide ed è stato rimosso dal framework JAR di compilazione.

I can still call some @hide methods (maybe just static ones?) and the app compiles and runs fine as far as I can tell. I just get a lint error

Come ha notato Karakuri, questo sicuramente mi sembra un errore di compilazione. Se provo il tuo codice in un progetto compileSdkVersion 22, ricevo un errore di compilazione. E quando vado a correre, ottengo:

/tmp/MyApplication/app/src/main/java/com/commonsware/myapplication/MainActivity.java 
Error:(16, 23) error: cannot find symbol method isEmailAddress(String) 
Error:Execution failed for task ':app:compileDebugJavaWithJavac'. 
> Compilation failed; see the compiler error output for details. 
Information:BUILD FAILED 

Ora, è possibile compilare contro metodi che sono stati precedentemente contrassegnati con @hide, perché erano non-nascosto in un Android SDK più tardi, e la vostra compileSdkVersion è a quel livello API o superiore. L'utilizzo di questi metodi su livelli API prima di quando sono stati ufficialmente aggiunti all'SDK è rischioso.

I don't care about the possibility of the API being changed

È necessario, a meno che non si stia costruendo solo per un dispositivo in cui si controlla il firmware, inclusi tutti gli aggiornamenti del sistema operativo. E, in questo caso, probabilmente stai costruendo il tuo firmware, e quindi puoi costruire il tuo JAR di framework SDK dal tuo fork di Android, dove rimuovi @hide dalle cose che vuoi veramente usare.

Also if there's any way to disable the lint on a case-by-case basis that would be helpful.

Sulla base di ciò che vedo dal tuo screenshot e dal mio PC, si tratta di un errore di compilazione dall'IDE. Non è possibile disabilitare gli errori di compilazione.

+0

Ah grazie per la risposta molto informativa. Sicuramente posso costruirlo nonostante l'errore (che mi sembra anche un errore di compilazione, ho pensato che fosse un lint perché si compila ancora con 0 errori). Immagino che dovrò investigare di più! – Timmmm

+1

@Timmmm: Anche se non riesco a riprodurre il tuo particolare "errore di compilazione che consente ancora la compilazione" per il tuo caso, * ho * ottenuto lo stesso fenomeno proprio ora quando provo ad usare il nuovo metodo 'shouldShowRequestPermissionRationale()' aggiunto a MNC v2 . Si presenta con quello che cerca il mondo come un errore di compilazione nell'editor, ma le build effettive vanno bene. Ho archiviato [un problema a riguardo] (https://code.google.com/p/android/issues/detail?id=182357). – CommonsWare

3

In qualche modo Google utilizza l'annotazione @hide per eliminare le classi e i metodi che non vogliono far parte dell'SDK pubblico da cui ha compilato il jar di framework Android scaricato e utilizzato per compilare il codice. (Non conosco le specifiche di come funziona, quindi non chiedere.) Ecco perché il tuo IDE non può compilare il tuo codice contro di loro - letteralmente non esistono. Tuttavia, il jar di framework Android su un dispositivo effettivo contiene queste classi e questi metodi, motivo per cui è possibile accedervi in ​​fase di runtime mediante reflection.

Ciò che viene visualizzato nel messaggio non è un errore di sfilacciamento, si tratta di un errore di compilazione. Non può risolvere il metodo, il che significa che non si tratta di una chiamata al metodo valida.