Criar um host de widgets

A tela inicial do Android, disponível na maioria dos dispositivos com esse SO, permite que o usuário incorpore widgets de app (ou widgets) para acesso rápido ao conteúdo. Se você estiver criando uma tela inicial substituta ou um app semelhante, também é possível permitir que o usuário incorpore widgets implementando AppWidgetHost. Isso não é algo que a maioria dos apps precisa fazer, mas, se você estiver criando seu próprio host, é importante entender as obrigações contratuais com as quais um host concorda implicitamente.

Esta página se concentra nas responsabilidades envolvidas na implementação de um AppWidgetHost personalizado. Para um exemplo específico de como implementar um AppWidgetHost, consulte o código-fonte da tela inicial do Android LauncherAppWidgetHost.

Esta é uma visão geral dos principais conceitos e classes envolvidos na implementação de um AppWidgetHost personalizado:

  • Host de widgets de apps: o AppWidgetHost fornece a interação com o serviço AppWidget para apps que incorporam widgets à interface. Um AppWidgetHost precisa ter um ID exclusivo no pacote do host. Esse ID persiste em todos os usos do host. Ele costuma ser um valor codificado que você atribui no seu app.

  • ID do widget de app: cada instância de widget recebe um ID exclusivo no momento da vinculação. Consulte bindAppWidgetIdIfAllowed() e, para mais detalhes, a seção Vinculação de widgets a seguir. O host recebe o ID exclusivo usando allocateAppWidgetId(). Ele é persistente durante o ciclo de vida do widget até ser excluído pelo host. Todo estado específico do host, como o tamanho e local do widget, precisa ser mantido pelo pacote de hospedagem e associado ao ID do widget de app.

  • Visualização do host de widgets de apps: pense em AppWidgetHostView como um frame em que o widget esteja agrupado sempre que ele precisar ser exibido. Um widget é associado a um AppWidgetHostView sempre que ele é inflado pelo host.

    • Por padrão, o sistema cria um AppWidgetHostView, mas o host pode criar a própria subclasse de AppWidgetHostView estendendo-a.
    • A partir do Android 12 (nível 31 da API), o AppWidgetHostView introduz os métodos setColorResources() e resetColorResources() para processar cores dinamicamente sobrecarregadas. O host é responsável por fornecer as cores a esses métodos.
  • Pacote de opções: o AppWidgetHost usa o pacote de opções para comunicar informações ao AppWidgetProvider sobre como o widget é exibido, por exemplo, a lista de faixas de tamanho e se o widget está em uma tela de bloqueio ou na tela inicial. Essas informações permitem que o AppWidgetProvider personalize o conteúdo e a aparência do widget com base em como e onde ele é exibido. É possível usar updateAppWidgetOptions() e updateAppWidgetSize() para modificar o pacote de um widget. Esses dois métodos acionam o callback onAppWidgetOptionsChanged() para o AppWidgetProvider.

Widgets de vinculação

Quando um usuário adiciona um widget a um host, um processo chamado vinculação ocorre. A vinculação refere-se à associação de um determinado ID de widget de app a um host e a um AppWidgetProvider específicos.

As APIs de vinculação também possibilitam que um host forneça uma interface personalizada para vinculação. Para usar esse processo, seu app precisa declarar a permissão BIND_APPWIDGET no manifesto do host:

<uses-permission android:name="android.permission.BIND_APPWIDGET" />

No entanto, esse é apenas o primeiro passo. No momento da execução, o usuário precisa conceder explicitamente permissão ao app para que ele possa adicionar um widget ao host. Para testar se seu app tem permissão para adicionar o widget, use o método bindAppWidgetIdIfAllowed(). Se bindAppWidgetIdIfAllowed() retornar false, o app precisará mostrar uma caixa de diálogo pedindo que o usuário conceda a permissão: "permitir" para a adição de widget atual ou "sempre permitir" para abranger todas as adições futuras.

Este snippet demonstra um exemplo de como exibir a caixa de diálogo:

Kotlin

val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_BIND).apply {
    putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
    putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName)
    // This is the options bundle described in the preceding section.
    putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options)
}
startActivityForResult(intent, REQUEST_BIND_APPWIDGET)

Java

Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName);
// This is the options bundle described in the preceding section.
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
startActivityForResult(intent, REQUEST_BIND_APPWIDGET);

O host precisa verificar se o widget adicionado por um usuário precisa de configuração. Para mais informações, consulte Permitir que os usuários configurem widgets de apps.

Responsabilidades do organizador

É possível especificar várias configurações para widgets usando os metadados AppWidgetProviderInfo. É possível recuperar essas opções de configuração, abordadas com mais detalhes nas seções a seguir, do objeto AppWidgetProviderInfo associado a um provedor de widgets.

Independentemente da versão do Android que você está segmentando, todos os hosts têm as seguintes responsabilidades:

  • Ao adicionar um widget, aloque o ID dele conforme descrito acima. Quando um widget é removido do host, chame deleteAppWidgetId() para desalocar o ID do widget.

  • Ao adicionar um widget, verifique se a atividade de configuração precisa ser iniciada. Normalmente, o host precisa iniciar a atividade de configuração do widget se ela existir e não estiver marcada como opcional especificando as flags configuration_optional e reconfigurable. Consulte Atualizar o widget pela atividade de configuração para mais detalhes. Essa é uma etapa necessária para muitos widgets antes que eles possam ser exibidos.

  • Os widgets especificam uma largura e altura padrão nos metadados AppWidgetProviderInfo. Esses valores são definidos em células (a partir do Android 12, se targetCellWidth e targetCellHeight forem especificados) ou em dps (se apenas minWidth e minHeight forem especificados). Consulte Atributos de dimensionamento de widget.

    Verifique se o widget está disposto com pelo menos essa quantidade de dps. Por exemplo, muitos hosts alinham ícones e widgets em uma grade. Nesse cenário, por padrão, o host adiciona um widget usando o número mínimo de células que satisfazem as restrições de minWidth e minHeight.

Além dos requisitos listados na seção anterior, versões específicas da plataforma introduzem recursos que colocam novas responsabilidades no host.

Determine sua abordagem com base na versão do Android segmentada

Android 12

O Android 12 (API de nível 31) agrupa um List<SizeF> extra que contém a lista de possíveis tamanhos em dps que uma instância de widget pode ocupar no pacote de opções. O número de tamanhos fornecidos depende da implementação do host. Normalmente, os hosts oferecem dois tamanhos para smartphones (retrato e paisagem) e quatro para dispositivos dobráveis.

Há um limite de MAX_INIT_VIEW_COUNT (16) no número de RemoteViews diferentes que um AppWidgetProvider pode fornecer para RemoteViews. Como os objetos AppWidgetProvider mapeiam um objeto RemoteViews para cada tamanho no List<SizeF>, não forneça mais de MAX_INIT_VIEW_COUNT tamanhos.

O Android 12 também introduz os atributos maxResizeWidth e maxResizeHeight em dps. Recomendamos que um widget que usa pelo menos um desses atributos não exceda o tamanho especificado por eles.

Outros recursos

  • Consulte a documentação de referência do Glance.