Android-系统分享使用小结

概述

说到分享,有很多第三方的SDK可供使用,比如友盟,mob都很好用。虽然集成相对容易,但是需要针对每个平台申请APPID 。所以在对应用分享需求不是很强烈,对分享界面要求不大的时候使用系统自带的分享功能足以满足需求,当然如果要保证各个手机上的界面统一,那么第三方的SDK是最好的选择。下面就记录一下自己在实现系统分享时所遇到的问题,和实现步骤。

如何进行分享

系统分享通过调用Intent.createChooser方法构建一个分享界面,核心代码如下:

        Intent intent = new Intent(Intent.ACTION_SEND);//设置分享行为
        intent.setType("*/*");//设置分享内容的类型mime
        /**
          * 添加分享内容
          * 注意:单个文件ACTION_SEND调用{@link Intent#putExtra}方法,
          * 多个ACTION_SEND_MULTIPLE调用{@link Intent#putParcelableArrayListExtra}法
          */
        //intent.putExtra(Intent.EXTRA_SUBJECT, contentTitle);//添加分享内容标题
        //intent.putExtra(Intent.EXTRA_TEXT, content);//添加分享内容
        intent.putExtra(Intent.EXTRA_STREAM,data);//传递分享数据
        //创建分享界面
        intent = Intent.createChooser(intent , title);//title为分享界面的标题
        activity.startActivity(intent);

说明:

  1. 第一行设置分享行为,单个图片文件为Intent.ACTION_SEND,多个为Intent.ACTION_SEND_MULTIPLE
  2. 第二行设置分享类型,其中mime类型介绍详见 android之MIME
  3. 上述代码中的data为uri类型,传递图片时注意对路径进行转化
    上述代码运行结果大致如下图:
    显示支持当前分享的第三方APP

如何筛选分享项

第一步做完了,那如何过滤掉不需要的分享渠道呢?下面给出一个分享图片的例子(只留下微信分享渠道),部分代码参考了自导自演的机器人,感谢

    /**
     * 分享图片(触发场景单个)
     * @param context 上下文
     */
    public void shareSingleImage(Context context) {
        Intent intent = new Intent(Intent.ACTION_SEND);
        //获取选中图片
        Uri imageUri = Uri.parse("file://"+imagepath.toString());
        // Log.d("resolveInfos","imageUri--->" + imageUri);
        intent.setType("image/*");//设置mime格式为图片
        //查询所有可以分享的activity
        //进行筛选
        List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        List<Intent> targetShareIntents = new ArrayList<>();
        if (!resolveInfos.isEmpty()){
           //过滤选择非邮件应用
          for (ResolveInfo resolveInfo : resolveInfos){
                Intent target = new Intent(Intent.ACTION_SEND);//设置分享行为 单个文件、图片
               /**
                 * 添加分享内容
                 * 注意:单个文件ACTION_SEND调用{@link Intent#putExtra}方法,
                 * 多个ACTION_SEND_MULTIPLE调用{@link Intent#putParcelableArrayListExtra}方法
                 */
                target.putExtra(Intent.EXTRA_STREAM,imageUri);
                target.setType("image/*");//设置分享内容mime类型
                ActivityInfo activityInfo = resolveInfo.activityInfo;
                PackageManager pm = ((Activity)context).getApplication().getPackageManager();
                //打印所有符合条件的APP
                Log.d("resolveInfos","packageName--->" + activityInfo.packageName + "  name--->" + activityInfo.name+" label--->"+activityInfo.applicationInfo.loadLabel(pm).toString()+" activity label--->"+activityInfo.loadLabel(pm).toString()+" intent-filter label--->"+resolveInfo.loadLabel(pm).toString());
               /**
                 * 获取activityinfo类中的基本信息 如 包名 activity名称,应用label activity label等
                 *  {@link activityInfo.packageName}                     应用包名,对应{@link applicationId 属性}
                 *  {@link activityInfo.name}                            activity名称,对应{@link <activity>}中的{@linkplain android:name 属性}
                 *  {@link activityInfo.applicationInfo.loadLabel(pm)};  应用名称,对应{@link <application>}中的{@linkplain android:label 属性}
                 *  {@link activityInfo.loadLabel(pm)};                  activity名称(未设置默认为应用名称),对应{@link <activity>}中的{@linkplain android.label属性}
                 *  {@link resolveInfo.loadLabel(pm)};                   intent名称(未设置默认为前两个中优先级高的),对应{@link <intent-filter>}中的{@linkplain android:label属性}
                 */
                //微信
                if (activityInfo.packageName.contains(ShareVariables.WECHAT)){
                        target.setPackage(activityInfo.packageName);
                        target.setClassName(activityInfo.packageName, activityInfo.name);
                    /**
                     * 由于直接传递intent 会导致微信QQ等部分(为intent-filter设置标签)的APP标签,在分享途径中丢失
                     * (很多应用是为activity设置label,并没有为intent-filter设置标签),
                     * 所以需要为传递intent的添加筛选出的标签。
                     */
                        targetShareIntents.add(target);
                }
           }
        Intent chooseIntent = Intent.createChooser(targetIntents.remove(0),null);
        if (chooseIntent == null) {
            return;
        }
        chooseIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,targetIntents.toArray(new Parcelable[]{}));
        //startActivityForResult(Intent.createChooser(intent, "选择应用"), 1001);;

        try {
            context.startActivity(chooseIntent);
        } catch (android.content.ActivityNotFoundException ex) {

            Toast.makeText(context, "找不到该分享应用组件", Toast.LENGTH_SHORT).show();
        }
        }
        
    }

