2016-10-12 28 views
0

私はアンドロイド21の前にウォークアラウンドshouldInterceptRequest(.. request)を見つけようとしています。だから私はshouldInterceptRequest(android.webkit.WebView, java.util.String)しか持っていない。しかし、アンドロイド-19上で動作しているとき、私は私が知っている必要があり、呼び出しにisMainFrameプロパティを見ることができます:私は直接の参照を持っていないので、Javaのコールバックで呼び出し元オブジェクトを取得するにはどうすればよいですか?

enter image description here

残念ながら、呼び出し元は、呼び出し中にthisを提供していません。私はどのように私のリスナーオブジェクト(WebViewClient)のメソッドの呼び出し側(IoThreadClientImpl)オブジェクト参照を取得することができますか?私は定期的なJavaの反射(またはいくつかの特定のアンドロイドの反射)を使用する必要がありますと信じています。

PS 1. Thread.currentThread().getStackTrace()は、呼び出し元オブジェクト、クラス/メソッド/行のみを提供しないため、適合しません。

PS 2.それは一般的なケースでは不可能だと思われ

答えて

0

...それが例外をスローするのでsettingカスタムSecurityManagerが解決策ではないようですが、私の場合はAwContentsインスタンスにIoThreadClientのためのプロキシを作成することができました呼び出しを傍受する - 必要な場合は2つの引数を持つshouldInterceptRequest - 私はちょうどそれを覚えて、元のインスタンスに呼び出しを渡します(必要な値は呼び出し元オブジェクトではなく呼び出し引数にあります)。

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; 
    } 
}