Android 桌面小组件(二)— 提示添加与启用配置页面

App中可能存在一些高频使用的功能,例如扫一扫、开启收付款码等。如果能够在不先打开App的情况下快速使用这些功能,将显著提升用户体验。

在上一篇文章Android 桌面小组件(一)--- 添加桌面小组件中介绍了如何创建桌面小组件并在桌面上添加。本文将进一步介绍提示用户添加小组件与启用小组件的配置页面。

提示用户添加小组件

App中配置好小组件之后,除了像上一篇文章中演示的那样在桌面直接添加小组件之外,从Android 8.0开始,系统支持App提示用户添加小组件到桌面。

具体步骤如下:

  1. AndroidManifest中声明App的小组件(在上一篇文件中已经介绍过,本文不再赘述)。
  2. 调用AppWidgetManager.requestPinAppWidget()方法,提示用户添加小组件。

调用requestPinAppWidget

调用AppWidgetManager.requestPinAppWidget()示例代码如下:

less 复制代码
class DesktopWidgetExampleActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = LayoutDesktopWidgetExampleActivityBinding.inflate(layoutInflater).also {
            setContentView(it.root)
        }

        binding.btnAddDesktopWidget.setOnClickListener {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                AppWidgetManager.getInstance(this).run {
                    // 先判断是否支持添加小组件
                    if (isRequestPinAppWidgetSupported) {
                        // 小组件信息
                        val widgetProvider = ComponentName(this@DesktopWidgetExampleActivity, DesktopWidgetExampleProvider::class.java)
                        // 添加成功的广播(如果不需要,可以用null)
                        val successCallback = PendingIntent.getBroadcast(this@DesktopWidgetExampleActivity, 0, Intent(this@DesktopWidgetExampleActivity, DesktopWidgetExampleProvider::class.java).apply { action = ACTION_PIN_WIDGET }, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
                        // 请求添加小组件
                        requestPinAppWidget(widgetProvider, null, successCallback)
                    }
                }
            }
        }
    }
}

效果演示

如图:

启用小组件的配置页面

假如小组件有一些可配置项,系统支持使用一个独立的配置页面对小组件的可配置项进行管理。

具体步骤如下:

  1. 创建配置页面。
  2. AndroidManifest中声明配置页面。
  3. AppWidgetProviderInfo配置文件中声明配置页面。

创建配置页面

注意事项:

  • 小组件的宿主(例如桌面)会将小组件的id通过Intent传入。
  • Activity必须返回结果,并且结果必须包含传入的小组件id。

创建的配置页面示例代码如下:

kotlin 复制代码
class DesktopWidgetConfigExampleActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = LayoutDesktopWidgetConfigExampleActivityBinding.inflate(layoutInflater).also {
            setContentView(it.root)
        }

        if (!SpUtils.isInit()) {
            SpUtils.init(this)
        }

        val appWidgetId = intent?.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID)
            ?: AppWidgetManager.INVALID_APPWIDGET_ID

        // 先将结果设置为Activity.RESULT_CANCELED,如果没有顺利执行完整个流程,系统会取消添加widget。
        setResult(Activity.RESULT_CANCELED, Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId))

        binding.btnSave.setOnClickListener {
            val targetWaterCount = binding.etInputTargetWaterCount.text.toString()
            updateWidget(this, AppWidgetManager.getInstance(this), appWidgetId, targetWaterCount)
            setResult(Activity.RESULT_OK, Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId))
            finish()
        }
    }

    private fun updateWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int, targetWaterCount: String) {
        // 可能不是初次创建时打开配置,所以需要使用保存的数据。
        val currentTotalWaterCount = SpUtils.getInt("currentTotalWaterCount", 0)
        appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(context.packageName, R.layout.layout_desktop_widget_example).apply {
            setTextViewText(R.id.tv_target_water_count, "目标饮水量(杯):$targetWaterCount")
            setTextViewText(R.id.tv_example_content, "当前饮水量(杯):$currentTotalWaterCount")
            setOnClickPendingIntent(R.id.btn_plus, PendingIntent.getBroadcast(context, 0, Intent(context, DesktopWidgetExampleProvider::class.java).apply { action = ACTION_INCREASE }, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE))
            setOnClickPendingIntent(R.id.btn_reduce, PendingIntent.getBroadcast(context, 0, Intent(context, DesktopWidgetExampleProvider::class.java).apply { action = ACTION_DECREASE }, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE))
        })
    }
}

AndroidManfiest中添加配置页面

小组件的宿主会通过携带ACTION_APPWIDGET_CONFIGUREIntent打开配置页面,因此配置页面的intent-filter要添加对应的action,示例代码如下:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    ......

    <application
        ......
        >
            android:name=".androidapi.desktopwidgets.DesktopWidgetConfigExampleActivity"
            android:exported="false">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
            </intent-filter>
        </activity>
    </application>
</manifest>

在AppWidgetProviderInfo配置文件中声明配置页面

在AppWidgetProviderInfo配置文件中,使用android:configure属性来声明配置文件,示例代码如下:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:configure="com.chenyihong.exampledemo.androidapi.desktopwidgets.DesktopWidgetConfigExampleActivity"
    android:widgetFeatures="reconfigurable"
    ...... />

PS: Android 9开始,增加了android:widgetFeatures属性,配置为reconfigurable时允许用户重新配置小组件,但是从Android 12开始才得到广泛支持。

效果演示

如图:

完整示例代码

所有演示代码已在示例Demo中添加。

ExampleDemo github

ExampleDemo gitee

相关推荐
m0_548514773 小时前
2024.12.10——攻防世界Web_php_include
android·前端·php
凤邪摩羯3 小时前
Android-性能优化-03-启动优化-启动耗时
android
凤邪摩羯3 小时前
Android-性能优化-02-内存优化-LeakCanary原理解析
android
喀什酱豆腐4 小时前
Handle
android
m0_748232925 小时前
Android Https和WebView
android·网络协议·https
m0_748251725 小时前
Android webview 打开本地H5项目(Cocos游戏以及Unity游戏)
android·游戏·unity
m0_748254667 小时前
go官方日志库带色彩格式化
android·开发语言·golang
zhangphil7 小时前
Android使用PorterDuffXfermode模式PorterDuff.Mode.SRC_OUT橡皮擦实现“刮刮乐”效果,Kotlin(2)
android·kotlin
爱学测试的李木子8 小时前
从0到1搭建 Android 自动化 python+appium 环境
android·软件测试·python·测试工具·自动化
咸芝麻鱼8 小时前
Android Studio | 连接手机设备后,启动App时出现:Waiting For DebuggerApplication (App名)...
android·adb·智能手机·android studio