本文已独家授权 郭霖 ( guolin_blog) 公众号发布!

首先声明,标题里的快捷键不是指开发人员使用频率极高的Ctrl+C和Ctrl+V;也不是IDE里Ctrl+D、Ctrl+F等常用快捷键。这里的快捷键,其实想要表达的是Android应用生成桌面快捷方式的细则。

试想,现在有一Windows用户想进入D盘——my文件夹里面的子文件去找文件(因为藏了些晦涩资源所以层级较深)。那么更加便利省力的操作是:点击选中文件夹——右键:发送到——桌面快捷方式,即可帮我们将快捷方式生成到桌面。该用户下次想使用这个文件夹,直接点击桌面上的快捷方式即可。这样做的好处在于,用户可以快速定位到某一应用具体的功能、干净利落。

当然,谷歌Android团队也考虑了这一点,给我们设计了原生API,方便我们开发人员更加便利的(Ctrl+C、V)生成桌面快捷方式。这样做的好处我想有以下几点,首先,提高了用户留存率,试想一个APP通过某种媒介生成了2个icon,这样是很容易吸引人的,因为生成桌面快捷方式的icon以及点击事件都是代码可控的,比如你的快捷方式的icon是一个萝莉或者御姐;正太或是直男?毕竟图片总有人会喜欢的嘛。其次,快捷方式的点击事件是控制的,跳转的界面控制在开发者(产品)手中等等。

言归正传,既然是生成桌面快捷方式,那么肯定需要权限,必要的权限如下:

    <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" /><!-- 添加快捷方式 --><uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /><!-- 移除快捷方式 --><uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" /><!-- 查询快捷方式 --><uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />

接着,因为Android难以言表的碎片化和厂商定制,所以还需要加一些权限来增加健壮性,下面直接copy就行:

   <uses-permission android:name="com.android.launcher2.permission.READ_SETTINGS" /><uses-permission android:name="com.android.launcher2.permission.WRITE_SETTINGS" /><uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" /><uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" /><uses-permission android:name="org.adw.launcher.permission.READ_SETTINGS" /><uses-permission android:name="org.adw.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="com.htc.launcher.permission.READ_SETTINGS" /><uses-permission android:name="com.htc.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="com.qihoo360.launcher.permission.READ_SETTINGS" /><uses-permission android:name="com.qihoo360.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="com.lge.launcher.permission.READ_SETTINGS" /><uses-permission android:name="com.lge.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="net.qihoo.launcher.permission.READ_SETTINGS" /><uses-permission android:name="net.qihoo.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="org.adwfreak.launcher.permission.READ_SETTINGS" /><uses-permission android:name="org.adwfreak.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="org.adw.launcher_donut.permission.READ_SETTINGS" /><uses-permission android:name="org.adw.launcher_donut.permission.WRITE_SETTINGS" /><uses-permission android:name="com.huawei.launcher3.permission.READ_SETTINGS" /><uses-permission android:name="com.huawei.launcher3.permission.WRITE_SETTINGS" /><uses-permission android:name="com.fede.launcher.permission.READ_SETTINGS" /><uses-permission android:name="com.fede.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="com.sec.android.app.twlauncher.settings.READ_SETTINGS" /><uses-permission android:name="com.sec.android.app.twlauncher.settings.WRITE_SETTINGS" /><uses-permission android:name="com.anddoes.launcher.permission.READ_SETTINGS" /><uses-permission android:name="com.anddoes.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="com.tencent.qqlauncher.permission.READ_SETTINGS" /><uses-permission android:name="com.tencent.qqlauncher.permission.WRITE_SETTINGS" /><uses-permission android:name="com.huawei.launcher2.permission.READ_SETTINGS" /><uses-permission android:name="com.huawei.launcher2.permission.WRITE_SETTINGS" /><uses-permission android:name="com.android.mylauncher.permission.READ_SETTINGS" /><uses-permission android:name="com.android.mylauncher.permission.WRITE_SETTINGS" /><uses-permission android:name="com.ebproductions.android.launcher.permission.READ_SETTINGS" /><uses-permission android:name="com.ebproductions.android.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="com.oppo.launcher.permission.READ_SETTINGS" /><uses-permission android:name="com.oppo.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="com.huawei.android.launcher.permission.READ_SETTINGS" /><uses-permission android:name="com.huawei.android.launcher.permission.WRITE_SETTINGS" /><uses-permission android:name="telecom.mdesk.permission.READ_SETTINGS" /><uses-permission android:name="telecom.mdesk.permission.WRITE_SETTINGS" /><uses-permission android:name="dianxin.permission.ACCESS_LAUNCHER_DATA" />

