Android 桌面快捷方式实现实例详解

目录
  • Shortcuts API 简介
  • 静态快捷方式
    • 快捷方式配置
    • 在Manifest中添加快捷方式配置
  • 动态快捷方式
  • 桌面快捷方式
    • 运行时创建
    • 支持用户主动创建
  • 打开多个Activity
  • 更新快捷方式
    • 启用和禁用
    • 更新快捷方式的样式
  • 示例

Shortcuts API 简介

快捷方式在各类App中已经十分常见,快捷方式可以让用户直达想要使用的功能,例如快速打开扫一扫、快速打开健康码等。对此,Android提供了Shortcuts API,本文介绍如何使用Shortcuts API来实现快捷方式。

在Android中,快捷方式通常显示在App的启动器或支持的助理中(例如Google 助理)。每个快捷方式对应一个或者多个Intent,当用户选中某个快捷方式时,系统会启动对应的Intent

需要注意:

  • 只有包含<action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" />Activity(即启动页)可以拥有快捷方式。
  • 不同设备支持的快捷方式数量可能不同,通常每个启动器最多显示4个快捷方式,可以通过ShortcutManagerCompat.getMaxShortcutCountPerActivity(context)来获取设备支持的快捷方式数量。

Android 支持下列三种快捷方式:

  • 静态快捷方式:通过xml配置生成。
  • 动态快捷方式:在运行时通过代码配置生成、更新和移除。
  • 桌面快捷方式:在运行时通过代码配置生成、更新,需要用户同意后才能添加。

下面分别介绍这三种类型的快捷方式如何实现。

静态快捷方式

快捷方式配置

在res/xml目录下创建shortcuts.xml,如下图:

注意,此方式仅在Android N_MR1(25)以上可用。

文件内容如下:

<?xml version ="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:enabled="true"
        android:icon="@drawable/icon_biometrics"
        android:shortcutDisabledMessage="@string/shortcuts_disable_message"
        android:shortcutId="biometrics"
        android:shortcutLongLabel="@string/biometrics_shortcuts_long_label"
        android:shortcutShortLabel="@string/biometrics_shortcuts_short_label">
        <!--快捷方式跳转的页面,必须配置-->
        <intent
            android:action="android.intent.action.VIEW"
            android:targetClass="com.chenyihong.exampledemo.androidapi.biometrics.BiometricActivity"
            android:targetPackage="com.chenyihong.exampledemo" />
    </shortcut>
</shortcuts>

配置文件中,每个shortcut标签必须配置的值为android:shortcutIdandroid:shortcutShortLabel,其余为可选配置。

属性名 属性值
android:shortcutId id, 不能设置为字符串资源,必须配置
android:shortcutShortLabel 简述,建议限制在10个字符以内,字符串资源,必须配置
android:shortcutLongLabel 详细描述,显示空间足够大时会显示此值,建议限制在25个字符内,字符串资源,非必须
android:icon 图标,图片的路径或图片资源文件,非必须
android:enabled 是否可用,布尔值,非必须
android:shortcutDisabledMessage 用户点击不可用的快捷方式时的提示语,仅在enable为false时生效,字符串资源,非必须

在Manifest中添加快捷方式配置

AndroidManifest中启动页标签下添加meta-data,如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chenyihong.exampledemo">
    <application
        ....
        >
        <activity
            android:name=".home.HomeActivity"
            android:exported="true"
            android:screenOrientation="portrait">
            <meta-data
                android:name="android.app.shortcuts"
                android:resource="@xml/shortcuts" />
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>
    </application>
</manifest>

效果如图:

动态快捷方式

可以在运行时通过代码添加或移除动态快捷方式,代码如下:

class ShortcutsActivity : AppCompatActivity() {
    private val locationShortcutId = "location"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: LayoutShortcutsActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_shortcuts_activity)
        binding.includeTitle.tvTitle.text = "Shortcuts Api"
        binding.btnCreateShortcut.setOnClickListener {
            // 创建动态快捷方式
            createDynamicShortcuts()
        }
        binding.btnRemoveShortcut.setOnClickListener {
            // 根据ID移除指定的动态快捷方式
            ShortcutManagerCompat.removeDynamicShortcuts(this, arrayListOf(locationShortcutId))
            // 移除所有的动态快捷方式
            // ShortcutManagerCompat.removeAllDynamicShortcuts(this)
        }
    }
    private fun createDynamicShortcuts() {
        val dynamicShortcuts = ShortcutManagerCompat.getDynamicShortcuts(this)
        val locationShortcut = ShortcutInfoCompat.Builder(this, locationShortcutId)
            .setShortLabel(getString(R.string.location_shortcuts_short_label))
            .setLongLabel(getString(R.string.location_shortcuts_long_label))
            .setDisabledMessage(getString(R.string.shortcuts_disable_message))
            .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
            .setIntent(Intent(Intent.ACTION_VIEW).apply {
                component = ComponentName(packageName, GpsSignalActivity::class.java.name)
            })
            .build()
        if (dynamicShortcuts.isEmpty() || !dynamicShortcuts.contains(locationShortcut)) {
            ShortcutManagerCompat.pushDynamicShortcut(this, locationShortcut)
        }
    }
}

效果如图:

桌面快捷方式

运行时创建

桌面快捷方式也十分常见,例如支付宝可以将扫一扫、乘车码等固定到桌面。可以通过如下代码添加桌面快捷方式:

class ShortcutsActivity : AppCompatActivity() {
    private val locationShortcutId = "location"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        binding.btnCreatePinShortcut.setOnClickListener {
            // 创建桌面快捷方式
            createPinShortcuts()
        }
    }
    private fun createPinShortcuts() {
        // 先判断是否支持添加桌面快捷方式
        if (ShortcutManagerCompat.isRequestPinShortcutSupported(this)) {
            val pinShortcutInfo = ShortcutInfoCompat.Builder(this, locationShortcutId)
                .setShortLabel(getString(R.string.location_shortcuts_short_label))
                .setLongLabel(getString(R.string.location_shortcuts_long_label))
                .setDisabledMessage(getString(R.string.shortcuts_disable_message))
                .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
                .setIntent(Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, GpsSignalActivity::class.java.name)
                })
                .build()
            val pinnedShortcutCallbackIntent = ShortcutManagerCompat.createShortcutResultIntent(this, pinShortcutInfo)
            val successCallback = PendingIntent.getBroadcast(this, 0, pinnedShortcutCallbackIntent, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_MUTABLE else 0)
            ShortcutManagerCompat.requestPinShortcut(this, pinShortcutInfo, successCallback.intentSender)
        }
    }
}

效果如图:

支持用户主动创建

可以通过配置创建快捷方式专用的Activity来支持用户主动创建桌面快捷方式,代码如下:

class CreateCameraShortcutActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: LayoutCreateShortcutsActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_create_shortcuts_activity)
        binding.tvTips.text = "Do you want to add the Camera Launcher icon to your home screen?"
        binding.btnAddShortcut.setOnClickListener {
            createPinShortcuts()
        }
        binding.btnReject.setOnClickListener {
            finish()
        }
    }
    private fun createPinShortcuts() {
        if (ShortcutManagerCompat.isRequestPinShortcutSupported(this)) {
            val pinShortcutInfo = ShortcutInfoCompat.Builder(this, "camera")
                .setShortLabel(getString(R.string.camera_shortcuts_short_label))
                .setLongLabel(getString(R.string.camera_shortcuts_long_label))
                .setDisabledMessage(getString(R.string.shortcuts_disable_message))
                .setIcon(IconCompat.createWithResource(this, R.drawable.icon_camera))
                .setIntent(Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, CameraActivity::class.java.name)
                })
                .build()
            val pinnedShortcutCallbackIntent = ShortcutManagerCompat.createShortcutResultIntent(this, pinShortcutInfo)
            setResult(RESULT_OK, pinnedShortcutCallbackIntent)
            finish()
        }
    }
}
// 在 manifest中配置activity
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chenyihong.exampledemo">
    <application
        ...
        >
        <activity
            android:name=".androidapi.shortcuts.CreateCameraShortcutActivity"
            android:exported="true"
            android:icon="@drawable/icon_camera"
            android:label="@string/label_camera"
            android:theme="@style/DialogActivity">
            <intent-filter>
                <action android:name="android.intent.action.CREATE_SHORTCUT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

