Programming
How to filter specific apps for ACTIONSEND intent and set a different text for each app
Sharing content from an Android application is a fundamental feature, allowing users to effortlessly distribute information across various platforms. However, the default Android share sheet often presents a long list of apps, making it cumbersome for users to find their preferred sharing destination. More importantly, developers might need to filter specific apps for ACTION_SEND intent and set a different text for each app, offering a tailored sharing experience. Imagine a scenario where sharing an article to Twitter requires a specific hashtag, while sharing it to a messaging app needs a concise summary. This level of customization, while not immediately obvious, is entirely achievable and can significantly enhance user experience and engagement within your application.
Understanding the Android Sharing Mechanism
The core of Android’s sharing functionality revolves around the ACTION_SEND intent. When you initiate a share, your app creates an Intent object with this action, specifying the type of data (e.g., text, image) and the content itself. The Android system then identifies all installed applications capable of handling this specific intent. Traditionally, Intent.createChooser() is used to present a standardized dialog that lists all compatible apps, allowing the user to select one. While convenient, this generic approach doesn’t offer the fine-grained control many developers seek.
The challenge with the default chooser is its lack of customization regarding the recipient applications and the content sent to them. Every app on the list receives the exact same Intent data. For instance, if you want to share a unique promotional code to a specific messaging app but a general link to a social media platform, the standard ACTION_SEND intent falls short. This limitation often leads to developers seeking advanced methods to curate the sharing experience, ensuring that the right message reaches the right platform, optimizing for each app’s unique context and user expectations.
According to the official Android Developers documentation on Sharing Simple Data, while ACTION_SEND is straightforward for basic sharing, more complex scenarios require deeper interaction with the PackageManager and custom intent construction. This highlights the need for a more programmatic approach when a generic share isn’t sufficient. Our goal is to move beyond the basic Intent.createChooser() and build a share dialog that is intelligent and dynamic, adapting to the specific sharing needs of your application.
Identifying and Targeting Specific Apps
To implement a custom sharing experience, the first step is to identify which applications on the user’s device can handle ACTION_SEND intents, and then specifically target the ones you want to include in your custom chooser. This process involves querying the Android PackageManager, which acts as a central registry for all installed applications and their capabilities. By understanding how to programmatically discover these apps, you gain the power to filter the list and present only the most relevant options to your users.
The PackageManager provides methods like queryIntentActivities() which return a list of ResolveInfo objects. Each ResolveInfo contains details about an activity that can handle a given intent, including the package name and class name—crucial identifiers for creating explicit intents. For example, if you want to target WhatsApp, you’d look for an activity within the “com.whatsapp” package that handles ACTION_SEND. This precise identification allows you to bypass the generic system chooser and construct intents specifically directed at chosen applications.
This approach gives developers unparalleled control over the sharing flow. Instead of relying on the system to decide which apps are shown, you can handpick a curated selection. This is particularly useful for internal sharing within an ecosystem of apps or when promoting specific sharing channels. For instance, an e-commerce app might prioritize sharing to messaging apps for product recommendations over general social media posts. The ability to specify app components directly is a powerful tool for crafting a highly intentional user experience.
Once you know how to identify specific apps, the next crucial step is to construct a custom share dialog that not only filters these apps but also allows you to set different text for each one. This involves creating an array of Intent objects, each tailored for a specific app and carrying unique content. This method leverages the Intent.createChooser() functionality in a more advanced way, using EXTRA_INITIAL_INTENTS to pre-populate the chooser with your custom intents.
To achieve this, you’ll first create a “main” sharing intent, typically one for a fallback or a general sharing option. Then, for each specific app you wish to target, you’ll create an explicit intent. An explicit intent specifies the exact ComponentName (package name and class name) of the activity you want to launch. Within each of these explicit intents, you can then add different EXTRA_TEXT values, ensuring that WhatsApp receives one message, Telegram another, and so on. These explicit intents are then bundled into an array and passed to Intent.createChooser().
Here’s a step-by-step guide to implement this dynamic sharing:
- Create a List of ResolveInfo Objects: Query the PackageManager to find all activities capable of handling ACTION_SEND for your desired MIME type (e.g., “text/plain”).
- Initialize a List for Targeted Intents: Create an ArrayList
to store your custom intents. - Iterate and Filter: Loop through the ResolveInfo list. For each ResolveInfo, check if its package name matches one of your target apps (e.g., “com.whatsapp”, “com.twitter.android”).
- Create App-Specific Intents: If a match is found, create a new Intent with ACTION_SEND. Set its ComponentName using the package name and class name from the ResolveInfo. Crucially, set the desired EXTRA_TEXT for that specific app.
- Add to List: Add this app-specific intent to your ArrayList
. - Prepare a Fallback Intent: Create a generic ACTION_SEND intent with a default message. This will be the primary intent for the chooser.
- Launch the Chooser: Call Intent.createChooser(fallbackIntent, “Share via…”) and add your ArrayList
as EXTRA_INITIAL_INTENTS. Start this intent.
This method ensures that when the user opens the share dialog, they see a curated list where each app, if selected, will receive the pre-configured text. This powerful customization allows for highly effective and context-aware sharing, directly addressing the need to enhance user sharing workflows.
Advanced Considerations and Best Practices
While dynamically filtering apps and customizing text is powerful, there are several advanced considerations and best practices to ensure a robust and user-friendly implementation. Handling edge cases, optimizing for performance, and maintaining a good user experience are paramount for any sharing feature within an Android application.
One critical aspect is robust error handling. What if a targeted app isn’t installed on the user’s device? Your code should gracefully handle such scenarios, perhaps by simply not including that app in the custom chooser or by falling back to a more general sharing option. Additionally, consider the Question & Answer :
How can you filter out specific apps when using the ACTION_SEND intent? This question has been asked in various ways, but I haven’t been able to gather a solution based on the answers given. Hopefully someone can help. I would like to provide the ability to share within an app. Following Android Dev Alexander Lucas’ advice, I’d prefer to do it using intents and not using the Facebook/Twitter APIs.