好了,权限已经添加完毕,下面就可以上代码了,首先是创建桌面快捷方式:

    //创建桌面快捷方式private void createShortCut(){//创建Intent对象Intent shortcutIntent = new Intent();//设置点击快捷方式,进入指定的Activity//注意:因为是从Lanucher中启动,所以这里用到了ComponentName//其中new ComponentName这里的第二个参数,是Activity的全路径名,也就是包名类名要写全。shortcutIntent.setComponent(new ComponentName(this.getPackageName(), "这里是包名.类名"));//给Intent添加 对应的flagshortcutIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS|Intent.FLAG_ACTIVITY_NEW_TASK);Intent resultIntent = new Intent();// Intent.ShortcutIconResource.fromContext 这个就是设置快捷方式的图标resultIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,Intent.ShortcutIconResource.fromContext(this,R.drawable.yuanbao));//启动的IntentresultIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);//这里可以设置快捷方式的名称resultIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "快捷名称");//设置ActionresultIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");//发送广播、通知系统创建桌面快捷方式sendBroadcast(resultIntent);}

创建桌面快捷方式的代码,理论上就是上面这些,ComponentName这个类用的较少,简单理解ComponentName的作用是,可以启动其他应用的Activity、Service(前提是要知道包名),然后搭配Intent使用,完成跳转。关于ComponentName与Activity、Service的参考代码如下:

    ComponentName  componentName = new ComponentName(param1,param2);param1:Activity、Service 所在应用的包名//获取应用的包名可以通过 this.getPackageName(); this代表当前的Activityparam2:Activity、Service的包名+类名 //这里是全路径名:对应的就是 this.getPackageName()+"YourActivity"//this.getPackageName()+"YourService"//ComponentName结合Activity的写法如下:     ComponentName componentName = new ComponentName(this.getPackageName(), this.getPackageName()+"YourActivity");Intent intent =new Intent();intent.setComponent(componentName);startActivity(intent);//ComponentName结合Service的写法如下:  ComponentName componentName = new ComponentName(this.getPackageName(), this.getPackageName()+"YourService");Intent intent = new Intent();intent.setComponent(componentName);startService(intent);

另外,还需要在清单配置文件里面,对应的Activity和Service需要加上android:exported = "true",这个android:exported标签,是用来指示该服务是否能够被其他应用程序组件调用或跟它交互。设置成true,则能够被调用或交互;设置false,也就意味不能被其他组件交互。APP入口的Activity不声明默认就是android:exported="true"。关于ComponentName的说明就到此为止,还不是很好理解的可以自行谷歌百度。综上,还需要在清单文件配置一些代码,参考如下:

            <activityandroid:exported="true"android:excludeFromRecents="true"android:name=".TestCreatIconActivity"><intent-filter><action android:name="android.intent.action.MAIN" <action android:name="test.intent.action.SHORTCUT" /><category android:name="android.intent.category.LAUNCHER" /><!-- 必须加上这个。否则无法直接使用自定的action --><category android:name="android.intent.category.DEFAULT" /></intent-filter></activity><activityandroid:name=".MainActivity"android:exported="true"android:excludeFromRecents="true"><intent-filter><action android:name="android.intent.action.MAIN" /></intent-filter></activity>

