android系统分享分析Intent.createChooser
系统提供的分享实现代码如下:
Intent send = new Intent(Intent.ACTION_SEND);
send.setType("text/plain");
send.putExtra(Intent.EXTRA_TEXT, url);
send.putExtra(Intent.EXTRA_SUBJECT, title);
c.startActivity(Intent.createChooser(send, "share title"));
我们先扒一扒源码这个是怎么实现分享
- Intent.ACTION_SEND很好理解,一个隐式intent的action,在这里调用会打开对应的暴漏出该action的app对应页面(可以自己写个app,然后暴漏该action 也会出现在分享列表中)
- 剩下就是通过intent把分享参数title text add进去
- createChooser()方法new Intent(ACTION_CHOOSER),返回的是一个Intent对象,弹出的选择框是一个Activity,在源码中搜索一下Action为com.android.internal.app.ChooserActivity的Activity
/android/frameworks/base/core/res/AndroidManifest.xml
- ChooserActivity调用了其父类ResolverActivity的OnCreate(),ResolverActivity相当于一个Activity的选择器,ChooserActivity在onCreate()方法里先获取传递进来的Intent对象,取得其中携带的目标Intent。如果只有一个Activity适配,将直接启动。 ResolverActivity(queryIntentActivities)就是这个选择对话框的Activity,这里获得适配Activity的icon和title等信息显示到对话框。如果没有调用createChooser()方法,如果有多个Activity适配一个intent的话也会打开一个选择对话框,不过这个对话框多了两个选项.
Custom choose intent
产品或者我们自己这个分享列表提出自己的要求,比如是否可以监听这个列表点击自定义跳转、把facebook whatsapp这两个app放在第一个、或者某个app不要出现在分享列表中 等这些需求该如何实现;
- 监听这个列表点击自定义跳转操作 答案是 NO,弹框是系统的ChooserActivity,并不存在暴漏出列表item点击的监听回调,而且从隐式intent设计来讲,列表中的app都是与其暴漏出的intent对应匹配上的,它的初衷就是匹配上来就跳转。参考回答 想实现监听跳转只能自定义分享列表list adapter填充列表数据 跳转等,我们上个版本就是这样实现的。核心代码是获取能分享的列表数据
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType("text/plain"); PackageManager pm = App.getInstance().getPackageManager(); List
- > listArrayList = new ArrayList<>();
List
activityList = pm.queryIntentActivities(sharingIntent, 0); List newActivityList = new ArrayList<>(); for (Iterator it = activityList.iterator(); it.hasNext(); ) { ResolveInfo info = it.next(); //过滤出facebook google+whatapp分享app单独处理 if (info.activityInfo.packageName.equals("com.facebook.katana") || info.activityInfo.packageName.equals("com.google.android.apps.plus") || info.activityInfo.packageName.equals("com.facebook.orca") || info.activityInfo.packageName.contains("whatsapp")) { it.remove(); newActivityList.add(info); } }
- 从上面的核心代码看既然能实现分享列表数据的过滤,那么排序和删除数据都可以简单实现。但也必须是自己自定义分享弹框列表实现。上个版本就是这么做的
- 放google+分享列表实现(先谈一个BottomSheetDialog展示特异强调的分享app和一个other按钮,点other再进入系统的分享列表) 1.难点是用过滤的分享数据实现系统的分享。之前系统的分享数据是在ChooserActivity中自己匹配的。可喜的找到了Intent中EXTRA_INITIAL_INTENTS参数。具体看代码源码
List
targetIntents = new ArrayList (); Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("text/plain"); for (ResolveInfo candidate : packages) { String packageName = candidate.activityInfo.packageName; Intent target = new Intent(android.content.Intent.ACTION_SEND); target.setType("text/plain"); if (uri != null) { shareIntent.setType("image/*"); shareIntent.putExtra(Intent.EXTRA_STREAM, uri); } target.putExtra(Intent.EXTRA_TEXT, shareText); target.setComponent(new ComponentName(packageName, candidate.activityInfo.name)); targetIntents.add(target); } Intent chooserIntent = Intent.createChooser(targetIntents.remove(0), title); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{})); context.startActivity(chooserIntent);
疑问
- 注意,这里没有使用Intent.setComponent来明确指定要启动的Activity,而是通过setPackageName和setClass来指定。这是因为,在createChooser处理过程中,第一个参数intent指定的component会在ResolverActivity中强制被设置为null。这样的结果是什么呢?当component被设置为null后,targetIntents.remove(0)其实就是emailIntent,那么createChooser会显示所有满足emailIntent的应用,然后在加上由EXTRA_INITIAL_INTENTS指定的应用。你会发现选择界面中出现了重复的应用。
推荐阅读
- android第三方框架(五)ButterKnife
- 第326天
- Android中的AES加密-下
- 带有Hilt的Android上的依赖注入
- 如何在Mac中的文件选择框中打开系统隐藏文件夹
- 单点登陆
- android|android studio中ndk的使用
- 姚老师互动问答会|姚老师互动问答会 # 问题001(如何更有智慧的和身边人分享金刚智慧())
- 焦点学习田源分享第267天《来访》
- 操作系统|[译]从内部了解现代浏览器(1)