Embauchez-moi

Je suis freelance ! Besoin d'un professionnel du développement web ? Pourquoi ne pas me passer un coup de fil ?

Plus d'infos sur… http://thibault.jouannic.fr

mots-cles : Ingénieur web freelance Symfony eZ Publish Solr

Créer un widget pour Android : exemples et bonnes pratiques

192/365 - Help, I'm Alive, My Heart Keeps Beating Like A Hammer
Creative Commons License photo credit : Helga Weber

Maintenant que nous avons un aperçu des concepts de base d’une application Android, nous allons nous lancer, et commencer par créer un widget.

Mais tout d’abord, qu’est-ce qu’un widget ? C’est un concept qui, il me semble (mais je n’en suis pas du tout sûr, ne me tapez pas si je me trompe) n’existe pas sur iPhone. Il s’agit d’une mini-application installable directement sur l’accueil du téléphone, et qui permet d’afficher des données et d’interagir avec l’utilisateur.

Les widgets sont à mon avis un des points forts d’Android : ils permettent d’avoir directement sous les yeux les données les plus importantes. Idéal pour afficher la météo, un calendrier ou une todo-liste, par exemple.

Attention, la documentation parle d’« App Widgets », pour éviter la confusion avec les traditionnels widgets de formulaires. Si on me demande mon avis, je trouve le nom particulièrement mal choisi. Mais personne ne me demande mon avis, alors nous ferons avec.

Avant de commencer, voici quelques bonnes pratiques que tout développeur de widget devrait suivre. Sinon quoi ? Sinon, vous allez énerver vos utilisateurs, qui auront vite fait de renvoyer votre widget dans les limbes.

  • Allez à l’essentiel : le but d’un widget n’est pas de remplacer une application complète. Il ne faut donc pas tenter de faire tenir toute son application dans un minuscule carré, mais plutôt fournir un raccourci vers les données / actions les plus importantes. Ce qui nous amène au point suivant :
  • Créez des widgets le plus petit possible : l’espace disponible sur la home est limité. Soyez respectueux, vous n’êtes pas tout seul. Si votre widget prend inutilement trop de place, il ne tardera pas à dégager.
  • Mollo sur la batterie : quand vous développez pour les mobiles, vos ressources sont trés limitées. Et c’est particulièrement vrai pour la durée de vie de la batterie. Soyez sympa avec vos utilisateurs, évitez de créer des widgets qui se mettent à jour trop souvent.

    Idéalement, un widget ne devrait pas se mettre à jour plus d’une fois toutes les 24h. Vous trouvez que ce n’est pas assez ? Offrez au moins à l’utilisateur la possibilité de configurer cette valeur. Mais une fois tous les quarts d’heures, c’est vraiment le maximum.

    Vous pensez que votre widget devrait se mettre à jour en temps réel ? U R DOING IT WRONG ! Ne cherchez pas, vous faites fausse route.

  • Travaillez l’aspect graphique : Google a émis des recommandations de design pour les widgets. Je sais que c’est trés personnel, mais je les trouve tout de même assez… repoussantes. J’attends avec impatience que Google fasse son boulot, et remédie à la situation. Si en plus on pouvait avoir le pack graphique en format gimp / svg, ce serait pas mal aussi, merci.
  • Ne créez pas un widget quand un lanceur suffit : je vois beaucoup d’applications / développeurs qui essayent d’émuler le fonctionnement d’un lanceur via un widget. C’est mal. Google recommande de ne pas le faire, d’abord parce que ça ne sert à rien, ensuite parce que l’aspect graphique des lanceurs n’est pas fixé. Le rendu de votre widget, super sur un beau HTC avec Sense, sera peut-être horrible chez un autre constructeur, ou avec une autre version d’Android.

Les mains dans le cambouis : déclarer son widget

Avant quoi que ce soit, nous allons déclarer notre widget dans le manifest du projet. Dans le fichier Manifest.xml :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="fr.miximum.widget" android:versionCode="1"
	android:versionName="1.0">
	<uses-sdk android:minSdkVersion="8" />
 
	<application android:icon="@drawable/icon" android:label="@string/app_name">
 
		<!-- Napply widget -->
		<receiver android:name="NapplyWidget">
			<intent-filter>
				<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
			</intent-filter>
			<meta-data android:name="android.appwidget.provider"
				android:resource="@xml/napply_widget_meta" />
		</receiver>
 
		<!-- Configure activity -->
		<activity android:name="WidgetConfigure" android:theme="@android:style/Theme.Dialog">
			<intent-filter>
				<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
			</intent-filter>
		</activity>
 
	</application>
