系統提供的分享實現代碼如下:
Intent send = new Intent(Intent.ACTION_SEND);
send.setType("text/plain");
send.putExtra(Intent.EXTRA_TEXT, url);
send.putExtra(Intent.EXTRA_SUBJECT, title);
c.startActivity(Intent.createChooser(send, "share title"));
我們先扒一扒源碼這個是怎麼實現分享
public static Intent createChooser(Intent target, CharSequence title) {
Intent intent = new Intent(ACTION_CHOOSER);
intent.putExtra(EXTRA_INTENT, target);
if (title != null) {
intent.putExtra(EXTRA_TITLE, title);
}
return intent;
}
- Intent.ACTION_SEND很好理解,一個隱式intent的action,在這裏調用會打開對應的暴漏出該action的app對應頁面(可以自己寫個app,然後暴漏該action 也會出現在分享列表中)
- 剩下就是通過intent把分享參數title text add進去
重點扒一扒Intent.createChooser
- createChooser()方法new Intent(ACTION_CHOOSER),返回的是一個Intent對象,彈出的選擇框是一個Activity,在源碼中搜索一下Action爲com.android.internal.app.ChooserActivity的Activity
/android/frameworks/base/core/res/AndroidManifest.xml
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.Holo.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:multiprocess="true">
<intent-filter>
<action android:name="android.intent.action.CHOOSER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
- ChooserActivity調用了其父類ResolverActivity的OnCreate(),ResolverActivity相當於一個Activity的選擇器,ChooserActivity在onCreate()方法裏先獲取傳遞進來的Intent對象,取得其中攜帶的目標Intent。如果只有一個Activity適配,將直接啓動。 ResolverActivity(queryIntentActivities)就是這個選擇對話框的Activity,這裏獲得適配Activity的icon和title等信息顯示到對話框。如果沒有調用createChooser()方法,如果有多個Activity適配一個intent的話也會打開一個選擇對話框,不過這個對話框多了兩個選項.
總結:這下大家應該清楚了,原來在調用createChooser()方法時候,系統又創建了一個新的Action爲ACTION_CHOOSER的Intent ,並把我們的原始Intent當成了參數傳進去 。選擇器的title是通過 EXTRA_TITLE傳入進去的。
Custom choose intent
產品或者我們自己這個分享列表提出自己的要求,比如是否可以監聽這個列表點擊自定義跳轉、把facebook whatsapp這兩個app放在第一個、或者某個app不要出現在分享列表中 等這些需求該如何實現;
-
監聽這個列表點擊自定義跳轉操作 答案是 NO,彈框是系統的ChooserActivity,並不存在暴漏出列表item點擊的監聽回調,而且從隱式intent設計來講,列表中的app都是與其暴漏出的intent對應匹配上的,它的初衷就是匹配上來就跳轉。參考回答 想實現監聽跳轉只能自定義分享列表list adapter填充列表數據 跳轉等,我們上個版本就是這樣實現的。核心代碼是獲取能分享的列表數據
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
PackageManager pm = App.getInstance().getPackageManager();
List<List<ResolveInfo>> listArrayList = new ArrayList<>();
List<ResolveInfo> activityList = pm.queryIntentActivities(sharingIntent, 0);
List<ResolveInfo> newActivityList = new ArrayList<>();
for (Iterator<ResolveInfo> it = activityList.iterator(); it.hasNext(); ) {
ResolveInfo info = it.next();
//過濾出facebook google+ whatapp 分享app單獨處理
if (info.activityInfo.packageName.equals("com.facebook.katana") || info.activityInfo.packageName.equals("com.google.android.apps.plus") || info.activityInfo.packageName.equals("com.facebook.orca") || info.activityInfo.packageName.contains("whatsapp")) {
it.remove();
newActivityList.add(info);
}
}
從上面的核心代碼看既然能實現分享列表數據的過濾,那麼排序和刪除數據都可以簡單實現。但也必須是自己自定義分享彈框列表實現。上個版本就是這麼做的
放google+分享列表實現(先談一個BottomSheetDialog展示特異強調的分享app和一個other按鈕,點other再進入系統的分享列表) 1.難點是用過濾的分享數據實現系統的分享。之前系統的分享數據是在ChooserActivity中自己匹配的。可喜的找到了Intent中EXTRA_INITIAL_INTENTS參數。具體看代碼源碼
List<Intent> targetIntents = new ArrayList<Intent>();
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
for (ResolveInfo candidate : packages) {
String packageName = candidate.activityInfo.packageName;
Intent target = new Intent(android.content.Intent.ACTION_SEND);
target.setType("text/plain");
if (uri != null) {
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
}
target.putExtra(Intent.EXTRA_TEXT, shareText);
target.setComponent(new ComponentName(packageName, candidate.activityInfo.name));
targetIntents.add(target);
}
Intent chooserIntent = Intent.createChooser(targetIntents.remove(0), title);
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{}));
context.startActivity(chooserIntent);
最終展現給用戶的選擇包括,符合createChooser第一個參數的應用(其實是指定了packageName和className的Intent),以及由EXTRA_INITIAL_INTENTS指定的應用
疑問
2.過濾數據處理後的系統分享彈框,與原聲系統分享彈框少了下面兩個按鈕,也少了上面最佳常用app的列表