如何从ACTION_SEND意图中排除特定应用程序?

12
我已使用以下代码从我的应用选择器中排除Facebook应用程序:

我已使用以下代码从我的应用选择器中排除Facebook应用程序:

 List<Intent> targetedShareIntents = new ArrayList<Intent>();
    Intent intent = new Intent(android.content.Intent.ACTION_SEND);
    intent.setType("image/*");
    List<ResolveInfo> resInfo = getActivity().getPackageManager().queryIntentActivities(intent, 0);
    if (!resInfo.isEmpty()) {
        for (ResolveInfo resolveInfo : resInfo) {
            String packageName = resolveInfo.activityInfo.packageName;
            Intent targetedShareIntent = new Intent(android.content.Intent.ACTION_SEND);
            targetedShareIntent.setType("image/*");
            targetedShareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "tooter.nl");
            if (!TextUtils.equals(packageName, "com.facebook.katana")) {


                targetedShareIntent.putExtra(android.content.Intent.EXTRA_TEXT, st);
                targetedShareIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri);
                targetedShareIntent.setPackage(packageName);
                targetedShareIntents.add(targetedShareIntent);
            }

        }
        Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(0), "Select app to share");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[targetedShareIntents.size()]));
        startActivity(chooserIntent);
    }

当我使用这个代码时,Facebook应用程序被删除了。但是令人难过的是,即使Twitter应用程序也从应用选择器中被删除了,还有其他不必要的应用程序,例如“Android系统”被列在了选择器上。我该怎么办?这个代码有什么问题或缺失吗?


除了 Facebook 和 Twitter,其余只显示“如果您想在 Facebook 和 Twitter 上共享数据,则应使用 Facebook 和 Twitter SDK@mrnobody”。 - MurugananthamS
@muruga5000 是的,我使用了Facebook SDK,因此我想在我的发送意图应用选择器中将其排除。然而,在我这样做的同时,Twitter也没有显示出来。我不需要一个单独的分享给Twitter,所以我想在应用选择器中包含它。 - mrnobody
@mrnobody,您想从本地共享意图中仅排除Facebook,对吗? - Swaminathan V
@RaguSwaminathan 是的 - mrnobody
@mrnobody,从targetedShareIntents中删除第一个项目并将其提供给createChooser的理由是什么?可解析意图的其余部分会发生什么? - Akh
显示剩余2条评论
7个回答

16

请查看下面我的答案。它将仅排除Facebook应用程序进行共享。

 void shareOnOtherSocialMedia() {

    List<Intent> shareIntentsLists = new ArrayList<Intent>();
    Intent shareIntent = new Intent();
    shareIntent.setAction(Intent.ACTION_SEND);
    shareIntent.setType("image/*");
    List<ResolveInfo> resInfos = getPackageManager().queryIntentActivities(shareIntent, 0);
    if (!resInfos.isEmpty()) {
      for (ResolveInfo resInfo : resInfos) {
        String packageName = resInfo.activityInfo.packageName;
        if (!packageName.toLowerCase().contains("facebook")) {
          Intent intent = new Intent();
          intent.setComponent(new ComponentName(packageName, resInfo.activityInfo.name));
          intent.setAction(Intent.ACTION_SEND);
          intent.setType("image/*");
          intent.setPackage(packageName);
          shareIntentsLists.add(intent);
        }
      }
      if (!shareIntentsLists.isEmpty()) {
        Intent chooserIntent = Intent.createChooser(shareIntentsLists.remove(0), "Choose app to share");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, shareIntentsLists.toArray(new Parcelable[]{}));
        startActivity(chooserIntent);
      } else
        Log.e("Error", "No Apps can perform your task");

    }
  }
}

在你想要的任何地方调用上述函数。

如有疑问,请告诉我。


太棒了!愉快地编程吧! :) - Swaminathan V
它给我报错,直接分享不可用。 - yogesh lokhande
请注意使用此方法,因为在Android 11中,包可见性会影响您可以查询哪些包以及哪些包实际上会显示给用户,即使它们在查询中被找到。 - Mira_Cole
1
它在Android 9及以下版本中运行正常,但在10及以上版本中不建议使用EXTRA_INITIAL_INTENTS,而应该使用EXTRA_EXCLUDE_COMPONENT。 - cmatic