</manifest>

Nous déclarons ici deux éléments. D’abord, le widget en lui-même. Ensuite, l’activity qui sera utilisée pour configurer notre widget à la création. Cette activity est facultative, mais nous allons en avoir besoin.

Notez que notre widget est déclaré via un tag « receiver », car les widget sont des broadcast receivers. En même temps, nous décrivons les types d’intents que le widget pourra recevoir. L’action « APPWIDGET_UPDATE » est une action système envoyée par Android lorsqu’il est temps de mettre à jour le widget. Les autres actions sont à usage interne, et seront envoyés par d’autres composants de notre application.

Un widget nécessite certaines metadatas pour fonctionner, qui sont définies dans un autre fichier xml. Ce fichier est référencé dans le tag « meta-data ».

Avant de voir ce fichier, notez que l’activity de configuration du widget est définie avec un style particulier qui la fera ressembler à une boite de dialogue. Notez également le filtre à intent utilisé.

Les metadatas

Voici le contenu du fichier res/xml/napply_widget_meta.xml :

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="72dp"
    android:minHeight="72dp"
    android:initialLayout="@layout/napply_widget_layout"
    android:updatePeriodMillis="0"
    android:configure="fr.miximum.widget.WidgetConfigure" >
</appwidget-provider>

Ces metadatas apportent les informations suivantes :

  1. La taille minimale du widget à l’écran. L’accueil par défaut d’Android est une grille de 4×4 cellules, et le côté minimal par défaut d’une cellule est de 74dp (density independant pixel). La formule pour calculer la longueur du côté est : (nb cellules * 74) – 2. Android arrondira automatiquement. Ici, on voit que notre widget nécessite une cellule en hauteur, et une en largeur.
  2. Le fichier de layout utilisé. Android respecte MVC, la vue des différents composants (le layout) est décrit dans des fichiers xml. Nous référençons ici le fichier qui décrira le layout du widget.
  3. La période d’update, c’est à dire la fréquence à laquelle Android lancera l’événement APPWIDGET_UPDATE. Comme nous allons gérer les mises à jour par nous même, nous désactivons cette valeur.
  4. L’activity de configuration, dont j’ai déjà parlé.

Et notre widget, il a quelle tête ?

Jusqu’à maintenant, nous n’avons fait que déclarer l’existence de notre widget. Nous allons maintenant définir à quoi il ressemble. Plus précisément, nous allons définir les éléments qui le composent, et quels styles leur appliquer. Dans le fichier res/layout/napply_widget_layout.xml :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/napply_widget"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_margin="4dp" >
 
    <TextView
        android:id="@+id/nap_time"
        android:text="Erase me"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:background="@drawable/widget_bg"
        style="@style/Widget.Text"/>
</RelativeLayout>

Il s’agit d’un layout trés simple : un simple champ texte centré verticalement dans un parent. Notez que nous affectons au texte un style (Widget.Text) et un fond (widget_bg).

Voici les styles utilisés (res/values/styles.xml) :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Widget">
        <item name="android:textColor">#fff</item>
    </style>
    <style name="Widget.Text">
        <item name="android:textSize">20dp</item>
        <item name="android:padding">7dp</item>
    </style>
</resources>

Rien de trés sorcier là-dedans. En ce qui concerne le fond, il est possible d’utiliser des images png, éventuellement améliorées avec la technique des ninepatch. Voyez cet exemple de 9patch, créé pour une autre de mes appli, et qui reprends le style du widget d’accueil d’Android.

Pour aller au plus simple, j’utiliserai ici une forme géométrique, définie dans le fichier res/drawable/widget_bg.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!-- Un bête rectangle aux bords arrondis, avec un dégradé en fond et un bord blanc -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
	android:shape="rectangle">
 
	<corners android:radius="7dp" />
	<stroke android:width="2dp" android:color="#ffffff" />
	<gradient android:angle="270" android:startColor="#cc333333"
		android:endColor="#cc000000" />
</shape>

Rendez-nous le Java, on a Champomy !

J’espère que vous aimez le xml, parce que pour le moment, nous n’avons mangé que ça. Mais rassurez-vous, le Java arrive.

Dans un premier temps, nous allons définir un widget qui ne fait que s’afficher à l’écran. C’est tout ? C’est tout !

/*
 * © Copyright 2011 Thibault Jouannic <thibault@jouannic.fr>. All Rights Reserved. Bla bla bla
 */
 
package fr.miximum.widget;
 
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.widget.RemoteViews;
 
public class NapplyWidget extends AppWidgetProvider {
 
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        final int N = appWidgetIds.length;
 
        // Perform this loop procedure for each App Widget that belongs to this
        // provider
        for (int i = 0; i < N; i++) {
            int appWidgetId = appWidgetIds[i];
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }
 
    /**
     * Update the widget
     *
     * @param context
     * @param appWidgetManager
     * @param appWidgetId
     */
    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
 
        // Prepare widget views
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.napply_widget_layout);
        views.setTextViewText(R.id.nap_time, "Erase me");
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }
}

Que fait cette classe ? D’abord, elle étend AppWidgetProvider, qui fournit des helpers à la création de widgets. La fonction « onUpdate » est appelée quand le widget reçoit un intent avec l’action APPWIDGET_UPDATE. À ce moment, la fonction d’update est appelée, qui récupère un objet layout à partir du xml via la classe RemoteViews, et qui l’affecte au widget.

Une fois cela fait, une instance de la classe « AppWidgetManager » est chargée de redessiner le widget.

Intrigué par la séquence « R.layout.napply_widget_layout » ? La classe « R » est automatiquement créée lors de la construction du projet, et contient des références à divers éléments déclarés dans le Xml.

Alors, je peux afficher mon widget ? Pas encore ! Car nous avons déclaré une activity de configuration du widget, et il faut la définir. Voici la classe WidgetConfigure :

package fr.miximum.widget;
 
import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
 
public class WidgetConfigure extends Activity {
 
    private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
 
    /** Called when the activity is created */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        // If the user closes window, don't create the widget
        setResult(RESULT_CANCELED);
 
        // Find widget id from launching intent
        Intent intent = getIntent();
        Bundle extras = intent.getExtras();
        if (extras != null) {
            mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
                    AppWidgetManager.INVALID_APPWIDGET_ID);
        }
 
        // If they gave us an intent without the widget id, just bail.
        if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
            Log.e("Napply", "Configuration Activity: no appwidget id provided");
            finish();
        }
 
        configureWidget(getApplicationContext());
 
        // Make sure we pass back the original appWidgetId before closing the activity
        Intent resultValue = new Intent();
        resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
        setResult(RESULT_OK, resultValue);
        finish();
    }
 
    /**
     * Configures the created widget
     * @param context
     */
    public void configureWidget(Context context) {
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        NapplyWidget.updateAppWidget(context, appWidgetManager, mAppWidgetId);
    }
}

Cette activity est la plus simple possible, c’est à dire qu’elle ne fait… rien. Au démarrage, elle configure le widget, et se ferme automatiquement.

Ensuite, selon les besoins, il sera possible de déclarer un layout, et d’effectuer toutes les actions possibles nécessaires à l’initialisation du widget.

Et au final…

Tout est maintenant prêt, il ne reste plus qu’à tester. Pour ça, il va falloir utiliser le SDK pour déclarer et lancer un émulateur Android. Ensuite, il suffira de construire le projet pour qu’il soit installé sur l’émulateur.

Enfin, sur l’émulateur, activez le widget pour obtenir ce résultat à la beauté indescriptible.

I want some action !

Notre widget est pour le moment d’une immobilité qui n’est pas sans rappeler certains parti politiques français (plutôt de gauche)[1], aussi allons nous lui rajouter un peu d’action : en cliquant dessus, je veux afficher un message de notification.

Dans la classe « NapplyWidget », voici le nouveau corps de la méthode « updateAppWidget » :

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
 
        // Prepare widget views
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.napply_widget_layout);
        views.setTextViewText(R.id.nap_time, "Erase me");
 
        // Prepare intent to launch on widget click
        Intent intent = new Intent(context, NapplyWidget.class);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        intent.setAction(ACTION_SHOW_NOTIFICATION);
 
        // Launch intent on widget click
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
        views.setOnClickPendingIntent(R.id.napply_widget, pendingIntent);
 
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

Nous déclarons un intent, avec une action spécifique (ACTION_SHOW_NOTIFICATION), qui sera envoyé à notre widget même. Ensuite, via la classe PendingIntent, nous indiquons que notre intent initial sera envoyé au clic sur le widget.

N’oubliez pas de définir la variable de classe :

public static final String ACTION_SHOW_NOTIFICATION = "fr.miximum.widget.SHOW_NOTIFICATION";

Puisque notre widget doit pouvoir recevoir cet intent, il ne faut pas oublier de le définir dans le Manifest :

<!-- Napply widget -->
<receiver android:name="NapplyWidget">
	<intent-filter>
		<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
		<action android:name="fr.miximum.widget.SHOW_NOTIFICATION" />
	</intent-filter>
	<meta-data android:name="android.appwidget.provider"
		android:resource="@xml/napply_widget_meta" />
</receiver>

Désormais, en cliquant sur notre widget, on lui envoie une intent avec l’action SHOW_NOTIFICATION. Seulement, ce message, nous n’en faisons pour le moment rien du tout. Remédions-y :

 
    /**
     * Handle new messages
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
 
        if (ACTION_SHOW_NOTIFICATION.equals(intent.getAction())) {
            showNotification(context);
        }
    }
 
    /**
     * Displays a notification message
     * @param context
     */
    protected void showNotification(Context context) {
        CharSequence message = "Clique moi ! Clique moi ! Clique moi !";
        int duration = Toast.LENGTH_SHORT;
        Toast toast = Toast.makeText(context, message, duration);
        toast.show();
    }

Le code est assez limpide, aussi me passerai-je de le commenter.[2] Encore une fois, le résultat est difficilement soutenable de beauté.

C’est tout pour aujourd’hui. La prochaine fois, nous jouerons avec les alarmes d’Android.

Notes :

  1. Oulà le troll ! [retour]
  2. il est midi, j’ai faim [retour]

Android : découvrir les concepts de base

Exemple de widget android

Voici donc notre premier article sur le développement d’applications Android. Dans cet article, nous allons découvrir quels sont les concepts de base d’Android, et comment ces composants s’articulent pour créer une application.

J’utiliserai Napply, l’application décrite dans mon article précédent, comme exemple de base. Pour les distraits et les paresseux, je rappelle que Napply est un widget qui permet de configurer son réveil en un clic. Jetez un coup d’œil à la capture ci-jointe pour avoir une idée du rendu final.

Je rappelle aussi que Napply est un logiciel-libre. Vous pouvez récupérer le code source, et construire vous-même le projet final.

Tout le monde est prêt ? C’est parti !

Première étape, installer son environnement de travail

Force est de constater que Google a mis le paquet pour nous favoriser la tâche des développeurs Android. Pour preuve, le SDK est extrèmement complet, et les outils mis à notre disposition nombreux et puissants. Enfin, tout ceci est parfaitement intégré dans un plugin Eclipse, ce qui fait qu’il est assez difficile (à mon grand dam, d’ailleurs) de se passer de cet IDE.

La première étape sera donc d’installer le SDK, de configurer son Eclipse, et vogue la galère ! Comme ces procédures sont déjà décrites extensivements, je serai fainéant et vous redirigerai vers d’autres introductions à Android.

Vous êtes paré ? Passons à la suite.

Découvrir les concepts de base

Toute application Android est invariablement composée des même briques de base, à savoir :

  • Activity : pour faire simple, une activity correspond à une fenêtre de votre application. Dans Napply, j’ai deux activities. La page « About » qui liste les instructions d’utilisation et qui se lance à l’installation de l’appli, et la page de configuration du widget, qui permet de choisir la durée de la sieste.
  • Service : un service est un processus qui effecute des traitements en arrière plan. On peut utiliser un service pour effectuer des traitements un peu trop couteux pour être lancés par une activity (et qui feraient freezer l’interface), ou l’utiliser réellement comme un daemon unix, et le laisser tourner ad vitam aeternam.

    Dans Napply, c’est un service qui se réveille quand un réveil doit sonner, et qui stream le fichier audio choisi.

  • Broadcast Receiver : c’est un écouteur de messages. Le système Android, de même que les autres applications, peuvent envoyer des messages dans le vent, sans spécifier de destinataires spécifiques. Par exemple, un message est envoyé pour indiquer que le système a fini de démarrer. Ou quand un nouveau signal wifi est détecté. Ou quand un nouveau sms est reçu.

    Les broadcast receivers peuvent s’enregistrer comme destinataires de certains types de messages. À la réception, ils seront alors libres d’effectuer d’autres actions.

    Dans Napply, quand l’alarme s’interrompt, le service lance un message ALARM_TERMINATED. La fenêtre de dialogue qui affiche les boutons « Snooze » et « Quitter » est à l’écoute de ce message, et se ferme automatiquement à sa réception.

    À noter : les widgets sont des broadcast receivers.

  • Content Provider : une application peut utiliser différents moyens de stocker des données (sql, préférences, fichier, réseau, etc.). Implémenter un content provider permet aux autres composants de l’application, et éventuellement aux autres applications, de récupérer ces données de manière centralisée.
  • Intent : j’ai parlé plus haut des messages envoyés par le système Android. Ces messages sont appelés Intent. Les intents sont de basiques structures de données remplies d’informations diverses. Les composants d’une application (sauf les content providers) sont lancés via des intents. Par exemple, quand mon widget démarre le service interne de gestion d’alarme, il envoie en fait un intent. Quand je clique sur le bouton « snooze », mon activity envoie un intent au service. etc.

    Les intents permettent aussi la communication inter-applications. Lancer un intent de mon appli me permet ainsi de démarrer une autre activité, fournie par une autre application, et de récupérer son résultat.

À l’aune de ces explications, voici comment s’articule notre application :

Décrire son application

Dernier élément de notre application : le fichier manifest. Tous les éléments de l’application qui doivent être portés à la connaissance du système Android doivent être décrits dans un fichier Manifest.xml, présent à la racine du projet. Ce fichier sert également à déclarer les prérequis de l’application, comme les permissions requises, ou la version minimale de l’OS nécessaire.

Pour exemple, voici le manifest final du projet :

<?xml version="1.0" encoding="utf-8"?>
<!-- © Copyright 2011 Thibault Jouannic <thibault@jouannic.fr>. All Rights 
	Reserved. This file is part of Napply. Napply is free software: you can redistribute 
	it and/or modify it under the terms of the GNU General Public License as 
	published by the Free Software Foundation, either version 3 of the License, 
	or (at your option) any later version. Napply is distributed in the hope 
	that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
	warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
	GNU General Public License for more details. You should have received a copy 
	of the GNU General Public License along with Napply. If not, see <http://www.gnu.org/licenses/>. -->
 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="fr.miximum.napply" android:versionCode="1"
	android:versionName="1.0.0">
 
	<uses-permission android:name="android.permission.VIBRATE" />
	<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
	<uses-permission android:name="android.permission.WAKE_LOCK" />
 
	<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="8" />
 
	<application android:label="@string/app_name" android:icon="@drawable/ic_launcher_napply">
 
		<!-- Napply widget -->
		<receiver android:name="NapplyWidget">
			<intent-filter>
				<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
				<action android:name="fr.miximum.napply.START_ALARM" />
				<action android:name="fr.miximum.napply.CANCEL_ALARM" />
				<action android:name="fr.miximum.napply.ALARM_TERMINATED" />
			</intent-filter>
			<meta-data android:name="android.appwidget.provider"
				android:resource="@xml/napply_widget_meta" />
		</receiver>
 
		<!-- Configure activity -->
		<activity android:name="WidgetConfigure" android:theme="@android:style/Theme.Dialog">
			<intent-filter>
				<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
			</intent-filter>
		</activity>
 
		<!-- Ring alarm service -->
		<service android:name="AlarmService">
			<intent-filter>
				<action android:name="fr.miximum.napply.RING_ALARM" />
				<action android:name="fr.miximum.napply.CANCEL_ALARM" />
				<action android:name="fr.miximum.napply.SNOOZE_ALARM" />
			</intent-filter>
		</service>
 
		<!-- Dialog to show cancel/snooze dialog -->
		<activity android:name="AlarmCancelDialog" android:label="@string/wake_up"
			android:theme="@android:style/Theme.Dialog">
		</activity>
 
		<activity android:name="About" android:label="@string/app_name">
			<intent-filter>
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
	</application>
</manifest>

Vous constaterez que l’on déclare ici les différents éléments de notre application : le widget, les activities, le service. Vous noterez également que l’on indique quels sont les types d’intent que recevront ces différents éléments.

C’est tout pour aujourd’hui. Dans notre prochain article, nous apprendrons à créer un widget.

Petite incursion dans le monde Android

androids eat apples!
Creative Commons License photo credit : laihiu

Tousse ! Tousse ! Tousse ! Pardonnez-moi, en ouvrant l’admin de mon blog, j’ai soulevé un sacré nuage de poussière qui encombre mes bronches. Laissez-moi ouvrir la fenêtre. Voilà qui est mieux.

Maintenant qu’il fait plus clair, je vais écrire sur le sujet du développement Android. J’ai en effet passé le dernier mois plongé dans le monde du système d’exploitation ouvert pour smartphones de Google, à tenter de maîtriser les arcanes du développement d’applications mobiles.

Étant donnée ma condition de développeur web professionnel, pénétrer l’univers d’Android a été comme de découvrir un nouveau monde, avec ses règles, ses lois, et son écosystème propre. Moi qui, il y a quelque temps, pensait que les nouvelles technos web (html5, css3, etc.) allaient rendre le développement mobile natif obsolète, me voilà aujourd’hui avec un avis tout différent.

Certes les nouvelles apis sont séduisantes, et permettront sans doute de concevoir des webapps performantes, mais le temps que ce soit fonctionnel et largement adopté, les quelques cheveux me restant seront sans doute blancs depuis longtemps.

Au secours ! Encore du web ?!

Not getting Involved
Creative Commons License photo credit : TarikB

C’est un avis personnel, mais je pense que ces technos ont raté le coche. Dans un monde parfait, elles seraient apparues 7 ou 8 ans plus tôt, auraient eu le temps de devenir matures, été utilisées pour concevoir la palanquée de services web2.0 apparue plus ou moins récemment, et été intégrées nativement dans les OS de smartphones.

Alors, elles auraient rempli leur rôle : fournir au monde un système de développement unifié et uniformisé, permettant de concevoir des systèmes d’informations simples ou complexes, sur un jeu de plate-formes hétéroclites.

Il s’agit malheureusement d’une douce utopie. J’ai encore des clients qui se plaignent que leur site est lent avec IE6, et le langage emblématique du web est juste un gros bricolage. Et ça me fatigue.

Bienvenue dans le monde Android

Hotline
Creative Commons License photo credit : splorp

Alors voilà, aujourd’hui, point de solution miracle pour concevoir des applications ouvertes multi plateformes. Venant de ce monde là, et habitué à l’hétéroclisme des technos web, découvrir l’écosystème Android fut agréablement rafraichissant.

Les avantages d’Android :

  • Android propose une API cohérente et unifée. J’ai un système d’exploitation sur lequel je me greffe, entièrement réalisé à partir d’un ensemble restreint de technologies parfaitement intégrées entre elles. Je fais du Java, du Xml, éventuellement un peu de SQL, et basta.
  • Android est documenté. Je veux faire une appli ? Je vais sur la doc du développeur Android, et j’ai sous les yeux TOUTES les étapes à suivre, de l’installation de l’environnement de dev, jusqu’à la publication de mon projet.
  • Android est ouvert (du moins, jusqu’à un certain point). Oui, c’est open-source. Et oui, le libre, c’est important
  • Android propose une facilité de publication. Je créé un compte sur le market, je clique sur publier, j’upload mon appli, et dans la minute, elle est disponible.
  • Ce n’est pas du PHP. Java, on aime ou on n’aime pas, mais quand on vient du monde PHP, qu’est-ce que ça soulage de bosser avec des technos un peu rigoureuses.

Évidemment, tout n’est pas non plus parfait. Allez, en vrac, quelques trucs qui me chiffonent :

  • Ça manque d’uniformisation. Surtout quand on compare ça avec le monde Apple, il est parfois risible de voir à quel point des applications peuvent être moches, et diverger entre elles en terme de présentation et d’affichage.
  • Ça tourne sur tout et n’importe quoi. Android a les défauts de ses qualités : quand vous créez une appli, il faut considérer qu’elle sera potentiellement installable sur des smarthones superévolués, sur des téléphones à l’écran riquiqui, sur des tablettes, des télés, et même des radios. La guerre des navigateurs, à côté, c’est un pique-nique sur l’herbe.
  • C’est fragmenté. Les versions d’Android se succèdent, et les constructeurs traînent parfois la patte à mettre à jour leur firmwares. On se retrouve alors avec un marché extrèmement fragmenté en termes de versions, et une portion non négligeable des téléphones tourne avec des versions obsolètes[1].
  • Big Brother is watching you. La décentralisation des données, vous connaissez ? Avec l’installation par défaut, vous en serez pour vos frais : gmail, gtalk, gmap, glocations, genpasseetdesmeilleurs, j’ai presque l’impression d’avoir vendu mes données et mon âme au diable.
  • C’est du Java. Bon, c’était gratuit. Mais avant de commencer, j’ai fait un mois de Python. Et passer de Python à Java, c’est rude.

Alors, on commence ?!

Ascension ou Décadence
Creative Commons License photo credit : Jean Lemoine

Je parle, je parle, mais je vous sent impatients de mettre les doigts dans le cambouis. Sans discutailler plus longtemps, je vous propose de jeter un œil au projet que je vais mettre en œuvre dans les futurs articles. Mais d’abord, une petite histoire.

Après le déjeuner, j’aime faire une petite sieste. Mais pas trop longtemps, sinon je me réveille de mauvaise humeur. Alors je prends mon téléphone. J’ouvre l’appli horloge. Je vais dans l’onglet réveil. Je configure le réveil pour sonner dans 25 minutes. Je ferme l’appli. Je passe le téléphone en mode silencieux. Et je peux dormir.

Ça ne me convient pas. Ce n’est pas simple. C’est trop complexe. Et si je me rends compte que j’ai oublié d’envoyer un mail urgent juste après avoir réglé l’alarme ? Je suis bon pour recommencer.

De plus, quand le réveil sonne, je dois poser mon doigt sur l’un des minuscules boutons « Répéter » ou « Quitter ». Je ne sais pas pour vous, mais personnellement, au réveil, j’ai l’occiput dans l’arrière-train, et localiser le bon bouton pour poser le doigt dessus est une tâche pénible.

Enfin, après ma sieste, j’ai une facheuse tendance à oublier de désactiver le mode silencieux, et à louper des appels.

Alors je me suis dit : « Je peux faire mieux ».

Découvrez Napply, le compagnon du siesteur

Merry sleepy christmas!
Creative Commons License photo credit : Dr. Hemmert

Comme la plupart des outils à succès, celui-ci a été conçu en réponse à la question : «  Quel serait mon outil rêvé ?  »

Dans mes rêves, je configure mon téléphone d’un seul geste. Je touche un bouton, et paf ! L’alarme est réglée, et le mode silencieux activé. Je peux dormir.

Dans mes rêves, quand je dois appuyer sur un bouton alors que je viens de me réveiller, ce bouton est énorme, et je ne risque pas de me tromper.

Dans mes rêves, quand je veux dormir quelques minutes de plus, je n’ai même pas besoin d’ouvrir les yeux : je saisi mon téléphone en tatônnant, et je le retourne. Paf, la sonnerie s’arrête, la répétition est activée, et je me rendors.

Dans mes rêves, quand je termine ma sieste, le mode silencieux de mon téléphone se désactive automatiquement.

Un rêve ? Plus maintenant, car cette application existe désormais. Si elle ne changera pas le monde, elle fait déjà un heureux : moi. Dans les prochains articles, nous allons prendre cette application pour base pour introduire différents concepts de développement d’applications Android.

D’ici là, faites de beaux rêves !

Notes :

  1. Je remarque qu’au fil des semaines, la situation semble s’améliorer toutefois [retour]

Lettre à mon administration

De : moi
À : L’adresse de contact de la DRJSCS34 (Direction Régionale de la Jeunesse, des Sports et de la Cohésion Sociale)

Madame, Monsieur,

Présent mercredi 23 février à la réunion de lancement de la campagne 2011 du CNDS, j’ai pu aujourd’hui récupérer les dossiers de demandes de subvention sur le site de la DRJSCS.

Je remarque toutefois que les dossiers ne sont disponibles qu’au format Microsoft Word (.doc). Peut-être savez-vous que ce format de fichier n’est pas le plus approprié pour créer et transmettre des documents publics ?

En effet, le format doc est la propriété de la société Microsoft, et ne peut être lu avec une fiabilité certaine que sur les logiciels de cette société (Word).

Il ne me semble pas trés éthique qu’une administration impose l’utilisation de logiciels coûteux (Windows + Office), alors même qu’il existe des alternatives libres d’utilisation et gratuites (ex : LibreOffice, anciennement OpenOffice).

My Reference Files
Creative Commons License photo credit : Tim Morgan

Par ailleurs, il existe des formats de fichiers standardisés (ex : OpenDocument), destinés à garantir l’interopérabilité dans l’échange de documents entre différentes suites bureautiques et différents systèmes d’exploitation. Il me semble que de par sa nature, l’administration publique devrait être attentive à l’accessiblité des informations qu’elle publie, et se contraindre à utiliser ces formats.

Enfin, je sais que le coût d’achat des licenses permettant d’utiliser les logiciels Windows et Microsoft Office est important. Je suis concerné par le fait que de l’argent public soit investi dans ces licences, alors même qu’il existe, je le répète, des alternatives libres et gratuites (LibreOffice, Linux).

Aussi, en tant que simple citoyen, j’aimerais connaître les raisons qui motivent l’utilisation de ces formats et l’investissement dans ces logiciels.

Je me tiens à votre disposition pour évoquer ces points avec vous. Dans l’attente de votre réponse, veuillez agréer, Madame, Monsieur, mes salutations distinguées.

SudWeb, plus qu’un mois pour répondre à l’appel à orateurs

Ceux qui ont passé les derniers mois en vacances au pôle nord ne sont peut-être pas au courant que le jeune et dynamique SudWeb a publié un appel à conférences. Attention, il ne reste plus qu’un mois pour y répondre.

Les valeureux élus auront le privilège de faire partie de la toute première édition d’un événement qui, à l’instar de son grand frère ParisWeb, deviendra n’en doutons pas incontournable. En plus, ils seront chouchoutés par l’équipe d’organisation, qui est composée de tout plein de membres super sympas, sans compter qu’ils pourront profiter du temps magnifique du Languedoc.

Allez, on se motive, hop ! hop ! hop !

Bye bye 2010 ! 2011, à nous deux !

Changer d’année me rends toujours un peu sentimental. Beaucoup d’amis, beaucoup d’amour, beaucoup de fêtes, de joie, de bonne chère et d’alcool (parfois un peu trop). Et une nouvelle année, toute belle, toute neuve, encore vierge, pleine de promesses et d’espoirs.

Puisse-t-elle être remplie de projets enthousiasmants, de rencontres enrichissantes, de voyages enchantants, et aussi d’épreuves, car les erreurs, les chutes, les échecs et les coups dans la tronche nous font grandir, pour peu qu’on les prenne pour ce qu’ils sont : des cadeaux du destin, des leçons de vie. Tomber sept fois, se relever huit.

En cette période d’allégresse et d’incertitudes, j’aime bien me retourner pour une petite rétrospective. Histoire de saluer dignement l’année qui s’enfuit, et d’entrer fermement dans celle qui démarre. Allez, c’est parti…

Mon top 3 bouquins

Mon top 3 découvertes musicales

  • Fito y los Fitipaldis. Je viens de décider qu’il s’agit du meilleur groupe de rock’n'roll de tous les temps. Du rock, du pur, du vrai. Du qui décrasse les oreilles.
  • Imelda May. Tout simplement.
  • Tom Waits. Mieux vaut tard que jamais. Cette voix… rauque…

Mon top 3 cinéma

  • Solutions locales pour un désordre global, un documentaire passionant sur l’agriculture, l’écologie, les paysans…
  • Fleur du désert. Biopic de Waris Dirie. J’avoue, j’ai pleuré.
  • Sing Lek Lek Tee Reak Wa Rak, une romance à l’eau de rose, au scénario banal à pleurer, et qui enchaîne cliché sur cliché… Et pourtant, j’en garde un tendre souvenir. Peut-être parce que je l’ai vu en Thaïlande, en VO, sans sous-titres. Et puis, c’est tellement bien joué :)

Mon top 3 bonnes idées

  • Apprendre le bépo : qu’il est bon de pouvoir clavioter des heures sans pratiquement bouger les doigts, sans plus ressentir aucune fatigue, aucune douleur, aucune usure dans les articulations.
  • Me mettre à mon compte. Quand même, lâcher son boulot et monter son affaire, c’est quelque chose. Ça change la vie. J’aime.
  • Passer à Python. C’est trés récent. C’est même en cours. Mais utiliser des vraies, des bonnes technos. Avec la communauté et les outils qui vont bien derrière… C’est rafraichissant. C’est bon. Ça me fait aimer mon métier plus que jamais.

Mon top 3 gros foirages

  • Me péter la clavicule le jour de mon départ en vacances.
  • Être malade pendant la soirée du nouvel an.
  • Allumer la mauvaise plaque électrique. Celle sous l’énorme pile de vaisselle en plastique.

Mon top 3 bonnes résolutions

  • Me mettre au développement mobile.
  • Vivre, apprendre, aimer
  • Continuer à être parfait ;)

Mon top 3 leçons apprises

  • Si tu es cher, on retiendra que tu es compétent. Si tu es bon marché, on retiendra… que tu es bon marché.
  • La peur de se lancer est souvent le plus grand obstacle qui nous retiens de faire de grandes choses.
  • Rien ne te fera autant grandir qu’une épreuve à surmonter.
  • En bonus : Quand tu es bourré… éteins ton téléphone mobile.

Bonne année à tous !