Могу ли я переопределить скрытый (но публичный) метод и вызвать его супер метод? - PullRequest
11 голосов
/ 23 марта 2012

Существует непубличный API, который мне нужно переопределить, чтобы обойти причуду с Android WebView.

API скрыт, но общедоступен:

/**
 * ...
 *
 * @hide pending API council approval
 */
public boolean selectText() {
    ...
}

Так что я могу переопределить его, просто объявив его в своем собственном классе WebView, за исключением @Override:

public boolean selectText() {
    ...
}

Можно ли вызвать метод super из моего переопределения? Обычно я мог написать:

public boolean selectText() {
    return super.selectText();
}

Но метод скрыт, поэтому super.selectText() недоступен. Если я использую отражение:

public boolean selectText() {
    return (Boolean) WebView.class.getMethod("selectText").invoke(this, (Object[]) null);
}

Я получаю бесконечный цикл, потому что он вызывает мой переопределенный метод.

Есть ли способ переопределить этот метод и иметь возможность вызывать метод super?

Спасибо!

Ответы [ 3 ]

4 голосов
/ 02 августа 2012

Есть ли способ переопределить этот метод и иметь возможность вызывать супер метод?

Нет, к сожалению, как объясняется в ответе на вопрос Как вызвать метод суперкласса с использованием Java-отражения Вы не можете решить эту проблему с помощью отражения.

1 голос
/ 05 мая 2014

На самом деле есть несколько способов сделать это, но они немного трудоемки, поэтому, вероятно, следует использовать в качестве последнего средства. Используя рутированное устройство, вы можете извлечь символы из jar-файлов фреймворка на устройстве и поместить их в android.jar в вашей папке sdk / platform /. Раньше для этого был скрипт; потерял его при смене места работы.

шагов из памяти (заметьте, у вас, вероятно, возникнут проблемы, поскольку я не помню шагов ... для опытных пользователей, которые понимают, к чему я стремлюсь):

  • adb pull / system / framework / * (это все файлы jar). Это может быть достаточно, чтобы получить framework.jar. распакуйте их.
  • для каждого, который, как я верю, даст вам classes.dex и манифест. Если вы просто получаете файлы классов, пропустите следующий шаг
  • dex2jar классы.dex и unjar classes_dex2jar.jar или что угодно вывод от dex2jar, который даст вам кучу файлов .class
  • возьмите файлы классов и добавьте их в свой android sdk android.jar файл (sdk / platform / android- # sdk # / android.jar).

Я предлагаю дублировать вашу папку android- # sdk # в папку android-1 # sdk #, чтобы android-19 превратился в android-119, а затем измените build.prop в папке, чтобы сказать ro.build.version.sdk = 119, а затем сборка против SDK 119. Таким образом, у вас есть выбор сборки против чистых 119 или ваших взломанных 119. Только не обращайтесь ни к каким файлам com.android.internal.R, потому что эти идентификаторы не точны в моем опыт.

Теперь вы сможете компилировать эти символы и получать к ним доступ в порядке. Хотя не злитесь, если они изменят то, как все работает, и они не обязаны поддерживать совместимость со сторонними приложениями.

Это работает, потому что тег hide используется только на этапе компиляции SDK и удаляет эти символы из файла android.jar, расположенного в вашем SDK. Если мы соберем все символы, которые скомпилированы на устройстве, и вставим их в ваш SDK-банку, это как если бы они никогда не были удалены.

В качестве альтернативы вы можете развернуть и построить полное дерево андроида (https://source.android.com/source/building.html), а затем построить свое приложение на основе полного исходного кода, что в первую очередь сводится к тому, чтобы взять уже скомпилированные символы и работать с ними.

0 голосов
/ 01 июня 2017
  1. ДА ВЫ МОЖЕТЕ:) - первая часть вопроса
  2. НЕТ, ВЫ НЕ МОЖЕТЕ - второй

решение 1) - лучшее, что вы можете здесь сделать, ближе всего к тому, чего вы хотите достичь

// to override method 
// which IDE doesn't see - those that contains {@ hide} text in JavaDoc
// simple create method with same signature
// but remove annotation
// as we don't know if method will be present or not in super class 
//
//@Override      
public boolean callMethod(String arg) {

    //  can we do it ?
    // boolean result = super.callMethod(arg)
    // no  why ? 
    // You may think you could perhaps
    // use reflection and call specific superclass method 
    // on a subclass instance.


/** 
 * If the underlying method is an instance method, it is 
 * invoked using dynamic method lookup as documented in The 
 * Java Language Specification, Second Edition, section 
 * 15.12.4.4; in particular, overriding based on the runtime
 * type of the target object will occur.
 */


   // but always you can see what super class is doing in its method 
   // and do the same by forward call in this method to newly created one
   // return modified  result 
  return doSomthingWhatSuperDo()
}

решения 2)

принадлежит ли вам объект (который вызывает этот метод)? а реализует интерфейс?

если так, то как насчет прокси?

  1. продлить класс
  2. создать прокси
  3. использовать прокси
  4. перехватить вызов метода
  5. на основании каких условий? вызвать собственную реализацию или вернуться к исходной?
...