una studio para otra mensajes mensajeria mensaje mandar llamar intent envio enviar desde como aplicaciones aplicacion abrir android android-intent android-sharing

android - studio - Cómo filtrar aplicaciones específicas para la intención de ACTION_SEND(y establecer un texto diferente para cada aplicación)



llamar a otra aplicacion desde android studio (11)

¿Cómo puede filtrar aplicaciones específicas cuando usa el intento de ACTION_SEND? Esta pregunta se ha formulado de varias maneras, pero no he podido reunir una solución basada en las respuestas dadas. Espero que alguien pueda ayudar. Me gustaría brindar la posibilidad de compartir dentro de una aplicación. Siguiendo el consejo de Android Dev Alexander Lucas , preferiría hacerlo utilizando intenciones y no utilizando las API de Facebook / Twitter.

Compartir usando el intento de ACTION_SEND es genial, pero el problema es (1) No quiero tener todas las opciones de uso compartido, preferiría limitarlo a FB, Twitter y Correo electrónico, y (2) no quiero compartir lo mismo para cada aplicación para compartir . Por ejemplo, en mi cuenta de Twitter voy a incluir algunas menciones y hashtags que se limitan a 140 caracteres o menos, mientras que el recurso compartido de Facebook incluirá un enlace y una imagen de la función.

¿Es posible limitar las opciones de ACTION_SEND (compartir) intento? He visto algo sobre el uso de PackageManager y queryIntentActivities, pero no he podido averiguar la conexión entre el PackageManager y el intento de ACTION_SEND.

O

En lugar de filtrar las aplicaciones para compartir, mi problema también podría resolverse si pudiera usar el intento de ACTION_SEND de ir directamente a Facebook o Twitter en lugar de abrir el cuadro de diálogo. Si ese fuera el caso, entonces podría crear mi propio diálogo y, cuando hagan clic en "Facebook", crear un intento específico de Facebook y simplemente enviarlos a Facebook. Lo mismo con Twitter.

¿O acaso no es posible? ¿Las API de Facebook y Twitter son la única manera?


Encontré una solución que me funciona buscando here (ver el tercer comentario en la primera respuesta). Este código busca un cliente de Twitter válido y lo usa para publicar el tweet. Nota: no le da una intención con los diversos clientes de Twitter y le permite elegir.

Compartir usando twitter:

Intent shareIntent = findTwitterClient(); shareIntent.putExtra(Intent.EXTRA_TEXT, "test"); startActivity(Intent.createChooser(shareIntent, "Share"));

Llamando a este método:

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; }

Facebook será similar con " com.facebook.katana ", aunque aún no puede establecer el texto del mensaje (en desuso en julio de 2011).

Fuente del código: intento de abrir el cliente de Twitter en Android


Esta solución muestra una lista de aplicaciones en un diálogo ListView que se asemeja al selector:

Depende de usted:

  1. obtener la lista de paquetes de aplicaciones relevantes
  2. dado un nombre de paquete, invoque el intento relevante

La clase de adaptador:

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; } }

y su uso:

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); }


Gracias a @dacoinminster. Hago algunas modificaciones a su respuesta, incluidos los nombres de los paquetes de las aplicaciones populares y la clasificación de esas aplicaciones.

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(); } }


He mejorado la respuesta de @dacoinminster y este es el resultado con un ejemplo para compartir tu aplicación:

// 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()])));


La forma más limpia es copiar las siguientes clases: ShareActionProvider, ActivityChooserView, ActivityChooserModel. Agregue la capacidad de filtrar los intentos en ActivityChooserModel y los métodos de soporte adecuados en ShareActionProvider. Creé las clases necesarias, puedes copiarlas en tu proyecto ( https://gist.github.com/saulpower/10557956 ). Esto no solo agrega la capacidad de filtrar las aplicaciones con las que le gustaría compartir (si conoce el nombre del paquete), sino también de desactivar el historial.

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); }


Pruebe esto solo por compartir tres aplicaciones: Facebook, Twitter, 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); } } }


Puedes probar el siguiente código, funciona perfectamente.

Aquí compartimos algunas aplicaciones específicas, que son Facebook, Messenger, Twitter, Google Plus y 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); } }


Que yo sepa, tiene muchas personas haciendo esta pregunta de varias maneras, pero nadie ha respondido completamente todavía.

Mi especificación exigía que el usuario pudiera elegir correo electrónico, Twitter, Facebook o SMS, con texto personalizado para cada uno. Así es como lo logré:

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); }

Encontré trozos de cómo hacer esto en varios lugares, pero no he visto todo en un lugar en otro lado.

Tenga en cuenta que este método también oculta todas las opciones tontas que no quiero, como compartir a través de wifi y bluetooth.

Espero que esto ayude a alguien.

Editar: En un comentario, me pidieron que explicara qué está haciendo este código. Básicamente, está creando ACTION_SEND para el cliente de correo electrónico nativo, luego insertando otras intenciones en el selector. Al hacer la intención original del correo electrónico específico se deshace de toda la basura adicional como wifi y bluetooth, luego tomo las otras intenciones que quiero de un ACTION_SEND genérico de tipo texto sin formato, y las ACTION_SEND antes de mostrar el selector.

Cuando tomo los intentos adicionales, configuro texto personalizado para cada uno.

Edit2: Ha pasado un tiempo desde que publiqué esto, y las cosas han cambiado un poco. Si está viendo gmail dos veces en la lista de opciones, intente eliminar el tratamiento especial para "android.gm" como se sugiere en un comentario de @h_k a continuación.

Dado que esta única respuesta es la fuente de casi todos mis puntos de reputación de , al menos debo intentar mantenerla actualizada.


Si desea una opción personalizada, entonces no debe confiar en el diálogo predeterminado proporcionado por Android para esta acción.

Lo que tienes que hacer es implementar el tuyo. Deberá consultar el PackageManager en el que los paquetes manejan la acción que necesita y luego, en función de la respuesta, aplicará el filtrado y el texto personalizado.

Específicamente, eche un vistazo al método queryIntentActivities de la clase PackageManager . Usted construye la intención que lanzaría el diálogo predeterminado (el intento ACTION_SEND), pase eso a este método y recibirá una lista de objetos que contienen información sobre las actividades que pueden manejar esa intención. Usando eso, puedes elegir los que quieras.

Una vez que construyes tu lista de paquetes que deseas presentar, necesitas construir tu propio diálogo de lista (preferiblemente una actividad con el tema del diálogo) que mostrará esa lista.

Una cosa a tener en cuenta es que es muy difícil hacer que el diálogo personalizado se vea como el predeterminado. El problema es que el tema utilizado en ese diálogo es un tema interno y su aplicación no lo puede usar. Puede intentar hacer que sea tan similar al original como desee o buscar un aspecto completamente personalizado (muchas aplicaciones lo hacen como la aplicación de la galería, etc.)


Tuve el mismo problema y esta solución aceptada no me ayudó, si alguien tiene el mismo problema, puede usar my fragmento de código:

// 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); }


Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "[email protected]", null)); emailIntent.putExtra(Intent.EXTRA_SUBJECT, text); startActivity(Intent.createChooser(emailIntent, "Send email..."));