15

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.

Timmmm
  • 88,195
  • 71
  • 364
  • 509

2 Answers2

27

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.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Ah thanks for the very informative answer. I definitely can build it despite the error (which also looks to me like a compile error; I assumed it was a lint because it still compiles with 0 errors). Guess I'll have to investigate more! – Timmmm Aug 10 '15 at 07:15
  • 1
    @Timmmm: While I could not reproduce your particular "compile error that still allows the build" for your case, I *did* get the same phenomenon just now when trying to use the new `shouldShowRequestPermissionRationale()` method added to MNC v2. It shows up with what looks for the world like a compile error in the editor, but actual builds are fine. I have filed [an issue about this](https://code.google.com/p/android/issues/detail?id=182357). – CommonsWare Aug 10 '15 at 15:06
  • Where can I find a way to use the "@hide" annotation? – android developer Apr 05 '21 at 08:06
  • @androiddeveloper: Sorry, I do not understand your question. – CommonsWare Apr 05 '21 at 10:35
  • @CommonsWare The "@hide" annotation isn't available if I add it myself. How can I use it in my own android-library modules? – android developer Apr 05 '21 at 10:49
  • @androiddeveloper: Beats me. I do not know what you are expecting it to do. The point behind `@hide` with the Android SDK is that the JAR you compile against is *different* than the JAR that gets used at runtime. That is not the case with AARs or JARs used in app development. Even if you say that you want to distribute a library where `@hide` replaces real methods with stubs... where and how will the consumer of that library get the real implementation to use at runtime? – CommonsWare Apr 05 '21 at 11:57
  • @CommonsWare I see. OK makes sense. Was hoping to find something similar to an issue I've been having, of Retrofit models being gone even though I've added Proguard rules for them. For some reason, even though they were obfuscated fine and weren't removed in the generated AAR file, no matter what I tried, the project that uses it on release variant ruined how they work. On debug it worked fine. – android developer Apr 05 '21 at 12:11
6

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.

Karakuri
  • 38,365
  • 12
  • 84
  • 104