Что означает @hide в исходном коде Android?

120

Для Activityисходного кода строка 3898 (ближе к низу):

/**
 * @hide
 */
public final boolean isResumed() {
    return mResumed;
}

Что @hideзначит?

Я обнаружил, что public class ChildActivity extends Activity { ... }не могу использовать / видеть Activity.isResumed(). Это нормально? Как я могу получить к нему доступ?

Midnite
источник

Ответы:

182

В Android есть два типа API-интерфейсов, которые недоступны через SDK.

Первый находится в упаковке com.android.internal. Второй тип API - это набор классов и методов, помеченных атрибутом @hide Javadoc .

Начиная с Android 9 (уровень API 28), Google вводит новые ограничения на использование интерфейсов , отличных от SDK , напрямую, через отражение или через JNI. Эти ограничения применяются всякий раз, когда приложение ссылается на интерфейс, не относящийся к SDK, или пытается получить его дескриптор с помощью отражения или JNI.

Но до уровня API 28 к скрытым методам можно было получить доступ через отражение Java. @hideАтрибут является лишь частью Javadoc (droiddoc также), так что @hideпросто означает , что метод / класс / поле исключен из API Docs.

Например, в checkUidPermission()методе ActivityManager.javaиспользуются @hide:

/** @hide */
public static int checkUidPermission(String permission, int uid) {
    try {
        return AppGlobals.getPackageManager()
                .checkUidPermission(permission, uid);
    } catch (RemoteException e) {
        // Should never happen, but if it does... deny!
        Slog.e(TAG, "PackageManager is dead?!?", e);
    }
    return PackageManager.PERMISSION_DENIED;
}

Однако мы можем назвать это отражением:

Class c;
c = Class.forName("android.app.ActivityManager");
Method m = c.getMethod("checkUidPermission", new Class[] {String.class, int.class});
Object o = m.invoke(null, new Object[]{"android.permission.READ_CONTACTS", 10010});
StarPinkER
источник
1
привет @StarPinkER, могу ли я предоставить разрешение "android.permission.CHANGE_COMPONENT_ENABLED_STATE" с использованием скрытого или внутреннего API или путем рефлексии?
Hardik
1
Сначала проверьте этот ответ . Это разрешение является подписью / системным разрешением. В большинстве случаев вы не можете получить это разрешение, если это не системные приложения. Это означает, что вам нужно изменить Android Source, чтобы принять ваше приложение, или сделать приложение системным и подписать его. Однако вы не сможете этого сделать, если не создадите свою собственную систему Android. Reflection может справиться с «сокрытием», но не может изменить логику системы безопасности Android. Вы можете себе представить, как мы можем легко атаковать Android-устройство, если у нас есть такая возможность. @Hardik
StarPinkER
2
Спасибо за ответ, но думаю, в ответе две проблемы, поправьте меня, если я ошибаюсь. Я получаю ошибку classnotfound, если пытаюсь найти ее с помощью «ActivityManager» вместо «android.app.ActivityManager» и «m.invoke (c», кажется, должно быть «m.invoke (null,» для статических методов и «m. invoke (o, ", где o - объект типа c, для динамических методов. Извините за мою польскую грамматику :)
lindenrovio
3
Просто примечание относительно отражения: поскольку эти методы / поля не являются частью официального SDK, нет гарантии, что они будут присутствовать в любой будущей версии Android.
sstn
2
Если аннотация удаляет только метод из документации, почему я не могу использовать его в коде?
Хавьер Дельгадо
25
  1. @hideиспользуется для вещей, которые должны быть видимыми по разным причинам, но не являются частью опубликованного API. Они не будут включены в документацию, когда она автоматически извлекает API из источника.

  2. Вы правы, вы не можете это изменить. Это нормально, это сделано специально, так как помечено как final. Вы должны иметь возможность использовать его, хотя редактор может не показывать его вам как один из вариантов в любом используемом им intellisense, потому что он отмечен значком @hide, и вы должны принять к сведению пункт 3 ниже.

  3. Вам не следует использовать его вообще, поскольку он не является частью API, и разработчики могут удалить его, когда захотят. Если бы они были склонны к садизму, они были бы даже вправе заменить его функцией, блокирующей устройство, на котором оно работало (хотя, возможно, и не в строгом юридическом смысле).

paxdiablo
источник
О да ... finalконечно, я не могу это изменить. Извините, это моя ошибка: x
midnite
Вы имеете в виду, что это происходит publicво всех классах на стадии разработки. Но действует privateли он /*package*/на пользователей вроде нас?
midnite
Хм ... Это просто комментарий. я понимаю его значение. Но что и где обеспечить такое поведение на уровне кода?
midnite
1
Почему это публично, я не могу комментировать. Возможно, реализация кода Activityраспределена по множеству классов, и всем им нужен доступ к этому члену. Суть в том, что является общественной , но не является частью API означает , что вы используете его на свой страх и риск.
paxdiablo
1
@midnite, у Eclipse есть собственный компилятор Java, который, без сомнения, интегрирован с материалом intellisense. Я бы посоветовал, если бы вы скомпилировали это с помощью Java SDK, он бы компилировался нормально. Не то чтобы я предлагал это, конечно, см. Пункт 3.
paxdiablo
4

@hideАннотацию означает , что этот интерфейс не является частью общественного API и не должен использоваться в вашем коде. Эти методы предназначены только для внутреннего использования AOSP.

Google фактически начал ограничивать использование интерфейсов, отличных от SDK . Это включает интерфейсы, отмеченные@hide

Методы разделены на четыре списка:

  • белый список: SDK
  • light-greylist: методы / поля без SDK, которые все еще доступны.
  • темно-серый список:
    • Для приложений, целевой SDK которых ниже уровня API 28: разрешено любое использование интерфейса темного серого списка.
    • Для приложений, целевой SDK которых - уровень API 28 или выше: то же поведение, что и черный список
  • черный список: ограничен независимо от целевого SDK. Платформа будет вести себя так, как если бы интерфейс отсутствовал. Например, он будет генерировать исключение NoSuchMethodError / NoSuchFieldException всякий раз, когда приложение пытается его использовать, и не будет включать его, когда приложение захочет узнать список полей / методов определенного класса.

Списки можно найти здесь: https://android.googlesource.com/platform/prebuilts/runtime/+/master/appcompat.

leonardkraemer
источник