...それが例外をスローするので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;
}
}