我想知道是否可以从我自己未创建的 PendingIntent 中获取更多信息。更准确地说:是否有可能以某种方式检索 PendingIntent
的原始 Intent
?我不需要执行它,但想打印它的内容。
查看 PendingIntent
的代码,它显示了一个隐藏的方法:
/** @hide */
public IIntentSender getTarget() {
return mTarget;
}
然而,这个 IIntentSender
也是隐藏的,并且与 Binder
和更多 IPC(我猜)相关的东西有关。没那么容易。有什么想法吗?
最佳答案
此方法适用于 Android 4.2.2 及以上版本:
/**
* Return the Intent for PendingIntent.
* Return null in case of some (impossible) errors: see Android source.
* @throws IllegalStateException in case of something goes wrong.
* See {@link Throwable#getCause()} for more details.
*/
public Intent getIntent(PendingIntent pendingIntent) throws IllegalStateException {
try {
Method getIntent = PendingIntent.class.getDeclaredMethod("getIntent");
return (Intent) getIntent.invoke(pendingIntent);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
以下是 Android 2.3 及更高版本 的不完整实现。它需要编写一段额外的 native (JNI) 代码。那么也许它会起作用。有关详细信息,请参阅 TODO
注释。
/**
* Return the Intent for PendingIntent.
* Return null in case of some (impossible) errors: see Android source.
* @throws IllegalStateException in case of something goes wrong.
* See {@link Throwable#getCause()} and {@link Throwable#getMessage()} for more details.
*/
public Intent getIntent(PendingIntent pendingIntent) throws IllegalStateException {
try {
Method getIntent = PendingIntent.class.getDeclaredMethod("getIntent");
return (Intent) getIntent.invoke(pendingIntent);
} catch (NoSuchMethodException e) {
return getIntentDeep(pendingIntent);
} catch (InvocationTargetException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
private Intent getIntentDeep(PendingIntent pendingIntent) throws IllegalStateException {
try {
Class<?> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
Method getDefault = activityManagerNativeClass.getDeclaredMethod("getDefault");
Object defaultManager = getDefault.invoke(null);
if (defaultManager == null) {
throw new IllegalStateException("ActivityManagerNative.getDefault() returned null");
}
Field mTargetField = PendingIntent.class.getDeclaredField("mTarget");
mTargetField.setAccessible(true);
Object mTarget = mTargetField.get(pendingIntent);
if (mTarget == null) {
throw new IllegalStateException("PendingIntent.mTarget field is null");
}
String defaultManagerClassName = defaultManager.getClass().getName();
switch (defaultManagerClassName) {
case "android.app.ActivityManagerProxy":
try {
return getIntentFromProxy(defaultManager, mTarget);
} catch (RemoteException e) {
// Note from PendingIntent.getIntent(): Should never happen.
return null;
}
case "com.android.server.am.ActivityManagerService":
return getIntentFromService(mTarget);
default:
throw new IllegalStateException("Unsupported IActivityManager inheritor: " + defaultManagerClassName);
}
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) {
throw new IllegalStateException(e);
}
}
private Intent getIntentFromProxy(Object defaultManager, Object sender) throws RemoteException {
Class<?> activityManagerProxyClass;
IBinder mRemote;
int GET_INTENT_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 160;
String iActivityManagerDescriptor = "android.app.IActivityManager";
try {
activityManagerProxyClass = Class.forName("android.app.ActivityManagerProxy");
Field mRemoteField = activityManagerProxyClass.getDeclaredField("mRemote");
mRemoteField.setAccessible(true);
mRemote = (IBinder) mRemoteField.get(defaultManager);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
// From ActivityManagerProxy.getIntentForIntentSender()
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(iActivityManagerDescriptor);
data.writeStrongBinder(((IInterface) sender).asBinder());
transact(mRemote, data, reply, 0);
reply.readException();
Intent res = reply.readInt() != 0
? Intent.CREATOR.createFromParcel(reply) : null;
data.recycle();
reply.recycle();
return res;
}
private boolean transact(IBinder remote, Parcel data, Parcel reply, int i) {
// TODO: Here must be some native call to convert ((BinderProxy) remote).mObject int
// to IBinder* native pointer and do some more magic with it.
// See android_util_Binder.cpp: android_os_BinderProxy_transact() in the Android sources.
}
private Intent getIntentFromService(Object sender) {
String pendingIntentRecordClassName = "com.android.server.am.PendingIntentRecord";
if (!(sender.getClass().getName().equals(pendingIntentRecordClassName))) {
return null;
}
try {
Class<?> pendingIntentRecordClass = Class.forName(pendingIntentRecordClassName);
Field keyField = pendingIntentRecordClass.getDeclaredField("key");
Object key = keyField.get(sender);
Class<?> keyClass = Class.forName("com.android.server.am.PendingIntentRecord$Key");
Field requestIntentField = keyClass.getDeclaredField("requestIntent");
requestIntentField.setAccessible(true);
Intent requestIntent = (Intent) requestIntentField.get(key);
return requestIntent != null ? new Intent(requestIntent) : null;
} catch (ClassCastException e) {
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
return null;
}
关于android - 获取有关 PendingIntent 的 Intent 的详细信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14241657/