Jacques Foucry bio photo

Jacques Foucry

IT, râleur et faiseur de pain

Email



Le deuxième article sur la compilation automatique pour iOS et diffusion OTA (Over The Air)

Résumé des épisodes précédents

Nous avons vu comment installer Java, Jenkins et faire un premier flux Jenkins pour compiler une application OSX.

Un flux pour iOS sur Simulateur

Cette fois-ci, nous allons voir comment faire une application iOS destinée au simulateur. En ligne de commande depuis une machine sous Linux l’intérêt est très limité. Mais ce deuxième flux va nous permettre d’avoir un squelette pour notre but ultime, la compilation d’une application iOS pour un périphérique et sa diffusion “Over The Air” (OTA).

Nous allons donc faire un nouveau job Jenkins. Appelons le iOS_Build.

Comme pour le précédent nous allons désigner un dépôt Git pour un projet iOS.

La commande de compilation est toujours “Execute Shell” avec la commande suivante :

1
$ xcodebuild -target MonProjet -configuration Debug -sdk iphonesimulator5.0
  • target doit être une target connue dans votre projet. Si vous n’avez pas en tête la liste des target de votre projet, vous pouvez utiliser certains paramètres de xcodebuild
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ xcodebuild -list -project /Users/Shared/Jenkins/Home/jobs/iOS_Build/workspace/MonProjet.xcodeproj
Information about project "MonProjet":
Targets:
MonProjet
MonProjetTests

Build Configurations:
Debug
Release

If no build configuration is specified and -scheme is not passed then "Release" is used.

Schemes:
MonProjet
  • Configuration correspond à l’une des configurations de build de votre projet. Vous avez dû noter que la ligne de commande précédente vous donnait aussi les configurations de build
  • sdk indique le SDK à utiliser ; ici il s’agit du SDK 5.0 pour le simulateur. Pour connaître la liste des SDK disponibles sur votre machine, utilisons encore une fois xcodebuild
1
2
3
4
5
6
7
8
9
10
$ xcodebuild -showsdks
Mac OS X SDKs:
 Mac OS X 10.6 -sdk macosx10.6
 Mac OS X 10.7 -sdk macosx10.7

iOS SDKs:
 iOS 5.0 -sdk iphoneos5.0

iOS Simulator SDKs:
 Simulator - iOS 5.0 -sdk iphonesimulator5.0

Si vous avez de la chance, votre build va fonctionner rapidement. Si ce n’est pas le cas regardez les traces dans Jenkins pour savoir ce qui ne fonctionne pas.

Un flux pour iOS sur iDevice

Et pour une compilation iOS, comment faire ? Partons du même projet, en le dupliquant (New Job et choisissez Copy existing job et donnez le nom de votre flux précédent).

Ce qui va changer dans ce nouveau, c’est une fois de plus la ligne de commande qui exécute xcodebuild.

Le premier changement est le SDK. iphonesimulator5.0 devient iphoneos5.0. Si vous décidez de tenter une compilation immédiatement, celle-ci va échouer.

1
Code Sign error: There are no valid certificate/private key pairs in the default keychain

Il faut indiquer à xcodebuild le certificat de signature de code à utiliser.

Note : Vous aurez besoin de la clef privée, de votre certificat de développeur et du provising profile de votre projet. Le plus simple est de passer par l’application Keychain Access (Trousseau d’Accès) sur votre machine de développement).

Jouons avec la keychain et les certificats

Export avec l’interface graphique du Trousseau d’accès

Dans les certificats, sélectionnez celui qui correspond à celui généré par Apple pour votre compte développeur et exportez-le. La clef privée est comprise dans cet export. Choisissez une extension .p12 (format pkcs12).

Export à la ligne de commande

Note à l’attention des chevelus qui nous lisent : ici, commence la vieillesse et la calvitie. Samson, si tu tiens à ta crinière fuit loin des keychain..
Toutefois, il est intéressant de le faire à ligne de commande pour rester dans le cadre de ce tutoriel.

Donc, sur la machine de développement, nous allons extraire les informations qui nous intéressent.

1
$ security export -k login.keychain -t identities -f pkcs12 -o $HOME/identities.p12 -P "passphrase"

La passphrase est celle de l’ouverture de votre keychain.

Transférez le fichier résultant sur votre machine de build. J’ai déposé le mien dans /Users/Shared.

Passons maintenant sur la machine de build. Pour apprendre des tas de choses (et parce que je n’ais pas d’écran branché sur cette machine) je vais manipuler la keychain à la ligne de commande.

