Android程序间跳转分析及重现

来源:互联网 发布:uefi ubuntu安装黑屏 编辑:程序博客网 时间:2024/05/16 16:17
Android应用程序之间有很多常用跳转,例如各种分享操作、选择本机图片作为头像的操作、利用第三方应用打开文件操作、发送邮件、从应用内跳转到应用市场评分操作等。

那么这些跳转是怎么实现的呢?假如我要做一个应用实现上述的某种功能,我该怎么入手呢?要解决这些问题,我觉得不妨把这些跳转事件拦截下来分析分析。


通过Intent跳转到一个Activity可以分为两类:

显式Intent直接指定包名和类名进行跳转,多用于在应用内部跳转或跳转到系统设置页面;

隐式Intent:通过IntentFilter 筛选出 action、category、data 类型全部符合要求的页面,假如合适页面不只一个,一般弹出窗口让用户选择。

程序间应用跳转大多采用隐式Intent,这也就是说我需要拦截和分析的也是隐式Intent跳转。


第一步:拦截Intent

在AndroidManifest.xml里面这样处理拦截页面,这里主要拦截常用跳转截:

<activity           android:name="com.jersey.intentanalyser.MainActivity"            android:label="@string/app_name"            android:launchMode="singleTop" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>            <!-- 处理Intent 我们需要匹配action,  category, 和对应的data所有mimeType类型 -->            <intent-filter>                <action android:name="android.intent.action.VIEW" />                <action android:name="android.intent.action.SEND" />                <action android:name="android.intent.action.SENDTO" />                <action android:name="android.intent.action.SEND_MULTIPLE" />                <action android:name="android.intent.action.GET_CONTENT" />                <category android:name="android.intent.category.DEFAULT" />                <category android:name="android.intent.category.OPENABLE" />                <category android:name="android.intent.category.BROWSABLE" />                <data android:mimeType="*/*" />            </intent-filter><pre name="code" class="html">            <!-- 处理Intent 我们需要匹配action,  category, 和对应的data常用scheme类型 -->            <intent-filter>                <action android:name="android.intent.action.VIEW" />                <action android:name="android.intent.action.SEND" />                <action android:name="android.intent.action.SENDTO" />                <action android:name="android.intent.action.SEND_MULTIPLE" />                <action android:name="android.intent.action.GET_CONTENT" />                <category android:name="android.intent.category.DEFAULT" />                <category android:name="android.intent.category.OPENABLE" />                <category android:name="android.intent.category.BROWSABLE" />                <data android:scheme="" />                <data android:scheme="content" />                <data android:scheme="http" />                <data android:scheme="https" />                <data android:scheme="market" />                <data android:scheme="geo" />                <data android:scheme="file" />            </intent-filter>        </activity>

第二步: 分析Intent

这里主要是对Intent内容的遍历:

       /*** * 分析Intent,将结果输出至TextView *  */private void handleIntent() {Intent intent = getIntent();TextView tv = (TextView) findViewById(R.id.textview);StringBuilder sb = new StringBuilder("<b>Intent:</b>");try {if (intent.getAction() != null)sb.append(getBolderTitleHtml("Action:") + intent.getAction());if (intent.getDataString() != null)sb.append(getBolderTitleHtml("DataString:")+ intent.getDataString());if (intent.getScheme() != null)sb.append(getBolderTitleHtml("Scheme:") + intent.getScheme());if (intent.getType() != null)sb.append(getBolderTitleHtml("Type:") + intent.getType());// Package和Component由于是用户选择以后添加的,不是最初的Intent内容,所以不再显示// if(intent.getPackage()!=null)sb.append("\n" + "Package:"// +intent.getPackage());// if(intent.getComponent()!=null)sb.append("\n" + "Component:"+// intent.getComponent());// 通过反射获取所有的FLAG名称,这里需要注意的是广播类型的FLAG是跟Activity有冲突的,需要屏蔽掉Class<?> intentClass = Class.forName("android.content.Intent");Field[] fileds = intentClass.getDeclaredFields();for (Field filed : fileds) {if (filed.getName().startsWith("FLAG_")&& (filed.getInt(intentClass) & intent.getFlags()) != 0&& (!filed.getName().startsWith("FLAG_RECEIVER_"))) {sb.append(getBolderTitleHtml("FLAG:") + filed.getName());}}if (intent.getCategories() != null)sb.append(getBolderTitleHtml("Categories:")+ intent.getCategories());if (intent.getData() != null)sb.append(getBolderTitleHtml("Data:") + intent.getData());if (intent.getClipData() != null)sb.append(getBolderTitleHtml("ClipData:")+ intent.getClipData());if (intent.getSourceBounds() != null)sb.append(getBolderTitleHtml("SourceBounds:")+ intent.getSourceBounds());// 遍历 BundleBundle bundle = intent.getExtras();if (bundle != null) {Set<String> set = bundle.keySet();if (set != null) {for (String ss : set) {sb.append(getBolderTitleHtml(ss + ":") + "\n"+ bundle.get(ss));}}}} catch (Exception e1) {e1.printStackTrace();}tv.setText(Html.fromHtml(sb.toString()));}/*** * 将属性名称转为html格式粗体 *  * @param str */private String getBolderTitleHtml(String str) {return "<br/><b>" + str + "</b>";}

Intent中所有FLAG定义二进制值如下,可以看到ACTIVITY跟广播RECEIVER是有相同部分的:

第三步 :继续跳转

想要复原用户选择之前的Intent,只需要将Package和Component设为空就可以了:

intent.setComponent(null);intent.setPackage(null);startActivity(Intent.createChooser(intent, ""));

程序分析测试如下:


APK已上传360手机市场:

http://zhushou.360.cn/detail/index/soft_id/2777363

代码

http://download.csdn.net/detail/jerseyho/8587997


0 0
原创粉丝点击