6

对于Android API 24及以上版本,您可以使用以下内容:

val components = arrayOf(ComponentName(applicationContext, YourActivity::class.java))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
   startActivity(Intent.createChooser(intent, null).putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS,components))

对于其余部分,您可以使用我写的这个解决方案(它允许您拥有一个要排除的条件)。

以下是一种更加通用的解决方案,可供选择在所有Android版本中要排除哪些内容:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val targetIntent = Intent(Intent.ACTION_SEND)
        targetIntent.type = "text/plain"
        targetIntent.putExtra(Intent.EXTRA_SUBJECT, "subject")
        targetIntent.putExtra(Intent.EXTRA_TEXT, "text")
        val excludedAppsPackageNames = hashSetOf( "com.pushbullet.android","com.android.bluetooth","com.google.android.apps.docs","com.google.android.gm")
        getIntentChooser(this, targetIntent, "choose!", object : ComponentNameFilter {
            override fun shouldBeFilteredOut(componentName: ComponentName): Boolean = excludedAppsPackageNames.contains(componentName.packageName)
        })?.let { startActivity(it) }
    }

    interface ComponentNameFilter {
        fun shouldBeFilteredOut(componentName: ComponentName): Boolean
    }

    private fun getIntentChooser(context: Context, intent: Intent, chooserTitle: CharSequence? = null, filter: ComponentNameFilter): Intent? {
        val resolveInfos = context.packageManager.queryIntentActivities(intent, 0)
//        Log.d("AppLog", "found apps to handle the intent:")
        val excludedComponentNames = HashSet<ComponentName>()
        resolveInfos.forEach {
            val activityInfo = it.activityInfo
            val componentName = ComponentName(activityInfo.packageName, activityInfo.name)
//            Log.d("AppLog", "componentName:$componentName")
            if (filter.shouldBeFilteredOut(componentName))
                excludedComponentNames.add(componentName)
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return Intent.createChooser(intent, chooserTitle).putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, excludedComponentNames.toTypedArray())
        }
        if (resolveInfos.isNotEmpty()) {
            val targetIntents: MutableList<Intent> = ArrayList()
            for (resolveInfo in resolveInfos) {
                val activityInfo = resolveInfo.activityInfo
                if (excludedComponentNames.contains(ComponentName(activityInfo.packageName, activityInfo.name)))
                    continue
                val targetIntent = Intent(intent)
                targetIntent.setPackage(activityInfo.packageName)
                targetIntent.component = ComponentName(activityInfo.packageName, activityInfo.name)
                // wrap with LabeledIntent to show correct name and icon
                val labeledIntent = LabeledIntent(targetIntent, activityInfo.packageName, resolveInfo.labelRes, resolveInfo.icon)
                // add filtered intent to a list
                targetIntents.add(labeledIntent)
            }
            val chooserIntent: Intent?
            // deal with M list seperate problem
            chooserIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                // create chooser with empty intent in M could fix the empty cells problem
                Intent.createChooser(Intent(), chooserTitle)
            } else {
                // create chooser with one target intent below M
                Intent.createChooser(targetIntents.removeAt(0), chooserTitle)
            }
            if (chooserIntent == null) {
                return null
            }
            // add initial intents
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toTypedArray<Parcelable>())
            return chooserIntent
        }
        return null
    }
}

6

