2012-03-17 23 views
18

Estoy tratando de convertir el iniciador ICS de stock en una aplicación independiente. Estoy casi allí: lo único que no funciona es el ícono de búsqueda y colocar widgets en la pantalla, lo que provoca un bloqueo.Agregar widgets a una página del iniciador sin bindAppWidgetId()

El bloqueo se debe a que el iniciador de existencias utiliza appWidgetManager.bindAppWidgetId(appWidgetId, componentName); para agregar widgets, que apparently only system apps have permission to do.

Así que mi pregunta es, ¿cuál es la forma correcta para una aplicación que no sea del sistema para agregar widgets y lograr la misma experiencia de IU que el stock ICS launcher?

Respuesta

8

ahora sé la respuesta definitiva. En Android 4.0, no puedes hacerlo. Terminé haciendo que mis usuarios eligieran el widget dos veces, lo que es una mierda, pero no hay forma de evitarlo.

¡En Android 4.1 arreglaron el problema!

¡Las aplicaciones de SDK ahora pueden alojar widgets y no tienen que usar la API de selector de widgets de basura! Puede consultar el código fuente de Jellybean Launcher2 para obtener más detalles, pero básicamente, cuando intente enlazar un widget por primera vez, aparecerá un cuadro de diálogo que dice "¿Desea permitir que esta aplicación vincule widgets?", Y luego el usuario puede decide otorgarle permiso o no.

No estoy seguro de por qué eligieron el cuadro de diálogo modal de concesión de permisos en lugar del modelo all-permissions-on-install que han utilizado para todo lo demás, pero lo que sea, ¡funciona!

¡Ahora solo tenemos que esperar 4 o 5 años hasta que todos tengan Android 4.1 o superior!

12

Timmmm,

Su problema es que usted está buscando para el objeto equivocado. Realmente no puedes controlar el AppWidgetManager. No es tu trabajo, es el del Sistema. Lo que PUEDE hacer es controlar un AppWidgetHost, solo requiere algunas semánticas. Aquí están los básicos.

EDIT: Antecedentes adicional en el proceso de encuadernación Widget

El AppWidgetManager es un objeto único que se ejecuta cuando se inicia el sistema. Esto significa que cada instancia de cada iniciador utiliza el mismo AppWidgetManager. Lo que los diferencia es su AppWidgetHost y las RemoteViews que actualmente tienen. El AppWidgetManager básicamente mantiene una lista de todos los hosts activos y los widgets que tienen. Un AppWidgetHost no es un objeto privilegiado. Es decir, cualquier actividad puede tener un solo host. Por lo tanto, una aplicación completa puede ser nada más que Widgets, si así lo desean.

Cuando crea una instancia del host, debe agregarle vistas. Entonces, básicamente es una lista de Vistas secundarias sin límites parentales obligatorios, excepto lo que su Actividad le dé. Primero, solicite una identificación (a través del myHost.allocateAppWidgetId()). Luego usa su actividad/cuadro de diálogo Seleccionar widget. El Diálogo devuelve el WidgetInfo. La Vista se recupera cuando le solicita al Anfitrión que cree la Vista (a través del createView) con el WidgetInfo y la ID que solicitó. Luego le pregunta al widget por su RemoteView.

Finalmente, vincula el widget al colocar la Vista en su Actividad como un Niño. Esto se realiza mediante el método addView() del ViewGroup que contiene todos sus widgets.

El proceso en acción (editado)

En primer lugar, usted tiene que asegurarse de que tiene esto en su manifiesto de Android:

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

A continuación, usted tiene que crear una AppWidgetHost (extiendo el mío para mi lanzador). La clave para el host es mantener una referencia al AppWidgetManager a través del AppWidgetManager.getInstance();.

AppWidgetHost myHost = new AppWidgetHost(context, SOME_NUMERICAL_CONSTANT_AS_AN_ID); 

Ahora, obtener su ID:

myHost.allocateAppWidgetId() 

El siguiente paso se lleva a cabo por cualquier método que se utiliza para obtener la información del widget. La mayoría de las veces se devuelve mediante una intención a través de onActivityResult. Ahora, todo lo que tienes que hacer es usar la appInfo y crear la vista. El WidgetId normalmente lo proporciona el resultado de actividad de widget de selección.