Sharing using the ACTION_SEND intent is great, but the problem is (1) I don’t want every sharing option there, I’d rather limit it to FB, Twitter, and Email, and (2) I don’t want to share the same thing to each sharing app. For example, in my twitter share I’m going to include some mentions and hashtags limited it to 140 chars or less, while the facebook share is going to include a link and a feature image.
Is it possible to limit the options for ACTION_SEND (share) intent? I’ve seen something about using PackageManager and queryIntentActivities, but haven’t been able to figure out the connection between the PackageManager and the ACTION_SEND intent.
OR
Rather than filter the sharing apps, my problem could also be solved if I could use the ACTION_SEND intent to go directly to facebook or twitter rather than popping up the dialog. If that were the case then I could create my own dialog and when they click “Facebook” create a Facebook-specific intent and just send them all the way to Facebook. Same with Twitter.
OR is it not possible? Are the Facebook and Twitter APIs the only way?
My spec called for the user to be able to choose email, twitter, facebook, or SMS, with custom text for each one. Here is how I accomplished that:
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); }
I found bits of how to do this in various places, but I haven’t seen all of it in one place anywhere else.
Note that this method also hides all the silly options that I don’t want, like sharing over wifi and bluetooth.
Edit: In a comment, I was asked to explain what this code is doing. Basically, it’s creating an ACTION_SEND intent for the native email client ONLY, then tacking other intents onto the chooser. Making the original intent email-specific gets rid of all the extra junk like wifi and bluetooth, then I grab the other intents I want from a generic ACTION_SEND of type plain-text, and tack them on before showing the chooser.
When I grab the additional intents, I set custom text for each one.
Edit2: It’s been awhile since I posted this, and things have changed a bit. If you are seeing gmail twice in the list of options, try removing the special handling for “android.gm” as suggested in a comment by @h_k below.
Since this one answer is the source of nearly all my stackoverflow reputation points, I have to at least try to keep it up to date.