1. 程式人生 > >Android-系統分享使用小結

Android-系統分享使用小結

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