Commençons pas obtenir la liste des keychain existantes :

1
2
3
$ security list-keychains
"/Users/jacques/Library/Keychains/login.keychain"
"/Library/Keychains/System.keychain"

Nous pouvons également connaître le contenu des keychains avec security dump-keychain ce qui va nous permettre de savoir si nous avons les éléments nécessaires à la compilation des applications iPhone.
Nous avons besoin du certificat racine d’Apple, du certificat du développeur, de sa clef privée et de sa clef publique.

Recherchons le certificat racine d’Apple :

1
2
3
4
5
$ security dump-keychain | grep -i "Apple Code Signing Certification Authority"
"alis"<blob>="Apple Code Signing Certification Authority"
"labl"<blob>="Apple Code Signing Certification Authority"
"subj"<blob>=0x307F310B300906035504061302555331133011060355040A130A4150504C4520494E432E31263024060355040B131D4150504C452043455254494649434154494F4E20415554484F52495459313330310603550403132A4150504C4520434F4445205349474E494E472043455254494649434154494F4E20415554484F52495459 "01771\0130\011\006\003U\004\006\023\002US1\0230\021\006\003U\004\012\023\012APPLE INC.1&0$\006\003U\004\013\023\035APPLE CERTIFICATION AUTHORITY1301\006\003U\004\003\023*APPLE CODE SIGNING CERTIFICATION AUTHORITY"
  "issu"455254494649434154494F4E20415554484F52495459313330310603550403132A4150504C4520434F4445205349474E494E472043455254494649434154494F4E20415554484F52495459 "01771\0130\011\006\003U\004\006\023\002US1\0230\021\006\003U\004\012\023\012APPLE INC.1&0$\006\003U\004\013\023\035APPLE CERTIFICATION AUTHORITY1301\006\003U\004\003\023*APPLE CODE SIGNING CERTIFICATION AUTHORITY"

Il est présent, tout va bien.

Cherchons à présent les informations sur le développeur (iPhone Developper) :

1
$ security dump-keychain | grep -i "iPhone Developer"

Je n’ai aucune réponse sur ma machine, preuve que je n’ai pas ces informations dans une keychain. Il va donc falloir importer les éléments dans une keychain. Et tout d’abord créer une nouvelle keychain.

Attention, il est nécessaire de faire cette keychain pour l’utilisateur qui fait tourner Jenkins, il faut donc devenir Jenkins

1
$ su - jenkins

Nous allons commencer par nous assurer que jenkins accède aux certificats racine d’Apple. C’est normalement le cas, ces certificats étant dans la keychain System.

1
2
3
4
5
$ security dump-keychain | grep -i "Apple Code Signing Certification Authority"
"alis"<blob>="Apple Code Signing Certification Authority"
"labl"<blob>="Apple Code Signing Certification Authority"
"subj"<blob>=0x307F310B300906035504061302555331133011060355040A130A4150504C4520494E432E31263024060355040B131D4150504C452043455254494649434154494F4E20415554484F52495459313330310603550403132A4150504C4520434F4445205349474E494E472043455254494649434154494F4E20415554484F52495459 "01771\0130\011\006\003U\004\006\023\002US1\0230\021\006\003U\004\012\023\012APPLE INC.1&0$\006\003U\004\013\023\035APPLE CERTIFICATION AUTHORITY1301\006\003U\004\003\023*APPLE CODE SIGNING CERTIFICATION AUTHORITY"
  "issu"<blob>=0x307F310B300906035504061302555331133011060355040A130A4150504C4520494E432E31263024060355040B131D4150504C452043455254494649434154494F4E20415554484F52495459313330310603550403132A4150504C4520434F4445205349474E494E472043455254494649434154494F4E20415554484F52495459 "01771\0130\011\006\003U\004\006\023\002US1\0230\021\006\003U\004\012\023\012APPLE INC.1&0$\006\003U\004\013\023\035APPLE CERTIFICATION AUTHORITY1301\006\003U\004\003\023*APPLE CODE SIGNING CERTIFICATION AUTHORITY"

Apparemment, tout va bien.

Créons notre keychain, que nous appellerons Jenkins.keychain pour des raisons de commodité, mais que vous pouvez nommer comme vous le désirez.

1
2
3
4
5
6
7
$ security create-keychain jenkins.keychain
password for new keychain:
retype password for new keychain:

$ security list-keychains
"/Users/Shared/Jenkins/Home/Library/Keychains/jenkins.keychain"
"/Library/Keychains/System.keychain"

