joliclic blog

Aller au contenu | Aller au menu | Aller à la recherche

Tag - dist_xul_app_fr

Fil des billets

vendredi, mai 27 2011

Distribuer votre appli XULRunner - 5 - Synthèse - toutes plateformes

This post exists also in english

Ce billet fait partie d'une série sur comment déployer une application XULRunner. Voir le préambule pour le contexte.

5 - Synthèse - toutes plateformes

5.1 Changements dans l'appli

Résumons les changements que nous avons apporté à l'application elle-même, pour chaque plateforme :

  • Linux
    • Nous avons ajouté quelques icônes png dans le dossier myapp/chrome/icons/default/ .
      Ceci permet d'avoir notre icône pour nos fenêtres et dans la barre de tâche.
      En details, 16x16px, 32x32px et 48x48px.

      Nous pouvons conserver ces changements globalement, ils n'auront pas d'impact sur les autres plateformes.

  • Windows
    • De manière similaire à Linux, nous avons ajouté quelques icônes .ico dans le dossier myapp/chrome/icons/default/, pour les mêmes raisons.
      Et nous avons créer cette icône depuis Linux avec le programme icotool.

      Nous pouvons conserver ces changements globalement, ils n'auront pas d'impact sur les autres plateformes.

  • Mac OSX
    • Nous avons ajouté un élément menubar principal dans toutes nos fenêtres non modales, avec quelques entrées avec un id spécifique.
      Ceci nous permet d'avoir nos propres entrées dans le Menu principal Mac.
      Ces entrées sont masquées (d'un point de vue XUL) par défaut.

      Nous pouvons conserver ces changements globalement, ils n'auront pas d'impact sur les autres plateformes, parce ces éléments XUL sont masqués pour les autres plateformes.

    • Nous avons ajouté un peu de code JavaScript à notre fichier js principal. Parce que sur un Mac l'appli ne quitte pas quand on ferme toutes les fenêtres.

      Nous pouvons conserver ces changements globalement, le code est multi-plateforme. Mieux, nous pouvons l'utiliser également sur les autres plateformes.

    • Nous avons ajouté un nouveau fichier, une fenêtre XUL masquée. Cette fenêtre est utilisée pour granir le Menu Mac principal quand toutes nos fenêtres sont fermées.

      Nous pouvons conserver ces changements globalement, ils n'auront pas d'impact sur les autres plateformes.

    • Et nous avons ajouté une préférence (browser.hiddenWindowChromeURL), pour utiliser la fenêtre cachée précédente.

      Nous pouvons conserver ces changements globalement, ils n'auront pas d'impact sur les autres plateformes.

Donc, finalement, ce sont de petits changements, et tous peuvent être ajouté globalement, car ils ne perturbent pas les plateformes non ciblées.

5.2 Données ajoutées

Pour une meilleure intégration aux différentes platformes, nous avons ajouté quelques données supplémentaires :

  • Linux
    • Un script shell utilisé comme lanceur, qui utilise de XULRunner ou de Firefox
      Un lien symbolique vers ce lanceur dans /usr/bin/ est également créé par nos installeurs.

    • Un fichier .desktop, A .desktop file, pour l'intégration au bureau, compris par tous les gestionnaires de fenêtre principaux.

    • et quelques icônes (png et svg), utilisées par les fichiers desktop.

  • Windows
    • Un vrai lanceur en C, en fait XAL (XUL App Launcher), qui permet de lancer facilement notre appli avec Firefox, sans aucune fenêtre noire de commande, et qui peut être personnalisé avec noytre icône.
      Ce lanceur peut être compilé directement depuis Linux.

    • Un script batch comme lanceur est également possible, mais avec les défauts inhérents.

  • Mac OSX
    • Pour cette platforme, nous avons en fait encapsulé notre appli dans un dossier avec une structure spéciale, avec quelques données, un Application Bundle

    • Un script shell utilisé comme lanceur, qui utilise Firefox (en fait un lien symbolique vers lui, placé dans notre bundle)

    • Uneicône icns, utilisée par le bundle pour l'exécutable et dans le dock.
      et nous avons créer cette icône depuis Linux avec le programme png2icns.

    • Un fichier Info.plist et un fichier PkgInfo, décrivant le bundle.

5.3 Installeurs créés

  • Multi-plateformes

    Pas de réelle intégration au bureau, et avec quelques limitations importante sur Mac, mais un tar.gz fonctionne et est simple.

  • Linux

    Nous avons créé un paquet deb pour les distributions basées sur Debian/Ubuntu, un deb similaire pour Maemo, et un rpm pour les distributions basées sur Red Hat/Fedora.

  • Windows

    Nous avons créer un vrai installeur/désinstalleur, directement depuis Linux, basé sur NSIS.

  • Mac OSX

    Le mode de distribution le plus convivial sur Mac, est de créer un dmg. Nous avons pu le créer depuis Linux, et avec un programme expérimental, de le compresser.

    Un simple tar.gz a aussi été créé.

5.4 Un script global et réutilisable

Dans chaque chapitres, nous avons utilisés des scripts bash pour créer tous nos installeurs et autres données.
Je vous propose maintenant un script global pour réaliser toutes ces tâches en une fois.

Plus, ce script peut être utilisé pour tout autre application XULRunner, nous avons juste à modifier un fichier de configuration.

Je n'écris ce script ici, vous le trouverez dans l'archive jointe à ce chapitre, mais voilà le fichier de configuration :

#!/bin/bash

#_______________________________________________________________________________
#
# script version: 1.0
# date: 2011-05-20
#_______________________________________________________________________________

# exit the script on errors
set -e

#_______________________________________________________________________________
#
# common configuration
#_______________________________________________________________________________

# The name of the application, will be the name of the executable for example.
# It should contain only [a-zA-Z_-.] and no whitespace.
APP_NAME=myapp

# The name of the application displayed on screen.
APP_DISPLAY_NAME=MyApp

# The absolute path to the directory containing this script. Don't modify this
# variable if you don't know what you are doing.
CUR_DIR=$(dirname "$0")
CUR_DIR=$(readlink -f -- "$CUR_DIR")

# The main folder of the sources (absolute path), containing the app, data,...
# Can be defined before, in some other scripts.
if [ ! $MAIN_DIR ]; then
MAIN_DIR=$(readlink -f -- "$CUR_DIR/..")
fi

# The folder where all resulted builds (installers, archives,...) will be copied
DIST_DIR=$MAIN_DIR/dist

# The temporary folder where all build are done
TMP_DIR=$MAIN_DIR/tmp

# Folder which contains extra useful programs for the build script
TOOLS_DIR=$MAIN_DIR/tools

# Folder which contains all build scripts, and the current config file
BUILDERS_DIR=$MAIN_DIR/builders

# The folder of the real sources of the XULRunner application
APP_SRC_DIR=$MAIN_DIR/$APP_NAME

# The folder of the extra data of the app (icons,...)
APP_DATA_DIR=$MAIN_DIR/data

# The folder of the used icons
# This folder must contains:
# icon16.png, icon22.png, icon26.png, icon32.png, icon40.png, icon48.png,
# icon128.png, icon48.svg, icon.ico, icon.icns, icon48.txt
# You can find some shell scripts in the data/icons folder to create the ico,
# icns et base64 icons.
APP_ICON_DIR=$APP_DATA_DIR/icons

# The current version of the app
APP_VERSION=1.0

# You can use a file named version in the main directory too, and uncomment the
# following line to set this variable
#APP_VERSION=$(cat "$MAIN_DIR/version")

# if the app contains some compiled code, and so it's architecture dependent,
# uncomment the following line
#ARCH_DEPENDENT=1


#_______________________________________________________________________________
#
# Linux specific
#_______________________________________________________________________________

# the folder which contains the Linux specifics data
LINUX_DIR=$APP_DATA_DIR/linux

# the desktop file, will be renamed as $APP_NAME.desktop
DESKTOP_FILE=$LINUX_DIR/desktop

# If this variable is set, the desktop file will be adapted, i.e. the strings
# @@APP_VERSION@@, @@APP_NAME@@, @@APP_DISPLAY_NAME@@, and
# @@APP_DESKTOP_CATEGORIE@@,..., will be replaced by their values. Simply
# comment the following line to not use this feature.
OPT_ADAPT_DESKTOP=1

# this value is displayed in a tooltip by the desktop
APP_DESKTOP_COMMENT="a Hello World XULRunner app"

# A value chosen in http://standards.freedesktop.org/menu-spec/latest/apa.html
# If you use multiple value, use a semicolon (;) as separator
# DON'T forget the last semicolon, even if there is only one value
APP_DESKTOP_CATEGORIE='Utility;'

# You can use this variable to put extra lines to the Desktop file, for example
# a localized comment
APP_DESKTOP_EXTRA='Comment[fr]=un Bonjour Monde pour XULRunner.\n'

# the generic Linux launcher, a shell script, for our app. Will be renamed as
# $APP_NAME.sh
LINUX_LAUNCHER=$LINUX_DIR/launcher.sh


#_______________________________________________________________________________
#
# deb package specific
#_______________________________________________________________________________

# Comment the following line if you don't want to generate a deb package
OPT_BUILD_DEB=1

# the debian folder used to build our generic deb
DEBIAN_DIR=$APP_DATA_DIR/debian

# If this variable is set, the files 'changelog', 'control', 'menu',
# 'myapp.link', and 'copyright' of the debian folder will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, @@DEB_CONTROL_VERSION@@, @@DEB_CONTROL_SECTION@@,
# @@DEB_MENU_SECTION@@, ..., will be replaced by their values. Simply comment
# the following line to not use this feature.
OPT_ADAPT_DEBIAN=1

# The version of the generated deb package.
DEB_CONTROL_VERSION=${APP_VERSION}-1

# the category of the app. See http://packages.debian.org/en/sid/
DEB_CONTROL_SECTION=Utilities

DEB_CONTROL_MAINTAINER='John Doe <johndoe@example.com>'

# author of the generated deb
DEB_CONTROL_AUTHOR=$DEB_CONTROL_MAINTAINER

DEB_CONTROL_HOMEPAGE='<http://example.com/myapp/>'

# name of the generated package
DEB_CONTROL_PACKAGE=$APP_NAME

# long description of the app for the generated deb. Can be multiline, see
# http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Description
# for the formatting (in short, add at least a space at the beginning of all
# lines apart the first)
DEB_CONTROL_DESCRIPTION='simple Hello World.
Powered by XULRunner.'

# if the app have other dependencies than Firefox, list them, separated by a
# comma. Important, this list MUST begin by a comma.
DEB_CONTROL_EXTRA_DEPENDENCIES=

# if the app contains some compiled code, and you want to use the
# ${shlibs:Depends} variable with debhelper, uncomment the following line
#DEB_CONTROL_USE_SHLIBS_DEPENDS=1

# the category for the Debian menu, see
# http://www.debian.org/doc/packaging-manuals/menu-policy/ch2.html#s2.1
DEB_MENU_SECTION='Applications/Programming'

DEB_DATE="$(date -R)"

DEB_COPYRIGHT='<Copyright (C) 2010 John Doe>'

# the short license for the generated deb
DEB_SHORT_LICENSE=$(cat "$LINUX_DIR/deb_short_license.txt")


#_______________________________________________________________________________
#
# maemo deb specific
#_______________________________________________________________________________

# Note that the debian specific variables are used as well to generate the
# maemo deb, so they must set.

# the APP_NAME specific for Maemo, can be the same as APP_NAME
MOBILE_APP_NAME=$APP_NAME

# the APP_DISPLAY_NAME specific for Maemo, can be the same as APP_DISPLAY_NAME
MOBILE_APP_DISPLAY_NAME=$APP_DISPLAY_NAME

# the name of the app for the package. Should be different than APP_NAME,
# otherwise there can be collision with the generic deb created by the other
# script
MAEMO_PKG_APPNAME=${APP_NAME}-mobile

# the desktop file for Maemo, will be renamed as $APP_NAME.desktop
MAEMO_DESKTOP_FILE=$LINUX_DIR/maemodesktop

# the launcher for Maemo, a shell script, for our app. Will be renamed as
# $APP_NAME.sh
MAEMO_LAUNCHER=$LINUX_DIR/maemolauncher.sh

# Comment the following line if you don't want to generate a deb package
OPT_BUILD_MAEMO_DEB=1

# the debian folder used to build our deb for Maemo
MAEMODEBIAN_DIR=$APP_DATA_DIR/maemodebian

# the categorie of the app for Maemo. See
# http://wiki.maemo.org/Packaging/Guidelines#Sections
DEB_CONTROL_SECTION_MAEMO=user/utilities

# the name of the generated deb for Maemo.
# Should really the same as MAEMO_PKG_APPNAME, see its comment.
DEB_CONTROL_PACKAGE_MAEMO=$MAEMO_PKG_APPNAME

# the description of the generated deb, especially for Maemo. See the comments
# for DEB_CONTROL_DESCRIPTION in this file for formatting.
DEB_CONTROL_DESCRIPTION_MAEMO=$DEB_CONTROL_DESCRIPTION

# like DEB_CONTROL_EXTRA_DEPENDENCIES, but for Maemo
DEB_CONTROL_EXTRA_DEPENDENCIES_MAEMO=

# the base64 file (text) of the icon for the Maemo deb.
# Can be generated by the script 'build_icon_base64.sh' in the data/icons dir.
MAEMO_BASE64_ICON="$APP_ICON_DIR/icon48.txt"


#_______________________________________________________________________________
#
# rpm package specific
#_______________________________________________________________________________

# Comment the following line if you don't want to generate a rpm package
OPT_BUILD_RPM=1

# path to the spec file used to generate the rpm
RPM_SPEC_FILE=$LINUX_DIR/rpmspec

# If this variable is set, the .spec file will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, @@RPM_VERSION@@, @@RPM_RELEASE@@, @@RPM_GROUP@@,
# @@RPM_LICENSE@@, @@RPM_URL@@, @@RPM_SOURCE@@, @@RPM_DATE@@, ...
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_RPM=1

# version of the app for the spec file: must contain only integer and digit, no
# strings like 'beta'
RPM_VERSION=$APP_VERSION

# the version of the generated rpm, not the app version
RPM_RELEASE='1%{?dist}'

# the short version of the generated rpm, without any string relative to the
# distribution or architecture
#RPM_RELEASE_SHORT=1
RPM_RELEASE_SHORT=$(echo $RPM_RELEASE | sed "s/%.*$//")

# breve summary of the app for the package. One line only.
RPM_SUMMARY='simple Hello World powered by XULRunner.'

# the category of the app. See /usr/share/doc/rpm/GROUPS
RPM_GROUP=Development/Tools

# keyword license
RPM_LICENSE='MPLv1.1 or GPLv2+ or LGPLv2+'

# url where the source of our app can be found
RPM_URL='http://example.com/myapp/'

# the name of the dummy tar.gz source archive, it will be built by this script.
RPM_SOURCE=${APP_NAME}-${RPM_VERSION}.tar.gz

# If the app need some build dependencies, uncomment the following line and add
# them here, separated by a comma. BUT you shouldn't have to, the logic here is
# that the built should have been done before, this script simply package the
# result.
#RPM_BUILDREQUIRES=

# if the app have other dependencies than Firefox, list them, separated by a
# comma. Important, this list MUST begin by a comma.
RPM_EXTRA_REQUIRES=

# long description of the app for the generated rpm. Can be multiline.
RPM_DESCRIPTION='simple Hello World
Powered by XULRunner.'

LC_TIME_BUFFER=$LC_TIME
export LC_TIME="en_EN.utf8"
RPM_DATE=$(date +"%a %b %e %Y")
export LC_TIME="$LC_TIME_BUFFER"

RPM_MAINTAINER='John Doe <johndoe@example.com>'


#_______________________________________________________________________________
#
# Windows specific
#_______________________________________________________________________________

# the folder which contains the Windows specifics data
WIN_DIR=$APP_DATA_DIR/win

# the version of the app used by some other variables. String.
WIN_VERSION=$APP_VERSION

# comment this line if you don't want to build xal, the launcher in C
OPT_BUILD_WIN_XAL=1

# source directory of xal
XAL_SRC_DIR=$TOOLS_DIR/xal-src

# the rc file used to build xal
WIN_RESOURCE=$WIN_DIR/resource.rc

# If this variable is set, the resource (.rc) file for xal will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, and @@WINRES_...@@
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_WINRES=1

WINRES_FILEVERSION='0,1,0,0'
# the FILEVERSION for Windows (<int,int,int,int>) will be deducted from the
# APP_VERSION. Comment this line if you don't want use this feature
OPT_CALC_WINRES_FVERSION=1

WINRES_PRODUCTVERSION='0,1,0,0'
# the PRODUCTVERSION for Windows (<int,int,int,int>) will be deducted from the
# APP_VERSION. Comment this line if you don't want use this feature
OPT_CALC_WINRES_PVERSION=1

WINRES_Comments='Published under the MPL 1.1/GPL 2.0/LGPL 2.1 licenses'
WINRES_CompanyName='John Doe Organization'
WINRES_FileDescription=$APP_DISPLAY_NAME
WINRES_FileVersion=$WIN_VERSION
WINRES_InternalName=$APP_NAME
WINRES_LegalCopyright='(c) 2010 John Doe'
WINRES_ProductName=$APP_DISPLAY_NAME
WINRES_ProductVersion=$WIN_VERSION

# Comment the following line if you don't want to generate the nsis installer
# for Windows
OPT_BUILD_WIN_INSTALLER=1

# the source folder of the nsis scripts used by this script
NSIS_SRC_DIR=$APP_DATA_DIR/nsis

# If this variable is set, the nsis script will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, and @@NSIS_...@@
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_NSIS=1

NSIS_PRODUCT_NAME=$APP_DISPLAY_NAME
NSIS_PRODUCT_INTERNAL_NAME=$APP_NAME
NSIS_PRODUCT_VERSION=$WIN_VERSION
NSIS_PRODUCT_WIN_VERSION='1.0.0.0'
# for nsis, the PRODUCTVERSION for Windows (<int,int,int,int>) will be deducted
# from the APP_VERSION. Comment this line if you don't want use this feature
OPT_CALC_NSIS_WINVERSION=1

# The license file text MUST be in the main root app folder, so in $APP_SRC_DIR.
# Otherwise, you can edit the nsis script and adapt it
NSIS_LICENCE_NAME='LICENSE.txt'

# the name of the generated nsis installer
NSIS_INSTALLER_NAME="$APP_DISPLAY_NAME-$APP_VERSION-install.exe"


#_______________________________________________________________________________
#
# Mac OSX specific
#_______________________________________________________________________________

# the folder which contains the Mac OSX specifics data
MAC_DIR=$APP_DATA_DIR/mac

# the simple and basic shell launcher for Mac. Used only for the
# multiplatform tar.gz
MAC_BASIC_LAUNCHER=$MAC_DIR/basic_launcher.sh

# the previous basic launcher will be renamed with this value
# Trick: if the extension is 'command', the file can double-clicked in the Mac
# Finder, then a terminal will be opened and the script will be launched.
MAC_BASIC_LAUNCHER_NAME=${APP_NAME}-mac.command

# Comment the following line if you don't want to generate the Application
# Bundle of the app for Mac.
OPT_BUILD_MAC_BUNDLE=1

# path to the used skeleton of the bundle
DMG_SKELET_DIR=$MAC_DIR/bundle_skelet

# If this variable is set, the nsis script will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, and @@MAC_...@@
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_MAC_INFO=1

MAC_BUNDLE_EXECUTABLE=${APP_NAME}-mac.sh
MAC_BUNDLE_INFOSTRING="$APP_DISPLAY_NAME $APP_VERSION"
MAC_BUNDLE_ICONFILE=$APP_NAME
MAC_BUNDLE_IDENTIFIER="net.yourcompany.${APP_NAME}"
MAC_BUNDLE_NAME=$APP_DISPLAY_NAME
MAC_BUNDLE_SHORTVERSIONSTRING=$APP_VERSION
MAC_BUNDLE_VERSION=$APP_VERSION

# with this option, the eventual icon 'myapp.icns' in the Contents/Resources
# folder of the used bundle skelet will be removed, and the icns icon of the
# icons folder will be added to the bundle renamed as MAC_BUNDLE_ICONFILE
MAC_BUNDLE_OVERWRITE_ICON=1

# comment the following line if you don't want to generate a dmg image
OPT_BUILD_MAC_DMG=1
# comment the following line if you don't want to customize the dmg image
OPT_CUSTOMIZE_DMG=1
# source folder of the data added to the dmg, to customize it
# Note that you have to recreate manually these customizations files if the
# DMG_VOLNAME is different than 'MyApp', in particular the background image
# will not be displayed. See the Howto.
# Comment the line to disabled this option.
DMG_CUSTOM_DATA_DIR=$MAC_DIR/dmg_extra_data

# the name of the mounted dmg disk image
DMG_VOLNAME="$APP_DISPLAY_NAME"
# the name of the generated dmg
DMG_NAME="$APP_NAME-$APP_VERSION.dmg"

# comment the following line if you don't want to compress the dmg. You need
# the <dmg> program to be able to do that
OPT_COMPRESS_DMG=1
# path to the dmg program, used to compress the dmg.
# see http://github.com/planetbeing/libdmg-hfsplus
# and http://shanemcc.co.uk/libdmg/
TOOL_DMG="$TOOLS_DIR/dmg"


#_______________________________________________________________________________
#
# Multi-platform tar.gz archive (usable on Linux, Windows, Mac OSX)
#_______________________________________________________________________________

# Note that al lot of previous variables (Linux, Windows, and Mac OSX specific)
# will be used to build this archive

# Comment the following line if you don't want to generate multi-platform tar.gz
# Note that if ARCH_DEPENDENT is active, this archive will NOT be built
OPT_BUILD_MULTI_TARGZ=1

# the name of the generated tar.gz
TARGZ_NAME=${APP_NAME}-${APP_VERSION}-multiplatform


#_______________________________________________________________________________

BUILD_CONFIG_INCLUDED=1

Pour utiliser ce script pour votre application, en raccourci vous devez remplacer toutes les données du dossier data, images, fichier... puis ouvrir et adapter le script build_config.sh pour votre appli.

En detail :

  • remplacer toutes les icônes du dossier data/icons par les votres.
    Si vous n'avez pas celles aux formats .ico et .icns, utilisez les scripts build_ico.sh et build_icns.sh pour les créer. Et utilisez le script build_base64.sh pour générer l'icône base64 pour le paquet Maemo.

  • Éditez et modifiez le fichier deb_short_license.txt dans le dossier data/linux.

  • Si vous voulez créer un dmg pour Mac OSX et le personnaliser, vous devez recréer les données utilisées, en particulier le fichier .DS_STORE, et remplacer celles du dossier data/mac/dmg_extra_data par les votres. Faites attention, il y a quelques fichiers cachés dans ce dossier sur Linux, parce que leur noms commencent par un point (.) (CTRL+H in Nautilus to show them ;).

  • Assurez vous d'avoir un fichier de licence dans le dossier principal de vottre appli, c'est nécessaire pour créer l'installeur Windows, et c'est vraiment une bonne pratique.

  • Toutes les autres données peuvent etre utilisées telles quelles, parce que leurs contenus sont parséx par les scripts et utilise le fichier de config, mais vous aussi pouvez les éditer et les modifier si vous le souhaitez.

  • Si vous voulez créer un dmg compressé pour Mac OSX, vous devez télécharger le programme libdmg depuis la page de l'auteur ou cette version modifiée, et le placer dans le dossier tools.

  • Enfin, éditer et adapter le fichier config.sh dans le dossier builders.
    Les paramètres les plus importants sont APP_NAME et APP_DISPLAY_NAME, beaucoup d'autres paramètres utilisent leurs valeurs.
    Et bien le chemin vers les sources de votre appli, çà peut être une bonne idée de les placer au même niveau que l'exemple myapp, mais ce n'est pas obligatoire.
    Remplacer bien sûr toutes les chaînes spécifiques à l'exemple myapp.

Puis dans un terminal :

  • cd myapp-src-global
  • sh ./build_all.sh

Et vous trouverez alors dans le dossier myapp-src-all/dist/ tous les installeurs créés.

5.5 Conclusions

Créer des applications XULRunner est facile, puissant et multi-plateforme, comme développer des extensions Firefox.

Vous pouvez utiliser des assistants sur mozdev.org pour générer des squelettes pour commencer une nouvelle appli (attention vous devrez adapter enregistrement chrome pour Firefox 4, l'assistant a besoin apparemment d'être mis à jour pour cette partie).

Nous avons vu dans ce tutoriel quelques petites parties auxquelles nous devons faire attention pour une meilleure intégration au bureau, et qu'il est relativement simple de créer des installeurs, depuis Linux, pour différentes plateformes cibles. Vous pouvez même réutiliser le script global, ou vous en inspirer, pour créer ces installeurs pour votre application.

Maintenant c'est à vous de faire de jolies applis, j'espère que ce tuto et le script global vous aideront.
Amusez vous bien ;) !

