ACTION_SEND Intent未显示全部浏览器,如何实现指定分享选项?
解决Intent选择器同时显示浏览器和复制到剪贴板的问题
你的问题核心在于ACTION_SEND和ACTION_VIEW的Intent匹配逻辑不同:
- 用
ACTION_SEND分享文本时,系统只会唤起注册了该Action(且支持text/plain类型)的应用,而Chrome、原生浏览器这类App的Intent Filter是针对ACTION_VIEW+http/httpsUri的,所以不会出现在选择器里。 - 用
ACTION_VIEW打开链接时,系统只会唤起能处理URL的浏览器类应用,而"复制到剪贴板"是系统为ACTION_SEND提供的特殊选项,自然不会出现在这里。
要同时满足两个需求,我们需要手动合并两类Intent的候选应用,自定义选择器对话框。下面是具体实现步骤:
步骤1:准备两个基础Intent
分别创建用于分享文本(获取复制选项)和打开链接(获取浏览器)的Intent:
private static final String WEB_URL = "https://www.google.ca/"; // 原分享Intent,用于获取复制到剪贴板等选项 Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_TEXT, WEB_URL); shareIntent.setType("text/plain"); // 打开链接的Intent,用于获取所有浏览器 Intent viewIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(WEB_URL));
步骤2:查询两类Intent的可处理应用
通过PackageManager获取两个Intent对应的ResolveInfo列表,这些信息包含了应用的图标、名称和启动信息:
PackageManager pm = getPackageManager(); List<ResolveInfo> shareResolves = pm.queryIntentActivities(shareIntent, 0); List<ResolveInfo> viewResolves = pm.queryIntentActivities(viewIntent, 0);
步骤3:合并列表并去重
有些应用可能同时支持两个Intent(比如Firefox),需要避免重复显示:
// 用HashMap去重,以packageName为唯一标识 Map<String, ResolveInfo> uniqueResolves = new HashMap<>(); // 添加分享类应用 for (ResolveInfo info : shareResolves) { uniqueResolves.put(info.activityInfo.packageName, info); } // 添加浏览器类应用 for (ResolveInfo info : viewResolves) { uniqueResolves.put(info.activityInfo.packageName, info); } // 转成List用于对话框显示 List<ResolveInfo> finalResolves = new ArrayList<>(uniqueResolves.values());
步骤4:构建自定义选择器对话框
用AlertDialog创建选择器,每个选项对应启动相应的Intent:
// 准备选项的文本和图标列表 List<CharSequence> labels = new ArrayList<>(); List<Drawable> icons = new ArrayList<>(); for (ResolveInfo info : finalResolves) { labels.add(info.loadLabel(pm)); icons.add(info.loadIcon(pm)); } // 创建对话框 AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("CHOOOOOSE"); builder.setAdapter(new ArrayAdapter<CharSequence>(this, android.R.layout.select_dialog_item, labels) { @Override public View getView(int position, View convertView, ViewGroup parent) { // 自定义列表项,显示图标+文字的样式 View view = super.getView(position, convertView, parent); TextView textView = view.findViewById(android.R.id.text1); textView.setCompoundDrawablesWithIntrinsicBounds(icons.get(position), null, null, null); textView.setCompoundDrawablePadding(16); return view; } }, (dialog, which) -> { // 点击选项后启动对应的Intent ResolveInfo info = finalResolves.get(which); ComponentName component = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); Intent targetIntent; // 判断当前选项属于分享类还是浏览类Intent if (shareResolves.contains(info)) { targetIntent = (Intent) shareIntent.clone(); } else { targetIntent = (Intent) viewIntent.clone(); } targetIntent.setComponent(component); startActivity(targetIntent); }); builder.show();
补充说明
- 这种方法可以完全自定义选择器的样式,你还可以根据需求添加过滤规则(比如只保留浏览器类应用和复制选项)。
- 不需要额外权限,因为只是查询已安装应用和启动Intent,都是Android的常规操作。
这样就能实现点击按钮后,选择器同时显示所有浏览器和"复制到剪贴板"选项啦!
内容的提问来源于stack exchange,提问作者Noma Citzen
相关产品推荐
相关产品推荐