Parfait, notre keychain est créée. Il faut maintenant importer les éléments issus de l’export de la machine de developpement.

1
2
3
4
5
$ security list-keychains
"/Users/Shared/Jenkins/Home/Library/Keychains/jenkins.keychain"
"/Library/Keychains/System.keychain"
macmini:~ jenkins$ security import /Users/Shared/FoucryJacques.p12 -k jenkins.keychain -t cert -f pkcs12 -T /usr/bin/codesign -T /usr/bin/xcodebuild -P motDePasse
1 identity imported.
  • le chemin vers le fichier .p12
  • -t cert, nous importons un certificat
  • -f pkcs12, il s’agit du format dans lequel se trouvent les données
  • -T xxxx, les applications qui ont accès à l’identité, ici xcodebuild et codesign
  • -P le mot de passe qui verrouille le fichier p12. Ce mot de passe a été renseigné au moment de l’export sur la machine de développement

Histoire d’être certains du succès de l’opération, vérifions que la keychian est bien renseignée :

1
2
3
4
$ security dump-keychain | grep -i "iPhone Developer"
"alis"<blob>="iPhone Developer: Jacques Foucry (K45L6X42KM)"
"labl"<blob>="iPhone Developer: Jacques Foucry (K45L6X42KM)"
"subj"<blob>=0x308193311A3018060A0992268993F22C6401010C0A3454354E4D52535036593136303406035504030C2D6950686F6E6520446576656C6F7065723A204A61637175657320466F7563727920284B34354C365834324B4D2931173015060355040B0C0E4A61637175657320466F7563727931173015060355040A0C0E4A61637175657320466F75637279310B3009060355040613024652 "02012231\0320\030\006\012\011222&amp;211223362,d\001\001\014\0124T5NMRSP6Y1604\006\003U\004\003\014-iPhone Developer: Jacques Foucry (K45L6X42KM)1\0270\025\006\003U\004\013\014\016Jacques Foucry1\0270\025\006\003U\004\012\014\016Jacques Foucry1\0130\011\006\003U\004\006\023\002FR"

Nous avons besoin de mettre le Provisioning Profiles dans un répertoire ~/Library/MobileDevice/Provisioning Profiles

Avant de reprendre la configuration de Jenkins, nous allons tenter de faire une compilation du produit en utilisant la même ligne de commande que celle que nous allons mettre dans le flux. Il faut bien sûr d’abord récupérer les sources avec une commande git clone.

Une fois les sources sur un coin de votre disque, rendez-vous dans le répertoire du projet et tentez la commande suivante :

1
2
3
4
5
6
$ xcodebuild -sdk iphoneos5.0 -project PillStock.xcodeproj -target MonProjet -configuration "Release"
...
/tmp/MonProjet/build/Release-iphoneos/PillStock.app: User interaction is not allowed.
Command /usr/bin/codesign failed with exit code 1

** BUILD FAILED **

Oh Oh, ça ne fonctionne pas… Le point c’est important est un peut plus haut : User interaction is not allowed.

En fait, notre keychain est fermé, il est nécessaire de l’ouvrir pour permettre l´accès aux données qu’elle contient.

1
2
3
4
$ security unlock-keychain jenkins.keychain
$ xcodebuild -sdk iphoneos5.0 -project PillStock.xcodeproj -target MonProjet -configuration "Release"
...
** BUILD SUCCEEDED **

Pas mal non ?

La même dans Jenkins

Sur ce coup-là, nous allons allez très vite. Un nouveau job, le dépôt git, la ligne de commande dans Execute Shell, test et PAF le chien !

La compilation échoue et les traces nous indiquent que xcodebuild ne peux pas signer les sources. Sans doute parce qu’il ne trouve pas le certificat dans la keychain par défaut.

Je vais vous épargner du temps. La keychain par défaut, c’est System.keychain. Parfais, mettons le certificat et la clef privée dans la keychain System… Ne marchera pas non plus, j’ai essayé.

Il semble en fait que la jvm et donc jenkins ne dialogue pas au même process pour ouvrir les keychain et les activer. Il en résulte que les processus de compilation ne peuvent pas accéder aux keychains ouverte par d’autres processus.

Notre problème n’est pas forcément insoluble, mais risque de nous demander de déployer une énergie assez importante. Comment passer outre ?

J’ai tenté pour vous l’idée du script qui déverrouille la keychain et fait la compilation. Pas de résultat positif non plus.

Alors, que faire ?


Billet Précédent Billet Suivant

Laisser un commentaire

Les commentaires sont soumis à modération.