Les éléments importants :

Dans AndroidManifest.xml :

<receiver android:name=".MonWidget" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/widget" />
        </receiver>

Il faut récupérer l'action APPWIDGET_UPDATE, et signaler la position d'un fichier xml qui décrit le widget, ici le fichier xml/widget.xml :

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="146dip" android:minHeight="72dip"
    android:updatePeriodMillis="2000" android:initialLayout="@layout/widget_layout" />

Il spécifie une taille minimale pour le widget. Pour obtenir la taille, mutipliez le nombre de cases voulues par 74 dip, puis enlevez 2 dip. Il faut également spécifier la période de mise à jour du widget, vous devriez garder cette valeur la plus haute possible pour réduire la consommation de votre widget, n'utilisez de faibles valeurs que pour le dev. Il faut également spécifier un layout initial pour notre widget, il s'agit d'un layout standard comme tout layout xml d'android, mais il subit les limitations que nous verrons plus bas.

Et enfin la classe MonWidget :

public class MonWidget extends AppWidgetProvider {
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {

        RemoteViews updateViews = new RemoteViews(context.getPackageName(),
                R.layout.widget_layout);
        
        updateViews.setTextColor(R.id.text, 0xFF000000);
        updateViews.setTextViewText(R.id.text, "Bonjour, Android");

        ComponentName thisWidget = new ComponentName(context, MonWidget.class);
        appWidgetManager.updateAppWidget(thisWidget, updateViews);
    }
}

Cette classe hérite AppWidgetProvider, la nouvelle classe du 1.5 qui est dédiée à la création de widget. Pour faire des actions à chaque update, il faut surcharger la méthode onUpdate et récupérer une RemoteViews de la manière ci-dessus.
Cependant, les widgets souffrent de limitations : la manipulation des vues doit se faire à travers le XML, et vous êtes obligés d'utiliser uniquement des vues de la liste suivante, sans possibilité d'y ajouter les vôtres :

AbsoluteLayout AnalogClock Button Chronometer FrameLayout ImageButton ImageView LinearLayout ProgressBar RelativeLayout TextView
De plus, la manipulation de RemoteViews offre assez peu de possibilités, il ne sera donc même pas possible d'utiliser toutes les fonctionnalités des vues autorisées (particulièrement au niveau de la détection de touches / pressions).

Les widgets sont donc de bons moyens de réaliser des agrégateurs de contenus, mais fabriquer un petit gadget interactif (du type xEyes par exemple) est pour l'instant impossible compte tenu des restrictions de sécurité.