AppWidgetProviderInfo withWidgetInfo 
     = AppWidgetManager.getInstance().getAppWidgetInfo(forWidgetId); 
AppWidgetHostView hostView 
     = myWidgetHost.createView(myContext, forWidgetId, withWidgetInfo); 
hostView.setAppWidget(forWidgetId, withWidgetInfo); 

Ahora solo enlaza la Vista como un niño a lo que quieras vincular.

myViewGroup.addView(hostView); 

Por supuesto, siempre hay que tener en cuenta dónde y cómo colocarlo, etc Además, usted tiene que asegurarse de que su AppWidgetHost es escuchar antes de empezar a añadir widgets.

myHost.startListening()

Para resumir

El proceso de unión Widget abarca muchos métodos y pasos, pero todo se produce a través de la AppWidgetHost. Debido a que los widgets están codificados fuera de tu espacio de nombres, no tienes ningún control excepto por dónde los pones y cómo dimensionas la vista. Dado que en última instancia son códigos que se ejecutan en su espacio pero fuera de su control, el AppWidgetManager actúa como un mediador neutral, mientras que el AppWidgetHost actúa como facilitador en nombre de su aplicación. Una vez que esto se entiende, su tarea es simple. Los pasos anteriores son todos los pasos necesarios para cualquier iniciador personalizado (incluido el mío).

EDIT: Aclaración final

El ICS Launcher hace esto también. El appWidgetManager que usan es solo un contenedor que contiene el AppWidgetHost y las llamadas al AppWidgetManager. Olvidé que muy poco de esto se explica en el sitio web de Android Development Central.

Espero que esto ayude! Avíseme si necesita más detalles.

FuzzicalLogic

+0

Gracias por la respuesta, pero desafortunadamente no parece resolver mi problema: 1. Creo que su uso de BIND_APPWIDGET no tiene ningún efecto, porque las aplicaciones que no son del sistema no pueden obtener ese permiso (vea el enlace en mi pregunta). 2. Estoy usando mi propia "actividad de widget de selección", la que está integrada en el iniciador de ICS. Puede que no haya entendido bien, pero estoy empezando a pensar que esto es imposible. – Timmmm

+0

Qué permisos se pueden dar depende de la ROM del teléfono/dispositivo. Por ejemplo, mi Samsung Moment me da ese permiso (no rooteado). Motorola Xoom (rooteado) no dará ese permiso, pero grita si no lo tengo. –

+0

¿Wow realmente? ¡Eso es ridículo! Parece que se pretende que no se lo den. Gracias por responder de todos modos. – Timmmm

4

acabo de encontrar este tutorial sobre cómo agregar appwidgets para aplicaciones normales, lo que podría ayudar: http://coderender.blogspot.com/2012/01/hosting-android-widgets-my.html

Este tutorial todavía utiliza la lista "AppWidget Selector", por lo que podría no funcionar para usted ya que ICS tiene el selector de widgets dentro del propio cajón de la aplicación.

embargo, valió la pena mencionar desde tutoriales sobre los widgets de alojamiento son muy raros :)

Cheers,
Yuvi

2

Fuzzical lógica, con su código de abajo,

AppWidgetProviderInfo withWidgetInfo 
     = AppWidgetManager.getInstance().getAppWidgetInfo(forWidgetId); 
AppWidgetHostView hostView 
     = myWidgetHost.createView(myContext, forWidgetId, withWidgetInfo); 
hostView.setAppWidget(forWidgetId, withWidgetInfo); 

si no tiene el permiso de bind_widget, widgethost tiene nada, cus withwidgetinfo es nulo, widgethost crear nada.

+1

para 'getAppWidgetInfo' para devolver un objeto, el' forWidgetId' debe estar ya enlazado: seleccionando el widget a través del selector de sistema o llamando a 'bindAppWidgetIdIfAllowed' o si eso devuelve falso simplemente' startActivityForResult (AppWidgetManager.ACTION_APPWIDGET_BIND) 'con los parámetros correctos (ver documentación). – TWiStErRob

Cuestiones relacionadas