这里的MainActivity,就是我点击快捷方式进入的Activity。可能你会说,我该如何传值给,快捷方式点进去的Activity?那么也是传统套路根据Intent来传值,也就是上面的shortcutIntent,参考代码如下:

                    //传参到指定界面,通过标识和具体数据执行shortcutIntent.putExtra("key1","xxx");shortcutIntent.putExtra("key2",true);shortcutIntent.putExtra("key3",233);...

好了,创建快捷方式的代码是通过sendBroadcast(resultIntent);来实现的,因此可以判断这是系统的广播。

删除桌面快捷方式
首先,用户可以直接在手机桌面拖拽快捷方式,进行删除
另外,上面的代码也实现了当删除APK以后,自动删除快捷方式(因为你跳转没有了目标,所以需要删除)由于代码删除快捷方式,网上的一些代码都有问题(又是令人无语的碎片化和厂商定制),所以这里不提供删除快捷方式的代码,理论上,上面2种手动删除实现即可。
值得注意的是,如果用户没有手动打开权限,也会创建失败,也需要提示用户手动对应用进行快捷方式权限授权设置。

Android 7.1系统快捷方式的变化:

从Android 7.1(API 25,也就是 minSdkVersion 25 )开始,新增了ShortcutManager,ShortcutManager,顾名思义,翻译过来就是快捷方式管理。
这个类可以对桌面久按应用图标弹出的快捷方式进行管理。

那么ShortcutManager的实现方式有2种:

第一种:XML注册
首先, 需要在res/xml目录下创建一个新的xml文件,根标签是shortcuts,参考代码如下:

<shortcuts xmlns:android="http://schemas.android.com/apk/res/android"><shortcutandroid:shortcutId="setting"android:enabled="true"android:icon="@drawable/yuanbao"android:shortcutShortLabel="@string/set_short_name"android:shortcutLongLabel="@string/set_long_name"android:shortcutDisabledMessage="@string/set_disable_msg"><intentandroid:action="android.intent.action.VIEW"android:targetPackage="com.share.shortcut"android:targetClass="com.share.shortcut.TargetActivity" /><categories android:name="android.shortcut.conversation"/></shortcut>
</shortcuts>

嗯,可以看到新增了很多标签,这些标签代表什么意思咧?首先是shortcut的外部标签:

shortcutId, 快捷方式的idenabled:表示这个shortcut是否可用,一般设置为true即可shortcutShortLabel:配置快捷方式的短名称, 如果长名称显示不下, 就显示短名称shortcutLongLabel: 配置快捷方式的长名称, launcher会优先选择长名称显示(优先级高于shortcutShortLabel)shortcutDisabledMessage:这个标签的意思是指:当我们点击一个不可用的shortcut时,给用户一个有效提示内部还有个intent标签:android:action,这里的action需要配置,否则会崩溃,默认写法是android.intent.action.VIEWtargetPackage:目标应用的包名,targetClass:点击快捷方式要跳转的目标类, 这里要注意的是android:action一定要配置, 否则会崩溃categories:这个标签谷歌团队仅提供了android.shortcut.conversation 这一种,所以直接复制即可

好了,现在通过XML已经写好了快捷方式,那现在该如何使用,让快捷方式生效?
那么,只需要在清单文件中启动Activity的里面,加入以下2行代码(也就是通过meta-data配置进去)即可看到效果:

        <activityandroid:launchMode="singleInstance"android:name=".MainActivity"android:excludeFromRecents="true"><intent-filter><action android:name="android.intent.action.MAIN" /><!--<action android:name="test.intent.action.SHORTCUT" />--><category android:name="android.intent.category.LAUNCHER" /><!-- 必须加上这个。否则无法直接使用自定的action --><category android:name="android.intent.category.DEFAULT" /></intent-filter>静态注册<meta-dataandroid:name="android.app.shortcuts"android:resource="@xml/shortcut"/></activity>

这里的meta-data就是配置了桌面快捷方式的一些信息。代码运行后,执行创建快捷方式的操作即可看到效果:

7.1系统效果图

