Intent是一个意图,一个描述了想要启动一个Activity、Broadcast或是Service的意图。它主要持有的信息是它想要启动的组件(Activity、Broadcast或是Service),在开发操作中,需要通过 startActivity , startService 或sendBroadcast 方法来启动这个意图执行某些操作!!
PendingIntent可以认为是对Intent的包装,实际上就是,供当前App或之外的其他App调用,而常见的是供外部App使用,外部App执行这个 PendingIntent时,间接地调用里面的Intent,即外部App延时执行PendingIntent中描述的Intent及其最终行为,PendingIntent主要持有的信息是它所包装的Intent和当前App Context,即使当前App已经不存在了,也能通过存在于PendingIntent里的
Context来执行Intent。当你把PendingIntent递交给别的程序进行处理时,PendingIntent仍然拥有PendingIntent原程序所拥有的权限,当你从系统取得一个PendingIntent时,一定要非常小心才行,比如,通常,如果Intent目的地是你自己的component(Activity/Service/BroadcastReceiver)的话,你最好采用在Intent中显示指定目的component名字的方式,以确保Intent最终能发到目的,否则Intent最后可能不知道发到哪里了。
可以这样理解:当你想在A activity中启动另一个B activity,那么你可以选择两种情况[立即启动或延时启动]:
1.通过intent配置需要启动的B activity,然后调用startActivity()方法,让他立即执行启动操作,跳转过去
2.另一种情况是,你虽然想启动另一个B activity,可是你并不想马上跳转到Bactivity页面,你想静等5分钟之后再跳转到Bactivity,那么你可以通过PendingIntent来实现[当然实现方式有很多啦,这里仅是想说明PendingIntent与intent的区别],PendingIntent可以包装第1步中的intent,然后通过AlarmManager这个定时器,定制5分钟之后启PendingIntent,实现这种延时操作,如果你还是听着似懂非懂,一头雾水,我表示很有压力了,我该怎么说你才能清楚呢,理论终究是抽象的,后见将会通过一个程序说明一下,程序中是启动一个BroadcastReceiver,其实原理都是一样的!!
如何获得一个PendingIntent呢?其实很简单:
1.你可以通过getActivity(Context context, int requestCode, Intent intent, int flags)系列方法从系统取得一个用于启动一个Activity的PendingIntent对象
2.可以通过getService(Context context, int requestCode, Intent intent, int flags)方法从系统取得一个用于启动一个Service的PendingIntent对象
3.可以通过getBroadcast(Context context, int requestCode, Intent intent, int flags)方法从系统取得一个用于向BroadcastReceiver的发送广播的PendingIntent对象
PendingIntent几个常量:
1.FLAG_CANCEL_CURRENT :如果AlarmManager管理的PendingIntent已经存在,那么将会取消当前的PendingIntent,从而创建一个新的PendingIntent
2.FLAG_UPDATE_CURRENT:如果AlarmManager管理的PendingIntent已经存在,可以让新的Intent更新之前PendingIntent中的Intent对象数据,例如更新Intent中的Extras,另外,我们也可以在PendingIntent的原进程中调用PendingIntent的cancel ()把其从系统中移除掉
3.FLAG_NO_CREATE :如果AlarmManager管理的PendingIntent已经存在,那么将不进行任何操作,直接返回已经存在的PendingIntent,如果PendingIntent不存在了,那么返回null
以上转:http://my.oschina.net/u/242041/blog/206710
同时注意:
【强制】使用 PendingIntent 时,禁止使用空 intent,同时禁止使用隐式 Intent
说明:
1) 使用 PendingIntent 时,使用了空 Intent,会导致恶意用户劫持修改 Intent 的内 容。禁止使用一个空 Intent 去构造 PendingIntent,构造 PendingIntent 的 Intent 一定要设置 ComponentName 或者action。
2) PendingIntent 可以让其他 APP 中的代码像是运行自己 APP 中。PendingIntent 的intent接收方在使用该intent时与发送方有相同的权限。在使用PendingIntent 时,PendingIntent 中包装的 intent 如果是隐式的 Intent,容易遭到劫持,导致 信息泄露。
正例:
Intent intent = new Intent(this, SomeActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_ UPDATE_CURRENT);
try {
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
反例 1:
Bundle addAccountOptions = new Bundle();
mPendingIntent = PendingTntent.getBroadcast(this, 0, new Intent, 0);
addAccountOptions.putParcelable(KEY_CALLER_IDENTITY, mPendingIntent);
addAccountOptions.putBoolean(EXTRA_HAS_MULTIPLE_USERS, Utils.hasMultipleUsers(this));
AccountManager.get(this).addAccount(
accountType,
null,
null,
addAccountOptions,
null,
mCallback,
null);
反例 2:
mPendingIntent 是通过 new Intent()构造原始 Intent 的,所以为“双无”Intent,这个 PendingIntent最终被通过AccountManager.addAccount方法传递给了恶意APP接 口。
Intent intent = new Intent("com.test.test.pushservice.action.METHOD");
intent.addFlags(32);
intent.putExtra("app",
PendingIntent.getBroadcast(this, 0, intent, 0));
如上代码PendingIntent.getBroadcast,PendingItent中包含的Intent为隐式intent, 因此当PendingIntent触发执行时,发送的intent很可能被嗅探或者劫持,导致intent 内容泄漏。
扩展参考:
1) https://developer.android.com/reference/android/app/PendingIntent.html
2) https://wiki.sei.cmu.edu/confluence/display/android/DRD21-J.+Always+pass+ explicit+intents+to+a+PendingIntent
3) http://www.droidsec.cn/android-broadcastanywhere%E6%BC%8F%E6%B4 %9E%E5%88%86%E6%9E%90/