Nicolas Martin

Vous pouvez télécharger tous les exemples de ce chapitre 5, le script global et XAL inclus, dans l'archive myapp-src-global.tar.gz .

Ou retrouver l'intégralité de ce tuto dans sa page dédiée, disponible en téléchargement avec tous les exemples compris.

L'application myapp, de developer.mozilla.org, est dans le Domaine Public.

L'icône utilisée est issue du Tango Desktop Project, et est dans le Domaine Public.

le lanceur C XUL App Launcher (XAL) est sous licence MIT.

Toutes les autres données ajoutées, et les fichiers en exemple, de ce chapitre 3, sont dans le Domain Public également.

jeudi, mai 26 2011

Distribuer votre appli XULRunner - 4 - Mac OSX

This post exists also in english

Ce billet fait partie d'une série sur comment déployer une application XULRunner. Voir le préambule pour le contexte.

4 - Mac OSX

4.1 Icônes pour Mac OSX

Nous avons besoin d'une icône icns Sur Mac les fenêtres n'ont pas d'icône, mais, plus tard, nous en utiliserons une dans le Dock. Et elle sera utilisée pour le bundle que nous créerons.

Nous pouvons générer ce fichier .icns directement depuis Linux. La restriction est que nous ne pouvons pas inclure des images avec pluieurs profondeur de couleur, mais des dimensions multiples est possible.
Nous avons besoin du programme png2icns compris dans le paquet icnsutils.
Sur Debian/Ubuntu:

apt_get install icnsutils

Nous obtenoons notre fichier icns à partir de plusieurs png avec :

png2icns icon.icns icon128.png icon48.png icon32.png icon16.png

Vous trouverez un script bash avec cette ligne de commande dans l'archive d'exemple relative à ce chapitre 4 (dans samples_chapter_4/data/icons/).

4.2 Créer un lanceur

Comme pour Linux, nous utiliserons un script shell pour notre lanceur. Mais nous avons plusieurs problèmes à résoudre.

le premier n'est pas trop difficile. Le programme readlink disponible sur Mac OSX n'est pas la version GNU, et nous ne pouvons pas utiliser l'option -f. Nous résouderons nous même cette fonctionnalité.

Un problème plus sérieux, est que nous ne pouvons pas déterminer où Firefox est installé. Donc, ici, nous imposerons une limitation, Firefox doit être installer à son emplacement par défaut, c'est à dire /Applications/ .

Note : si vous une suggestions pour déterminer où est installer Firefox, merci de me le faire savoir ;) .

Voici ce script, myapp-mac.sh, bien que ce ne soit pas exactement celui que nous utiliserons plus tard :

#!/bin/sh

set -e

# see http://stackoverflow.com/questions/7665/how-to-resolve-symbolic-links-in-a-shell-script
# get the absolute path of the executable
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && \
pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0")

# resolve symlinks
while [ -h $SELF_PATH ]; do
DIR=$(dirname -- "$SELF_PATH")
SYM=$(readlink $SELF_PATH)
SELF_PATH=$(cd $DIR && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
done

CUR_DIR=$(dirname "$SELF_PATH")

if [ -x /Applications/Firefox.app/Contents/MacOS/firefox-bin ]; then
/Applications/Firefox.app/Contents/MacOS/firefox-bin -app "$CUR_DIR/application.ini" $@
elif [ -x /Library/Frameworks/XUL.framework/xulrunner-bin ]; then
/Library/Frameworks/XUL.framework/xulrunner-bin "$CUR_DIR/application.ini" $@
else
echo "Error: unable to find Firefox or XULRunner!"
fi

Si nous essayons ce lanceur, nous pouvons voir 2 autres problèmes, l'icône affichée dans le dock est celui de Firefox, et le menu principal, quand nous fermons toutes les fenêtres de notre appli, est celui de Firefox.
il y a des solutions à ces problèmes, comme nous le verrons dans les prochaines parties.

Notez que si vous voulez vraiment utiliser un tel script, sans un bundle, vous pouvez vouloir l'utiliser avec l'extension .command plutôt que .sh, car alors le fichier peut être double-cliqué dans le Finder de Mac, ce qui ouvrira un terminal, puis l'appli.

4.3 Quelques spécifités Mac

Une particularité sur Mac, est le Menu principal contrôler par le système d'exploitation, et correspondant à l'application courante qui a le focus. Et quand toutes les fenêtres d'une même application sont fermées, ce menu reste présent tant que l'on ne quitte pas l'application;

Ceci est bien pris en charge dans une application XULRunner, mais nous devons ajouter un peu de code pour celà.

Quelques docuementation sur MDN:

Si notre appli utilises un élément menubar principal, XULRunner/Firefox l'utilisera (en fait le premier menubar) pour créer ce menu spécial. Si vous n'en avez pas, vous devriez en créer un, masquer par défaut pour les autres plateformes, il permettra la construction de ce menu.

les entrées dans le menu "pomme" sont construits d'après des éléments avec des id réservés. Vous devriez créer au moins quelques entrées, pour permettre de quitter l'appli par exemple.

Voici la liste des id disponibles correspondants à ces entrées (sources) :

id de l'élément item du menu correspondant
aboutName À propos de cette application
menu_preferences Préférences...
menu_mac_services Services
menu_mac_hide_app Masquer l'appli
menu_mac_hide_others Masquer les autres
menu_mac_show_all Tout afficher
menu_FileQuitItem Quitter

et voici un exemple d'un menu xul minimal pour cet usage :

  <commandset id="main-commands">
<command id="cmd:quit" oncommand="myappQuitApplication();"/>
</commandset>

<keyset id="ui-keys">
<key id="key:quitApp" key="Q" modifiers="accel" command="cmd:quit"/>
<key id="key:hideApp" key="H" modifiers="accel"/>
<key id="key:hideOthersApp" key="H" modifiers="accel,alt"/>
</keyset>

<menubar id="main-menubar" hidden="true">
<menu id="mac-menu">
<menupopup>
<menuitem id="menu_mac_hide_app" label="Hide My App" key="key:hideApp"/>
<menuitem id="menu_mac_hide_others" label="Hide Others" key="key:hideOthersApp"/>
<menuitem id="menu_mac_show_all" label="Show All"/>
<menuitem id="menu_FileQuitItem" label="Quit" key="key:quitApp" command="cmd:quit"/>
</menupopup>
</menu>
</menubar>

Bien sur, comme pour les autres parties de l'appli, les chaînes utilisées dans les labels et clés devraient être localisées. Mais ce n'est pas le propos de ce tutoriel.

La fonction myappQuitApplication a été ajoutée dans le fichier main.js de notre appli :

function myappQuitApplication() {
const Cc = Components.classes;
const Ci = Components.interfaces;

let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit);

return true;
}

Enfin, le dernier problème : quand toutes les fenêtres de notre appli sont fermées, en fait l'appli ne quitte pas, et le menu principal demeure. Plus, tel quel, c'est le menu de Firefox que nous voyons.
En fait, il y a une fenêtre speciale et cachée que XULRunner utilises pour ce menu. Donc nous devons créer une telle fenêtre, et définir une préférence pour la spécifier.

Voilà la préférence ajoutée dans defaults/preferences/pref.js :

pref("browser.hiddenWindowChromeURL", "chrome://myapp/content/hiddenWindow.xul");

Et le contenu de hiddenWindow.xul, qui contient uniquement notre menubar :

<window id="hiddenWindow"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript">
<![CDATA[
function myappQuitApplication() {
const Cc = Components.classes;
const Ci = Components.interfaces;

let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit);

return true;
}
]]>
</script>

<commandset id="main-commands">
<command id="cmd:quit" oncommand="myappQuitApplication();"/>
</commandset>

<keyset id="ui-keys">
<key id="key:quitApp" key="Q" modifiers="accel" command="cmd:quit"/>
<key id="key:hideApp" key="H" modifiers="accel"/>
<key id="key:hideOthersApp" key="H" modifiers="accel,alt"/>
</keyset>

<menubar id="main-menubar" hidden="true">
<menu id="mac-menu">
<menupopup>
<menuitem id="menu_mac_hide_app" label="Hide My App" key="key:hideApp"/>
<menuitem id="menu_mac_hide_others" label="Hide Others" key="key:hideOthersApp"/>
<menuitem id="menu_mac_show_all" label="Show All"/>
<menuitem id="menu_FileQuitItem" label="Quit" key="key:quitApp" command="cmd:quit"/>
</menupopup>
</menu>
</menubar>
</window>

4.4 Créer un "Application Bundle"

Sur Mac OSX, les applications sont empaquetées dans un format spécial nommé Application Bundle. C'est en fait un dossier, nommé avec l'extension .app, et avec une structure particulière.

Quelques documentations utiles :

Voici une proposition d'un dossier .app pour notre appli :

    |- MyApp.app/
|- Contents/
|- MacOS/
|- chrome/
|- defaults/
|- application.ini
|- chrome.manifest
|- foxstub
|- myapp-mac.sh
|- Resources/
|- myapp.icns
|- Info.plist
|- PkgInfo

le dossier MacOS contient en fait tous les fichiers et dossiers de notre appli XULRunner.

le dossier Resources contient uniquement notre icône au format icns.

Le fichier PkgInfo contient uniquement la chaîne APPL????. Je ne suis pas sûr que ce fichier soit réellement nécessaire, il semble important pour la compatibilité avec Mac OS 9.
La valeur spécifie que ce bundle est une application, et comme nous n'avons pas d'identifiant de 4 caractères valide, nous utilisons 4 points d'interrogation (????).

Le fichier Info.plist décrit notre appli :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>myapp-mac.sh</string>
<key>CFBundleGetInfoString</key>
<string>MyApp 1.0</string>
<key>CFBundleIconFile</key>
<string>myapp</string>
<key>CFBundleIdentifier</key>
<string>net.yourcompany.myapp</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MyApp</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0.0.0</string>
<key>NSAppleScriptEnabled</key>
<true/>
</dict>
</plist>

Quelques commentaires sur ces propriétés :

CFBundleExecutable pointe sur notre lanceur, le script shell nommé myapp-mac.sh.

la valeur de CFBundleIconFile est myapp parce que notre icône dans le dossier Resources est nommée myapp.icns. Maintenant, l'utilisateur final visualise notre bundle avec notre icône.

CFBundleIdentifier est formaté tel que domaine inversé point nom de l'application. Ce doit être un identifiant unique pour notre appli.

CFBundlePackageType spécifie que c'est un "application bundle" (APPL).

La valeur de CFBundleSignature est ???? parce que nous n'avons pas de signature. C'est supposé être un identifiant unique de 4 caractères, et supposé être obtenue après un enregistrement auprès d'Apple. Tel que je le comprend, c'est exiger essentiellement pour Mac OS 9. Ne vous inquiétez pas, je n'ai pas vu de problème avec cette valeur ;) .