说完了第一种XML注册在来说第二种注册:代码动态注册
首先,获取系统服务,固定写法:getSystemService(ShortcutManager.class);获取ShortcutManager类对象
接着,获取完ShortcutManager对象以后,通过setDynamicShortcuts( List<ShortcutInfo> )方法去设置Shortcut快捷方式具体的名字、icon以及逻辑。
既然,现在要通过ShortcutInfo去完成信息填充,那么我们就先看下ShortcutInfo的基本写法:

//获取系统服务得到ShortcutManager对象ShortcutManager  systemService = getSystemService(ShortcutManager.class);if (Build.VERSION.SDK_INT >= 25) {//设置Intent跳转逻辑Intent intent = new Intent(ShortCut7_0Activity.this, TargetActivity.class);intent.setAction(Intent.ACTION_VIEW);//设置IDShortcutInfo shortcutInfo = new ShortcutInfo.Builder(this, "onlyId")//设置短标题        .setShortLabel("雅蠛蝶")//设置长标题.setLongLabel("江山留胜迹")//设置icon.setIcon(Icon.createWithResource(this, R.drawable.yuanbao))//设置Intent.setIntent(intent).build();//这样就可以通过长按图标显示出快捷方式了systemService.setDynamicShortcuts(Arrays.asList(shortcutInfo));

以上代码就可以创建桌面快捷方式,通过ShortcutInfo的Builder写法可以动态的插入快捷方式的名称、icon、以及Intent逻辑。值得一提的是,ShortcutManager最大可以创建5个,但桌面上只能最多只能显示4个快捷方式,可能是谷歌团队基于何种情况的考虑进行的限制,这里就不做深入研究。另外,快捷方式的顺序排列是:前面添加的显示在下方,后面添加的显示在上面。

7.1系统多快捷方式效果图

另外,移除快捷方式可以调用如下API:
void removeDynamicShortcuts(@NonNull List shortcutIds);

Android 8.0系统快捷方式的变化:

可能是谷歌出新版本需要优化增加既有版本的一些功能从Android 8.0(API 26,也就是 minSdkVersion 26,也就是Android O )开始,对ShortcutManager这个类新增了更多的管理措施。
那么O系统主要的扩充说明有那些?我这里就简单说明下,

一:

APP可以使用requestPinShortcut(ShortcutInfo,IntentSender)将现有的快捷方式(静态或动态)或全新的快捷方式固定到支持的启动器。这俩参数的意思是:
ShortcutInfo对象 - 如果快捷方式已存在,则该对象仅包含快捷方式的ID。如果快捷方式不存在,新的ShortcutInfo对象必须包含新快捷方式的ID,意图和短标签。
PendingIntent对象 - 此意图表示如果快捷方式成功固定到设备的启动器,您的应用程序将收到回调。

分析:也就是说,谷歌要求新的快捷方式需要编写的严谨,然后该快捷方式是否固定到设备加了新的判断标准

二:

由于Android O中引入的后台执行限制,最好使用清单声明的接收器来接收回调。
另外,为了防止其他应用程序调用接收器,需要将属性赋值android:exported =“false”添加到接收者的清单条目中。

分析:针对O系统对于服务的严格限制,这是对快捷方式功能的扩充

三:

并不是所有的启动器都支持固定快捷方式!!!所以,如果要确定该APP是否支持国定快捷方式,可以使用isRequestPinShortcutSupported()这个方法的返回值。
根据返回值,可以决定隐藏App中允许,用户固定快捷方式的选项。该方法返回TRUE,则意味着,桌面支持requestPinShortcut;
但是用户也可能会更改,更改选项以后,再次启动APP返回值可能就会发生变化。另外,系统版本低于Android O,那么它支持使用旧的私有意图com.android.launcher.action.INSTALL_SHORTCUT。
requestPinShortcut这个方法请求创建固定的快捷方式。默认启动器将收到该请求,并要求用户批准。如果用户批准,将创建快捷方式,并且将发送resultIntent。但是,如果请求被用户拒绝,则不会向呼叫者发送任何响应。需要注意的是,只有具有前台活动或前台服务的应用程序才能调用此方法。否则,它将抛出IllegalStateException。