效果如图:

打开多个Activity

每个快捷方式都可以配置多个Intent,当用户选中此快捷方式时,会链式的打开所有Intent对应的页面,代码如下:

// 静态快捷方式
<?xml version ="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:enabled="true"
        android:icon="@drawable/icon_search_48"
        android:shortcutDisabledMessage="@string/shortcuts_disable_message"
        android:shortcutId="search"
        android:shortcutLongLabel="@string/search_shortcuts_long_label"
        android:shortcutShortLabel="@string/search_shortcuts_short_label">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetClass="com.chenyihong.exampledemo.home.HomeActivity"
            android:targetPackage="com.chenyihong.exampledemo" />
        <intent
            android:action="android.intent.action.VIEW"
            android:targetClass="com.chenyihong.exampledemo.androidapi.search.SearchActivity"
            android:targetPackage="com.chenyihong.exampledemo" />
    </shortcut>
</shortcuts>
// 动态快捷方式(桌面快捷方式与此类似)
class ShortcutsActivity : AppCompatActivity() {
    private val locationShortcutId = "location"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        binding.btnCreateMultipleIntentsShortcut.setOnClickListener {
            createMultipleIntentsDynamicShortcuts()
        }
    }
    private fun createMultipleIntentsDynamicShortcuts() {
        val dynamicShortcuts = ShortcutManagerCompat.getDynamicShortcuts(this)
        val locationShortcut = ShortcutInfoCompat.Builder(this, locationShortcutId)
            .setShortLabel(getString(R.string.location_shortcuts_short_label))
            .setLongLabel(getString(R.string.location_shortcuts_long_label))
            .setDisabledMessage(getString(R.string.shortcuts_disable_message))
            .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
            .setIntents(arrayOf(
                Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, HomeActivity::class.java.name)
                },
                Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, GpsSignalActivity::class.java.name)
                }))
            .build()
        if (dynamicShortcuts.isEmpty() || !dynamicShortcuts.contains(locationShortcut)) {
            ShortcutManagerCompat.pushDynamicShortcut(this, locationShortcut)
        }
    }
}

效果如图:

更新快捷方式

启用和禁用

在需要的时候,例如当定位不可用时禁止定位快捷方式,定位恢复可用时重新启用快捷方式,代码如下:

class ShortcutsActivity : AppCompatActivity() {
    private val locationShortcutId = "location"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        binding.btnEnableShortcut.setOnClickListener {
            // 启用快捷方式
            ShortcutManagerCompat.enableShortcuts(this, arrayListOf(ShortcutInfoCompat.Builder(this, locationShortcutId)
                .setShortLabel(getString(R.string.location_shortcuts_short_label))
                .setLongLabel(getString(R.string.location_shortcuts_long_label))
                .setDisabledMessage(getString(R.string.shortcuts_disable_message))
                .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
                .setIntent(Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, GpsSignalActivity::class.java.name)
                })
                .build()
            ))
        }
        binding.btnDisableShortcut.setOnClickListener {
            // 禁用快捷方式,需要传入禁用原因,当用户点击时会显示
            ShortcutManagerCompat.disableShortcuts(this, arrayListOf(locationShortcutId), "Location function is currently unavailable")
        }
    }
}

效果如图:

注意,根据效果图可以看到,禁用后动态快捷方式会被移除,再次启用后不会自动添加,需要手动添加。

更新快捷方式的样式

