Android分享中,如何过滤指定的应用,并且对不同的分享方式发送不同的内容?

安卓系统本身可以很简便的实现分享功能,因为我们只需向startActivity传递一个ACTION_SEND的Intent,系统就为我们弹出一个应用程序列表,如果我们再指定intent为chooser的方式,那么这个列表就就会有个指定的标题,如下:

这就是分享界面。

其实凡是以隐式intent调用activity,如果能处理该intent的应用有多个的话,都会出现一个选择应用的对话框,这种对话框除了列出应用列表,还为你提供是永久选择,还是只是这次选择。比如我们发送了这样一个浏览网页的intent:

String url = "http://www.example.com";
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);

那么系统会为我们列出能接收这个intent的应用(一般浏览器都会实现,相当于一种约定),界面如下:

注意上面的对话框只是单纯列出了应用,而且比分享对话框还多了两个选择方式的按钮,所以仅仅这样还不符合分享功能的需求。

分享的需求有两点:

每次都列出所有应用;

不再提示只是一次选择还是永久选择;

为此,我们需要通过Intent来创建chooser:

Intent chooserIntent = Intent.createChooser(intent, "Select app to share");

intent的createChooser方法调用后,上面提到的两个不符合需求的问题就不存在了,其实这就是分享功能的本质,他只不过是利用了Intent的机制而已。

利用系统的api实现分享的代码如下:

Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TITLE, title);
        intent.putExtra(Intent.EXTRA_SUBJECT, subject);
        intent.putExtra(Intent.EXTRA_TEXT, content);
        Intent chooserIntent = Intent.createChooser(intent, "Select app to share");
        if (chooserIntent == null) {
            return;
        }
        try {
            startActivity(chooserIntent);
        } catch (android.content.ActivityNotFoundException ex) {
            Toast.makeText(this, "Can't find share component to share", Toast.LENGTH_SHORT).show();
        }

一般,通过上面的代码,提供的分享方式有各种应用:邮件,信息,蓝牙,微博,Twitter,二维码扫描器等。

  1. 但是,第一:我想过滤掉蓝牙,

  2. 其次:我想对邮件分享详细的内容,对信息和微博等分享较简短的内容,对二维码扫描器只分享URL。

解决的办法是得到所有能处理ACTION_SEND的应用程序包名,然后根据名字来过滤或者特殊处理。主要用到getPackageManager().queryIntentActivities方法。

String contentDetails = "";
        String contentBrief = "";
        String shareUrl = "";
        Intent it = new Intent(Intent.ACTION_SEND);
        it.setType("text/plain");
        List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(it, 0);
        if (!resInfo.isEmpty()) {
            List<Intent> targetedShareIntents = new ArrayList<Intent>();
            for (ResolveInfo info : resInfo) {
                Intent targeted = new Intent(Intent.ACTION_SEND);
                targeted.setType("text/plain");
                ActivityInfo activityInfo = info.activityInfo;
                // judgments : activityInfo.packageName, activityInfo.name, etc.
                if (activityInfo.packageName.contains("bluetooth") || activityInfo.name.contains("bluetooth")) {
                    continue;
                }
                if (activityInfo.packageName.contains("gm") || activityInfo.name.contains("mail")) {
                    targeted.putExtra(Intent.EXTRA_TEXT, contentDetails);
                } else if (activityInfo.packageName.contains("zxing")) {
                    targeted.putExtra(Intent.EXTRA_TEXT, shareUrl);
                } else {
                    targeted.putExtra(Intent.EXTRA_TEXT, contentBrief);
                }
                targeted.setPackage(activityInfo.packageName);
                targetedShareIntents.add(targeted);
            }
            Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(0), "Select app to share");
            if (chooserIntent == null) {
                return;
            }
            // A Parcelable\[\] of Intent or LabeledIntent objects as set with
            // putExtra(String, Parcelable\[\]) of additional activities to place
            // a the front of the list of choices, when shown to the user with a
            // ACTION_CHOOSER.
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable\[\] {}));
            try {
                startActivity(chooserIntent);
            } catch (android.content.ActivityNotFoundException ex) {
                Toast.makeText(this, "Can't find share component to share", Toast.LENGTH_SHORT).show();
            }
        }

如果我们想指定一个应用来分享,那么可以将上面的代码做些修改:

private void initShareIntent(String type) {
    boolean found = false;
    Intent share = new Intent(android.content.Intent.ACTION_SEND);
    share.setType("image/jpeg");
    // gets the list of intents that can be loaded.
    List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(share, 0);
    if (!resInfo.isEmpty()){
        for (ResolveInfo info : resInfo) {
            if (info.activityInfo.packageName.toLowerCase().contains(type) ||
                    info.activityInfo.name.toLowerCase().contains(type) ) {
                share.putExtra(Intent.EXTRA_SUBJECT,  "subject");
                share.putExtra(Intent.EXTRA_TEXT,     "your text");
                share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(myPath)) ); // Optional, just if you wanna share an image.
                share.setPackage(info.activityInfo.packageName);
                found = true;
                break;
            }
        }
        if (!found)
            return;
        startActivity(Intent.createChooser(share, "Select"));
    }
}

然后在需要分享的地方加上:

initShareIntent("twi");

其实这种方法的前提是你必须知道某个应用的包名大致是什么样,比如qq的微信和微博的包名其实没有qq

initShareIntent(``"qq"``);是没有用的,你可以先将他们打印出来看长什么样子,然后在调用。以下是我总结的一些常用应用包名:

case ID_QQWEIBO:
    initShareIntent("com.tencent.wblog");
    break;
case ID_WEIXIN:
    initShareIntent("com.tencent.mm");
    break;
case ID_EVERNOTE:
    initShareIntent("evernote");
    break;
case ID_SINAWEIBO:
    initShareIntent("com.sina.weibo");
    break;
case ID_RENREN:
    initShareIntent("renren");
    break;
case ID_QQ:
    initShareIntent("tencent.mobileqq");
    break;