分析:也就是说,这种启动器的固定快捷方式能否成功很大程度跟用户的操作密切相关(这个可以跟产品吹一波了)。另外可以看到O系统对于服务的严格控制,严格控制后台服务需要使用前台服务的举措在于让应用更加安全(因此IntentService在新版本上要慎用。当然谷歌在开发者文档上针对后台服务这一问题也给了对应的解决办法),这也看到了谷歌技术团队对后续版本使用应用安全的决心。
综上:可以有以下代码

  @RequiresApi(api = Build.VERSION_CODES.O)public static void testShortCut(Context context) {ShortcutManager shortcutManager = (ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE);boolean requestPinShortcutSupported = shortcutManager.isRequestPinShortcutSupported();Log.i(TAG, "启动器是否支持固定快捷方式: "+requestPinShortcutSupported);if (requestPinShortcutSupported) {Intent shortcutInfoIntent = new Intent(context, TargetActivity.class);shortcutInfoIntent.setAction(Intent.ACTION_VIEW);ShortcutInfo info = new ShortcutInfo.Builder(context, "tzw").setIcon(Icon.createWithResource(context, R.drawable.yuanbao)).setShortLabel("O系统短").setLongLabel("O系统长").setIntent(shortcutInfoIntent).build();//当添加快捷方式的确认弹框弹出来时,将被回调CallBackReceiver里面的onReceive方法PendingIntent shortcutCallbackIntent = PendingIntent.getBroadcast(context, 0, new Intent(context, CallBackReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);shortcutManager.requestPinShortcut(info, shortcutCallbackIntent.getIntentSender());}}
 class CallBackReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Log.i(TAG, "onReceive: 固定快捷方式的回调");}}

下面是应用启动后,Android Studio自带8.0模拟器,首先创建快捷方式的逻辑顺序:

O系统启动器快捷方式

点击ADD...以后,我们的应用就显示这样了,可以看到快捷方式向卫星一样挂靠在应用icon上面:

允许之后

如果点击CANCEL,那么就没有创建,退出以后icon还是原样,当我们第二次打开应用,选择申请桌面快捷方式的时候,又会弹出上面的申请界面。

这篇博客花了一些时间,因为要考虑三种不同情况(如果想要看到三种情况的效果,需要手动更改 minSdkVersion版本号、以及对应版本的模拟器资源),当然也参考了一些作者的文章。源码里面有所有代码,如果写的不好或者有任何问题可以直接在评论区或者github指出。

文章用到的源码

如果这篇文章对你有帮助,希望各位看官留下宝贵的star,谢谢。

Ps:著作权归作者所有,转载请注明作者, 商业转载请联系作者获得授权,非商业转载请注明出处(开头或结尾请添加转载出处,添加原文url地址),文章请勿滥用,也希望大家尊重笔者的劳动成果。