运行结果如下图所示
筛选微信后的显示
我们会发现满足了我们的要求,但是如何区分微信应用下的微信收藏,微信朋友,朋友圈呢?还有为什么之前显示的“发送给朋友”等不同字样都变成了微信呢?下面先解决第一个问题

如何区分部分APP下不同分享界面(以微信为例)

自导自演的机器人文章中通过标签解决了这个问题。因为每个activity都有自己的标签。但是这样指定在不同语言下会很麻烦。

下面给出自己的解决方法,首先贴一下之前代码打印出的log信息(部分)
log信息
我们可以通过activityInfo.name属性来区分不同的界面

如何还原过滤前APP分享途径的描述

在上一步的截图中我们发现朋友圈,微信,微信收藏的描述都变成了微信,那么如何变成过滤之前的描述呢?下面先来说明一下出现该问题的原因:
1、当我们执行

target.setPackage(activityInfo.packageName);
target.setClassName(activityInfo.packageName, activityInfo.name);

时,会将AndroidManufest文件中的activity标签中的label属性设置为分享渠道下的文字描述。而label属性的优先级为 application <activity<intent-filter 优先级高的标签中未设置label属性会默认只用上一级标签中的label属性
再看一下log
在这里插入图片描述
这里我们可以看到,微信没有为activity设置标签,默认显示为application的标签值,所以出现了上图所示的情况

解决方案:
我们需要将符合筛选条件的intent 设置label值。于是上网查找相应方法,结果没有找到。于是自己去intent类中寻找结果。找了半天没有找到如何为intent添加标签。于是寻找开发文档。果然在文档中找到了答案。intent 有个直接子类LabeledIntent 可以为其设置标签。通过其构造方法LabeledIntent(Intent origIntent, String sourcePackage,
CharSequence nonLocalizedLabel, int icon)设置标签
代码如下:

    /**
    * 分享图片(触发场景单个)
    * @param context 上下文
    */
   public void shareSingleImage(Context context) {
       Intent intent = new Intent(Intent.ACTION_SEND);
       //获取选中图片
       Uri imageUri = Uri.parse("file://"+imagepath.toString());
       // Log.d("resolveInfos","imageUri--->" + imageUri);
       intent.setType("image/*");//设置mime格式为图片
       //查询所有可以分享的activity
       //进行筛选
       List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
       List<LabeledIntent> targetShareIntents = new ArrayList<>();
       if (!resolveInfos.isEmpty()){
          //过滤选择非邮件应用
         for (ResolveInfo resolveInfo : resolveInfos){
               Intent target = new Intent(Intent.ACTION_SEND);//设置分享行为 单个文件、图片
              /**
                * 添加分享内容
                * 注意:单个文件ACTION_SEND调用{@link Intent#putExtra}方法,
                * 多个ACTION_SEND_MULTIPLE调用{@link Intent#putParcelableArrayListExtra}方法
                */
               target.putExtra(Intent.EXTRA_STREAM,imageUri);
               target.setType("image/*");//设置分享内容mime类型
               ActivityInfo activityInfo = resolveInfo.activityInfo;
               PackageManager pm = ((Activity)context).getApplication().getPackageManager();
               //打印所有符合条件的APP
               Log.d("resolveInfos","packageName--->" + activityInfo.packageName + "  name--->" + activityInfo.name+" label--->"+activityInfo.applicationInfo.loadLabel(pm).toString()+" activity label--->"+activityInfo.loadLabel(pm).toString()+" intent-filter label--->"+resolveInfo.loadLabel(pm).toString());
              /**
                * 获取activityinfo类中的基本信息 如 包名 activity名称,应用label activity label等
                *  {@link activityInfo.packageName}                     应用包名,对应{@link applicationId 属性}
                *  {@link activityInfo.name}                            activity名称,对应{@link <activity>}中的{@linkplain android:name 属性}
                *  {@link activityInfo.applicationInfo.loadLabel(pm)};  应用名称,对应{@link <application>}中的{@linkplain android:label 属性}
                *  {@link activityInfo.loadLabel(pm)};                  activity名称(未设置默认为应用名称),对应{@link <activity>}中的{@linkplain android.label属性}
                *  {@link resolveInfo.loadLabel(pm)};                   intent名称(未设置默认为前两个中优先级高的),对应{@link <intent-filter>}中的{@linkplain android:label属性}
                */
               //微信
               if (activityInfo.packageName.contains(ShareVariables.WECHAT)){
                       target.setPackage(activityInfo.packageName);
                       target.setClassName(activityInfo.packageName, activityInfo.name);
                   /**
                    * 由于直接传递intent 会导致微信QQ等部分(为intent-filter设置标签)的APP标签,在分享途径中丢失
                    * (很多应用是为activity设置label,并没有为intent-filter设置标签),
                    * 所以需要为传递intent的添加筛选出的标签。
                    */
                       LabeledIntent targeted = new LabeledIntent(target,activityInfo.packageName,resolveInfo.loadLabel(pm),resolveInfo.icon);
                   targetShareIntents.add(targeted);
               }
          }
       Intent chooseIntent = Intent.createChooser(targetIntents.remove(0),null);
       if (chooseIntent == null) {
           return;
       }
       chooseIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,targetIntents.toArray(new Parcelable[]{}));
       //startActivityForResult(Intent.createChooser(intent, "选择应用"), 1001);;

       try {
           context.startActivity(chooseIntent);
       } catch (android.content.ActivityNotFoundException ex) {

           Toast.makeText(context, "找不到该分享应用组件", Toast.LENGTH_SHORT).show();
       }
       }
       
   }

结果如下图所示:
在这里插入图片描述

参考
[1]: https://www.jianshu.com/p/88f166dd43b7

猜你喜欢

转载自blog.csdn.net/fighting_2017/article/details/85230934