Maintenant voyons une belle astuce. Tel quel, l'utilisateur final voit notre appli avec notre icône, mais quand il la lance, l'icône dans le dock est celle de Firefox.
Dans l'arborescence du dossier de notre bundle, vous pouvez voir un fichier nommé foxstub, ce fichier est en fait un lien symbolique vers l'exécutable de Firefox.

Ce lien est obtenu simplement, dans le dossier MacOS, avec :

ln -s /Applications/Firefox.app/Contents/MacOS/firefox-bin foxstub

Maintenant quand l'utilisateur lance notre appli, c'est bien notre icône qui est affichée dans le dock :) .

En fait, notre icône apparait dans le dock, puis disparait, et réapparait de nouveau, parce que notre script est lancé, puis l'exécutable lié. mais ce n'est pas un gros problème.

Voici le script modifié de notre lanceur myapp-mac.sh, qui utilise dorénavant le lien symbolique vers Firefox :

#!/bin/sh

set -e

# see http://stackoverflow.com/questions/7665/how-to-resolve-symbolic-links-in-a-shell-script
# get the absolute path of the executable
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && \
pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0")

# resolve symlinks
while [ -h $SELF_PATH ]; do
DIR=$(dirname -- "$SELF_PATH")
SYM=$(readlink $SELF_PATH)
SELF_PATH=$(cd $DIR && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
done

CUR_DIR=$(dirname "$SELF_PATH")

if [ -x "$CUR_DIR/foxstub" ]; then
"$CUR_DIR/foxstub" -app "$CUR_DIR/application.ini" $@
else
echo "Error: unable to find Firefox or XULRunner!"
fi

Nous allons générer notre "application bundle" à la'ide d'un script bash. Il est vraiment simple, nous avons juste à copier le contenu de notre appli dans le dossier MacOS. Voici le contenu de build_mac.sh :

#!/bin/bash

# exit the script on errors
set -e

TMP_DIR=./tmp

# get the absolute path of our TMP_DIR folder
TMP_DIR=$(readlink -f -- "$TMP_DIR")

# re-create the TMP_DIR folder
rm -rfv "$TMP_DIR"
mkdir -v "$TMP_DIR"

# create the .app folder
mkdir -v "$TMP_DIR/MyApp.app"

# copy our bundle skeleton
# (our launcher myapp-mac.sh and our symbolic link foxstub are included)
cp -rv data/bundle_skelet/. "$TMP_DIR/MyApp.app/"

# copy our app
cp -rv myapp/* "$TMP_DIR/MyApp.app/Contents/MacOS/"

# apply the correct permissions
chmod -R 755 "$TMP_DIR/MyApp.app"

# and copy the result in our main src folder
rm -frv MyApp.app
cp -Rv "$TMP_DIR/MyApp.app" ./

Ce script sera continuer par la suite. Mais pour le moment, en résultat, nous avons créer "l'Application Bundle" MyApp.app dans notre dossier source principal.

4.5 Empaqueter un tar.gz et un dmg

Pour distribuer notre bundle, nous devons créer une archive. Je propose 2 solutions, chacune avec ses avantages et inconvénients.

Créer un tar.gz

La première et la plus simple, est de créer un tar.gz. Ce format est bien pris en charge par Mac OSX. Le seul problème est l'utilisateur final risque de ne pas trouver celà très convivial. Voici ce qu'il a à faire :

  1. télécharger le fichier myapp.tar.gz.
  2. l'ouvrir. En fait le comportement par défaut est de décompresser l'archive dans le même dossier.
  3. aller dans le dossier décompressé
  4. déplacer par glisser/déposer le bundle où il le souhaite, par exemple dans /Applications/

Le problème est la phase 2, certains utilisateurs ne comprennent pas que l'archive est décompressée, et où.

pour créer ce tar.gz, nous ajoutons les lignes suivantes dans notre script build_mac.sh :

# create a sub-directory for the tar.gz creation
mkdir "$TMP_DIR/myapp-1.0"

# copy our bundle
# (It would be possible to add other files, the license for example)
cp -rv "$TMP_DIR/MyApp.app" "$TMP_DIR/myapp-1.0/"

rm -fv myapp-mac-1.0.tar.gz

cd "$TMP_DIR"
tar -zcvf "../myapp-mac-1.0.tar.gz" myapp-1.0
cd -
Créer un dmg

la seconde solution est de créer une archive dmg. En fait c'est un format d'image disque.
C'est une solution habituelle sur cette plateforme, et utilisée par Firefox par exemple.

Nous pouvons créer un dmg depuis Linux, mais avec une limitation : nous ne pouvons pas générer de dmg compressé. Enfin en fait il y a une méthode expérimentale de le faire, que je vais vous proposé ensuite, mais elle est encore expérimentale.
L'article le plus utile que j'ai trouvé sur ce sujet est ce billet de l'auteur de DMDirc. Nous allons suivre les mêmes méthodes.

La méthode la plus simple sur linux est d'utiliser mkisofs, ou genisoimage. genisoimage est un fork du premier, utilisé par certaines distributions, et comme un lien symbolique nommé mkisofs est également installé par ces distributions, j'utiliserai la commande mkisofs dans la suite du script.
Pour l'installer sur Debian/Ubuntu :

apt-get install genisoimage

Nous ajoutons dans notre script build_mac.sh :

# create the dmg
rm -fv myapp-1.0.dmg
mkisofs -V 'MyApp' -no-pad -r -apple -o "myapp-1.0.dmg" "$TMP_DIR/myapp-1.0"

Avec cette ligne, nous créons le fichier myapp-1.0.dmg, qui contient tous les fichiers et dossiers inclus dans le dossier $TMP_DIR/myapp-1.0, avec un nom de volume 'MyApp' (le titre de la fenêtre quand le dmg est monté sur Mac). Et tous les fichiers et dossiers dans le dmg ont les droits 755. the 755 rights.

Compresser ce dmg

La seule solution trouvée pour réaliser cette tâche sur Linux, mentionné dans ce billet, est d'utiliser le programme dmg du projet libdmg-hfsplus.
L'auteur dit clairement :

THE CODE HEREIN SHOULD BE CONSIDERED HIGHLY EXPERIMENTAL

traduction approximative :

CE CODE DOIT ÊTRE CONSIDÉRER COMME HAUTEMENT EXPÉRIMENTAL

Noter que le dernier commit du projet que j'ai essayé ne compilait pas (quelqu'un a rapporté le bug).
Et l'auteur de DMDirc rapporte un autre bug d'une version précédente. Mais essayer sa And the author of DMDirc report another bug in a previous version. But I have tried its version légèrement modifiée, avec succès !
Donc vous devriez l'essayer.

Voici les lignes ajoutées à notre script :

# try to compress our dmg, if the the command <dmg> is available
# see http://github.com/planetbeing/libdmg-hfsplus
# and http://shanemcc.co.uk/libdmg/
if [ -x "./tools/dmg" ]; then
# rename temporarily our dmg
mv myapp-1.0.dmg myapp-1.0.dmg.pre
# compress
"./tools/dmg" dmg myapp-1.0.dmg.pre myapp-1.0.dmg
rm -fv myapp-1.0.dmg.pre
fi

Noter que je n'inclus pas le programme dmg dans l'archive jointe, vous devrez le télécharger vous même depuis les liens précédents, et le placer dans le dossier tools.

Créer un dmg depuis Mac OSX

pour information, pour créer un dmg directement depuis Mac OSX, il existe le programme hdiutil. Pour créer un dmg compressé et s'ouvrant automatiquement, d'après un dossier nommé "myFolder", quelque chose du genre devrait marcher :

#!/bin/bash

hdiutil create -volname "myapp-1.0" -fs HFS+ -srcfolder "myFolder" -format UDRW myapp-temp.dmg

hdiutil convert myapp-temp.dmg -format UDZO -imagekey zlib-level=9 -o myapp.dmg

rm -fv myapp-temp.dmg
Personnaliser le dmg

il est possible de personnaliser notre dmg quand il est monté, c'est à dire la fenêtre affichée, par exemple : dimensions de l'icône, image d'arrière plan, dimensions de la fenêtre...

L'idée est de créer un dmg en lecture/écriture sur un mac, de le personnaliser manuellement, puis de faire une copie du fichier .DS_STORE et de toutes les autres données. Ensuite nous utiliserons ces données lors de la création de notre dmg à l'aide de notre script.
Cette partie ne peut être faite que manuellement et directement depuis un Mac.

Créer une image disque en lecture/écriture

Sur un Mac, ouvrez "Utilitaires de disque" dans le dossier "Utilitaires".
Cliquer sur "Nouvelle image".
Choisissez le même nom que le futur nom de volume de notre dmg (MyApp).
N'utilisez pas un format journalisé, pour être capable de choisir une "petite" taille pour ce dmg. La taille importe peu, elle doit juste être suffisante pour copier notre appli et les autres données.
Comme format d'image, choisissez image disque en lecture et écriture Puis cliquer sur "créer".

Ajouter nos données sur l'image disque

Maintenant montez ce dmg en cliquant dessus. Et ouvrez le.
Copiez notre appli dans la fenêtre ouverte. Nous pouvons copier le lien symbolique vers /Applications également, si il existe. Sinon nous le créerons dans un terminal plus tard.

Ouvrez un terminal, depuis les Utilitaires.
Allez dans l'image disque monté :
cd /Volumes/MyApp
puis créez un dossier nommé .background :
mkdir .background
comme ce nom commence par un point (.), ce dossier est caché, comme sur Linux.
copiez notre image d'arrière plan dans ce dossier :
cp pathToOurImage/background.png /Volumes/MyApp/.background/
Et, si besoin, créez le lien symbolique vers /Applications :
ln -s /Applications /Volumes/MyApp/Applications

Personnaliser l'image disque

Maintenant donnez le focus à la fenêtre du disque monté, et ouvrez "Afficher les options de présentation" depuis le menu "Présentation"
Sélectionner Image pour l'airrière plan, puis cliquer sur le bouton.
Nous devons sélectionner le fichier background.png dans le disque monté, mais comme ce fichier est dans un dossier caché, nous ne pouvons pas le voir. Pas d'inquiétude, taper Apple+Shift+G :
puis taper /Volumes/MyApp/.background/, puis entrée.
sélectionnez maintenant notre png.
Choissisez la taille d'icône, par exemple 128, arrangez les par aucun, puis déplacez les où vous le souhaitez, et adapter la taille de fenêtre à votre arrière-plan.

Maintenant fermer cette fenêtre, et éjecter le disque. Puis monter le de nouveau, et ouvrez le.

Copier la personnalisation créée

Dans un terminal, copiez le fichier .DS_STORE créé à la racine du disque monté :
cp /Volumes/MyApp/.DS_STORE pathToSave/myDS_STORE

Maintenant nous avons enfin tous les fichiers nécessaires pour notre script, nous avons juste à copier le fichier .DS_STORE et le dossier .background avec le fichier background.png . Le dmg que nous créerons aura la même personnalisation.
Copions ces données dans nos sources :

    |- samples_chapter_4/
|- data/
|- bundle_skelet/
|- dmg_extra_data/
|- .background/
|- background.png
|- Applications
|- .DS_STORE

Et nous ajoutons les lignes suivantes à notre script build_mac.sh, avant de créer le dmg :

# copy eventual extra data, by example a symbolic link to /Applications
if [ $(ls -A "data/dmg_extra_data" | wc -c) -ne 0 ]; then
cp -Rv data/dmg_extra_data/. "$TMP_DIR/myapp-1.0/"
fi

Notez que cette personnalisation est dépendente du nom de volume utilisé, en particulier pour l'image d'arrière plan, parce que le fichier .DS_STORE utilise des chemins absolus vers le disque monté, et le nom de volume en fait partie.
Donc si vous changer le nom de volume, vous devez recréer manuellement cette personnalisation...

Lancer notre script de build

Pour lancer notre script (sur Linux), et créer nos dmg et tar.gz, dans un terminal :

  • cd samples_chapter_4
  • sh ./build_mac.sh

Et, en résultat, nous avons finalement le dossier MyApp.app, et les fichiers myapp-1.0.dmg et myapp-1.0.tar.gz dans notre dossier de source principal.

Nicolas Martin

Vous pouvez télécharger tous les exemples de ce chapitre 4 (Mac OSX) dans l'archive samples_chapter_4.tar.gz .

L'application myapp, de developer.mozilla.org, est dans le Domaine Public.

L'icône utilisée est issue du Tango Desktop Project, et est dans le Domaine Public.

Toutes les autres données ajoutées, et les fichiers en exemple, de ce chapitre 4, sont dans le Domain Public également.

mercredi, mai 25 2011

Distribuer votre appli XULRunner - 3 - Windows

This post exists also in english

Ce billet fait partie d'une série sur comment déployer une application XULRunner. Voir le préambule pour le contexte.

3 - Windows

3.1 Icônes pour Windows

Nous avons besoin d'une icône au format .ico. Elle sera utilisée par nos fenêtres, et par notre lanceur.

Il est facile de faire un fichier .ico sur Linux, nous avons juste besoin du programme icotool, disponible dans le paquet icoutils.
Sur Debian/Ubuntu :

apt-get install icoutils

Puis nous créons le fichier ico à partir de plusieurs png de différentes tailles, 16x16 px, 32x32 px, et 48x48 px. Il serait possible d'utiliser plus de png, avec différentes profondeurs de couleur par exemple.

icotool -c -o icon.ico icon16.png icon32.png icon48.png

Vous trouverez un script bash avec cette ligne de commande dans l'archive example de ce chapitre 3 (dans samples_chapter_3/data/icons/).

Pour utiliser notre icône pour nos fenêtres, plutôt que celle de firefox ou de xulrunner, nous avons juste à mettre cette icône, renommée default.ico, dans le dossier icons/default situé dans notre dossier chrome principal.
Cette icône sera utilisée par tous les <window> XUL sans un attribut id.
Mais le <window> XUL principal de myapp a l'attribut id="main", donc pour cette fenêtre nous devons avoir une icône nommée main.ico, située dans le même dossier.

    |- samples_chapter_3/
|- myapp/
|- chrome
|- icons/
|- default/
|- default.ico
|- main.ico

3.2 Créer un lanceur (batch ou C)

Le lanceur le plus simple est un script batch. Voici le contenu de myapp.bat :

set CUR_DIR=%~dp0

START firefox -app $CUR_DIR\application.ini

Ce fichier doit être placé dans le dossier principal de notre appli. Ça marche, il lance notre appli via le fichier application.ini de notre appli.
Mais il se passe quelque chose de gênant, une fenêtre noire de commande est également ouverte.

Pour éviter ce defaut, nous allons créer un lanceur en C.

Nous utiliserons le code de XAL (XUL Application Launcher). C'est un programme léger en C, sous licence MIT, il lance une application XULRunner avec Firefox, avec l'argument -app et application.ini. Il doit être placé dans le dossier principal de l'application (comme le batch précédent). Bonus, il prend en charge d'éventuels arguments supplémentaires (comme -jsconsole), quand il est utilisé en ligne de commande. Et nous pouvons ajouter notre icône, et quelques autres informations sur l'application, via un fichier .rc.

Cet exécutable peut etre compilé avec n'importe quel compilateur C, son code est indépendant du code de Mozilla. Personnellement je le compile avec MinGW, sur Linux, avec succés. Si vous voulez utiliser un autre compilateur, éditer le fichier build, et adapter les variables CC et RESCOMP.

pour installer MinGW sur Debian/Ubuntu:

apt-get install mingw32

Je ne publie pas ici le code source C, vous le trouverez dans l'archive relative à ce chapitre, où dans sa page dédiée.

Nous pouvons personnaliser ce lanceur, en utilisant un fichier resource (.rc), insérer notre icône et spécifier quelques informations (vendeur, nom de l'appli, version,...).

Voici le contenu du fichier myapp-res.rc :

APPLICATION_ICON ICON "myapp.ico"

1 VERSIONINFO
FILEVERSION 0,1,0,0
PRODUCTVERSION 0,0,0,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "000004B0"
BEGIN
VALUE "Comments", "Published under the MPL 1.1/GPL 2.0/LGPL 2.1 licenses"
VALUE "CompanyName", "John Doe Organization"
VALUE "FileDescription", "MyApp"
VALUE "FileVersion", "1.0.0"
VALUE "InternalName", "MyApp"
VALUE "LegalCopyright", "(c) 2010 John Doe"
VALUE "ProductName", "MyApp"
VALUE "ProductVersion", "0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x000, 1200
END
END

Quelques détails sur ce contenu :

La ligne APPLICATION_ICON ICON "myapp.ico" insère notre icône

Les entrées FILEVERSION et PRODUCTVERSION utilisent un format spécial, en résumé entier virgule entier virgule entier virgule entier.

La ligne VALUE "Translation", 0x000, 1200 spécifie que les chaînes (string) utilisées dans les champs d'information sont en Unicode.

Nous pouvons compiler ce lanceur, en utilisant notre fichier resource, avec le script build.sh fourni avec XAL :

sh build.sh myapp myapp-res.rc

Après compilation, la taille du fichier créé est de ~21Ko, donc vraiment léger (notez que le poids de l'icône est incluse).

3.3 Créer un script NSIS

Il existe plusieurs solution pour créer des installeurs pour Windows. Ici nous utiliserons NSIS, car : il est open source, nous pouvons construire notre installeur depuis Linux, et qu'il est facile et puissant.
Firefox lui-même utilise NSIS pour son installeur Windows.

Pour installer les outils NSIS sur Debian/Ubuntu :

apt-get install nsis

NSIS utilise son propre language de script pour créer les installeurs. Nous pouvons utiliser des pages par défaut, en créer de nouvelles personnalisées, gérer les fichiers lors de l'installation/désinstallation, agir sur le Registre Windows,...
Je ne vais pas faire une documentation complète sur NSIS ici, voyez leur wiki, il y a beaucoup d'explications et d'exemples.
Vous devriez avoir des exemples et une doc disponibles en local, une fois nsis installé, dans /usr/share/doc/nsis/Examples et /usr/share/doc/nsis/Doc.

Mais voilà le principal script proposé, et j'explique par la suite quelles actions sont réalisées :

!define PRODUCT_NAME "MyApp"
!define PRODUCT_INTERNAL_NAME "myapp"
!define PRODUCT_VERSION "1.0"
!define PRODUCT_WIN_VERSION "1.0.0.0"

!define MESSAGEWINDOW_NAME "${PRODUCT_NAME}MessageWindow"

!define HKEY_ROOT "HKLM"
!define UN_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"

!define LICENSE_PATH "${PRODUCT_INTERNAL_NAME}\LICENSE.txt"

!define INSTALLER_NAME "${PRODUCT_NAME}-${PRODUCT_VERSION}-install.exe"
!define TMP_UNINSTALL_EXE "${PRODUCT_INTERNAL_NAME}_uninstall.exe"

;--------------------------------
;Variables

; The name of the product installed
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"

; The file to write
OutFile "${INSTALLER_NAME}"

SetCompressor /final /solid lzma
ShowInstDetails show
ShowUninstDetails show

; The default installation directory
InstallDir $PROGRAMFILES\${PRODUCT_NAME}

; Request application privileges for Windows Vista
RequestExecutionLevel admin

Var Shortcuts_Dialog
Var Shortcuts_Label
Var Shortcuts_SM_Checkbox
Var Shortcuts_SM_Checkbox_State
Var Shortcuts_D_Checkbox
Var Shortcuts_D_Checkbox_State

Var Previous_Uninstall
Var Previous_Uninstall_dir
Var TempUninstallPath

!include "MUI2.nsh"
!include "FileFunc.nsh"

VIProductVersion "${PRODUCT_WIN_VERSION}"

VIAddVersionKey "ProductName" "${PRODUCT_NAME}"
;VIAddVersionKey "CompanyName" "${CompanyName}"
;VIAddVersionKey "LegalTrademarks" "${BrandShortName} is a Trademark of"
;VIAddVersionKey "LegalCopyright" "${CompanyName}"
VIAddVersionKey "LegalCopyright" ""
VIAddVersionKey "FileVersion" "${PRODUCT_VERSION}"
VIAddVersionKey "ProductVersion" "${PRODUCT_VERSION}"
VIAddVersionKey "FileDescription" "${PRODUCT_NAME} Installer"
VIAddVersionKey "OriginalFilename" "${INSTALLER_NAME}"

!define MUI_FINISHPAGE_RUN "$INSTDIR\${PRODUCT_INTERNAL_NAME}.exe"

;--------------------------------
; Pages

!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "${LICENSE_PATH}"
!insertmacro MUI_PAGE_DIRECTORY
Page custom onShortcutsPageCreate
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH

!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES


!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "French"

!include ./l10n/fr.nsh
!include ./l10n/en_US.nsh


;--------------------------------

Function .onInit
; an eventual previous version of the app should not be currently running.
; Abort if any.
; Explanation, when the application is running, a window with the className
; productnameMessageWindow exists
FindWindow $0 "${MESSAGEWINDOW_NAME}"
StrCmp $0 0 +3
MessageBox MB_OK|MB_ICONEXCLAMATION "${PRODUCT_NAME} is running. Please close it first" /SD IDOK
Abort

StrCpy $Shortcuts_SM_Checkbox_State 1
StrCpy $Shortcuts_D_Checkbox_State 1
FunctionEnd

Function un.onInit
; see Function .onInit
FindWindow $0 "${MESSAGEWINDOW_NAME}"
StrCmp $0 0 +3
MessageBox MB_OK|MB_ICONEXCLAMATION "${PRODUCT_NAME} is running. Please close it first" /SD IDOK
Abort
FunctionEnd

; custom page creation, for the shortcuts installation, using nsDialog
Function onShortcutsPageCreate
!insertmacro MUI_HEADER_TEXT $(l10n_SHORTCUTS_PAGE_TITLE) \
$(l10n_SHORTCUTS_PAGE_SUBTITLE)

nsDialogs::Create 1018
Pop $Shortcuts_Dialog

${If} $Shortcuts_Dialog == error
Abort
${EndIf}

${NSD_CreateLabel} 0 6 100% 12u $(l10n_CREATE_ICONS_DESC)
Pop $Shortcuts_Label

${NSD_CreateCheckbox} 15u 20u 100% 10u $(l10n_ICONS_STARTMENU)
Pop $Shortcuts_SM_Checkbox
GetFunctionAddress $0 OnSMCheckbox
nsDialogs::OnClick $Shortcuts_SM_Checkbox $0

${If} $Shortcuts_SM_Checkbox_State == ${BST_CHECKED}
${NSD_Check} $Shortcuts_SM_Checkbox
${EndIf}

${NSD_CreateCheckbox} 15u 40u 100% 10u $(l10n_ICONS_DESKTOP)
Pop $Shortcuts_D_Checkbox
GetFunctionAddress $0 OnDCheckbox
nsDialogs::OnClick $Shortcuts_D_Checkbox $0

${If} $Shortcuts_D_Checkbox_State == ${BST_CHECKED}
${NSD_Check} $Shortcuts_D_Checkbox
${EndIf}

nsDialogs::Show
FunctionEnd

; event when the Start Menu shortcut is (un)checked in the custom page
Function OnSMCheckbox
${NSD_GetState} $Shortcuts_SM_Checkbox $Shortcuts_SM_Checkbox_State
Pop $0 # HWND
FunctionEnd

; event when the Desktop shortcut is (un)checked in the custom page
Function OnDCheckbox
${NSD_GetState} $Shortcuts_D_Checkbox $Shortcuts_D_Checkbox_State
Pop $0 # HWND
FunctionEnd

Function WriteUninstallReg
WriteRegStr ${HKEY_ROOT} ${UN_KEY} "DisplayName" \
"${PRODUCT_NAME} (${PRODUCT_VERSION})"
WriteRegStr ${HKEY_ROOT} ${UN_KEY} "UninstallString" \
"$INSTDIR\uninstall.exe"
WriteRegStr ${HKEY_ROOT} ${UN_KEY} "QuietUninstallString" \
"$INSTDIR\uninstall.exe /S"
WriteRegStr ${HKEY_ROOT} ${UN_KEY} "InstallLocation" \
"$INSTDIR"
WriteRegStr ${HKEY_ROOT} ${UN_KEY} "DisplayIcon" \
"$INSTDIR\${PRODUCT_INTERNAL_NAME}.exe"
WriteRegStr ${HKEY_ROOT} ${UN_KEY} "DisplayVersion" \
"${PRODUCT_VERSION}"

${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0
WriteRegDWORD ${HKEY_ROOT} ${UN_KEY} "EstimatedSize" "$0"
FunctionEnd

; The stuff to install
Section ""
; uninstall an eventual previous installation
ReadRegStr $Previous_Uninstall ${HKEY_ROOT} ${UN_KEY} "UninstallString"
ClearErrors
${If} $Previous_Uninstall != ""
StrCpy $Previous_Uninstall_dir $Previous_Uninstall
${GetParent} $Previous_Uninstall $Previous_Uninstall_dir

IfFileExists "$Previous_Uninstall" myUninstallPrevious myInstall
${Else}
goto myInstall
${EndIf}

myUninstallPrevious:
; copy the previous uninstaller into TEMP
ClearErrors
StrCpy $TempUninstallPath "$TEMP\${TMP_UNINSTALL_EXE}"
CopyFiles /SILENT "$Previous_Uninstall" "$TempUninstallPath"
IfErrors myInstall

ClearErrors
ExecWait '"$TempUninstallPath" /S _?=$Previous_Uninstall_dir'

ClearErrors
Delete "$TempUninstallPath"

;MessageBox MB_OK "UNINSTALL: finished"

myInstall:
SetOutPath $INSTDIR

; copy the files
File /r ${PRODUCT_INTERNAL_NAME}\*

WriteUninstaller "uninstall.exe"

Call WriteUninstallReg

${If} $Shortcuts_SM_Checkbox_State == ${BST_CHECKED}
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}.lnk" \
"$INSTDIR\${PRODUCT_INTERNAL_NAME}.exe"
${EndIf}

${If} $Shortcuts_D_Checkbox_State == ${BST_CHECKED}
CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" \
"$INSTDIR\${PRODUCT_INTERNAL_NAME}.exe"
${EndIf}
SectionEnd

;--------------------------------
; Uninstaller

Section "Uninstall"
MessageBox MB_OK|MB_ICONEXCLAMATION "$INSTDIR" /SD IDOK
; Remove installed files and uninstaller
!include ./uninstall_files.nsi
Delete "$INSTDIR\uninstall.exe"

; remove installed directories
!include ./uninstall_dirs.nsi
RMDir /r "$INSTDIR\extensions"

; Remove shortcuts, if any
Delete "$SMPROGRAMS\${PRODUCT_NAME}.lnk"
Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
;TODO remove eventual quicklaunch Too

; Remove the installation directory used (if empty)
RMDir "$INSTDIR"

; and delete the registry key for uninstall
DeleteRegKey ${HKEY_ROOT} ${UN_KEY}
SectionEnd

Quelques explications sur ce script :

Il utilise le thème par défaut "modern". Mais il serait possible de le personnaliser.

Certaines parties sont localisées ("traduites"), en insérant d'autres scripts nsis (décrits plus loin).

Il utilise quelques pages nsis par défaut, et une personnalisée pour la création des raccourcis sur le bureau et dans le menu démarrez.

L'installation et la désinstallation sont annulées si notre application est actuellement lancée.
En fait, quand notre application est en fonctionnement, XULRunner/Firefox crée une fenêtre Windows native avec une classe MyAppMessageWindow, le nom de cette classe est la valeur du champ Name dans application.ini concaténée avec "MessageWindow".
Le script vérifie juste si une telle fenêtre avec ce nom de classe est ouverte, et annule le traitement.

Il crée quelques entrées minimales dans La Base de Registre, pour permettre la désinstallation du programme avec l'outil "ajouter/supprimer des programmes" de Windows.

Si notre appli est déjà installée, la précédente version est désinstallée avant la nouvelle installation, en utilisant le désinstalleur précédent. Et, pour être plus précis, ce précédent désinstalleur est copié et lancé depuis le dossier "Temp" de Windows.

Pour la désinstallation, nous avons besoin de la liste complète des fichiers et dossiers installés. Ces listes seront créés dynamiquement plus tard, pour le moment dans ce script nous les insérons en tant que scripts nsis supplémentaires (uninstall_files.nsi et uninstall_dirs.nsi).

Maintenant voici le contenu de l'un des scripts localisés ("traduit"), en_US.nsh :

;!!! IMPORTANT: this must file must be edited with ANSI charset (in fact the
; Windows CP-1252 charset), but if there's no special character, UTF-8 is ok,
; because it's a subset ;)

LangString l10n_SHORTCUTS_PAGE_TITLE ${LANG_ENGLISH} \
"Set Up Shortcuts"
LangString l10n_SHORTCUTS_PAGE_SUBTITLE ${LANG_ENGLISH} \
"Create Program Icons"
LangString l10n_CREATE_ICONS_DESC ${LANG_ENGLISH} \
"Create icons for ${PRODUCT_NAME}:"
LangString l10n_ICONS_DESKTOP ${LANG_ENGLISH} \
"On my &Desktop"
LangString l10n_ICONS_STARTMENU ${LANG_ENGLISH} \
"In my &Start Menu Programs folder"

Nous devons faire attention à l'encodage des ces fichiers, celui-ci en anglais ne devrait pas poser de problème, mais celui en français doit être édité avec le charset Windows CP-1252 par exemple. Ces variables sont utilisées simplement dans notre script principal avec, par exemple, $(l10n_SHORTCUTS_PAGE_TITLE).

Notez que l'esperluette & dans les définitions de chaîne définissent des raccourcis clavier pour les contrôles dans l'interface utilisateur, ici il y a alt+D et alt+S.

3.4 Créer l'installeur

Nous avons maintenant tous les fichiers pour créer l'installeur. Voyons l'arborescence de nos sources :

    |-samples_chapter_3
|- data/
|- icons/
|- icon.ico
|- myapp.bat
|- myapp-res.rc
|- myapp/
|- win
|- nsis/
|- l10n/
|- en_US.nsh
|- fr.nsh
|- myapp.nsi
|- xal-src/
|- build.sh
|- clean.sh
|- main.c

Nous devons construire notre lanceur à partir des sources C et de nos données (icône et resource). Et créer 2 scripts nsis additionnels, pour lister les fichiers de notre appli. Puis nous pourrons créer notre installeur avec makensis. Nous allons faire celà dans un dossier temporaire. Voici le script, nommé build_win.sh :

#!/bin/bash

# exit the script on errors
set -e

TMP_DIR=./tmp

# get the absolute path of our TMP_DIR folder
TMP_DIR=$(readlink -f -- "$TMP_DIR")

# re-create the TMP_DIR folder
rm -rfv "$TMP_DIR"
mkdir -v "$TMP_DIR"

# copy our app
cp -rv myapp "$TMP_DIR/"

# copy the XAL launcher sources
cp -rv win/xal-src "$TMP_DIR/xal"
# and our icon and resource file
cp -v data/icons/icon.ico "$TMP_DIR/xal/myapp.ico"
cp -v data/myapp-res.rc "$TMP_DIR/xal/"

# build the launcher
cd "$TMP_DIR/xal/"
sh build.sh myapp myapp-res.rc
cd -

# copy the launchers in the right folder
cp -v data/myapp.bat "$TMP_DIR/myapp/"
cp -v "$TMP_DIR/xal/myapp.exe" "$TMP_DIR/myapp/"

# delete the xal sources
rm -rv "$TMP_DIR/xal"

# create the nsis script listing the files to unsinstall
cd "$TMP_DIR/myapp"
find . -maxdepth 1 -type f > ../uninstall_files.nsi
sed -i -r "s|^\./(.*)$| Delete \"\$INSTDIR\\\\\1\"|" ../uninstall_files.nsi

# and the list of directory
ls -d */ > ../uninstall_dirs.nsi
sed -i -r "s|^(.*)/$| RMDir /r \"\$INSTDIR\\\\\1\"|" ../uninstall_dirs.nsi
cd -

# copy the other nsis scripts
cp -rv win/nsis/* "$TMP_DIR/"

# and create the installer
makensis "$TMP_DIR/myapp.nsi"

# finally, copy our installer in the root sources dir
cp -v "$TMP_DIR/MyApp-1.0-install.exe" ./

echo "Windows installer for myapp created."

Pour lancer ce script, dans un terminal :

  • cd samples_chapter_3
  • sh ./build_win.sh

Et en résultat nous avons finalement le fichier MyApp-1.0-install.exe dans le dossier samples_chapter_3 :) .

Nicolas Martin

Vous pouvez télécharger tous les exemples de ce chapitre 3 (Windows) dans l'archive samples_chapter_3.tar.gz .

L'application myapp, de developer.mozilla.org, est dans le Domaine Public.

L'icône utilisée est issue du Tango Desktop Project, et est dans le Domaine Public.

le lanceur C XUL App Launcher (XAL) est sous licence MIT.

Toutes les autres données ajoutées, et les fichiers en exemple, de ce chapitre 3, sont dans le Domain Public également.

mardi, mai 24 2011

Distribuer votre appli XULRunner - 2.4 - Empaqueter un rpm

This post exists also in english

Ce billet fait partie d'une série sur comment déployer une application XULRunner. Voir le préambule pour le contexte.

2 - Linux

2.4 Empaqueter un rpm

2.4.1 Préalable

Dans cette partie nous allons créer un paquet rpm, pour les distributions basée sur rpm, comme Red Hat, Fedora, Suse,... (j'ai testé uniquement sur Fedora, merci de me faire savoir si vous rencontrez des problèmes sur les autres).

Nous pouvons créer ce rpm aussi bien depuis d'autres distributions Linux, basées sur Debian par exemple (c'est ce que je fais), nous avons juste besoin de l'executable rpmbuild, et pour celà il suffit d'installer rpm :

apt-get install rpm

Quelques liens de documentation :

Je suppose que nous n'avons pas besoin de compilation pour notre appli, mais si ce n'est pas le cas, compiler simplement avant l'empaquètement (malgré le fait que ce soit déconseillé dans ce guide).

2.4.2 Fichiers RPM

pour créer un rpm, nous sommes supposé paramétrer une configuration utilisateur pour la création de tout rpm. Mais il est possible de faire celà dans un dossier local, c'est ce que nous allons faire.

Nous devons créer les dossiers suivants, et un fichier myapp.spec :

    |- samples_chapter_2/
|- myapp/
|- rpmbuild/
|- BUILD/
|- RPMS/
|- SOURCES/
|- SPECS/
|- SRPMS/
|- myapp.spec

En fait c'est la même structure que pour un environnement général de création rpm, mais local.

Le fichier .spec est le 'script' utilisé par rpmbuild pour créer le rpm. Il est supposé utiliser une archive source au format tar.gz, que nous allons créer spécialement pour lui plus tard.

Voici le contenu de notre spec :

Name:           myapp
Version: 1.0
Release: 1%{?dist}
Summary: simple Hello World powered by XULRunner.

Group: Development/Tools
License: MPLv1.1 or GPLv2+ or LGPLv2+
URL: http://example.com/myapp/
Source: myapp-1.0.tar.gz
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id} -un)

#BuildRequires:
Requires: firefox >= 3.6

%description
simple Hello World
Powered by XULRunner.

%prep
%setup

%build

%install
rm -rf %{buildroot}
mkdir -p %{buildroot}%{_libdir}
cp -R myapp %{buildroot}%{_libdir}/
mkdir -p %{buildroot}%{_bindir}

ln -s %{_libdir}/myapp/myapp.sh %{buildroot}%{_bindir}/myapp

mkdir -p %{buildroot}%{_datadir}/applications
cp data/myapp.desktop %{buildroot}%{_datadir}/applications/

mkdir -p %{buildroot}%{_datadir}/icons/hicolor/16x16/apps
cp data/icons/icon16.png \
%{buildroot}%{_datadir}/icons/hicolor/16x16/apps/myapp.png

mkdir -p %{buildroot}%{_datadir}/icons/hicolor/22x22/apps
cp data/icons/icon22.png \
%{buildroot}%{_datadir}/icons/hicolor/22x22/apps/myapp.png

mkdir -p %{buildroot}%{_datadir}/icons/hicolor/32x32/apps
cp data/icons/icon32.png \
%{buildroot}%{_datadir}/icons/hicolor/32x32/apps/myapp.png

mkdir -p %{buildroot}%{_datadir}/icons/hicolor/48x48/apps
cp data/icons/icon48.png \
%{buildroot}%{_datadir}/icons/hicolor/48x48/apps/myapp.png

mkdir -p %{buildroot}%{_datadir}/icons/hicolor/scalable/apps
cp data/icons/icon48.svg \
%{buildroot}%{_datadir}/icons/hicolor/scalable/apps/myapp.svg

%post
touch --no-create %{_datadir}/icons/hicolor &>/dev/null || :
if [ -x %{_bindir}/gtk-update-icon-cache ]; then
%{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor;
fi

%postun
touch --no-create %{_datadir}/icons/hicolor &>/dev/null || :
if [ -x %{_bindir}/gtk-update-icon-cache ]; then
%{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor;
fi


%clean
rm -rf $RPM_BUILD_ROOT


%files
%defattr(-,root,root,-)
%{_bindir}/myapp
%{_libdir}/myapp
%{_datadir}/applications/myapp.desktop
%{_datadir}/icons/hicolor/16x16/apps/myapp.png
%{_datadir}/icons/hicolor/22x22/apps/myapp.png
%{_datadir}/icons/hicolor/32x32/apps/myapp.png
%{_datadir}/icons/hicolor/48x48/apps/myapp.png
%{_datadir}/icons/hicolor/scalable/apps/myapp.svg
#%doc

%changelog
* Fri Oct 8 2010 John Doe <johndoe@example.com> 1.0-1
- first publication

Voyons en détail certaines entrées de ce fichier :

Name ne devrait contenir aucun caractère blanc.

Version doit contenir uniquement des chiffres (et des points), pas de chaîne comme "beta".

L'entrée Group doit être choisie dans la liste du fichier /usr/share/doc/rpm/GROUPS . Vous devez l'avoir sur votre ordinateur avec l'installation de rpm.

Release est la version du rpm pour cette version de l'appli, et %{?dist} sera remplacé par rpmbuild par la distribution courante. Celà ne sera pas complété sur une distribution non rpm (comme Debian), vous pouvez le supprimer si vous le désirez.

Pour l'entrée License, vous devez choisir un mot clé court (short keyword) dans cette liste.

L'entrée Source doit correspondre exactement au tar.gz que nous créerons plus tard.

La ligne BuildArch: noarch spécifie que notre appli n'est pas spécifique à l'architecture. Si votre appli contient du code compilé, vous devez supprimer cette ligne, et un rpm spécifique à l'architecture courante sera construit.

La valeur de BuildRoot est une valeur habituelle.

BuildRequires est commenté (avec un #), comme nous n'avons pas de compilation.

Enfin, l'entrée Requires contient les autres paquets qui sont nécessaires au fonctionnement de notre appli. Vous pourriez en ajouter d'autres, séparés par des virgules (,). Notez que vous ne pouvez pas déclarer de dépendances alternatives, comme pour un deb. C'est pourquoi nous déclarons Firefox et non XULRunner comme dépendance, dans le cas éventuel où le Firefox de la distribution n'est pas basée sur XULRunner.

Par la suite nous copierons notre archive tar.gz dans le dossier SOURCES.
Puis la section %prep et l'instruction %setup la décompresseront dans le dossier BUILD.
La section %build est vide, parce que nous n'avons pas de compilation à faire.

Dans la section %install, nous installons notre appli.
Ce sont des commandes shell, le dossier courant de travail est la source tar.gz non compressée. %{buildroot} est la racine de l'installation local de notre appli, ce sera la racine de l'ordinateur / lors de l'installation réelle.
%{_libdir}, %{_bindir}, et %{_datadir} correspondent respectivement à /usr/lib/, /usr/bin/, et /usr/share/. Je suppose que c'est le cas pour les principales distributions basées sur rpm, si je me trompe, merci de me corriger, car il faudrait alors redéfinir certaines variables.
Donc dans cette section, nous recréons le dossier initial buildroot. Puis nous créons le lien vers notre lanceur dans /usr/bin/, copions notre appli dans /usr/lib/, et copions notre fichier desktop et nos icônes aux bons emplacements dans /usr/share/.

les sections %post et %postun déclarent quelques actions après que notre appli sera installée ou désinstallée. Nous mettons à jour la base des icônes pour le gestionnaire de fenêtre.
Si l'appli prend en charge certains types mime, i.e. peut ouvrir certains type de fichier, celà doit être spécifier dans le fichier .desktop . Et vous devez ajouter le code suivant dans ces sections %post et %postun :

if [ -x /usr/bin/update-desktop-database ]; then
update-desktop-database &> /dev/null || :
fi

La section %files est obligatoire, et contient la liste complète des fichiers/dossiers installés par notre appli.

Enfin, le format de la section %changelog, est décrite dans cette doc.

2.4.3 Créer le rpm

Maintenant que nous avons tout ce dont nous avons besoin, nous allons créer un script pour créer une "fausse" archive source pour rpmbuild, qui contiendra notre appli, notre fichier desktop, et nos icônes. Nous placerons cette archive dans le dossiers SOURCES, puis invoquerons rpmbuild localement avec notre fichier spec. Et en fait, nous ferons tout celà dans un dossier temporaire, pour laisser nos sources propres.

Note: rmpbuild semble bugger si il y a des espaces dans le chemin du dossier de travail, donc faites attention avec le nom des (sous)dossiers où vous placez les sources.
Le script suivant s'arrêtera si c'est le cas.

Voilà ce script :

#!/bin/bash

# exit the script on errors
set -e

TMP_DIR=./tmp
SRC_VERSION=1.0

# get the absolute path of our TMP_DIR folder
TMP_DIR=$(readlink -f -- "$TMP_DIR")

# re-create the TMP_DIR folder
rm -rfv "$TMP_DIR"
mkdir -v "$TMP_DIR"

# copy the rmpbuild tree folder
cp -rv rpmbuild/* "$TMP_DIR/"

# create a source tar.gz archive for rpmbuild into SOURCES
mkdir -v "$TMP_DIR/myapp-$SRC_VERSION"
cp -rv myapp "$TMP_DIR/myapp-$SRC_VERSION/"
cp -rv data "$TMP_DIR/myapp-$SRC_VERSION/"
cd "$TMP_DIR"
# clean eventual tempory files
find . -type f -name *.*~ -exec rm {} \;
tar -zcvf "$TMP_DIR/SOURCES/myapp-$SRC_VERSION.tar.gz" \
"myapp-$SRC_VERSION"
cd -
rm -rv "$TMP_DIR/myapp-$SRC_VERSION"

# rmpbuild seems to have a bug, it can't handle a _topdir with whitespace
if [ -n "$(echo "$TMP_DIR" | grep '[ ]')" ]; then
echo "the path '$TMP_DIR' contains whitespace, rpmbuild will failed. script aborted!"
exit 1
fi

# build the rpm from our spec, specify our local build tree
rpmbuild --define="_topdir $TMP_DIR" -bb "$TMP_DIR/myapp.spec"

# and finally copy our created rpm in to into the current folder
cp -v "$TMP_DIR/RPMS/noarch/myapp-$SRC_VERSION-1.noarch.rpm" ./

Pour créer notre rpm, dans un terminal :

  • cd samples_chapter_2
  • sh ./build_rpm.sh

Et en résultat nous avons finalement le fichier myapp-1.0-1.noarch.rpm dans le dossier myapp-src :) .

Nicolas Martin

Vous pouvez télécharger tous les exemples de ce chapitre 2 (Linux) dans l'archive samples_chapter_2.tar.gz .

L'application myapp, de developer.mozilla.org, est dans le Domaine Public.

L'icône utilisée est issue du Tango Desktop Project, et est dans le Domaine Public.

Toutes les autres données ajoutées, et les fichiers en exemple, sont dans le Domain Public également.

dimanche, mai 22 2011

Distribuer votre appli XULRunner - 2.2 - Empaqueter un deb

This post exists also in english

Ce billet fait partie d'une série sur comment déployer une application XULRunner. Voir le préambule pour le contexte.

2 - Linux

2.2 Empaqueter un deb

2.2.1 Synopsis

Ok, nous avons notre lanceur, et tous les fichiers nécessaires à l'intégration au bureau (voir le chapitre 2.1). Nous allons maintenant créer un paquet deb, pour les distributions basées sur Debian, comme Ubuntu.

La principale documentation pour la création de deb est Debian Policy Manual. et vous pouvez trouver également utile cette autre doc de Debian et celle ci d'Ubuntu.

Je suppose que notre appli ne contient pas de code compilé, mais si c'est le cas, compilez le simplement avant de créer le paquet. Nous créerons ce deb manuellement.

Nous allons utiliser debhelper et fakeroot. Nous devons créer quelques fichiers utilisés par les scripts debian, copier nos sources et fichiers de bureau aux bons emplacements, et exécuter quelques scripts.

Pour celà, nous devons installer debhelper et fakeroot.

sur Debian/Ubuntu:

  • apt-get install debhelper fakeroot

Sur Fedora, malheureusement debhelper n'est pas encore disponible dans les dépôts, mais devrait l'être un jour, voir les bugs #591190, #591389, #642160, et #591332.

Sur OpenSuse il y a un paquet nommé 'deb' qui l'installe.

sur les autres distributions... faites le moi savoir ;)

Le deb créé installera myapp dans le dossier /usr/lib/ , c'est l'emplacement standard sur Linux.

2.2.2 Fichiers Debian

pour construire notre deb, nous devons créer un dossier debian à coté de notre application, contenant plusieurs fichiers utilisés par les programmes de debhelper
Vous pouvez utiliser dh_make pour créer un tel squelette, mais ici nous allons créer ces fichiers nous-même :

    |- samples_chapter_2/
|- myapp/
|- debian/
|- changelog
|- compat
|- control
|- copyright
|- menu
|- postinst
|- myapp.links

Le fichier changelog est décrit en détail ici dans la doc, il contient :

myapp (1.0-1) unstable; urgency=low

* Initial release

-- John Doe <johndoe@example.com> Fri, 26 Nov 2010 10:10:35 +0100

Note : soyez précis dans le format de ce fichier, il doit réellement être précis, voir la doc.

Note : la date doit être au format RFC822, vous pouvez l'obtenir avec date -R dans un terminal.

Le fichier compat contient simplement la compatibilité de debhelper, soit juste 7 .

Le fichier control est le plus important. Voici un exemple :

Source: myapp
Section: Utilities
Priority: extra
Maintainer: John Doe <johndoe@example.com>
Build-Depends: debhelper (>= 7)
Standards-Version: 3.7.2
Homepage: <http://example.com/myapp/>

Package: myapp
Architecture: all
Depends: xulrunner (>= 1.9.2) | firefox (>= 3.6)
Description: simple Hello World.
Powered by XULRunner.

Choisissez une Section dans cette liste.

Si votre application contient du code compilé, vous devez supprimer la ligne Architecture: all, car son but est précisement de créer un paquet indépendant de la plateforme. Sans cette entrée, le deb sera spécifique à l'architecture actuelle.

Si votre appli nécessite d'autres dépendances, ajoutez les séparés par une virgule. Si l'appli contient du code compilé, vous pouvez vouloir utiliser la valeur ${shlibs:Depends}, ainsi à la construction du paquet certaines dépendances seront calculées. Par exemple :

Depends: xulrunner (>= 1.9.2) | firefox (>= 3.6), ${shlibs:Depends}

Le format du champ Description est décrit en détail dans cette doc.

Le fichier copyright peut contenir par exemple :

This package was debianized by John Doe <johndoe@example.com> on
Sat, 16 Oct 2010 17:55:17 +0200

It was downloaded from <http://example.com/myapp/>

Upstream Author(s):
John Doe <johndoe@example.com>

Copyright:
<Copyright (C) 2010 John Doe>

License:
***** BEGIN LICENSE BLOCK *****
Version: MPL 1.1/GPL 2.0/LGPL 2.1

The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.

The Original Code is MyApp.

The Initial Developer of the Original Code is John Doe.
Portions created by the Initial Developer are Copyright (C) 2010
the Initial Developer. All Rights Reserved.

Contributor(s):
John Doe (johndoe@example.com)

Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.

***** END LICENSE BLOCK *****

Le fichier menu contient :

?package(myapp):needs="X11" section="Applications/Programming"\
title="MyApp" command="/usr/bin/myapp"

Choisissez une section dans cette liste.

Le fichier postinst est un script lancé à la fin de l'installation du deb. Il permet de reconstruire le cache des icônes système par exemple.

#!/bin/sh
# postinst script for myapp
#
# see: dh_installdeb(1)

set -e

# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package

case "$1" in
configure)
# for icons of the app
if [ -x /usr/bin/gtk-update-icon-cache ]; then
gtk-update-icon-cache -f /usr/share/icons/hicolor
fi

# uncomment only if the installed app handle some mime-type
#if [ "$2" == "" ]; then
# if [ -x /usr/bin/update-desktop-database ]; then
# update-desktop-database /usr/share/applications
# fi
#fi
;;

abort-upgrade|abort-remove|abort-deconfigure)
;;

*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac

# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.

#DEBHELPER#

exit 0

Enfin, le fichier myapp.links contient les liens à créer après l'installation du deb.

/usr/lib/myapp/myapp.sh /usr/bin/myapp
2.2.3 Créer le deb

Ok, nous avons maintenant tous les fichiers nécessaires, nous pouvons créer notre deb. Nous devons créer un dossier portant le même nom que notre application dans le dossier debian, et y copier les fichiers de la même manière que sur le système final.

    |- debian/
|- myapp/
|- usr
|- lib
|- myapp/
|- share
|- applications/
|- myapp.desktop
|- icons/
|- hicolor/
|- 16x16/
|- apps
|- myapp.png
|- 22x22/
|- apps
|- myapp.png
|- 32x32/
|- apps
|- myapp.png
|- 48x48/
|- apps
|- myapp.png
|- scalable/
|- apps
|- myapp.svg

Et nous allons appliquer quelques script debhelper.

Voici un script shell complet, nommé build_deb.sh, il crée un dossier temporaire 'tmp', et y copie nos fichiers debian, notre application, et nos fichiers desktop, puis crée le deb :

#!/bin/bash

# exit the script on errors
set -e

TMP_DIR=./tmp

# get the absolute path of our TMP_DIR folder
TMP_DIR=$(readlink -f -- "$TMP_DIR")

# re-create the TMP_DIR folder
rm -rfv "$TMP_DIR"
mkdir -v "$TMP_DIR"

#copy the debian folder into TMP_DIR
cp -rv "./debian" "$TMP_DIR/"

# create into TMP_DIR the folder where copy our app
mkdir -pv "$TMP_DIR/debian/myapp/usr/lib"

# and copy the app
cp -rv "./myapp" "$TMP_DIR/debian/myapp/usr/lib/"

# create the folder for the .desktop file and copy it
mkdir -pv "$TMP_DIR/debian/myapp/usr/share/applications"
cp -v "./data/myapp.desktop" \
"$TMP_DIR/debian/myapp/usr/share/applications/"

# create the folder and copy our icons
mkdir -pv "$TMP_DIR/debian/myapp/usr/share/icons/hicolor/16x16/apps"
cp -v "./data/icons/icon16.png" \
"$TMP_DIR/debian/myapp/usr/share/icons/hicolor/16x16/apps/myapp.png"

mkdir -pv "$TMP_DIR/debian/myapp/usr/share/icons/hicolor/22x22/apps"
cp -v "./data/icons/icon22.png" \
"$TMP_DIR/debian/myapp/usr/share/icons/hicolor/22x22/apps/myapp.png"

mkdir -pv "$TMP_DIR/debian/myapp/usr/share/icons/hicolor/32x32/apps"
cp -v "./data/icons/icon32.png" \
"$TMP_DIR/debian/myapp/usr/share/icons/hicolor/32x32/apps/myapp.png"

mkdir -pv "$TMP_DIR/debian/myapp/usr/share/icons/hicolor/48x48/apps"
cp -v "./data/icons/icon48.png" \
"$TMP_DIR/debian/myapp/usr/share/icons/hicolor/48x48/apps/myapp.png"

mkdir -pv "$TMP_DIR/debian/myapp/usr/share/icons/hicolor/scalable/apps"
cp -v "./data/icons/icon48.svg" \
"$TMP_DIR/debian/myapp/usr/share/icons/hicolor/scalable/apps/myapp.svg"

cd "$TMP_DIR"

# clean eventual tempory files
find . -type f -name *.*~ -exec rm {} \;

# deb creation
fakeroot dh_link
fakeroot dh_fixperms
fakeroot dh_installdeb
# uncomment the following line if you have some compiled code and use ${shlibs:Depends} in control file
#dh_shlibdeps
fakeroot dh_gencontrol
fakeroot dh_md5sums
fakeroot dh_builddeb

echo "deb created for myapp :)"

Pour créer notre deb, dans un terminal :

  • cd samples_chapter_2
  • sh ./build_deb.sh

En résultat nous avons finalement le fichier myapp_1.0-1_all.deb dans le dossier samples_chapter_2 :) .

Nicolas Martin

Vous pouvez télécharger tous les exemples de ce chapitre 2 (Linux) dans l'archive samples_chapter_2.tar.gz .

L'application myapp, de developer.mozilla.org, est dans le Domaine Public.

L'icône utilisée est issue du Tango Desktop Project, et est dans le Domaine Public.

Toutes les autres données ajoutées, et les fichiers en exemple, sont dans le Domain Public également.

samedi, mai 21 2011

Distribuer votre appli XULRunner - 2.1 - Linux commun

This post exists also in english

Ce billet fait partie d'une série sur comment déployer une application XULRunner. Voir le préambule pour le contexte.

2 - Linux

2.1 Linux commun

2.1.1 Généralités

Nous ciblons la plateforme Linux dans cette partie. Et c'est le cas le plus simple.

Pour toutes les distributions que j'ai essayées, XULRunner est disponible depuis le gestionnaire de paquets, et Firefox est basé sur lui. Donc XULRunner peut facilement être une dépendance de notre application.

2.1.2 Créer un lanceur

Il est facile de créer un lanceur, créons simplement un script shell nommé myapp.sh, dans le dossier principal de notre application (celui qui contient application.ini), avec le contenu suivant :

#!/bin/sh

CUR_DIR=$(dirname $(readlink -f "$0"))

if [ -x /usr/bin/xulrunner ]; then
/usr/bin/xulrunner "$CUR_DIR/application.ini" $@
elif [ -x /usr/bin/firefox ]; then
/usr/bin/firefox -app "$CUR_DIR/application.ini" $@
else
echo "Error: unable to find XULRunner or Firefox!"
fi

et rendons le exécutable :

chmod +x myapp.sh

Le script trouve dans quel dossier il se trouve, puis lance le fichier application.ini via xulrunner s'il le trouve, sinon via firefox avec l'argument -app. Le script passe aussi les éventuels arguments supplémentaires (comme -jsconsole par exemple).

Plus tard dans ce tutoriel, quand nous créerons les paquets deb et rpm, nous ajouterons un lien symbolique vers ce fichier dans /usr/bin .

Note: l'argument -f de readlink utilisé dans ce script est disponible uniquement dans la version GNU, donc dans toutes les distributions Linux, mais pas forcément sur d'autres systèmes de type Unix, comme Mac OSX par exemple.

2.1.3 Des icônes pour nos fenêtres

Pour l'instant, notre application est lancée, mais l'icône affichée dans la barre de tâches est celle générique de XULRunner, ou celle de Firefox. Il est facile d'afficher notre propre icône. Créons simplement un dossier nommé 'icons' à l'intérieur du dossier chrome principal de notre appli, puis créons dans celui-ci un autre nommé 'default'. Copions 3 fichiers png, nommés default16.png, default32.png, et default48.png. Et c'est tout, maintenant c'est notre icône qui est affichée.

    |- samples_chapter_2/
|- myapp/
|- chrome
|- icons/
|- default/
|- default16.png
|- default32.png
|- default48.png
 2.1.4 Intégration au bureau

Pour une intégration complète au bureau, nous devons maintenant créer quelques fichiers supplémentaires, un fichier .desktop, et quelques icône associées. Ainsi notre appli apparaitra dans le menu Applications du gestionnaire de fenêtres.

En exemple, voici le contenu d'un fichier myapp.desktop :

[Desktop Entry]
Version=1.0
Encoding=UTF-8
Name=MyApp
Comment=a Hello World XULRunner app
Comment[fr]=un Bonjour Monde pour XULRunner.
Exec=/usr/bin/myapp
Terminal=false
Type=Application
Categories=Utility;
Icon=myapp

Voir cette documentation pour les détails, et celle ci pour choisir les Catégories.

L'entrée Exec est décrite en détail ici, nous utilisons un lien symbolique vers notre lanceur, depuis /usr/bin/ (le standard pour les exécutables sur Linux). Son emplacement réel sera dans /usr/lib/myapp/.

L'entrée Icon contient le nom de notre icône, que nous créerons par la suite.

L'entrée Comment est optionnelle, et peut être localisée (comme quelques autres entrées, voyez la spécification), ici nous définissons sune valeur par défaut, et une française (fr).

Si l'appli gère certains types mime, i.e. peut ouvrir certains types de fichiers, vous devez ajouter une ligne avec l'entrée MimeType, par exemple :

MimeType=text/html;text/xml;application/xhtml+xml;

Ce fichier myapp.desktop est sensé être placé à l'étape finale dans le dossier /usr/share/applications/ folder.
(Voir http://www.freedesktop.org/wiki/Specifications/menu-spec et http://www.freedesktop.org/wiki/Specifications/basedir-spec pour plus de détail)

Maintenant nous avons besoin de quelques icônes. Nous utiliserons des png et svg (xpm est également possible, mais semble déprécié, nous n'utiliserons pas ce format). Nous pouvons avoir différentes tailles, personnellement je me restreint à 4 png (16x16, 22x22, 32x32, 48x48), comme suggéré par les Tango Guidelines, plus un svg de 48x48.

Ces images doivent être nommées myapp.png, et myapp.svg .

Et elles doivent finalement être placées dans les dossiers suivants :

  • /usr/share/icons/hicolor/16x16/apps/myapp.png
  • /usr/share/icons/hicolor/22x22/apps/myapp.png
  • /usr/share/icons/hicolor/32x32/apps/myapp.png
  • /usr/share/icons/hicolor/48x48/apps/myapp.png
  • /usr/share/icons/hicolor/scalable/apps/myapp.svg
 2.1.5 Distribuer un tar.gz

Notre application est utilisable telle quelle avec son lanceur, vous pouvez donc la distribuer avec un simple tar.gz. Pour le créer :

tar -zcvf myapp.tar.gz myapp

Un utilisateur peut le télécharger, le décompresser n'importe où, et lancer l'appli via myapp.sh.

Mais pour être plus convivial, un paquet utilisable avec le gestionnaire de paquet de sa distribution, avec l'intégration au bureau complète, est préférable. C'est ce que nous verrons dans les prochaines sections.

Nicolas Martin

Vous pouvez télécharger tous les exemples de ce chapitre 2 (Linux) dans l'archive samples_chapter_2.tar.gz .

L'application myapp, de developer.mozilla.org, est dans le Domaine Public.

L'icône utilisée est issue du Tango Desktop Project, et est dans le Domaine Public.

Toutes les autres données ajoutées, et les fichiers en exemple, sont dans le Domain Public également.

- page 1 de 2