Android开发之桌面快捷键使用细则(原创)相关推荐

  1. Android开发效率—Eclipse快捷键

    很多过去使用Visual Studio开发软件的网友可能不熟悉Java开发环境,今天Android开发网告诉大家一些提高Android开发效率的Eclipse快捷键,可以有效率的帮助我们管理代码和减少 ...

  2. Android 跳过开机界面 直接软件自启动 Android做自己的桌面 替代原生桌面 Android开发自己桌面

    1,关于lancher 要开发一个自己的桌面,作为程序员,觉得好多的应用都在偷偷的跑流量. 开发一个桌面程序,然后常驻系统服务,定时检查服务. 对系统的其他应用网络进行监控.把一些常用的功能集成进来. ...

  3. 【android开发】桌面小挂件( APP Widgets )

    APP小挂件指的是一个小型的应用View控件,他可以嵌入到其他应用程序中(比如说桌面),并接受定期的更新.你可以通过Widget Provider来自己发布一个.一个可以持有其他App小挂件的应用组件 ...

  4. 计算机学习入门、进阶、Android开发及其它

    注:根据自己粗浅的经验,给师弟师妹写了一篇文章,贴到此处. 一.计算机基础知识 一个典型的计算机专业本科学生掌握的主要有5方面,构成了计算机能力的基础. 一门静态语言 尤其以C++和Java为主.C语 ...

  5. android自动创建快捷方式,Android开发之生成桌面快捷方式细则(原创)

    本文已独家授权 郭霖 ( guolin_blog) 公众号发布! 申明,标题里的快捷方式不是指开发人员使用频率极高的Ctrl+C和Ctrl+V:也不是IDE里Ctrl+D.Ctrl+F等常用快捷键.这 ...

  6. Google Map和桌面组件 Android开发教程

    本文节选于机械工业出版社推出的<Android应用开发揭秘>一 书,作者为杨丰盛.本书内容全面,详细讲解了Android框架.Android组件.用户界面开发.游戏开发.数据存储.多媒体开 ...

  7. Android开发原创教程

    qianqianlianmeng Android开发原创教程 活动帖子: http://www.apkbus.com/android-17709-1-1.html 安卓巴士ID 参赛帖子名称 巴士评分 ...

  8. Android音乐App桌面图标制作以及启动页面开发(简易音乐 一)

    Android音乐App桌面图标制作以及启动页面开发( 简易音乐 一 ) 关于 效果 第一步 第二步 第一步 修改SplashAcitivity的布局页面 第二步 修改androidmanifest. ...

  9. Android开发-如何判断当前页面是否是桌面(Home)

    1Android桌面的简介: 在Android系统中,任何一个可见的界面都属于一个应用程序,桌面也是一个应用程序.例如,我们通常打开手机看到的第一个界面就属于桌面应用.Android系统会自带一个桌面 ...

  10. Android开发:Android Studio常用快捷键汇总(Mac电脑和Windows电脑快捷键的对比)

    用Mac电脑的时候,需要注意的就是键盘的一些按键和Windows电脑键盘按键的区别,同样的,使用Mac电脑进行Android开发,一些常用的快捷键会和Windows电脑的快捷键有所不同,本节就来分享一 ...

最新文章

  1. 状态和面向对象编程——1.定位步骤
  2. XHTML学习笔记 Part2:核心元素
  3. jQuery页面顶部下拉广告
  4. 如果把钱存入余额宝时,所有人都在受益,那么谁在亏损呢?
  5. 14.mac apche
  6. 英语发音规则---W字母
  7. 微软Whitehorse modeler的背后
  8. PDG转PDF注定会文件膨胀、质量下降吗?
  9. eact+redux仿微信聊天室和vue+web端聊天室
  10. 阿里云Landing Zone系列--2 资源目录之--多账号
  11. [BJDCTF2020]Mark loves cat详细解法与思路
  12. nand flash基础时序
  13. 国产麒麟系统PXE安装-传统bios(legacy)引导
  14. 程序员过中秋丨用代码制作一个祝福小网页(html+css)
  15. linux启动zabbix服务,zabbix监控Linux系统服务的流程
  16. 使用Jquery、HTML、CSS、JS实现下拉菜单列表
  17. 增量式pid分析 及 参数整定
  18. 9.Python之异常处理
  19. 关于数据冗余的一点思考
  20. 【Python实验】Numpy基础

热门文章

  1. List集合去除重复对象及equals()、hashCode()方法的作用
  2. mysql if / case / limit / join / 数据类型 、oracle decode 及其它sql对比
  3. 常用sql server 语句
  4. Python 基礎 - 變量
  5. 2019.01.01洛谷 P4725/P4726 多项式对数/指数函数(牛顿迭代)
  6. [题解]诸侯安置(dp+组合)
  7. eclipse环境下基于已构建struts2项目整合spring+hibernate
  8. SecureCRT连接Ubuntu,centos失败解决
  9. linux-du命令详解
  10. 关于查看网页源文件不显示源代码(打开的是桌面文件夹)的问题