在需要的时候,例如用户切换语言时可以更新快捷方式的样式,显示匹配当前语言的文案,代码如下:

class ShortcutsActivity : AppCompatActivity() {
    private val locationShortcutId = "location"
    private var english = true
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        binding.btnUpdateShortcut.setOnClickListener {
            updateDynamicShortcuts()
        }
    }
    private fun updateDynamicShortcuts() {
        english = !english
        ShortcutManagerCompat.updateShortcuts(this, arrayListOf(
            ShortcutInfoCompat.Builder(this, locationShortcutId)
                .setShortLabel(if (english) getString(R.string.location_shortcuts_short_label) else "使用定位")
                .setLongLabel(if (english) getString(R.string.location_shortcuts_long_label) else "通过定位获取位置信息")
                .setDisabledMessage(if (english) getString(R.string.shortcuts_disable_message) else "此快捷方式不可用")
                .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
                .setIntent(Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, GpsSignalActivity::class.java.name)
                })
                .build()
        ))
    }
}

效果如图:

注意,通过代码只能更新动态快捷方式和桌面快捷方式,如果更新了静态快捷方式会崩溃。

示例

整合之后做了个示例Demo,代码如下:

// 快捷方式配置文件
<?xml version ="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:enabled="true"
        android:icon="@drawable/icon_biometrics"
        android:shortcutDisabledMessage="@string/shortcuts_disable_message"
        android:shortcutId="biometrics"
        android:shortcutLongLabel="@string/biometrics_shortcuts_long_label"
        android:shortcutShortLabel="@string/biometrics_shortcuts_short_label">
        <!--快捷方式跳转的页面,必须配置-->
        <intent
            android:action="android.intent.action.VIEW"
            android:targetClass="com.chenyihong.exampledemo.androidapi.biometrics.BiometricActivity"
            android:targetPackage="com.chenyihong.exampledemo" />
    </shortcut>
    <shortcut
        android:enabled="true"
        android:icon="@drawable/icon_search_48"
        android:shortcutDisabledMessage="@string/shortcuts_disable_message"
        android:shortcutId="search"
        android:shortcutLongLabel="@string/search_shortcuts_long_label"
        android:shortcutShortLabel="@string/search_shortcuts_short_label">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetClass="com.chenyihong.exampledemo.home.HomeActivity"
            android:targetPackage="com.chenyihong.exampledemo" />
        <intent
            android:action="android.intent.action.VIEW"
            android:targetClass="com.chenyihong.exampledemo.androidapi.search.SearchActivity"
            android:targetPackage="com.chenyihong.exampledemo" />
    </shortcut>
</shortcuts>
// 弹窗样式的Activity Style
<resources xmlns:tools="http://schemas.android.com/tools">
    <style name="DialogActivity" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        <!-- 背景色透明度 -->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!-- 无标题 -->
        <item name="android:windowNoTitle">true</item>
        <!-- 半透明,设置为false无透明效果 -->
        <item name="android:windowIsTranslucent">true</item>
        <!-- 模糊 -->
        <item name="android:backgroundDimEnabled">true</item>
        <!-- 窗口样式Dialog -->
        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
    </style>
</resources>
// Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chenyihong.exampledemo">
    <application
        ...
        >
        <activity
            android:name=".home.HomeActivity"
            android:exported="true"
            android:screenOrientation="portrait">
            <meta-data
                android:name="android.app.shortcuts"
                android:resource="@xml/shortcuts" />
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>
        <activity
            android:name=".androidapi.shortcuts.ShortcutsActivity"
            android:exported="false"
            android:screenOrientation="portrait" />
        <activity
            android:name=".androidapi.shortcuts.CreateCameraShortcutActivity"
            android:exported="true"
            android:icon="@drawable/icon_camera"
            android:label="@string/label_camera"
            android:theme="@style/DialogActivity">
            <intent-filter>
                <action android:name="android.intent.action.CREATE_SHORTCUT" />
            </intent-filter>
        </activity>
        <activity
            android:name=".androidapi.shortcuts.CreateLocationShortcutActivity"
            android:exported="true"
            android:icon="@drawable/icon_location"
            android:label="@string/label_location"
            android:theme="@style/DialogActivity">
            <intent-filter>
                <action android:name="android.intent.action.CREATE_SHORTCUT" />
            </intent-filter>
        </activity>
    </application>
