You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jetpack Compose应用中托管并绘制已安装应用Widget

开发Android Launcher:Jetpack Compose中集成已安装App Widget的问题与求助

我正在使用Jetpack Compose开发一款Android Launcher,目标是实现在主屏幕加载并展示所有已安装应用Widget的功能,但始终找不到完整、可靠的参考资料。曾参考过Medium文章和一篇早期博客内容,但讲解不完整,按其方法操作时出现大量错误。尝试让ChatGPT生成相关代码,但代码无法正常运行,以下是生成的代码:

MainActivity代码

class MainActivity : ComponentActivity() {

    private lateinit var appWidgetHost: AppWidgetHost
    private lateinit var appWidgetManager: AppWidgetManager
    private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        appWidgetHost = AppWidgetHost(this, APP_WIDGET_HOST_ID)
        appWidgetManager = AppWidgetManager.getInstance(this)

        requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
            if (isGranted) {
                // Permission granted, continue with widget setup
                println("permission")
                setupWidgets()
            } else {
                setContent{
                    WidgetsScreenExampleTheme {
                        Surface(
                            modifier = Modifier.fillMaxSize(),
                            color = MaterialTheme.colorScheme.background
                        ) {
                            println("no permission")
                            Text(
                                text = "permission not found",
                                style = TextStyle(color = Color.Black, fontSize = TextUnit(10f, TextUnitType.Sp))
                            )

                        }
                    }
                }
            }
        }
        checkAndRequestWidgetPermission()
    }

    private fun checkAndRequestWidgetPermission() {
        val permission = "android.permission.BIND_APPWIDGET"
        when {
            ContextCompat.checkSelfPermission(
                this,
                permission
            ) == PackageManager.PERMISSION_GRANTED -> {
                // Permission already granted, continue with widget setup
                setupWidgets()
            }
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {
                // Permission not granted, request it from the user
                requestPermissionLauncher.launch(permission)
            }
            else -> {
                // For versions below Android M, permission is granted at installation time
                // Continue with widget setup
                setupWidgets()
            }
        }
    }

    private fun setupWidgets() {
        // Continue with widget setup here
        setContent {
            WidgetsScreenExampleTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    WidgetsView(
                        Modifier
                            .fillMaxSize(),
                        appWidgetHost,
                        appWidgetManager,
                        APP_WIDGET_HOST_ID
                    )
                }
            }
        }
    }

    companion object {
        const val APP_WIDGET_HOST_ID = 1
    }
}

AppWidgetHostView Composable代码

@Composable
fun AppWidgetHostView(
    appWidgetManager: AppWidgetManager,
    appWidgetHost: AppWidgetHost,
    appWidgetId: Int,
    modifier: Modifier = Modifier
) {
    val appWidgetHostView = appWidgetHost.createView(
        LocalContext.current,
        appWidgetId,
        appWidgetManager.getAppWidgetInfo(appWidgetId)
    )

    DisposableEffect(appWidgetHostView) {
        onDispose {
            appWidgetHost.deleteAppWidgetId(appWidgetId)
        }
    }

    // Measure the app widget size
    appWidgetHostView.measure(
        View.MeasureSpec.makeMeasureSpec(100.dp.value.toInt(), View.MeasureSpec.EXACTLY),
        View.MeasureSpec.makeMeasureSpec(100.dp.value.toInt(), View.MeasureSpec.EXACTLY)
    )

    // Layout the app widget
    appWidgetHostView.layout(
        0,
        0,
        appWidgetHostView.measuredWidth,
        appWidgetHostView.measuredHeight
    )

    // Draw the app widget
    AndroidView(
        factory = { appWidgetHostView },
        modifier = modifier
    )
}

AppWidgetListItem Composable代码

@Composable
fun AppWidgetListItem(appWidget: AppWidget, appWidgetHostId: Int) {
    val context = LocalContext.current
    val appWidgetHost = AppWidgetHost(context, appWidgetHostId)
    val appWidgetManager = AppWidgetManager.getInstance(context)

    val (isExpanded, setExpanded) = remember { mutableStateOf(false) }
//    val remoteViews = appWidgetManager.getAppWidgetViews(appWidget.appWidgetId)

    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
            .background(MaterialTheme.colorScheme.background)
            .clickable { setExpanded(!isExpanded) }
    ) {
        Text(text = appWidget.appWidgetInfo.label)

        if (isExpanded) {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 8.dp)
            ) {
                AppWidgetHostView(
                    appWidgetManager = appWidgetManager,
                    appWidgetHost = appWidgetHost,
                    appWidgetId = appWidget.appWidgetId,
                    modifier = Modifier.fillMaxWidth()
                )
            }
        }
    }
}

WidgetsView Composable代码

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun WidgetsView(
    modifier: Modifier = Modifier,
    appWidgetHost: AppWidgetHost,
    appWidgetManager: AppWidgetManager,
    appWidgetHostId: Int
) {
    val context = LocalContext.current

    val appWidgetIds = appWidgetHost.appWidgetIds
    val appWidgets = appWidgetIds.map { appWidgetId ->
        val appWidgetInfo = appWidgetManager.getAppWidgetInfo(appWidgetId)
        if (appWidgetInfo != null) {
            AppWidget(appWidgetId, appWidgetInfo)
        } else {
            null
        }
    }.mapNotNull { it }

    Column {
        TopAppBar(
            title = {
                Text(text = "Installed Widgets")
            },
            actions = {
                IconButton(onClick = { /* Handle settings action */ }) {
                    Icon(imageVector = Icons.Default.Star, contentDescription = null)
                }
            }
        )

        LazyColumn {
            items(appWidgets.size) { i ->
                AppWidgetListItem(appWidgets[i], appWidgetHostId)
            }
        }
    }
}

希望能得到针对这段代码的问题反馈,以及实现该功能的优质参考资源指引。


内容的提问来源于stack exchange,提问作者Dhruv Bansal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 20:50:53