如何过滤ACTION_SEND意图的特定应用程序(并为每个应用程序设置不同的文本)
如何在使用ACTION_SEND意图时过滤出特定的应用程序? 这个问题已经有了各种各样的问题,但是根据给出的答案,我还没有能够收集到一个解决scheme。 希望有人能帮助。 我想提供在应用程序内共享的能力。 遵循Android开发者Alexander Lucas的build议 ,我宁愿使用intent而不使用Facebook / Twitter API。
使用ACTION_SEND意图共享是伟大的,但问题是(1)我不希望每个分享选项那里,我宁愿限制到FB,Twitter和电子邮件,和(2)我不想分享每个共享应用程序都是一样的 。 例如,在我的twitter分享中,我将包括一些提及和标签,将其限制为140个字符或更less,而facebook分享将包括链接和特征图像。
是否可以限制ACTION_SEND(份额)意图的选项? 我已经看到了一些关于使用PackageManager和queryIntentActivities,但还没有能够找出PackageManager和ACTION_SEND意图之间的连接。
要么
如果我可以使用ACTION_SEND意图直接转到Facebook或Twitter,而不是popup对话框,则可以解决我的问题,而不是过滤共享应用程序。 如果是这样的话,我可以创build自己的对话框,当他们点击“Facebook”时,创build一个Facebook特定的意图,并将它们一直发送到Facebook。 和Twitter一样。
或者是不可能的? Facebook和Twitter API是唯一的方法吗?
据我所知,StackOverflow有很多人以各种方式提出这个问题,但没有人完全回答。
我的规范要求用户能够select电子邮件,推特,脸书或短信,并为每一个自定义文本。 以下是我的成就:
public void onShareClick(View v) { Resources resources = getResources(); Intent emailIntent = new Intent(); emailIntent.setAction(Intent.ACTION_SEND); // Native email client doesn't currently support HTML, but it doesn't hurt to try in case they fix it emailIntent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(resources.getString(R.string.share_email_native))); emailIntent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.share_email_subject)); emailIntent.setType("message/rfc822"); PackageManager pm = getPackageManager(); Intent sendIntent = new Intent(Intent.ACTION_SEND); sendIntent.setType("text/plain"); Intent openInChooser = Intent.createChooser(emailIntent, resources.getString(R.string.share_chooser_text)); List<ResolveInfo> resInfo = pm.queryIntentActivities(sendIntent, 0); List<LabeledIntent> intentList = new ArrayList<LabeledIntent>(); for (int i = 0; i < resInfo.size(); i++) { // Extract the label, append it, and repackage it in a LabeledIntent ResolveInfo ri = resInfo.get(i); String packageName = ri.activityInfo.packageName; if(packageName.contains("android.email")) { emailIntent.setPackage(packageName); } else if(packageName.contains("twitter") || packageName.contains("facebook") || packageName.contains("mms") || packageName.contains("android.gm")) { Intent intent = new Intent(); intent.setComponent(new ComponentName(packageName, ri.activityInfo.name)); intent.setAction(Intent.ACTION_SEND); intent.setType("text/plain"); if(packageName.contains("twitter")) { intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_twitter)); } else if(packageName.contains("facebook")) { // Warning: Facebook IGNORES our text. They say "These fields are intended for users to express themselves. Pre-filling these fields erodes the authenticity of the user voice." // One workaround is to use the Facebook SDK to post, but that doesn't allow the user to choose how they want to share. We can also make a custom landing page, and the link // will show the <meta content ="..."> text from that page with our link in Facebook. intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_facebook)); } else if(packageName.contains("mms")) { intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.share_sms)); } else if(packageName.contains("android.gm")) { // If Gmail shows up twice, try removing this else-if clause and the reference to "android.gm" above intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(resources.getString(R.string.share_email_gmail))); intent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.share_email_subject)); intent.setType("message/rfc822"); } intentList.add(new LabeledIntent(intent, packageName, ri.loadLabel(pm), ri.icon)); } } // convert intentList to array LabeledIntent[] extraIntents = intentList.toArray( new LabeledIntent[ intentList.size() ]); openInChooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents); startActivity(openInChooser); }
我发现在不同的地方如何做到这一点,但我没有在其他地方的一个地方看到这一切。
请注意,这种方法也隐藏了我不想要的所有愚蠢选项,例如通过WiFi和蓝牙共享。
希望这有助于某人。
编辑:在评论中,我被要求解释这个代码在做什么。 基本上,它只是为本地电子邮件客户端创buildACTION_SEND意图,然后将其他意图添加到select器上。 使原来的意向电子邮件特定摆脱所有额外的垃圾,如wifi和蓝牙,然后我抓住其他intent我想从通用ACTION_SENDtypes的明文,并在显示select器之前钉他们。
当我抓住额外的意图,我设置每个人的自定义文本。
编辑2:自从我发布了这一段时间以来,事情发生了一些变化。 如果您在选项列表中看到gmail两次,请尝试删除“android.gm”的特殊处理,如下面@ h_k的注释中所build议的那样。
由于这个答案几乎是所有我的stackoverflow声誉点的来源,我不得不至less尝试保持它最新:)
如果你想要一个定制的选项,那么你不应该依靠android提供的这个动作的默认对话框。
你需要做的是推出自己的。 您将需要查询PackageManager处理您需要的操作的包,然后根据回复,应用过滤和自定义文本。
具体来说,看一下PackageManager类的queryIntentActivities方法。 您构build了启动默认对话框(ACTION_SEND意图)的意图,将其传递给此方法,您将收到包含可处理该意图的活动信息的对象列表。 使用这个,你可以select你想要的。
一旦你build立你想要呈现的包列表,你需要build立你自己的列表对话框(最好是一个对话框主题的活动),它将显示该列表。
要注意的一点是,使自定义对话框看起来像默认对话框是非常困难的。 问题是在该对话框中使用的主题是一个内部主题,不能由您的应用程序使用。 您可以尝试使其与本机类似,也可以进行完全自定义的外观(许多应用程序都像图库应用程序一样)
find一个适合我的解决scheme,在这里find (见第一个答案的第三个评论)。 这段代码寻找一个有效的twitter客户端,并用它发布推文。 注意:它不会给你一个与各种Twitter客户端的意图,并允许你select。
使用twitter分享:
Intent shareIntent = findTwitterClient(); shareIntent.putExtra(Intent.EXTRA_TEXT, "test"); startActivity(Intent.createChooser(shareIntent, "Share"));
调用这个方法:
public Intent findTwitterClient() { final String[] twitterApps = { // package // name - nb installs (thousands) "com.twitter.android", // official - 10 000 "com.twidroid", // twidroid - 5 000 "com.handmark.tweetcaster", // Tweecaster - 5 000 "com.thedeck.android" }; // TweetDeck - 5 000 }; Intent tweetIntent = new Intent(); tweetIntent.setType("text/plain"); final PackageManager packageManager = getPackageManager(); List<ResolveInfo> list = packageManager.queryIntentActivities( tweetIntent, PackageManager.MATCH_DEFAULT_ONLY); for (int i = 0; i < twitterApps.length; i++) { for (ResolveInfo resolveInfo : list) { String p = resolveInfo.activityInfo.packageName; if (p != null && p.startsWith(twitterApps[i])) { tweetIntent.setPackage(p); return tweetIntent; } } } return null; }
尽pipe你仍然不能设置消息文本(2011年7月不推荐使用),但是Facebook将使用“com.facebook.katana”类似。
代码来源: http : //regis.decamps.info/blog/2011/06/intent-to-open-twitter-client-on-android/
试试这个共享只有三个应用程序 – 脸书,推特,KakaoStory。
public void onShareClick(View v){ List<Intent> targetShareIntents=new ArrayList<Intent>(); Intent shareIntent=new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setType("text/plain"); List<ResolveInfo> resInfos=getPackageManager().queryIntentActivities(shareIntent, 0); if(!resInfos.isEmpty()){ System.out.println("Have package"); for(ResolveInfo resInfo : resInfos){ String packageName=resInfo.activityInfo.packageName; Log.i("Package Name", packageName); if(packageName.contains("com.twitter.android") || packageName.contains("com.facebook.katana") || packageName.contains("com.kakao.story")){ Intent intent=new Intent(); intent.setComponent(new ComponentName(packageName, resInfo.activityInfo.name)); intent.setAction(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, "Text"); intent.putExtra(Intent.EXTRA_SUBJECT, "Subject"); intent.setPackage(packageName); targetShareIntents.add(intent); } } if(!targetShareIntents.isEmpty()){ System.out.println("Have Intent"); Intent chooserIntent=Intent.createChooser(targetShareIntents.remove(0), "Choose app to share"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetShareIntents.toArray(new Parcelable[]{})); startActivity(chooserIntent); }else{ System.out.println("Do not Have Intent"); showDialaog(this); } } }
此解决scheme显示类似于select器的ListView对话框中的应用程序列表:
您可以:
- 获取相关应用程序包列表
- 给定一个包名称,调用相关的意图
适配器类:
import java.util.List; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; public class ChooserArrayAdapter extends ArrayAdapter<String> { PackageManager mPm; int mTextViewResourceId; List<String> mPackages; public ChooserArrayAdapter(Context context, int resource, int textViewResourceId, List<String> packages) { super(context, resource, textViewResourceId, packages); mPm = context.getPackageManager(); mTextViewResourceId = textViewResourceId; mPackages = packages; } @Override public View getView(int position, View convertView, ViewGroup parent) { String pkg = mPackages.get(position); View view = super.getView(position, convertView, parent); try { ApplicationInfo ai = mPm.getApplicationInfo(pkg, 0); CharSequence appName = mPm.getApplicationLabel(ai); Drawable appIcon = mPm.getApplicationIcon(pkg); TextView textView = (TextView) view.findViewById(mTextViewResourceId); textView.setText(appName); textView.setCompoundDrawablesWithIntrinsicBounds(appIcon, null, null, null); textView.setCompoundDrawablePadding((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12, getContext().getResources().getDisplayMetrics())); } catch (NameNotFoundException e) { e.printStackTrace(); } return view; } }
及其用法:
void doXxxButton() { final List<String> packages = ...; if (packages.size() > 1) { ArrayAdapter<String> adapter = new ChooserArrayAdapter(MyActivity.this, android.R.layout.select_dialog_item, android.R.id.text1, packages); new AlertDialog.Builder(MyActivity.this) .setTitle(R.string.app_list_title) .setAdapter(adapter, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item ) { invokeApplication(packages.get(item)); } }) .show(); } else if (packages.size() == 1) { invokeApplication(packages.get(0)); } } void invokeApplication(String packageName) { // given a package name, create an intent and fill it with data ... startActivityForResult(intent, rq); }
你可以尝试下面的代码,它完美的作品。
在这里,我们分享到一些特定的应用程序,这些应用程序是Facebook,Messenger,Twitter,Google Plus和Gmail。
public void shareIntentSpecificApps() { List<Intent> intentShareList = new ArrayList<Intent>(); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setType("text/plain"); List<ResolveInfo> resolveInfoList = getPackageManager().queryIntentActivities(shareIntent, 0); for (ResolveInfo resInfo : resolveInfoList) { String packageName = resInfo.activityInfo.packageName; String name = resInfo.activityInfo.name; Log.d(TAG, "Package Name : " + packageName); Log.d(TAG, "Name : " + name); if (packageName.contains("com.facebook") || packageName.contains("com.twitter.android") || packageName.contains("com.google.android.apps.plus") || packageName.contains("com.google.android.gm")) { if (name.contains("com.twitter.android.DMActivity")) { continue; } Intent intent = new Intent(); intent.setComponent(new ComponentName(packageName, name)); intent.setAction(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_SUBJECT, "Your Subject"); intent.putExtra(Intent.EXTRA_TEXT, "Your Content"); intentShareList.add(intent); } } if (intentShareList.isEmpty()) { Toast.makeText(MainActivity.this, "No apps to share !", Toast.LENGTH_SHORT).show(); } else { Intent chooserIntent = Intent.createChooser(intentShareList.remove(0), "Share via"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentShareList.toArray(new Parcelable[]{})); startActivity(chooserIntent); } }
最干净的方法是复制以下类:ShareActionProvider,ActivityChooserView,ActivityChooserModel。 添加在ActivityChooserModel中过滤意图的function,以及ShareActionProvider中适当的支持方法。 我创build了必要的类,你可以将它们复制到你的项目中( https://gist.github.com/saulpower/10557956 )。 这不仅增加了过滤您想与之共享的应用程序的能力(如果您知道程序包名称),还可以closures历史logging。
private final String[] INTENT_FILTER = new String[] { "com.twitter.android", "com.facebook.katana" }; @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.journal_entry_menu, menu); // Set up ShareActionProvider's default share intent MenuItem shareItem = menu.findItem(R.id.action_share); if (shareItem instanceof SupportMenuItem) { mShareActionProvider = new ShareActionProvider(this); mShareActionProvider.setShareIntent(ShareUtils.share(mJournalEntry)); mShareActionProvider.setIntentFilter(Arrays.asList(INTENT_FILTER)); mShareActionProvider.setShowHistory(false); ((SupportMenuItem) shareItem).setSupportActionProvider(mShareActionProvider); } return super.onCreateOptionsMenu(menu); }
我已经改进了@dacoinminster的答案,这是分享你的应用程序的例子的结果:
// Intents with SEND action PackageManager packageManager = context.getPackageManager(); Intent sendIntent = new Intent(Intent.ACTION_SEND); sendIntent.setType("text/plain"); List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(sendIntent, 0); List<LabeledIntent> intentList = new ArrayList<LabeledIntent>(); Resources resources = context.getResources(); for (int j = 0; j < resolveInfoList.size(); j++) { ResolveInfo resolveInfo = resolveInfoList.get(j); String packageName = resolveInfo.activityInfo.packageName; Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name)); intent.setType("text/plain"); if (packageName.contains("twitter")) { intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.twitter) + "https://play.google.com/store/apps/details?id=" + context.getPackageName()); } else { // skip android mail and gmail to avoid adding to the list twice if (packageName.contains("android.email") || packageName.contains("android.gm")) { continue; } intent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.largeTextForFacebookWhatsapp) + "https://play.google.com/store/apps/details?id=" + context.getPackageName()); } intentList.add(new LabeledIntent(intent, packageName, resolveInfo.loadLabel(packageManager), resolveInfo.icon)); } Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:")); emailIntent.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.subjectForMailApps)); emailIntent.putExtra(Intent.EXTRA_TEXT, resources.getString(R.string.largeTextForMailApps) + "https://play.google.com/store/apps/details?id=" + context.getPackageName()); context.startActivity(Intent.createChooser(emailIntent, resources.getString(R.string.compartirEn)).putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new LabeledIntent[intentList.size()])));
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "android@bankbazzar.com", null)); emailIntent.putExtra(Intent.EXTRA_SUBJECT, text); startActivity(Intent.createChooser(emailIntent, "Send email..."));
我有同样的问题,这个接受的解决scheme没有帮助我,如果有人有同样的问题,你可以使用我的代码片段:
// example of filtering and sharing multiple images with texts // remove facebook from sharing intents private void shareFilter(){ String share = getShareTexts(); ArrayList<Uri> uris = getImageUris(); List<Intent> targets = new ArrayList<>(); Intent template = new Intent(Intent.ACTION_SEND_MULTIPLE); template.setType("image/*"); List<ResolveInfo> candidates = getActivity().getPackageManager(). queryIntentActivities(template, 0); // remove facebook which has a broken share intent for (ResolveInfo candidate : candidates) { String packageName = candidate.activityInfo.packageName; if (!packageName.equals("com.facebook.katana")) { Intent target = new Intent(Intent.ACTION_SEND_MULTIPLE); target.setType("image/*"); target.putParcelableArrayListExtra(Intent.EXTRA_STREAM,uris); target.putExtra(Intent.EXTRA_TEXT, share); target.setPackage(packageName); targets.add(target); } } Intent chooser = Intent.createChooser(targets.remove(0), "Share Via"); chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targets.toArray(new Parcelable[targets.size()])); startActivity(chooser); }
感谢@dacoinminster。 我对他的答案做了一些修改,包括stream行的应用程序的包名称和这些应用程序的sorting。
List<Intent> targetShareIntents = new ArrayList<Intent>(); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setType("text/plain"); PackageManager pm = getActivity().getPackageManager(); List<ResolveInfo> resInfos = pm.queryIntentActivities(shareIntent, 0); if (!resInfos.isEmpty()) { System.out.println("Have package"); for (ResolveInfo resInfo : resInfos) { String packageName = resInfo.activityInfo.packageName; Log.i("Package Name", packageName); if (packageName.contains("com.twitter.android") || packageName.contains("com.facebook.katana") || packageName.contains("com.whatsapp") || packageName.contains("com.google.android.apps.plus") || packageName.contains("com.google.android.talk") || packageName.contains("com.slack") || packageName.contains("com.google.android.gm") || packageName.contains("com.facebook.orca") || packageName.contains("com.yahoo.mobile") || packageName.contains("com.skype.raider") || packageName.contains("com.android.mms")|| packageName.contains("com.linkedin.android") || packageName.contains("com.google.android.apps.messaging")) { Intent intent = new Intent(); intent.setComponent(new ComponentName(packageName, resInfo.activityInfo.name)); intent.putExtra("AppName", resInfo.loadLabel(pm).toString()); intent.setAction(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, "https://website.com/"); intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_text)); intent.setPackage(packageName); targetShareIntents.add(intent); } } if (!targetShareIntents.isEmpty()) { Collections.sort(targetShareIntents, new Comparator<Intent>() { @Override public int compare(Intent o1, Intent o2) { return o1.getStringExtra("AppName").compareTo(o2.getStringExtra("AppName")); } }); Intent chooserIntent = Intent.createChooser(targetShareIntents.remove(0), "Select app to share"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetShareIntents.toArray(new Parcelable[]{})); startActivity(chooserIntent); } else { Toast.makeText(getActivity(), "No app to share.", Toast.LENGTH_LONG).show(); } }