Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What exactly does Android's @hide annotation do?

Lots of internal APIs in Android are marked @hide. What exactly does this do?

Another answer says that it only hides the methods from Javadoc, but that you can use reflection to access them.

That makes no sense though - if they are only hidden from Javadoc then you surely wouldn't need reflection to access them. In fact I've found that I don't. 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:

Cannot resolve method

Note that the above code still compiles fine.

I don't care about the possibility of the API being changed so I am happy using the private API, but can someone explain this behaviour? Also if there's any way to disable the lint on a case-by-case basis that would be helpful.

like image 788
Timmmm Avatar asked Aug 09 '15 19:08

Timmmm


2 Answers

What exactly does this do?

It controls what is in the android.jar that you are compiling against.

When you have, say, compileSdkVersion 19 in your build.gradle file, what is really happening is that $ANDROID_SDK/platforms/android-19/android.jar is being added to your compile-time classpath.

That JAR is created as part of compiling Android itself. The Android framework classes are analyzed, and a copy of them is created. This copy:

  • Strips out all classes, methods, fields, etc. marked with @hide

  • Has stub implementations of all the methods that remain (literally throw new RuntimeException("Stub!"), the last time I looked)

  • Retains the JavaDoc comments for everything that remains

The JavaDocs are built off of this source tree (which is why the JavaDocs do not show hidden methods), and the SDK edition of the framework JAR is compiled off of this source tree.

but that you can use reflection to access them

That is because, at runtime, the real framework JAR is in your runtime classpath, compiled off of the real source for the framework classes. It contains everything that was marked with @hide and was stripped out of the compile-time framework JAR.

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

As Karakuri noted, that sure looks like a compile error to me. If I try your code in a compileSdkVersion 22 project, I get a compile error. And when I go to run it, I get:

/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

Now, you can compile against methods that were formerly marked with @hide, because they were un-hidden in a later Android SDK, and your compileSdkVersion is on that API level or higher. Using those methods on API levels prior to when they were officially added to the SDK is risky.

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

You should, unless you are building only for one device where you control the firmware, including all OS updates. And, in that case, you are probably building your own firmware, and so you can build your own SDK framework JAR from your Android fork, where you remove @hide from the things you want to really use.

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

Based on what I see from your screenshot and my PC, that is a compile error from the IDE. You cannot disable compile errors.

like image 110
CommonsWare Avatar answered Oct 21 '22 23:10

CommonsWare


Somehow Google uses the @hide annotation to strip out the classes and methods they don't want to be part of the public SDK fromt he compiled android framework jar that you download and use to compile your code against. (I don't know the specifics of how that works, so don't ask.) That's why your IDE cannot compile your code against them -- they literally don't exist. However, the android framework jar on an actual device DOES contain these classes and methods, which is why they can be accessed at runtime using reflection.

What you displayed in your post is not a lint error, that is a compile error. It cannot resolve the method, meaning it thinks it's not a valid method call.

like image 42
Karakuri Avatar answered Oct 21 '22 22:10

Karakuri