Apache Adobe Flex TutorialTutoriaux Adobe Flex & AIR en Français

19sept/100

AIR pour Android – Application P2P Radar (Google Maps 3D, Twitter et Stratus)

Avec l'arrivée du SDK Android 2.5 qui commence à être très complet et fonctionnel, on voir arriver de nombreuses applications, présentées sous la forme de mashup. Un mashup, pour ceux qui auraient raté la grande époque du web 2.0, c'est une application qui fait cohabiter et communiquer plusieurs services Web.

Chez Adobe, il y a LCCS (LiveCycle Collaboration Service) qui propose de nombreux services (partage de bureau à distance, communication webcam / audio, tableau blanc partagé, chat, etc.) mais on peut bien sûr utiliser les services d'autres APIs. Parmi les plus célèbres, on a Google Maps (API la plus populaire sur le net) par exemple, qui vous permet d'afficher une carte gratuitement.

L'application présentée dans ce billet est nommée P2P Radar. C'est une application Air (bureautique) avec une version pour Android qui est basée sur le même code source:

P2P-Radar from Mark Doherty on Vimeo.

Elle est développé par un Adobe Platform Evangelist (India) nommé Mark Doherty.

Comme vous pouvez le voir sur cette vidéo, on commence par se logger sur Twitter. Cela se fait grâce au nouveau composant StageWebView d'Adobe 2.5  qui permet d'intégrer dans votre application, le navigateur natif d'Android (un peu comme le fait le composant HTMLLoader classique d'Air). Une fois authentifié, l'application permet d'afficher une carte du monde des différentes personnes connectées à l'application. Celles-ci sont affichées sur la carte 3D par des markers.

Grâce aux possibilités de Peer 2 Peer offertes par le service Stratus, les personnes connectées peuvent communiquer directement. Dans le cas de cette application, on peut appeler directement l'autre personne.

Voici le lien vers l'article original. Bonne nouvelle pour les curieux, les sources sont disponibles en téléchargement !

P2P Radar for Android

18sept/100

AIR pour Android – Empêcher la mise en veille de l'écran, pour application vidéo par ex.

L'API permet de modifier la mise en veille automatique de l'écran. En effet, la mise en veille de l"écran un téléphone est très rapide sur les environnements mobiles pour pouvoir économiser la batterie au maximum. Ainsi, si le système ne détecte aucune action utilisateur (tap ou touche), l'écran va se mettre en veille après environ 1 minute.

Ce comportement par défaut permet donc d'économiser la durée de vie de la batterie mais parfois, il va interrompre l'expérience utilisateur. L'exemple le plus courant est celui d'un player vidéo en Air. Si vous activez la lecture de la vidéo, l'utilisateur ne fera pas forcement d'action (tap) pendant la lecture. Il devrait donc rallumer le téléphone toutes les minutes ce qui peut devenir géant.

Pour ce genre d'application, Air propose une API indiquant au système qu'il ne doit pas éteindre l'écran. Il suffit d'utiliser la propriété "systemIdleMode" et de lui assigner une constante de la classe SystemIdleMode.

Une fois la vidéo lue, n'oubliez pas de repasser l'application dans un mode de mise en veille classique afin de ne pas drainer la batterie.

Code de démonstration

Stopper la mise en veille du mobile:

NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;

Remettre le système dans un mode normal:

NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.NORMAL;

Permissions Android

Pour pouvoir utiliser cette fonctionnalité, il vous faut ajouter une permission Android. Ainsi, lors de l'installation de l'application, l'utilisateur sera averti que l'application peut modifier le mode de mise en veille.

Pour rajouter ces permissions, modifiez le descripteur XML de votre application:

<android>
 <manifestAdditions>
  <![CDATA[
  <manifest>
   <uses-permission android:name="android.permission.WAKE_LOCK" />
   <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
  </manifest>
  ]]>
 </manifestAdditions>
</android>
17sept/102

Flash, Flex et intégration continue: Le guide complet (SVN, Maven, Hudson & co)

Si vous travaillez dans une grosse entreprise, vous avez forcement entendu parler d'intégration continue (Continuous Integration alias CI). Si vous ne connaissez pas cette technique, je vous invite vivement à vous y intéresser :) .

Comme son nom l'indique, cette technique implique l'intégration continue de votre code ainsi que le lancement de tests à intervalles régulier. Le processus d'intégration continue est intimement couplé à celui du versionning (SVN par ex.) de votre code source. Ainsi, lorsqu'un utilisateur va faire un "commit" (envoi de modification vers le versionning), le processus d'intégration continue peut lancer un build pour vérifier l'intégrité du code.

Dans le même temps, si vous avez créé des tests unitaires, ceux-ci seront lancés automatiquement. Si le processus échoue, vous pouvez être averti, par mail par exemple.

L'intégration continue est souvent faite sur une machine, qui va automatiser le processus. Cette machine est souvent appelé serveur d'intégration continue. Elle va s'occuper de récupérer les sources, capter les commit, lancer les builds / test etc. Une fois le build effectué, cela vous permet aussi d'avoir un emplacement où seront placées les dernières versions de votre application (aussi appelées SNAPSHOT). Les solutions les plus connues sont Hudson et CruiseControl.

La mise en place d'un système d'intégration continue est considéré comme une bonne pratique dans le monde du développement. En effet, elle procure de nombreux avantages mais peu parfois être longue et laborieuse.

Pour vous aider dans la mise en place d'un serveur d'intégration continue, voici d'excellents articles:

Cas réel d'utilisation chez Business Geografic

L'entreprise dans laquelle je travaille (Business Geografic) a mis en place un système d'intégration continue. Ce système est basé sur les technologies:

  • SVN pour le versionning (Git pour certains)
  • Maven pour la gestion des dépendances
  • FlexMojos pour la compilation des projets Flex avec Maven
  • Nexus comme gestionnaire de repository Maven
  • Ant (pour tout ce que Maven ne sait pas faire)
  • Hudson comme serveur d'intégration continue
  • Redmine comme Bug Tracker

Le processus est maintenant au point mais sa mise en place a pris plusieurs mois, avec 2 personnes d'en occupant régulièrement. Il faut dire que notre cas n'est pas le plus simple car c'est un mix de nombreuses technologies avec des projets très important à gérer (en terme de volume).

Remplis sous: ActionScript Lire la suite
16sept/100

AIR pour Android – Parcourir la carte SD et lire une image avec File et FileStream

Dans le tutorial précédent, on a vu que l'on pouvait accéder à la carte mémoire du portable Android grâce à la classe File et ses propriétés static (userDirectory & co). Tout comme on peut lire des fichiers du disque dur d'un ordinateur avec Air, on peut lire les fichiers de la carte SD du mobile Android.

Dans cette application, je permet de lister le contenu du dossier de la carte SD puis d'ouvrir un fichier par son nom. J'ai fait une sorte de navigateur ultra simplifié, on a le listing à plat des dossiers (sans afficher les dossiers cachés). Lorsque l'on double click dans la liste, cela ouvre le dossier et liste le détail des fichiers / dossiers qui la compose.

Le bouton BACK du téléphone ou le bouton "Browse SD Card" permettent de revenir à la racine de la carte SD.

Lorsque l'on double-click sur un fichier image, celui-ci est chargé dans l'application. J'aurai pu faire l'effort de lire les fichiers audio et texte mais j'ai eu la flemme :P . On peut bien sûr lire n'importe quel fichier (XML, texte, …).

Pour l'ouverture de fichiers, j'utilise les classes File et FileStream:

http://livedocs.adobe.com/flex/3/langref/flash/filesystem/File.html

http://livedocs.adobe.com/flex/3/langref/flash/filesystem/FileStream.html

Code de l'application

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" paddingLeft="0" paddingRight="0"
                paddingTop="0" paddingBottom="0"
                applicationComplete="application1_applicationCompleteHandler(event)">
  <mx:Style>
    global {
      font-size: 24;
    }
  </mx:Style>
  <mx:Script>
    <![CDATA[
      import mx.collections.ArrayCollection;
      import mx.events.FlexEvent;
      import mx.events.ListEvent;

      [Bindable]
      private var _files:ArrayCollection = null;

      protected function application1_applicationCompleteHandler(event:FlexEvent):void {
        this.stage.addEventListener(KeyboardEvent.KEY_DOWN, downHandler);
        onGetDirectories();
      }

      public function downHandler(event:KeyboardEvent):void {

        switch (event.keyCode) {
          case Keyboard.BACK:
            // to prevent app going to background use following
            event.preventDefault();
            onGetDirectories();
            //do action related to BACK key
            break;
          case Keyboard.SEARCH:
            //do action related to SEARCH key
            showInfo("SEARCH key");
            break;
          case Keyboard.MENU:
            //do action related to MENU key
            showInfo("MENU key");
            break;
          default:
            break;
        }
      }

      private function onGetDirectories():void {
        var userDirectory:File = File.userDirectory;
        getDirectories(userDirectory);
      }

      private function switchToFileList(value:Boolean):void {
        fileList.visible = fileList.includeInLayout = value;
        mainImage.visible = mainImage.includeInLayout = !value;
      }

      private function getDirectories(file:File):void {
        switchToFileList(true);
        var fileListing:Array = file.getDirectoryListing();
        _files = new ArrayCollection(fileListing);
        _files.filterFunction = filesFilterFunction;
        _files.refresh();
      }

      private function filesFilterFunction(item:Object):Boolean {
        var file:File = item as File;
        if (!file) {
          return false;
        }
        if (file.isHidden) {
          return false;
        }
        return true;
      }

      private function onItemDoubleClick(event:ListEvent):void {
        var selectedFile:File = fileList.selectedItem as File;
        if (!selectedFile) {
          return;
        }
        if (selectedFile.isDirectory && !selectedFile.isHidden) {
          getDirectories(selectedFile);
          return;
        }
        var extension:String = selectedFile.extension.toLowerCase();
        switch (extension) {
          case "jpg":
          case "jpeg":
          case "png":
            getFile(selectedFile);
            break;
        }
      }

      private function getFile(file:File):void {
        if (file) {
          showInfo(file.nativePath);
          var imageData:ByteArray = new ByteArray;
          var stream:FileStream = new FileStream();
          stream.open(file, FileMode.READ);
          stream.readBytes(imageData);
          stream.close();
          mainImage.source = imageData;
          switchToFileList(false);
        } else {
          showInfo("Impossible de récupérer le fichier");
        }
      }

      private function showInfo(text:String):void {
        log.text = text;
      }
    ]]>
  </mx:Script>
  <mx:ApplicationControlBar left="0" right="0" bottom="0" height="80" paddingTop="8" paddingLeft="8"
                            paddingBottom="8" paddingRight="8" horizontalGap="8" verticalGap="8"
                            dock="true">
    <mx:Box width="100%">
      <mx:HBox>
        <mx:Button id="getPictureButton" label="Browse SD Card" click="onGetDirectories();"
                   height="100%" width="100%" enabled="true" />
      </mx:HBox>
      <mx:Label id="log" fontSize="18" />
    </mx:Box>
  </mx:ApplicationControlBar>
  <mx:List id="fileList" dataProvider="{_files}" labelField="name" width="100%" height="100%"
           itemDoubleClick="onItemDoubleClick(event)" doubleClickEnabled="true">
  </mx:List>
  <mx:Image id="mainImage" width="100%" height="100%" visible="false" includeInLayout="false" />
</mx:Application>

Démonstration vidéo

Télécharger le projet au format FXP

Télécharger l'application au format APK

16sept/100

Rencontrez les barbus de la team Flash Player chez Adobe à Paris

Adobe organise le 1er Octobre une rencontre avec 2 stars de la team Flash Player: Thibault Imbert et Mike Chambers. Au passage, n'hésitez pas à lire leurs blogs respectifs, ils contiennent des articles toujours très pointus.

Les voilà en photo:

Thibault-Imbert-et-Mike-Chambers

Cela se passera dans les locaux d'Adobe Systems France à Paris entre 14h et 17h. Les thèmes abordés seront:

- Optimisation de l’AS3 pour le développement Android
- Dernières innovations du Flash Player

Pour pouvoir participer, il suffit de vous inscrire:

Inscription rencontre Team Flash Player 1er Octobre à Paris