简体   繁体   English

我可以覆盖隐藏(但公共)方法并调用其超级方法吗?

[英]Can I override a hidden (but public) method and call its super method?

There is a non public api that I need to override in order to workaround a quirk with Android's WebView. 我需要覆盖一个非公共API,以便使用Android的WebView解决问题。

The api is hidden but it is public: api是隐藏的,但它是公开的:

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

So I can override it by simply declaring it in my own WebView class, minus the @Override: 所以我可以通过简单地在我自己的WebView类中声明它来覆盖它,减去@Override:

public boolean selectText() {
    ...
}

Is it possible to call the super method from my override? 是否可以从我的覆盖中调用super方法? Normally I could write: 通常我可以写:

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

But the method is hidden, so super.selectText() is not available. 但该方法是隐藏的,因此super.selectText()不可用。 If I use reflection: 如果我使用反射:

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

I get an infinite loop because it calls my overridden method. 我得到一个无限循环,因为它调用我的重写方法。

Is there anyway to override this method AND be able to call the super method? 反正有没有覆盖这个方法,并能够调用超级方法?

Thanks! 谢谢!

Is there anyway to override this method AND be able to call the super method? 反正有没有覆盖这个方法,并能够调用超级方法?

No, unfortunately, as is explained in the answer to the question How to call a superclass method using Java reflection you cannot solve this problem with reflection. 不幸的是,正如在如何使用Java反射调用超类方法的问题的答案中解释的那样,您无法通过反射解决此问题。

There are actually a couple ways to do this, but they're a little labor intensive, so probably should be used as a last resort. 实际上有几种方法可以做到这一点,但它们有点劳动密集型,所以可能应该作为最后的手段使用。 With a rooted device, you can extract the symbols from the framework jars on the device and put them into the android.jar in your sdk/platforms/ folder. 使用root设备,您可以从设备上的框架jar中提取符号,并将它们放入sdk / platforms /文件夹中的android.jar中。 Used to have a script to do this; 曾经有一个脚本来做这件事; lost it in switching jobs. 在转换工作时失去了它。

steps from memory (note you'll probably have trouble as I don't remember the steps... for advanced users who understand what I'm trying to get at): 记忆中的步骤(请注意,您可能会遇到麻烦,因为我不记得步骤...对于了解我想要了解的内容的高级用户):

  • adb pull /system/framework/* (these are all jar files). adb pull / system / framework / *(这些都是jar文件)。 It might be enough to get framework.jar. 获得framework.jar可能就足够了。 unzip them. 解压缩它们。
  • for each one I believe will give you a classes.dex and a manifest. 对于每一个,我相信会给你一个classes.dex和一个清单。 If you just get class files, skip the next step 如果您只是获取类文件,请跳过下一步
  • dex2jar the classes.dex and unjar the classes_dex2jar.jar or whatever the output is from dex2jar, which will give you a bunch of .class files dex2jar classes.dex和unjar classes_dex2jar.jar或来自dex2jar的输出,这将为你提供一堆.class文件
  • take the class files and add them to your android sdk android.jar file (sdk/platforms/android-#sdk#/android.jar). 获取类文件并将它们添加到android sdk android.jar文件(sdk / platforms / android- #sdk#/ android.jar)。

I suggest duplicating your android-#sdk# folder into an android-1#sdk# folder, so android-19 becomes android-119, and then change build.prop in the folder to say ro.build.version.sdk=119, and then build against sdk 119. This way you have the choice of building against a clean 119 or your hacked 119. Just don't refer to any com.android.internal.R files because those ids are not accurate in my experience. 我建议将android-#sdk#文件夹复制到android-1#sdk#文件夹中,这样android-19就会变成android-119,然后在文件夹中更改build.prop来说ro.build.version.sdk = 119,然后构建对抗sdk 119.这样你可以选择构建一个干净的119或你的黑客119.只是不要参考任何com.android.internal.R文件,因为这些ID在我的经验不准确。

You'll now be able to compile against these symbols and access them fine. 您现在可以针对这些符号进行编译并正确访问它们。 Though don't get mad if they change how things work, and they have no obligation to maintain compatibility with 3rd party apps. 虽然如果他们改变了工作方式,也不要生气,他们也没有义务保持与第三方应用程序的兼容性。

This works because the hide tag is only used during the SDK compile step and strips these symbols from the android.jar located in your sdk. 这是因为hide标记仅在SDK编译步骤中使用,并从位于sdk中的android.jar中删除这些符号。 If we gather all the symbols that are compiled onto the device and stick them into your sdk jar, it's like they were never stripped. 如果我们收集编译到设备上的所有符号并将它们粘贴到你的sdk jar中,就好像它们从未被剥离一样。

Alternatively you could pull down and build the full android tree ( https://source.android.com/source/building.html ) and then build your app against the full source, which the first step is essentially getting around by taking already compiled symbols and working with them. 或者你可以下拉并构建完整的android树( https://source.android.com/source/building.html ),然后针对完整的源代码构建你的应用程序,这第一步基本上是通过已经编译完成的符号并与他们合作。

  1. YES You CAN :) - first part of question 是的你可以:) - 问题的第一部分
  2. NO You CAN'T - second one 不,你不能 - 第二个

solution 1) - best what you can do here closest to what you want to achieve 解决方案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()
}

solutions 2) 解决方案2)

does the object (which calls this method) belongs to you? 对象(调用此方法)属于您吗? and implements interface? 并实现接口?

if so how about proxy ? 如果是这样代理怎么样?

  1. extend class 延伸课程
  2. create proxy 创建代理
  3. use proxy 使用代理服务器
  4. intercept method call 拦截方法调用
  5. based on some conditions ? 根据一些条件? call own implementation or fall back to originally? 调用自己的实现还是回归原来的?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM