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

相关推荐
500了6 小时前
Kotlin基本知识
android·开发语言·kotlin
人工智能的苟富贵7 小时前
Android Debug Bridge(ADB)完全指南
android·adb
小雨cc5566ru12 小时前
uniapp+Android面向网络学习的时间管理工具软件 微信小程序
android·微信小程序·uni-app
bianshaopeng13 小时前
android 原生加载pdf
android·pdf
hhzz13 小时前
Linux Shell编程快速入门以及案例(Linux一键批量启动、停止、重启Jar包Shell脚本)
android·linux·jar
火红的小辣椒14 小时前
XSS基础
android·web安全
勿问东西16 小时前
【Android】设备操作
android
五味香16 小时前
C++学习,信号处理
android·c语言·开发语言·c++·学习·算法·信号处理
图王大胜18 小时前
Android Framework AMS(01)AMS启动及相关初始化1-4
android·framework·ams·systemserver
工程师老罗20 小时前
Android Button “No speakable text present” 问题解决
android