2016-10-12 2 views
0

Я пытаюсь пройти пешком shouldInterceptRequest(.. request) до android-21. Так что у меня только shouldInterceptRequest(android.webkit.WebView, java.util.String). Но при работе на андроид-19 я могу увидеть isMainFrame недвижимости в запустившем, что мне нужно знать:Как получить объект invoker в моем обратном вызове в Java?

enter image description here

К сожалению Вызывающий не обеспечивает this в вызове, поэтому я не имеет прямую ссылку. Как я могу получить ссылку на объект invoke (IoThreadClientImpl) в методе моего объекта-слушателя (WebViewClient)? Я считаю, что необходимо использовать регулярное отражение в Java (или какое-то конкретное андроидное отражение).

PS 1. Thread.currentThread().getStackTrace() не подходит, поскольку он не предоставляет объект-вызывающий объект, класс/метод/линию.

PS 2. Кажется, что setting обычай SecurityManager не решение, так как он бросает исключение ..

ответ

0

кажется, что это невозможно в общем случае, но в моем случае я был в состоянии создать прокси-сервер для IoThreadClient в AwContents инстанции и вызов перехвата - если это мой обязательный метод shouldInterceptRequest с 2 аргументами - я просто его помню, а затем передаю вызов в исходный экземпляр (требуемое значение не было в объекте invoker, а в аргументах вызова).

инъекции прокси в WebView наследнику:

private synchronized void initIoThreadClient() 
    { 
    final Object awContents = ReflectionUtils.extractProperty(this, new String[] 
     { 
     "mProvider", 
     "mAwContents" 
     }); 

    final String ioThreadClientProperty = "mIoThreadClient"; 
    final Object originalClient = ReflectionUtils.extractProperty(
     awContents, 
     new String[] 
     { 
     ioThreadClientProperty 
     }); 

    // avoid injecting twice (already injected Proxy instance has another class name) 
    if (!originalClient.getClass().getSimpleName().startsWith("$Proxy")) 
    { 
     Object proxyClient = Proxy.newProxyInstance(
     originalClient.getClass().getClassLoader(), 
     originalClient.getClass().getInterfaces(), 
     new IoThreadClientInvocationHandler(originalClient)); 

     // inject proxy instead of original client 
     boolean injected = ReflectionUtils.injectProperty(awContents, ioThreadClientProperty, proxyClient); 
     if (injected) 
     { 
     Integer mNativeAwContents = (Integer) ReflectionUtils.extractProperty(awContents, "mNativeAwContents"); 
     Object mWebContentsDelegate = ReflectionUtils.extractProperty(awContents, "mWebContentsDelegate"); 
     Object mContentsClientBridge = ReflectionUtils.extractProperty(awContents, "mContentsClientBridge"); 
     Object mInterceptNavigationDelegate = ReflectionUtils.extractProperty(awContents, "mInterceptNavigationDelegate"); 

     boolean invoked = ReflectionUtils.invokeMethod(awContents, "nativeSetJavaPeers", new Object[] 
      { 
      mNativeAwContents, awContents, mWebContentsDelegate, 
      mContentsClientBridge, proxyClient, mInterceptNavigationDelegate 
      }); 
     if (!invoked) 
     { 
      e("Failed to inject IoThreadClient proxy"); 
     } 
     } 
    } 

IoThreadClientInvocationHandler класс:

public class IoThreadClientInvocationHandler implements InvocationHandler 
{ 
    private final String TAG = Utils.getTag(IoThreadClientInvocationHandler.class); 

    public static transient Boolean isMainFrame; 
    private Object wrappedObject; 

    public IoThreadClientInvocationHandler(Object wrappedObject) 
    { 
    this.wrappedObject = wrappedObject; 
    } 

    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
    { 
    // intercept invocation and store 'isMainFrame' argument 
    if (method.getName().startsWith("shouldInterceptRequest") && args.length == 2) 
    { 
     String url = (String)args[0]; 
     isMainFrame = (Boolean)args[1]; 

     Log.d(TAG, "isMainFrame=" + isMainFrame + " for " + url); 
    } 
    return method.invoke(wrappedObject, args); 
    } 
} 

ReflectionUtils класс:

public class ReflectionUtils 
{ 
    public static Object extractProperty(Object target, String field) 
    { 
    return extractProperty(target, target.getClass(), field); 
    } 

    public static Object extractProperty(Object target, Class clazz, String field) 
    { 
    try 
    { 
     Field f = clazz.getDeclaredField(field); 
     if (!f.isAccessible()) 
     { 
     f.setAccessible(true); 
     } 
     return f.get(target); 
    } 
    catch (NoSuchFieldException e) 
    { 
     return extractProperty(target, clazz.getSuperclass(), field); 
    } 
    catch (Exception e) 
    { 
     return null; 
    } 
    } 

    public static Object extractProperty(Object target, String []fields) 
    { 
    Object eachTarget = target; 
    for (int i = 0; i < fields.length; i++) 
    { 
     eachTarget = extractProperty(eachTarget, eachTarget.getClass(), fields[i]); 
     if (eachTarget == null) 
     { 
     return null; 
     } 
    } 
    return eachTarget; 
    } 

    public static boolean injectProperty(Object target, String field, Object value) 
    { 
    try 
    { 
     Field f = target.getClass().getDeclaredField(field); 
     if (!f.isAccessible()) 
     { 
     f.setAccessible(true); 
     } 
     f.set(target, value); 
     return true; 
    } 
    catch (Exception e) 
    { 
     return false; 
    } 
    } 

    public static boolean invokeMethod(Object target, String methodName, Object[] args) 
    { 
    Method[] methods = target.getClass().getDeclaredMethods(); 
    for (Method eachMethod : methods) 
    { 
     if (eachMethod.getName().equals(methodName)) 
     { 
     try 
     { 
      if (!eachMethod.isAccessible()) 
      { 
      eachMethod.setAccessible(true); 
      } 
      eachMethod.invoke(target, args); 
      return true; 
     } 
     catch (Exception e) 
     { 
      return false; 
     } 
     } 
    } 
    return false; 
    } 
} 
Смежные вопросы