Android и Facebook разделяют намерения
Я занимаюсь разработкой приложения для Android, и мне интересно узнать, как можно обновить статус пользователя приложения из приложения, используя намерения общего доступа Android.
Посмотрев SDK Facebook, кажется, что это достаточно легко сделать, однако я хочу позволить пользователю сделать это через обычное всплывающее окно Share Intent? видел здесь:
Я пробовал обычный код намерения поделиться, однако он больше не работает для Facebook.
public void invokeShare(Activity activity, String quote, String credit) {
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, activity.getString(R.string.share_subject));
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, "Example text");
activity.startActivity(Intent.createChooser(shareIntent, activity.getString(R.string.share_title)));
}
ОБНОВЛЕНИЕ: сделав больше копаний, похоже, что это ошибка в приложении Facebook, которая еще не устранена! ( ошибка на фейсбуке) Между тем, похоже, мне просто придется смириться с негативом "Обмен не работает!!!" обзоры. Ура Facebook:*(
12 ответов
Приложение Facebook не обрабатывает ни
EXTRA_SUBJECT
или жеEXTRA_TEXT
поля.
Вот ссылка на ошибку: https://developers.facebook.com/bugs/332619626816423
Спасибо @billynomates:
Дело в том, если вы поместите URL в
EXTRA_TEXT
поле, это работает. Как будто они намеренно убирают любой текст.
Очевидно, что Facebook больше (с 2014 года) не позволяет настраивать экран обмена, независимо от того, открываете ли вы URL-адрес sharer.php или используете намерения Android более специализированными способами. Посмотрите, например, эти ответы:
- "Sharer.php больше не позволяет настраивать."
- "Вам нужно использовать Facebook Android SDK или Easy Facebook Android SDK, чтобы делиться ими".
В любом случае, используя обычный Intents, вы все равноможете поделиться с ним URL-адресом, но не любым текстом по умолчанию, как прокомментировал billynomates. (Кроме того, если у вас нет URL-адреса для общего доступа, просто запустить приложение Facebook с пустым диалоговым окном "Написать сообщение" (т. Е. Обновить статус) так же легко; используйте приведенный ниже код, но пропуститеEXTRA_TEXT
.)
Вот лучшее решение, которое я нашел, которое не предполагает использования каких-либо SDK Facebook.
Этот код открывает официальное приложение Facebook напрямую, если оно установлено, и в противном случае возвращается к открытию sharer.php в браузере. (Большинство других решений в этом вопросе вызывают огромный диалог "Полное действие с использованием…", который вообще не оптимален!)
String urlToShare = "https://stackru.com/questions/7545254";
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
// intent.putExtra(Intent.EXTRA_SUBJECT, "Foo bar"); // NB: has no effect!
intent.putExtra(Intent.EXTRA_TEXT, urlToShare);
// See if official Facebook app is found
boolean facebookAppFound = false;
List<ResolveInfo> matches = getPackageManager().queryIntentActivities(intent, 0);
for (ResolveInfo info : matches) {
if (info.activityInfo.packageName.toLowerCase().startsWith("com.facebook.katana")) {
intent.setPackage(info.activityInfo.packageName);
facebookAppFound = true;
break;
}
}
// As fallback, launch sharer.php in a browser
if (!facebookAppFound) {
String sharerUrl = "https://www.facebook.com/sharer/sharer.php?u=" + urlToShare;
intent = new Intent(Intent.ACTION_VIEW, Uri.parse(sharerUrl));
}
startActivity(intent);
(Учитываяcom.facebook.katana
название пакета, см . комментарий MatheusJardimB.)
Результат выглядит так на моем Nexus 7 (Android 4.4) с установленным приложением Facebook:
Обычный способ
Обычный способ создать то, что вы просите, это просто сделать следующее:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, "The status update text");
startActivity(Intent.createChooser(intent, "Dialog title text"));
Это работает без каких-либо проблем для меня.
Альтернативный способ (возможно)
Потенциальная проблема заключается в том, что вы также разрешаете отправку сообщения по электронной почте, SMS и т. Д. Следующий код - это то, что я использую в приложении, которое позволяет пользователю отправлять мне электронное письмо. -почта с помощью Gmail. Я предполагаю, что вы могли бы попытаться изменить его, чтобы он работал только с Facebook.
Я не уверен, как он реагирует на любые ошибки или исключения (я предполагаю, что это произойдет, если Facebook не установлен), поэтому вам, возможно, придется немного его протестировать.
try {
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
String[] recipients = new String[]{"e-mail address"};
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, recipients);
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "E-mail subject");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "E-mail text");
emailIntent.setType("plain/text"); // This is incorrect MIME, but Gmail is one of the only apps that responds to it - this might need to be replaced with text/plain for Facebook
final PackageManager pm = getPackageManager();
final List<ResolveInfo> matches = pm.queryIntentActivities(emailIntent, 0);
ResolveInfo best = null;
for (final ResolveInfo info : matches)
if (info.activityInfo.packageName.endsWith(".gm") ||
info.activityInfo.name.toLowerCase().contains("gmail")) best = info;
if (best != null)
emailIntent.setClassName(best.activityInfo.packageName, best.activityInfo.name);
startActivity(emailIntent);
} catch (Exception e) {
Toast.makeText(this, "Application not found", Toast.LENGTH_SHORT).show();
}
Я обнаружил, что вы можете поделиться только текстом или изображением, не используя оба Intents
, Ниже код разделяет только изображение, если оно существует, или только текст, если изображение не выходит. Если вы хотите поделиться обоими, вам нужно использовать Facebook SDK отсюда.
Если вы используете другое решение вместо приведенного ниже кода, не забудьте также указать имя пакета com.facebook.lite, которое является именем пакета Facebook Lite. Я не тестировал, но com.facebook.orca - это имя пакета Facebook Messenger, если вы хотите настроить таргетинг на него.
Вы можете добавить больше методов для обмена с WhatsApp, Twitter...
public class IntentShareHelper {
/**
* <b>Beware,</b> this shares only image if exists, or only text if image does not exits. Can't share both
*/
public static void shareOnFacebook(AppCompatActivity appCompatActivity, String textBody, Uri fileUri) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT,!TextUtils.isEmpty(textBody) ? textBody : "");
if (fileUri != null) {
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("image/*");
}
boolean facebookAppFound = false;
List<ResolveInfo> matches = appCompatActivity.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo info : matches) {
if (info.activityInfo.packageName.toLowerCase().startsWith("com.facebook.katana") ||
info.activityInfo.packageName.toLowerCase().startsWith("com.facebook.lite")) {
intent.setPackage(info.activityInfo.packageName);
facebookAppFound = true;
break;
}
}
if (facebookAppFound) {
appCompatActivity.startActivity(intent);
} else {
showWarningDialog(appCompatActivity, appCompatActivity.getString(R.string.error_activity_not_found));
}
}
public static void shareOnWhatsapp(AppCompatActivity appCompatActivity, String textBody, Uri fileUri){...}
private static void showWarningDialog(Context context, String message) {
new AlertDialog.Builder(context)
.setMessage(message)
.setNegativeButton(context.getString(R.string.close), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setCancelable(true)
.create().show();
}
}
Для получения Uri из File используйте следующий класс:
public class UtilityFile {
public static @Nullable Uri getUriFromFile(Context context, @Nullable File file) {
if (file == null)
return null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
try {
return FileProvider.getUriForFile(context, "com.my.package.fileprovider", file);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} else {
return Uri.fromFile(file);
}
}
// Returns the URI path to the Bitmap displayed in specified ImageView
public static Uri getLocalBitmapUri(Context context, ImageView imageView) {
Drawable drawable = imageView.getDrawable();
Bitmap bmp = null;
if (drawable instanceof BitmapDrawable) {
bmp = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
} else {
return null;
}
// Store image to default external storage directory
Uri bmpUri = null;
try {
// Use methods on Context to access package-specific directories on external storage.
// This way, you don't need to request external read/write permission.
File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");
FileOutputStream out = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 90, out);
out.close();
bmpUri = getUriFromFile(context, file);
} catch (IOException e) {
e.printStackTrace();
}
return bmpUri;
}
}
Для написания FileProvider используйте эту ссылку: https://github.com/codepath/android_guides/wiki/Sharing-Content-with-Intents
В Lollipop (21) вы можете использовать Intent.EXTRA_REPLACEMENT_EXTRAS
переопределить намерение специально для Facebook (и указать только ссылку)
https://developer.android.com/reference/android/content/Intent.html
private void doShareLink(String text, String link) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
Intent chooserIntent = Intent.createChooser(shareIntent, getString(R.string.share_via));
// for 21+, we can use EXTRA_REPLACEMENT_EXTRAS to support the specific case of Facebook
// (only supports a link)
// >=21: facebook=link, other=text+link
// <=20: all=link
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
shareIntent.putExtra(Intent.EXTRA_TEXT, text + " " + link);
Bundle facebookBundle = new Bundle();
facebookBundle.putString(Intent.EXTRA_TEXT, link);
Bundle replacement = new Bundle();
replacement.putBundle("com.facebook.katana", facebookBundle);
chooserIntent.putExtra(Intent.EXTRA_REPLACEMENT_EXTRAS, replacement);
} else {
shareIntent.putExtra(Intent.EXTRA_TEXT, link);
}
chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(chooserIntent);
}
Вот что я сделал (для текста). В коде я копирую любой необходимый текст в буфер обмена. В первый раз, когда человек пытается использовать кнопку "Поделиться намерением", я выскакиваю уведомление, в котором объясняется, что если он хочет поделиться с Facebook, ему нужно нажать "Facebook", а затем нажать и удерживать, чтобы вставить (это означает, что он знает, что Facebook сломал систему намерений Android). Тогда соответствующая информация находится в поле. Я мог бы также включить ссылку на этот пост, чтобы пользователи тоже могли пожаловаться...
private void setClipboardText(String text) { // TODO
int sdk = android.os.Build.VERSION.SDK_INT;
if(sdk < android.os.Build.VERSION_CODES.HONEYCOMB) {
android.text.ClipboardManager clipboard = (android.text.ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setText(text);
} else {
android.content.ClipboardManager clipboard = (android.content.ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
android.content.ClipData clip = android.content.ClipData.newPlainText("text label",text);
clipboard.setPrimaryClip(clip);
}
}
Ниже приведен метод работы с предыдущими версиями.
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_share:
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "text here");
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); //TODO
ClipData clip = ClipData.newPlainText("label", "text here");
clipboard.setPrimaryClip(clip);
setShareIntent(shareIntent);
break;
}
return super.onOptionsItemSelected(item);
}
Кажется, в версии 4.0.0 Facebook так много всего изменилось. Это мой код, который работает нормально. Надеюсь, это поможет вам.
/**
* Facebook does not support sharing content without using their SDK however
* it is possible to share URL
*
* @param content
* @param url
*/
private void shareOnFacebook(String content, String url)
{
try
{
// TODO: This part does not work properly based on my test
Intent fbIntent = new Intent(Intent.ACTION_SEND);
fbIntent.setType("text/plain");
fbIntent.putExtra(Intent.EXTRA_TEXT, content);
fbIntent.putExtra(Intent.EXTRA_STREAM, url);
fbIntent.addCategory(Intent.CATEGORY_LAUNCHER);
fbIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
fbIntent.setComponent(new ComponentName("com.facebook.katana",
"com.facebook.composer.shareintent.ImplicitShareIntentHandler"));
startActivity(fbIntent);
return;
}
catch (Exception e)
{
// User doesn't have Facebook app installed. Try sharing through browser.
}
// If we failed (not native FB app installed), try share through SEND
String sharerUrl = "https://www.facebook.com/sharer/sharer.php?u=" + url;
SupportUtils.doShowUri(this.getActivity(), sharerUrl);
}
Это решение работает также. Если Facebook не установлен, он просто запускает обычный share-диалог. Если есть, и вы не вошли в систему, он переходит к экрану входа в систему. Если вы вошли в систему, он откроет диалоговое окно "Поделиться" и вставит "URL общего ресурса" из Intent Extra.
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, "Share url");
intent.setType("text/plain");
List<ResolveInfo> matches = getMainFragmentActivity().getPackageManager().queryIntentActivities(intent, 0);
for (ResolveInfo info : matches) {
if (info.activityInfo.packageName.toLowerCase().contains("facebook")) {
intent.setPackage(info.activityInfo.packageName);
}
}
startActivity(intent);
Самый простой способ, которым я мог найти способ передать сообщение из моего приложения в Facebook, - это программно скопировать его в буфер обмена и предупредить пользователя, что у него есть возможность вставить. Это избавляет пользователя от необходимости делать это вручную; мое приложение не вставляет, но пользователь может.
...
if (app.equals("facebook")) {
// overcome fb 'putExtra' constraint;
// copy message to clipboard for user to paste into fb.
ClipboardManager cb = (ClipboardManager)
getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("post", msg);
cb.setPrimaryClip(clip);
// tell the to PASTE POST with option to stop showing this dialogue
showDialog(this, getString(R.string.facebook_post));
}
startActivity(appIntent);
...
Facebook не позволяет обмениваться текстовыми данными с Intent.EXTRA_TEXT
но вы можете поделиться текстом + ссылкой с Facebook Messenger, используя это, это прекрасно работает для меня
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, text+url link);
sendIntent.setType("text/plain");
sendIntent.setPackage("com.facebook.orca");
startActivity(sendIntent);
Вот то, что я сделал, открыв приложение Facebook со ссылкой
shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setComponent(new ComponentName("com.facebook.katana",
"com.facebook.katana.activity.composer.ImplicitShareIntentHandler"));
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, videoUrl);
public void invokeShare(Activity activity, String quote, String credit) {
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, activity.getString(R.string.share_subject));
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, "Example text");
shareIntent.putExtra("com.facebook.platform.extra.APPLICATION_ID", activity.getString(R.string.app_id));
activity.startActivity(Intent.createChooser(shareIntent, activity.getString(R.string.share_title)));
}