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);
說明:
- 第一行設定分享行為,單個圖片檔案為Intent.ACTION_SEND,多個為Intent.ACTION_SEND_MULTIPLE
- 第二行設定分享型別,其中mime型別介紹詳見 android之MIME
- 上述程式碼中的data為uri型別,傳遞圖片時注意對路徑進行轉化
上述程式碼執行結果大致如下圖:
如何篩選分享項
第一步做完了,那如何過濾掉不需要的分享渠道呢?下面給出一個分享圖片的例子(只留下微信分享渠道),部分程式碼參考了自導自演的機器人,感謝
/**
* 分享圖片(觸發場景單個)
* @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資訊(部分)
我們可以通過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();
}
}
}
結果如下圖所示: