Comme vous vous en doutez, la gestion de la systray va nous permettre non seulement d'afficher une icône dans celle-ci mais aussi de gérer un menu contextuel associé à cette icône.

Pour la mise à jour, Adobe a tout prévu ! Tout est automatique, ou presque.

Pour ceux qui ne peuvent plus attendre, voici une petite démo :

Texte de remplacement


Voici maintenant quelques bouts de code qui vous aideront à mieux comprendre comment tout cela fonctionne.

Concernant la gestion de la Systray, voici comment on procède :

//on importe les classes requises
import flash.display.SystemTrayIcon;
import flash.system.Shell;
import flash.display.NativeMenu;
import flash.display.NativeMenuItem;
 
public function sendToSysTray():void{
	
	//on rend la fenêtre invisible
	stage.nativeWindow.visible = false;
        //on spécifie l'icône de la Systray
	Shell.shell.icon.bitmaps = SysTrayIcon;
        //on spécifie le ToolTip de l'icône
	SystemTrayIcon(Shell.shell.icon).tooltip = "Phiphou_AIR_Test";
        //on spécifie l'action à effectuer sur le click de l'icône
	SystemTrayIcon(Shell.shell.icon).addEventListener(MouseEvent.CLICK, onIconClick);
}
		
private function onIconClick(evt:MouseEvent):void{
		
	//on rend la fenêtre visible
        stage.nativeWindow.visible = true;
        //on "vide" l'icône
	Shell.shell.icon.bitmaps = [];
}

L'icône de la sysTray est en fait un Array, qui contient des images "Embedées". On peut utiliser la classe fournie dans les docs d'Adobe, comme ceci :

package com.phiphou.application
{
    import flash.desktop.Icon;
      
    public class AIRMenuIcon extends Icon
    {
        
        [Embed(source='assets/icons/logo128.png')]
        private var icon128:Class;
        
        [Embed(source='assets/icons/logo48.png')]
        private var icon48:Class;
        
        [Embed(source='assets/icons/logo32.png')]
        private var icon32:Class;       
 
        [Embed(source='assets/icons/logo16.png')]
        private var icon16:Class;           		
		
        public function AIRMenuIcon():void{
            var iconImages:Array = [(new icon16()).bitmapData];
            this.bitmaps = iconImages;
        }
    }
}

Et donc, on créera notre icône comme ceci :

public var SysTrayIcon:Array = new AIRMenuIcon().bitmaps;

Pour rajouter un menu contextuel à l'icône, on fera comme ceci :

//on spécifie le menu pour l'icône
SystemTrayIcon(Shell.shell.icon).menu = createMenu();
 
//on crée le menu
private function createMenu():NativeMenu{
	var menu:NativeMenu = new NativeMenu();
	menu.addItem(new NativeMenuItem("New"));
	menu.addItem(new NativeMenuItem("Open"));
	menu.addItem(new NativeMenuItem("Save"));
	menu.addItem(new NativeMenuItem("",true));
	menu.addItem(new NativeMenuItem("Exit"));
		    
	//on rajoute un écouteur pour chacun des items
        for each (var item:NativeMenuItem in menu.items){
		 item.addEventListener(Event.SELECT,itemSelected);
	}
	return menu;
}
		
private function itemSelected(event:Event):void{
    		
    	     //Actions selon l'item selectioné 
             switch(event.target.label){
			    	
	     case "Exit" :
	     dispatchEvent(new FlexEvent("closePanel"));
	     break;
			    	
	}
    		
}

Comme vous le voyez, ce n'est rien de très compliqué.

Pour la gestion de la mise à jour, je ne vais pas vous donner tout mon code, mais juste les points essentiels. Le principe est le suivant :

on récupère d'abord le numéro de version de l'application :

public function getVersion():void{
           var loader:URLLoader = new URLLoader();
           loader.addEventListener(Event.COMPLETE, readVersion);
           var request:URLRequest = new URLRequest("app-resource:/META-INF/AIR/application.xml");
           loader.load(request);
       }
 
public  function readVersion(event:Event):void {
           var loader:URLLoader = URLLoader(event.target);
           var xml:XML = XML(loader.data);
           //on récupère ici la version courante
           currentVersion = xml.@version; 
}

Puis on lit un fichier xml stocké sur un serveur externe, et qui contient le numéro de la dernière version en cours, ainsi que l'url vers le fichier .air de la dernière version et éventuellement d'autres informations. Ce fichier ressemble à ça :

 
<?xml version="1.0" encoding="ISO-8859-1" ?> 
<currentVersion version="1.5 Beta" downloadLocation="http://air.phiphou.com/Update/phiphou_air_test.air" forceUpdate="false" message="Correction de divers bugs
Ajout de fonctionalités" />

Pour le lire, on utilisera par exemple un HttpService, ou bien un WebService.

Ensuite, on compare les deux chaines :

Si elles sont identiques, c'est que l'application est bien à jour.

Sinon, c'est qu'une mise à jour est disponible. On récupère alors le fichier d'installation de la nouvelle version, dont l'url est indiquée dans le fichier xml qu'on vient de récupérer, et on le stocke dans un dossier temporaire. Un fois ce fichier récupéré, on lance la mise à jour.

private var file:File
private var urlStream:URLStream = new URLStream();
private var fileData:ByteArray = new ByteArray();
 
public function getUpdate():void{
           var urlReq:URLRequest=new URLRequest(version.@downloadLocation);
           urlStream.addEventListener(Event.COMPLETE, newVersionloaded);
           urlStream.load(urlReq);
}
       
private function newVersionloaded(event:Event):void {
           //on lit en binaire le fichier reçu.
           urlStream.readBytes(fileData, 0, urlStream.bytesAvailable);
           writeAirFile();
}
       
private function writeAirFile():void {
          
        //on crée un dossier temporaire pour stocker le fichier d'update
        file = File.createTempDirectory().resolvePath("Update.air");
	var fileStream:FileStream = new FileStream();          
        fileStream.addEventListener(Event.CLOSE, fileClosed);
        //on écrit le fichier reçu dans ce dossier temporaire
        fileStream.openAsync(file, FileMode.WRITE);
        fileStream.writeBytes(fileData, 0, fileData.length);
        fileStream.close();
       }
      
       private function fileClosed(event:Event):void {
           //Quand le fichier est écrit dans le dossier
           //temporaire, on lance l'opération d'Update
           var updater:Updater = new Updater();
           updater.update(file,version.@version);
       }

Et c'est tout ! Le reste est automatique : l'application va se fermer, la mise à jour va être installée et l'application va redémarrer.

Voilà pour aujourd'hui 8-) .