</manifest>
// 示例Activity
class ShortcutsActivity : AppCompatActivity() {
    private val locationShortcutId = "location"
    private var english = true
    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: LayoutShortcutsActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_shortcuts_activity)
        binding.includeTitle.tvTitle.text = "Shortcuts Api"
        binding.btnCreateShortcut.setOnClickListener {
            // 创建动态快捷方式
            createDynamicShortcuts()
        }
        binding.btnRemoveShortcut.setOnClickListener {
            // 根据ID移除指定的动态快捷方式
            ShortcutManagerCompat.removeDynamicShortcuts(this, arrayListOf(locationShortcutId))
            // 根据ID移除指定的动态快捷方式
            // ShortcutManagerCompat.removeAllDynamicShortcuts(this)
        }
        binding.btnCreatePinShortcut.setOnClickListener {
            // 创建桌面快捷方式
            createPinShortcuts()
        }
        binding.btnCreateMultipleIntentsShortcut.setOnClickListener {
            createMultipleIntentsDynamicShortcuts()
        }
        binding.btnEnableShortcut.setOnClickListener {
            // 启用快捷方式
            ShortcutManagerCompat.enableShortcuts(this, arrayListOf(ShortcutInfoCompat.Builder(this, locationShortcutId)
                .setShortLabel(getString(R.string.location_shortcuts_short_label))
                .setLongLabel(getString(R.string.location_shortcuts_long_label))
                .setDisabledMessage(getString(R.string.shortcuts_disable_message))
                .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
                .setIntent(Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, GpsSignalActivity::class.java.name)
                })
                .build()
            ))
        }
        binding.btnDisableShortcut.setOnClickListener {
            // 禁用快捷方式,需要传入禁用原因,当用户点击时会显示
            ShortcutManagerCompat.disableShortcuts(this, arrayListOf(locationShortcutId), "Location function is currently unavailable")
        }
        binding.btnUpdateShortcut.setOnClickListener {
            // 更新快捷方式
            updateDynamicShortcuts()
        }
    }
    private fun createDynamicShortcuts() {
        val dynamicShortcuts = ShortcutManagerCompat.getDynamicShortcuts(this)
        val locationShortcut = ShortcutInfoCompat.Builder(this, locationShortcutId)
            .setShortLabel(getString(R.string.location_shortcuts_short_label))
            .setLongLabel(getString(R.string.location_shortcuts_long_label))
            .setDisabledMessage(getString(R.string.shortcuts_disable_message))
            .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
            .setIntent(Intent(Intent.ACTION_VIEW).apply {
                component = ComponentName(packageName, GpsSignalActivity::class.java.name)
            })
            .build()
        if (dynamicShortcuts.isEmpty() || !dynamicShortcuts.contains(locationShortcut)) {
            ShortcutManagerCompat.pushDynamicShortcut(this, locationShortcut)
        }
    }
    private fun createMultipleIntentsDynamicShortcuts() {
        val dynamicShortcuts = ShortcutManagerCompat.getDynamicShortcuts(this)
        val locationShortcut = ShortcutInfoCompat.Builder(this, locationShortcutId)
            .setShortLabel(getString(R.string.location_shortcuts_short_label))
            .setLongLabel(getString(R.string.location_shortcuts_long_label))
            .setDisabledMessage(getString(R.string.shortcuts_disable_message))
            .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
            .setIntents(arrayOf(
                Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, HomeActivity::class.java.name)
                },
                Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, GpsSignalActivity::class.java.name)
                }))
            .build()
        if (dynamicShortcuts.isEmpty() || !dynamicShortcuts.contains(locationShortcut)) {
            ShortcutManagerCompat.pushDynamicShortcut(this, locationShortcut)
        }
    }
    private fun updateDynamicShortcuts() {
        english = !english
        ShortcutManagerCompat.updateShortcuts(this, arrayListOf(
            ShortcutInfoCompat.Builder(this, locationShortcutId)
                .setShortLabel(if (english) getString(R.string.location_shortcuts_short_label) else "使用定位")
                .setLongLabel(if (english) getString(R.string.location_shortcuts_long_label) else "通过定位获取位置信息")
                .setDisabledMessage(if (english) getString(R.string.shortcuts_disable_message) else "此快捷方式不可用")
                .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
                .setIntent(Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, GpsSignalActivity::class.java.name)
                })
                .build()
        ))
    }
    private fun createPinShortcuts() {
        // 先判断是否支持添加桌面快捷方式
        if (ShortcutManagerCompat.isRequestPinShortcutSupported(this)) {
            val pinShortcutInfo = ShortcutInfoCompat.Builder(this, locationShortcutId)
                .setShortLabel(getString(R.string.location_shortcuts_short_label))
                .setLongLabel(getString(R.string.location_shortcuts_long_label))
                .setDisabledMessage(getString(R.string.shortcuts_disable_message))
                .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
                .setIntent(Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, GpsSignalActivity::class.java.name)
                })
                .build()
            val pinnedShortcutCallbackIntent = ShortcutManagerCompat.createShortcutResultIntent(this, pinShortcutInfo)
            val successCallback = PendingIntent.getBroadcast(this, 0, pinnedShortcutCallbackIntent, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_MUTABLE else 0)
            ShortcutManagerCompat.requestPinShortcut(this, pinShortcutInfo, successCallback.intentSender)
        }
    }
}
// 支持用户创建桌面快捷方式
class CreateCameraShortcutActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: LayoutCreateShortcutsActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_create_shortcuts_activity)
        binding.tvTips.text = "Do you want to add the Camera Launcher icon to your home screen?"
        binding.btnAddShortcut.setOnClickListener {
            createPinShortcuts()
        }
        binding.btnReject.setOnClickListener {
            finish()
        }
    }
    private fun createPinShortcuts() {
        if (ShortcutManagerCompat.isRequestPinShortcutSupported(this)) {
            val pinShortcutInfo = ShortcutInfoCompat.Builder(this, "camera")
                .setShortLabel(getString(R.string.camera_shortcuts_short_label))
                .setLongLabel(getString(R.string.camera_shortcuts_long_label))
                .setDisabledMessage(getString(R.string.shortcuts_disable_message))
                .setIcon(IconCompat.createWithResource(this, R.drawable.icon_camera))
                .setIntent(Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, CameraActivity::class.java.name)
                })
                .build()
            val pinnedShortcutCallbackIntent = ShortcutManagerCompat.createShortcutResultIntent(this, pinShortcutInfo)
            setResult(RESULT_OK, pinnedShortcutCallbackIntent)
            finish()
        }
    }
}
// 支持用户创建桌面快捷方式
class CreateLocationShortcutActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: LayoutCreateShortcutsActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_create_shortcuts_activity)
        binding.tvTips.text = "Do you want to add the Location Launcher icon to your home screen?"
        binding.btnAddShortcut.setOnClickListener {
            createPinShortcuts()
        }
        binding.btnReject.setOnClickListener {
            finish()
        }
    }
    private fun createPinShortcuts() {
        if (ShortcutManagerCompat.isRequestPinShortcutSupported(this)) {
            val pinShortcutInfo = ShortcutInfoCompat.Builder(this, "location")
                .setShortLabel(getString(R.string.location_shortcuts_short_label))
                .setLongLabel(getString(R.string.location_shortcuts_long_label))
                .setDisabledMessage(getString(R.string.shortcuts_disable_message))
                .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location))
                .setIntent(Intent(Intent.ACTION_VIEW).apply {
                    component = ComponentName(packageName, GpsSignalActivity::class.java.name)
                })
                .build()
            val pinnedShortcutCallbackIntent = ShortcutManagerCompat.createShortcutResultIntent(this, pinShortcutInfo)
            setResult(RESULT_OK, pinnedShortcutCallbackIntent)
            finish()
        }
    }
}

ExampleDemo github

ExampleDemo gitee

以上就是Android 快捷方式实现实例详解的详细内容,更多关于Android 桌面快捷方式的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android程序开发之手机APP创建桌面快捷方式

    预览效果图: 需要权限: <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> 配置文件:AndroidManifest.xml <activity android:name="com.myself.news.activity.GuideActivity" android:label="@string/title_activi

  • Android O添加桌面快捷方式的示例

    手机升级到安卓O后,突然发现创建快捷方式的功能失效了,查询一番后发现:安卓O要使用ShortcutManager来创建快捷方式. 安卓N及以下版本: Intent addShortcutIntent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");//"com.android.launcher.action.INSTALL_SHORTCUT" // 不允许重复创建 addShortcutInt

  • Android编程创建桌面快捷方式的常用方法小结【2种方法】

    本文实例讲述了Android编程创建桌面快捷方式的常用方法.分享给大家供大家参考,具体如下: Android在桌面上生成快捷方式有两种情况,一种是直接在桌面直接生成;一种是长按桌面,在弹出的快捷菜单中生成. 谈谈在桌面上直接生成.个人觉得这个比较爽快,既然都是快捷方式了干嘛还要再隐藏一层呢?当然喜欢桌面干净的就比较喜欢第二个了. 第一个是通过广播(Broadcast)的形式向Luncher发送请求生成快捷方式的. 在网上找到关于这方面的注册信息. <!--设置wallpapaer的activit

  • Android如何创建桌面快捷方式

    Android创建桌面的快捷方式 概述 :创建桌面快捷方式相当与创建一个程序的入口,就像我们程序在安装完毕后会自动创建一个图标到桌面.其实创建桌面快捷方式跟创建一个程序入口差不多,但是像QQ会话一样创建一个QQ好友的会话快捷方式,就得动态的创建图标,名字了. 1.首先权限是必不可少的 <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> 2.然后就是在你项目配置

  • Android编程实现向桌面添加快捷方式的方法

    本文实例讲述了Android编程实现向桌面添加快捷方式的方法.分享给大家供大家参考,具体如下: 有时候为了使用方便,需要在桌面上添加快捷方式,下面是两种添加快捷方式的方法: 方法1: void setshortCut() { Intent addShortcut = new Intent(); // 设置快捷方式的名字 addShortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, "快捷方式练习"); // 构建快捷方式中专门的图标 Parcelab

  • Android应用创建桌面快捷方式代码

    android的快捷方式比较简单,就是发一个系统的广播,然后为快捷方式设置Intent--- package com.xikang.android.slimcoach.utils; /** * @author huiych * 创建快捷方式 * @created 2013-02-21 * */ import android.content.Intent; import android.os.Parcelable; import com.xikang.android.slimcoach.AppXi

  • Android 桌面快捷方式实现实例详解

    目录 Shortcuts API 简介 静态快捷方式 快捷方式配置 在Manifest中添加快捷方式配置 动态快捷方式 桌面快捷方式 运行时创建 支持用户主动创建 打开多个Activity 更新快捷方式 启用和禁用 更新快捷方式的样式 示例 Shortcuts API 简介 快捷方式在各类App中已经十分常见,快捷方式可以让用户直达想要使用的功能,例如快速打开扫一扫.快速打开健康码等.对此,Android提供了Shortcuts API,本文介绍如何使用Shortcuts API来实现快捷方式.

  • Android 帧动画的实例详解

    Android 帧动画的实例详解 对于 Android 帧动画 大体上可以理解成 一张张图片 按一定顺序切换, 这样当连续几张图是一组动画时,就可以连起来了看成是一个小电影,你懂得 好得,比就装到这里,下面开始进入正题,由于产品需求 需要做一个 声音喇叭动态切换的样式,我特么第一就想到是帧动画切换,然后就百度了一些资料,发现 真的, 现在这个网上太多的资料是 copy粘贴过来的, 一错全错,对于这种情况我只想说,made,一群垃圾, 所以今天我将带你们走进Android 正确帧动画地址. 第一步

  • Android的搜索框架实例详解

    基础知识 Android的搜索框架将代您管理的搜索对话框,您不需要自己去开发一个搜索框,不需要担心要把搜索框放什么位置,也不需要担心搜索框影响您当前的界面.所有的这些工作都由SearchManager类来为您处理(以下简称"搜索管理器"),它管理的Android搜索对话框的整个生命周期,并执行您的应用程序将发送的搜索请求,返回相应的搜索关键字. 当用户执行一个搜索,搜索管理器将使用一个专门的Intent把搜索查询的关键字传给您在配置文件中配置的处理搜索结果的Activity.从本质上讲

  • Android Intent封装的实例详解

    Android Intent封装的实例详解 什么是Intent: Intent是协调应用间.组件之间的通讯和交互.通过Intent你可以启动Activity.Service.Broadcasts.更可以跨程序调用第三方组件.例如:启动拨打电话界面.音乐播放等. 组件     启动 Activity startActicity() Service startService(),bindService( ) Broadcasts sendBroadcast() 使用Intent: 栗子:在一个Act

  • Android 完全退出的实例详解

    Android 完全退出的实例详解 首先,在基类BaseActivity里,注册RxBus监听: public class BaseActivity extends AppCompatActivity { Subscription mSubscription; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Utils.intiSySBar(thi

  • Android 中ContentProvider的实例详解

    Android 中ContentProvider的实例详解 Content Provider 的简单介绍: * Android中的Content Provider 机制可支持在多个应用中存储和读取数据.这也是跨应用 共享数据的唯一方式.在Android系统中,没有一个公共的内存区域,供多个应用共享存储数据: * Android 提供了一些主要数据类型的ContentProvider ,比如:音频.视频.图片和私人通讯录等: 在android.provider 包下面找到一些android提供的C

  • Android 中 ActivityLifecycleCallbacks的实例详解

    Android 中 ActivityLifecycleCallbacks的实例详解           以上就是使用ActivityLifecycleCallbacks的实例,代码注释写的很清楚大家可以参考下, MyApplication如下: package com.cc; import java.util.LinkedList; import android.app.Activity; import android.app.Application; import android.os.Bun

  • Android全局获取Context实例详解

    Android全局获取Context实例详解 在弹出Toast 启动活动 发送广播 操作数据库 使用通知等等时都需要Context 如果操作在活动中进行是很简单的,因为活动本身就是一个Context对象 但是当逻辑代码脱离了Activity类,此时使用Context就需要一些技巧了: 我们可以定制一个自己的Application类,以便管理程序内一些全局状态信息,比如全局Context 代码如下: public class MyApplication extends Application{ p

  • Android IPC机制Messenger实例详解

    Android IPC机制Messenger实例详解 前言: Messenger可以翻译成信使,通过它可以在不同进程间传递Message对象有了它就可以轻松实现进程间的数据传递了. Messenger使用的方法相对AIDL比较简单,它对AIDL做了一层封装是的我们不需要像采用AIDL那样去实现进程通信那么麻烦,可以看看他的源码有AIDL的迹象. public final class Messenger implements Parcelable { private final IMessenge

  • Java中的instanceof关键字在Android中的用法实例详解

    在下面介绍Android中如何使用instanceof关键字开发更方便时,先来温习一下java中instanceof的概念. instanceof大部分的概念是这样定义的:instanceof是Java的一个二元操作符,和==,>,<是同一类东西.由于它是由字母组成的,所以也是Java的保留关键字.它的作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据.举个栗子: String s = "I AM an Object!"; boolean isObj

随机推荐