以前玩手機的時候偶然發現了一個效果,長按應用圖標會顯示出幾個快捷方式(相似IOS系統的3D Touch功能),點擊後能夠直接進入相應的頁面,不須要點擊應用圖標來啓動應用,而且快捷方式能夠放到桌面上單獨顯示,就像下圖這樣:android
索性就來研究一下這個效果是如何實現的,經過查閱網絡上的資料,瞭解到該效果是經過Android 7.1(API level 25)版本的新特性***App Shortcuts***來實現的。納尼!Android 7.1版本就已經添加了,我居然如今才知道(o(╥﹏╥)o)。不過既然清楚了實現方式,下面就來具體研究一下這個App Shortcuts特性。git
App Shortcuts是Android 7.1的新特性,指長按app圖標出現的快捷方式,能夠爲app的關鍵功能添加更快捷的入口而無需打開app,點擊快捷方式能夠訪問相應的應用功能,,這種快捷方式也能夠被拖拽到桌面單獨放置,成爲單獨的桌面快捷方式。 每一個快捷方式都引用了一個或多個Intent,點擊快捷方式會啓動Intent所指定的的操做,能夠爲任何Intent的操做建立一個快捷方式。github
Shortcuts
的實現有三種形式:靜態快捷方式
、動態快捷方式
和固定快捷方式
,下面咱們就具體看一下這三種類型的快捷方式分別是如何實現的。數組
靜態快捷方式(Static shortcuts),是在資源文件中配置的快捷方式。建立靜態快捷方式有如下幾個步驟:bash
1)在資源文件res
下新建xml目錄,新建文件shortcuts.xml
,文件名不是固定的。微信
<?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android"> <shortcut android:icon="@drawable/ic_settings" android:shortcutId="setting" android:shortcutLongLabel="@string/shortcut_setting_long" android:shortcutShortLabel="@string/shortcut_setting_short"> <intent android:action="com.example.shortcutstest.SETTING" android:targetClass="com.example.shortcutstest.SettingActivity" android:targetPackage="com.example.shortcutstest" /> </shortcut> </shortcuts> 複製代碼
根節點shortcuts
下能夠添加一個或多個shortcut
標籤,每一個shortcut
表示一個快捷方式,內部配置了快捷方式的詳細信息,包括名稱、圖標以及要啓動的Intent等,shortcut
標籤經常使用的幾個屬性以下:markdown
android:shortcutId:快捷方式的id,須要保證是惟一的。不能將此屬性的值設置爲資源字符串,例如@string/foo
。網絡
android:shortcutLongLabel:快捷方式的長名稱,若是有足夠的空間,Launcher會優先顯示長名稱,若是可能,將長度限制爲25個字符。此屬性的值必須是資源字符串,例如@string/shortcut_long_label
。app
android:shortcutShortLabel:快捷方式的短名稱,長名稱顯示不下的狀況下才會顯示短名稱,若是可能,將長度限制爲10個字符。此屬性的值必須是資源字符串,例如 @string/shortcut_short_label
。ide
android:icon:快捷方式的圖標。
android:shortcutDisabledMessage:當用戶嘗試啓動已禁用的快捷方式時提示的信息,用於向用戶解釋爲何禁用該快捷方式。若是android:enabled="true"
,即快捷方式是啓用的,那麼此屬性的值無效。此屬性的值必須是資源字符串,例如@string/shortcut_disabled_message
。
android:enabled:是否啓用快捷方式,該值爲true
時,用戶點擊快捷方式能夠啓動指定的Intent操做;該值爲false
時,還須要指定android:shortcutDisabledMessage
,當用戶點擊快捷方式時會提示該信息。禁用的快捷方式不會顯示出來,所以若是要禁用快捷方式,通常仍是直接從xml文件中移除比較好。
上面的幾個屬性中,android:shortcutId
和android:shortcutShortLabel
是必需要配置的,不然快捷方式不會顯示,其餘幾個都是可選擇的。
還須要在shortcut
標籤內部配置Intent,指定點擊快捷方式時要執行的操做,和Activity的intent-filter
相似,intent
標籤有如下幾個屬性:
android:action:指定Intent要啓動的操做或任務,該屬性必需要指定,不然不會顯示快捷方式。
android:targetClass:要跳轉的目標類。
android:targetPackage:要跳轉的目標應用包名。
關於Intent的配置測試了一下,若是隻配置了action
,在目標Activity的intent-filter
中指定相同的action
(注意不要忘記指定category
爲android.intent.category.DEFAULT
),就像Activity的隱式跳轉那樣,點擊快捷方式是能夠啓動Activity的;若是intent-filter
中指定的action
不匹配或者沒有配置intent-filter
,點擊快捷方式會提示「未安裝該應用」,這時若是同時配置了targetClass
和targetPackage
(兩個都要配置,不然也會提示「未安裝該應用」),就能夠正常跳轉了。
一個快捷方式能夠配置多個Intent,點擊快捷方式後會顯示最後一個Intent指定的Activity,並將前幾個Intent指定的Activity加入到返回棧中。好比下面的配置,點擊快捷方式後,最後會顯示SettingActivity,點擊返回鍵會返回到MainActivity。
<intent android:action="android.intent.action.MAIN" android:targetClass="com.example.shortcutstest.MainActivity" android:targetPackage="com.example.shortcutstest" /> <intent android:action="com.example.shortcutstest.SETTING" android:targetClass="com.example.shortcutstest.SettingActivity" android:targetPackage="com.example.shortcutstest" /> 複製代碼
此外,shortcut
標籤下還能夠配置一個categories
標籤,爲應用程序快捷方式執行的操做類型提供分組,例如建立新的聊天消息,目前官方只提供了android.shortcut.conversation
。
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" /> </activity> </application> 複製代碼
須要注意,配置快捷方式的Activity必須知足action
是android.intent.action.MAIN
而且category
是android.intent.category.LAUNCHER
,即應用啓動頁面。 這樣就建立好了靜態快捷方式,最終實現的效果以下:
靜態快捷方式的配置雖然很簡單,但也是有數量限制的,最多隻能顯示4個,若是配置了超過4個,多餘的則不會顯示,應用並不會報錯。 動態快捷方式。
除了靜態快捷方式,系統還提供了更加靈活的方式來添加快捷方式,即動態快捷方式(Dynamic Shortcuts),能夠在應用運行過程當中添加快捷方式。官方提供了一個類ShortcutManager,能夠實現快捷方式的建立、更新和刪除等操做。
首先經過getSystemService(ShortcutManager.class)
得到ShortcutManager
對象。而後使用ShortcutInfo.Builder
來構建快捷方式,採用建造者模式配置快捷方式的信息,方法名都很清楚,和靜態快捷方式的配置對照着看就能夠,這裏就不具體說了。最後調用ShortcutManager
的setDynamicShortcuts()
方法來設置快捷方式。完整代碼以下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { ShortcutManager shortcutManager = getSystemService(ShortcutManager.class); Intent settingIntent = new Intent(this, SettingActivity.class); settingIntent.setAction("com.example.shortcutstest.SETTING"); ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(this, "setting") .setShortLabel("設置") .setLongLabel("設置") .setIcon(Icon.createWithResource(this, R.drawable.ic_settings)) .setIntent(settingIntent) .build(); shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutInfo)); } 複製代碼
若是須要配置多個Intent也是能夠的,在構建ShortcutInfo時調用setIntents()
方法就能夠了,參數傳入一個Intent數組。實現的效果和靜態快捷方式同樣,顯示最後一個Intent指定的Activity,並將前幾個Intent指定的Activity添加到返回棧中。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { ShortcutManager shortcutManager = getSystemService(ShortcutManager.class); Intent mainIntent = new Intent(this, MainActivity.class); mainIntent.setAction(Intent.ACTION_MAIN); Intent settingIntent = new Intent(this, SettingActivity.class); settingIntent.setAction("com.example.shortcutstest.SETTING"); ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(this, "setting") .setShortLabel("設置") .setLongLabel("設置") .setIcon(Icon.createWithResource(this, R.drawable.ic_settings)) .setIntents(new Intent[]{mainIntent, settingIntent}) .build(); shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutInfo)); } 複製代碼
動態快捷方式也是有數量限制的,調用ShortcutManager的getMaxShortcutCountPerActivity()
方法能夠獲取Shortcut的最大個數(靜態和動態總共),該方法返回值是5,也就是最多能夠添加5個快捷方式,可是實際上每一個Launcher最多隻能顯示4個快捷方式。針對快捷方式數量限制,我在本身的手機上測試了一下,狀況以下:
1.靜態快捷方式等於或超過5個,不配置動態快捷方式,應用不會報錯,最後只顯示4個快捷方式。 2.動態快捷方式配置5個,不配置靜態快捷方式,應用不會報錯,最後只顯示4個快捷方式。 3.動態快捷方式超過5個,不配置靜態快捷方式,應用拋出錯誤
Max number of dynamic shortcuts exceeded
。 4.靜態快捷方式+動態快捷方式等於5個,最後只顯示4個快捷方式。 5.靜態快捷方式+動態快捷方式超過5個,應用拋出錯誤Max number of dynamic shortcuts exceeded
。
由此能夠發現,靜態快捷方式和動態快捷方式最多能添加5個,可是實際上最多隻能顯示4個,所以咱們仍是應該控制快捷方式的數量不超過4個,不然可能會致使應用Crash。 對於快捷方式的顯示順序,最前面顯示的是靜態快捷方式,而後是動態快捷方式,對於同一類快捷方式,內部默認是按照添加的順序排列的,即先添加的快捷方式顯示在前面,後添加的顯示在後面。這裏所說的「前面」和「後面」是先相對於應用圖標而言的,越靠近應用圖標則順序越靠前(靠上仍是靠下與應用圖標在屏幕中的位置有關),反之則靠後,以下圖所示。
能夠經過ShortcutInfo的getRank()
方法得到快捷方式的順序,數值爲非負的連續整數,從0開始,值越小則順序越靠前。
// 得到全部的靜態快捷方式 List<ShortcutInfo> staticShortcutList = shortcutManager.getManifestShortcuts(); for (ShortcutInfo shortcutInfo : staticShortcutList) { Log.e("TAG", "靜態快捷方式" + shortcutInfo.getId() + "的順序爲:" + shortcutInfo.getRank()); } // 得到全部的動態快捷方式 List<ShortcutInfo> dynamicShortcutList = shortcutManager.getDynamicShortcuts(); for (ShortcutInfo shortcutInfo : dynamicShortcutList) { Log.e("TAG", "動態快捷方式" + shortcutInfo.getId() + "的順序爲:" + shortcutInfo.getRank()); } 複製代碼
在構建ShortcutInfo時能夠調用ShortcutInfo.Builder
的setRank()
方法來改變默認的順序。雖然ShortcutInfo自己也有setRank()
方法,可是該方法是@hide
的,所以只有動態快捷方式才能改變顯示順序。 此外,addDynamicShortcuts()
方法也能夠用於添加動態快捷方式,從字面意思上咱們也能知道它和setDynamicShortcuts()
的不一樣,一樣能夠添加快捷方式,setDynamicShortcuts()
會覆蓋原有的快捷方式,而addDynamicShortcuts()
是將快捷方式添加到原有的快捷方式列表中。
經過ShortcutManager的updateShortcuts(List<ShortcutInfo> shortcutInfoList)
方法能夠更新現有的快捷方式,構建ShortcutInfo時須要指定相同的id
,根據id
去找到要更新的快捷方式。須要注意只有動態快捷方式和後面要說的固定快捷方式才能更新,若是傳入了一個靜態快捷方式的id
,應用會拋出錯誤Manifest shortcut ID=XX may not be manipulated via APIs
。
ShortcutManager shortcutManager = getSystemService(ShortcutManager.class); Intent intent = new Intent(this, SettingActivity.class); intent.setAction("com.example.shortcutstest.SETTING"); ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(this, "setting") .setShortLabel("設置更新") .setLongLabel("設置更新") .setIcon(Icon.createWithResource(this, R.drawable.ic_settings)) .setIntent(intent) .build(); shortcutManager.updateShortcuts(Arrays.asList(shortcutInfo)); 複製代碼
經過ShortcutManager的removeDynamicShortcuts(List<String> shortcutIds)
方法能夠刪除動態快捷方式,參數傳入要刪除的快捷方式id列表。和更新同樣,若是傳入靜態快捷方式的id會報錯。
ShortcutManager shortcutManager = getSystemService(ShortcutManager.class); mShortcutManager.removeDynamicShortcuts(Arrays.asList("setting")); 複製代碼
此外,還有一個removeAllDynamicShortcuts()
方法,能夠用來刪除全部的動態快捷方式。
須要注意,若是在刪除以前將快捷方式固定到了桌面上(這種稱做固定快捷方式,後面還會提到),在刪除以後該快捷方式的圖標不會消失,點擊後依然能夠完成正常跳轉。這種固定在桌面上的快捷方式只能用戶手動來移除,所以更好的一種作法是在刪除快捷方式後判斷該快捷方式是否被固定到了桌面上,若是是的話就再禁用該快捷方式,並提示用戶該快捷方式已被刪除,禁用快捷方式的方法下面會提到。
// 得到全部的固定快捷方式 List<ShortcutInfo> pinnedShortcutList = shortcutManager.getPinnedShortcuts(); for (ShortcutInfo shortcutInfo : pinnedShortcutList) { if (shortcutInfo.getId().equals("setting")) { // 禁用被刪除的快捷方式 mShortcutManager.disableShortcuts(Arrays.asList("call"), "該快捷方式已被刪除"); } } 複製代碼
經過ShortcutManager
的disableShortcuts()
方法能夠禁用快捷方式,第一個參數傳入要禁用的快捷方式id列表,第二個參數是disabledMessage
,用於提示用戶禁用快捷方式的緣由,該參數也能夠不傳。一樣地,不能經過該方法禁用靜態快捷方式,禁用靜態快捷方式是經過在xml文件中配置來實現的。
ShortcutManager shortcutManager = getSystemService(ShortcutManager.class); shortcutManager.disableShortcuts(Arrays.asList("setting"), "該快捷方式已被禁用"); 複製代碼
禁用以後,長按應用圖標不會顯示該快捷方式,若是此前將快捷方式固定到了桌面上,禁用後圖標會變成灰色,點擊圖標會彈出提示信息,即上面傳入的第二個參數disabledMessage
,沒有傳的話就提示默認信息。
固定快捷方式(Pinned shortcuts)指的是在桌面上顯示爲一個圖標的快捷方式,下圖爲官方給出的示意圖。咱們已經知道了能夠經過拖拽來把建立好的靜態/動態快捷方式固定在桌面上,接下來介紹一下如何直接建立固定快捷方式。
在Android 8.0(API level 26)及更高版本上,系統支持直接建立固定快捷方式,建立的步驟以下:
一、經過ShortcutManager的isRequestPinShortcutSupported()
方法判斷是否支持固定快捷方式,返回true表示支持,false
表示不支持,該方法是Android 8.0纔有的,所以在調用前須要判斷一下。也可使用ShortcutManagerCompat.isRequestPinShortcutSupported(context)
方法,該方法兼容了Android 8.0如下版本。
二、建立一個ShortcutInfo對象,指定要固定的快捷方式,若是要固定的是已經建立好的快捷方式,那麼在構建ShortcutInfo時只須要傳id就能夠了,須要注意固定的快捷方式不能是已禁用的,不然應用會報錯;若是要固定一個新的快捷方式,就像建立動態快捷方式那樣構建一個ShortcutInfo就行了。
三、經過requestPinShortcut()
方法來固定快捷方式,該方法有兩個參數對象,第一個參數是咱們上面建立好的ShortcutInfo對象,第二個參數是一個IntentSender對象,能夠經過PendingIntent.getIntentSender()
來得到,當固定快捷方式成功後,會執行該Intent指定的操做,包括啓動Activity、發送廣播等,若是固定快捷方式成功後不須要作額外處理的話該參數傳null就能夠。
完整代碼以下:
ShortcutManager shortcutManager = getSystemService(ShortcutManager.class); if (shortcutManager.isRequestPinShortcutSupported()) { Intent intent = new Intent(this, SettingActivity.class); intent.setAction("com.example.shortcutstest.NAVIGATION"); ShortcutInfo pinShortcutInfo = new ShortcutInfo.Builder(this, "navigation") .setShortLabel("導航") .setLongLabel("導航") .setIcon(Icon.createWithResource(this, R.drawable.ic_navigation)) .setIntent(intent) .build(); // 註冊固定快捷方式成功廣播 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("com.example.shortcutstest.PINNED_BROADCAST"); PinnedReceiver receiver = new PinnedReceiver(); registerReceiver(receiver, intentFilter); Intent pinnedShortcutCallbackIntent = new Intent("com.example.shortcutstest.PINNED_BROADCAST"); PendingIntent successCallback = PendingIntent.getBroadcast(this, 0, pinnedShortcutCallbackIntent, 0); shortcutManager.requestPinShortcut(pinShortcutInfo, successCallback.getIntentSender()); 複製代碼
這裏註冊一個廣播接收器,當固定快捷方式成功時會發送廣播,咱們能夠在onReceive()
方法中添加一些邏輯。
public class PinnedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "固定快捷方式成功", Toast.LENGTH_SHORT).show(); } } 複製代碼
固定快捷方式會彈出一個提示對話框,用戶點擊確認後纔會將快捷方式添加到桌面,並執行requestPinShortcut()方法第二個參數指定的操做。
和靜態/動態快捷方式不一樣,固定快捷方式是沒有數量限制的。動態快捷方式的更新和禁用方法也能夠用在固定快捷方式中,可是固定快捷方式是沒法經過代碼動態刪除的,只能經過用戶的手動操做才能刪除,如下三種方式能夠刪除固定快捷方式:
長按圖標移除
進入應用設置頁面,選擇清除數據
卸載應用
本文主要介紹了Android 7.1版本的新特性——App shortcuts,即應用快捷方式,爲用戶提供了App經常使用功能的快捷入口,省去了打開App跳轉指定頁面的操做。快捷方式有三種形式:
1)靜態快捷方式:在xml文件中配置,應用安裝以後沒法進行更新、刪除和禁用,有數量限制。
2)動態快捷方式:在應用運行時經過代碼動態建立快捷方式,能夠動態更新、刪除和禁用,有數量限制。
3)固定快捷方式:以桌面圖標的形式顯示,能夠經過拖拽來把已建立好的靜態/動態快捷方式固定在桌面上。Android 8.0及以上版本支持直接建立固定快捷方式,須要用戶手動確認後纔會建立桌面圖標,能夠動態更新和禁用,刪除只能經過用戶手動操做,沒有數量限制。
最後說一下我本身的見解,雖然這個特性很是方便,可是它有一個很大的缺點就是不容易被發現,估計不少人可能還不知道這個功能,畢竟咱們只有在卸載應用時纔會長按應用圖標,並且如今使用了該特性的應用也不是不少,連微信這種主流App都沒有使用。做爲開發者咱們不光本身要了解這些特性,也應該讓更多的人瞭解到這樣的一些便捷特性。 本文的相關代碼我已經上傳到了github,你們若是有須要的話能夠參考一下。
Demo地址:github.com/StephenZKCu…