由于Facebook应用程序有一个损坏的分享意图(涉及用户原创性),我不得不将其排除在外,使用Intent#EXTRA_EXCLUDE_COMPONENTS,我采用了以下措施:

        Intent intent = new Intent(Intent.ACTION_SEND);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            intent.setTypeAndNormalize("text/plain");
        } else {
            intent.setType("text/plain");
        }
        intent.putExtra(Intent.EXTRA_TEXT, "Text to share");

        Intent chooser = Intent.createChooser(intent, "Share Text");

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

            ArrayList<ComponentName> targets = new ArrayList<>();

            // remove facebook which has a broken share intent
            for (ResolveInfo candidate : requireActivity().getPackageManager().queryIntentActivities(intent, 0)) {
                String packageName = candidate.activityInfo.packageName;
                if (packageName.toLowerCase().contains("facebook")) {
                    targets.add(new ComponentName(packageName, candidate.activityInfo.name));
                }
            }
            chooser.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, targets.toArray(new ComponentName[0]));
        }

        startActivity(chooser);

这仅适用于 Android N 及以上版本。


这是2021年几乎所有新设备中唯一可行的解决方案。谢谢。 - Mohit Rajput

5

谢谢您进行验证,因为我一直在想为什么Intent.EXTRA_EXCLUDE_COMPONENTS没有起作用。 - user9599745

2

基于Ragu Swaminathan的回答更新的Kotlin回答

fun share() {

        val shareIntent = Intent()
        shareIntent.action = Intent.ACTION_SEND
        shareIntent.type = "text/plain"
        val resInfoList = activity?.packageManager?.queryIntentActivities(shareIntent, 0)

        val shareIntentList = arrayListOf<Intent>()

        if (resInfoList?.isNotEmpty() == true) {
            for (resInfo in resInfoList) {
                val packageName = resInfo.activityInfo.packageName
                if (!packageName.toLowerCase().contains("discord")) {
                    val intent = Intent()
                    intent.component = ComponentName(packageName, resInfo.activityInfo.name)
                    intent.action = Intent.ACTION_SEND
                    intent.type = "text/plain"
                    intent.`package` = packageName
                    intent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.")
                    shareIntentList.add(intent)
                }
            }
        }

        if (shareIntentList.isEmpty()) {
            Toast.makeText(activity, "No apps to share!", Toast.LENGTH_LONG).show()
        } else {
            val chooserIntent = Intent.createChooser(Intent(), "Choose app to share")
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, shareIntentList.toTypedArray())
            activity?.startActivity(chooserIntent)
        }
    }

1
它只显示了3个意图,而不是15个已列入白名单的意图,在API 29上。 - Evgen Bodunov

0
感谢Ragu Swaminathan的回答,它完美地排除了IntentChooser中特定应用程序。但是,由于“shareIntentLists”添加在“chooserIntent”的前面,如果列表大小不是4的倍数,则可能会出现一些空白。为解决此问题,请尝试:
Intent chooserIntent = Intent.createChooser(new Intent(), "Choose app to share");

0

将targetSdkVersion更新为31后,旧的解决方案将停止工作。 以下解决方案适用于所有Android版本

在清单文件AndroidManidest.xml中

(在Android api 31中,默认情况下queryIntentActivities()将返回空列表,为了从queryIntentActivities中获取所需的结果,您需要在清单文件中添加以下查询参数。)

<manifest>
   <queries>
      <intent>
         <!--Change the action and data depending on you share intent-->
         <action android:name="android.intent.action.SEND" /> 
         <data android:mimeType="text/*"/>

      </intent>
   </queries>
</manifest>

在活动文件共享功能中

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("text/plain");

shareIntent.putExtra(Intent.EXTRA_TEXT, "Link");
shareIntent.putExtra(Intent.EXTRA_SUBJECT,"Description")

ArrayList<ComponentName> excludedComponents = new ArrayList<ComponentName>();
PackageManager packageManager = context.getPackageManager();
for (ResolveInfo resolveInfo : packageManager.queryIntentActivities(shareIntent, 0)){
String packageName = resolveInfo.activityInfo.packageName;
//change facebook with whichever app you want to exclude or you can directly search for the specific package name
   if (packageName.contains("facebook")){
   excludedComponents.add(new 
   ComponentName(packageName,resolveInfo.activityInfo.name));
   }
}

Intent intentChooser = Intent.createChooser(shareIntent, "Share");
intentChooser.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, excludedComponents.toArray(new Parcelable[]{}));
startActivity(intentChooser);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接