Android и Facebook разделяют намерения

85

Я разрабатываю приложение для 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 ) А пока похоже, что мне просто придется смириться с негативом «Обмен не работает !!!» обзоры. Приветствую Facebook: * (

Джозеф Вудворд
источник
был сломан уже около года с несколькими исправлениями, я не понимаю, почему они не исправят это !!
Натан Шверманн,
4
Все еще сломан. Я начинаю думать, что они не исправляют это специально, чтобы заставить вас использовать их тупой facebook sdk.
UncleIstvan
5
Ух, похоже, что Facebook официально ответил, что не считает такое поведение нарушенным и не будет его менять: developers.facebook.com/bugs/332619626816423
Скотт В.
1
Так что, по крайней мере, никакого исправления или обходного пути? Мы должны жить с пустым посланием? : /
Ixx
1
К сожалению, единственное решение или обходной путь - интегрировать их SDK в ваше приложение.
Джозеф Вудворд,

Ответы:

97

Приложение Facebook не обрабатывает поля EXTRA_SUBJECTили EXTRA_TEXT.

Вот ссылка на ошибку: https://developers.facebook.com/bugs/332619626816423

Спасибо @billynomates:

Дело в том, что если вы поместите URL-адрес в EXTRA_TEXTполе, он действительно работает. Как будто они намеренно вырезают любой текст.

Гёксель Гюрен
источник
30
Дело в том, что если вы поместите URL-адрес в поле EXTRA_TEXT, он действительно работает. Это как если бы они намеренно вырезали любой текст.
MSpeed
1
Это действительно глупо, что это все еще работает на iOS (на момент написания), но не работает на Android.
Питер К.
На facebook можно публиковать только ссылки с намерением поделиться.
Миша Акопов
2
Пользователи должны вводить контент вручную: «обратите внимание, что предварительное заполнение параметра сообщения предлагаемым контентом, который пользователь может редактировать, также является нарушением политики» youtube.com/watch?v=tGz48L0m5nc
kouretinho
1
@PeterK. вы нашли способ отправить текст на facebook?
Karan Khurana
115

По-видимому, Facebook больше (по состоянию на 2014 год) не позволяет настраивать экран совместного использования, независимо от того, открываете ли вы URL-адрес sharer.php или используете намерения Android более специализированными способами. См., Например, эти ответы:

В любом случае, используя простые намерения, вы все равно можете поделиться с ним URL-адресом, но не текстом по умолчанию , как прокомментировали billynomates . (Кроме того, если у вас нет URL-адреса, которым можно поделиться, просто запустить приложение Facebook с пустым диалоговым окном «Написать сообщение» (т.е. обновление статуса) также легко; используйте приведенный ниже код, но оставьте его EXTRA_TEXT.)

Вот лучшее решение, которое я нашел, не требующее использования каких-либо SDK для Facebook.

Этот код открывает официальное приложение Facebook напрямую, если оно установлено, а в противном случае возвращается к открытию sharer.php в браузере. (Большинство других решений в этом вопросе вызывают огромный диалог «Завершить действие, используя…», что совсем не оптимально!)

String urlToShare = "/programming/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:

введите описание изображения здесь

Йоник
источник
3
com.facebook.katana - имя пакета для приложения Facebook, а com.facebook.orca - для приложения FB Messenger. Вы можете выбрать нужный пакет. Если вы не укажете один, будет использован первый найденный (не очень хорошо)
MatheusJardimB
1
Хороший улов, спасибо! Я обновил ответ. Оказывается, Facebook выпустил и другие приложения ( Home и Pages Manager ), которые также будут соответствовать com.facebookпрефиксу.
Jonik
helow ... если я хочу заполнить сообщение edittext, то как работать с facebook.
Das
как установить текст с URL-адресом?
Ананд Савджани
Вы не можете (как указано жирным шрифтом в самом начале). Пожалуйста, прочтите ответ.
Jonik
16

Обычный способ

Обычный способ создать то, о чем вы просите, - просто сделать следующее:

    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 и т. Д. Следующий код - это то, что я использую в приложении, которое позволяет пользователю отправлять мне электронные письма. -mail через 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();
    }
Мичелл Бак
источник
3
Спасибо за ваш ответ. Это то, что меня смущает, первый фрагмент кода, который вы опубликовали, отлично подходит для публикации в любом другом приложении с доступными намерениями общего доступа, однако с намерением Facebook он переводит пользователя на пустую страницу Facebook «Написать что-то», как если бы она не отправляла ( или возможно получение) текста в поле EXTRA_TEXT.
Джозеф Вудворд
Хм, с первым на моем планшете работает нормально. Попробуйте, как указано, без поля EXTRA_SUBJECT. Кажется, это имеет значение.
Мичелл Бак
1
Собственно, только что проверил и да - сломано. Раньше работал.
Мичелл Бак
Да, как упоминалось в моем отредактированном первом посте, похоже, что это ошибка в приложении Facebook, которая существует с апреля 2011 года (!). Тем не менее, спасибо, что нашли время ответить на мой вопрос.
Джозеф Вудворд,
4
@TomSusel Ага, Facebook надо разобраться. Однако это работает при включении URL-адреса. Спасибо за отрицательный голос ;-)
Michell Bak
5

Я обнаружил, что вы можете делиться только текстом или изображением , но не обоими 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 из файла используйте класс ниже:

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

Джемшит Искендеров
источник
4

Вот что я сделал (для текста). В коде я копирую любой текст в буфер обмена. В первый раз, когда человек пытается использовать кнопку с намерением поделиться, я всплываю с уведомлением, в котором объясняется, что если он хочет поделиться в 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

В Lollipop (21) вы можете использовать, Intent.EXTRA_REPLACEMENT_EXTRASчтобы переопределить намерение специально для Facebook (и указать только ссылку)

https://developer.android.com/reference/android/content/Intent.html#EXTRA_REPLACEMENT_EXTRAS

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);
}
Саймон Реджиани
источник
2

Кажется, в версии 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);
    }
Хесам
источник
1
что такое SupportUtils?
Silvia H
2

Это решение тоже работает. Если Facebook не установлен, он просто запускает обычный диалог обмена. Если есть, и вы не вошли в систему, он переходит на экран входа в систему. Если вы вошли в систему, он откроет диалоговое окно общего доступа и вставит «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);
Томми
источник
0

Вот что я сделал, открыв приложение 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);
Наянеш Гупте
источник
2
у меня не сработало. вероятно, Facebook изменил название ImplicitShareIntentHandler.
Хесам
0
    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)));
}
Зоран Николовски
источник
0

Facebook не позволяет обмениваться данными в виде обычного текста, Intent.EXTRA_TEXTно вы можете поделиться текстом + ссылкой с помощью этого мессенджера facebook, это отлично работает для меня

            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);
Киран Богра
источник
0

Самый простой способ передать сообщение из моего приложения в 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);
...
Нед
источник