Android和Facebook共享意图

89

我正在开发一个Android应用,想知道如何使用Android的共享意图从应用内更新应用用户的状态。

查看了Facebook的SDK后,似乎很容易做到这一点,但我希望允许用户通过常规的共享意图弹出窗口来执行此操作?如下所示:

pop up

我已尝试了通常的共享意图代码,但似乎无法再针对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 bug)暂时看来,我只能忍受负面的“分享不起作用!”评论。谢谢Facebook :*(


1
已经有一年多了,一直存在问题,经过多次修订,我不明白为什么他们不修复它!! - Nathan Schwermann
4
还是坏的。我开始觉得他们故意不修复它,以便让你使用他们愚蠢的Facebook SDK。 - UncleIstvan
5
哎呀,看起来Facebook现在正式回应称他们不认为这种行为有问题,并且不会改变它:https://developers.facebook.com/bugs/332619626816423 - Scott W
1
那么没有任何解决方法或变通之类的吗?我们必须接受空消息吗? :/ - User
1
不幸的是,唯一的解决方法或变通方法就是将他们的 SDK 集成到您的应用程序中。 - Joseph Woodward
显示剩余3条评论
12个回答

117

显然,Facebook不再允许您自定义共享屏幕(截至2014年),无论您是只打开sharer.php URL还是以更专业的方式使用Android意图。例如,参见以下答案:

无论如何,如billynomates评论所述,使用普通意图,您仍然可以共享URL,但不能与之一起共享任何默认文本。(此外,如果您没有要共享的URL,只需启动带有空“编写帖子”(即状态更新)对话框的Facebook应用程序同样容易;使用下面的代码,但省略EXTRA_TEXT。)

这是我找到的最佳解决方案,不涉及使用任何Facebook SDK。

如果官方Facebook应用已安装,则此代码会直接打开它;否则会回退到在浏览器中打开sharer.php。(在本问题中,大多数其他解决方案都会弹出一个巨大的“完整操作使用…”对话框,这并不是最佳选择!)

String urlToShare = "https://dev59.com/xmsz5IYBdhLWcg3w9ssQ";
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应用程序,结果看起来像这样:

enter image description here


3
"com.facebook.katana" 是 Facebook 应用程序的包名,"com.facebook.orca" 则是 FB Messenger 应用程序的包名。您可以更改为所需的正确包名。如果您没有指定一个,将使用找到的第一个(不好)。 - MatheusJardimB
1
好的,谢谢提醒!我已经更新了答案。事实证明,Facebook还发布了其他应用程序(HomePages Manager),它们也符合com.facebook前缀。 - Jonik
你好...如果我想要填充帖子编辑文本框,那么如何与Facebook协作? - Das
如何将文本与URL一起设置? - Anand Savjani
你不能(如粗体所述,在非常开头附近)。请仅阅读答案。 - Jonik
显示剩余3条评论

98

Facebook应用程序无法处理EXTRA_SUBJECTEXTRA_TEXT字段。

以下是错误链接:https://developers.facebook.com/bugs/332619626816423

感谢@billynomates:

问题在于,如果您将URL放入EXTRA_TEXT字段中,它会起作用。就像他们有意剥离任何文本一样。


31
问题是,如果您将URL放到EXTRA_TEXT字段中,它确实起作用。就好像它们有意地剥夺了任何文本一样。 - MSpeed
1
在撰写本文时,这仍然可以在iOS上运行,但在Android上无法运行,这真的很愚蠢。 - Peter K.
2
用户必须手动输入内容:“请注意,预先填充消息参数与建议内容,用户可以编辑,这也是一种政策违规行为。” - kouretinho
1
@PeterK,你找到在Facebook上发送文本的方法了吗? - Karan Khurana
https://rogerkeays.com/how-to-remove-the-facebook-android-sharing-intent - Slamit
显示剩余2条评论

17

常规方法

创建你所需的内容,通常的做法是简单地执行以下步骤:

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

对我来说,这个方法可以无问题地运行。

另一种可能的方法

这样做的潜在问题是,你也允许消息通过电子邮件、短信等方式发送。以下代码是我在一个应用程序中使用的代码,它允许用户使用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 字段中的文本。 - Joseph Woodward
1
实际上,我刚刚检查了一下,是的 - 它坏了。以前可以工作。 - Michell Bak
@MichellBak 我想分享一些文本,但是我想为Gmail/电子邮件分享长正文文本,而为其他所有内容分享短文本。我该怎么做? Gmail/电子邮件是否接受任何额外的正文字段? 有人知道吗?请帮忙。 - Maulik Vora
@MaulikVora 我认为你做不到,因为这需要你知道用户从意图对话框中选择了什么。 - Michell Bak
4
嗯,Facebook应该整顿一下了。但是如果包括URL,它确实有效。感谢您的投票负数;-) - Michell Bak
显示剩余2条评论

5

我发现使用Intents只能分享文本图片,无法同时分享两者。以下代码只分享存在的图片,如果不存在则只分享文本。如果想要分享两者,需要使用这里的Facebook SDK。

如果您使用的是除下面代码以外的其他解决方案,请不要忘记指定包名com.facebook.lite,它是Facebook Lite的包名。我没有测试过,但如果您还想针对Facebook Messenger,则com.facebook.orca是其包名。

您可以添加更多方法与WhatsAppTwitter等分享。

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
在安卓5.0(Lollipop)系统中,您可以使用 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);
}

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

2

似乎在Facebook的4.0.0版本中有很多变化。这是我的代码,它运行良好。希望能对你有所帮助。

    /**
     * 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 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 不允许使用 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);

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

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