Un autre canal de distribution — le Mac App Store
La série précédente couvrait la configuration initiale pour distribuer directement une application macOS avec un Developer ID. Une fois que vous avez les certificats, la notarisation, les mises à jour automatiques Sparkle et un flux de mises à jour hébergé en place, vous pouvez laisser les utilisateurs télécharger un fichier .dmg directement sans passer par l’App Store.
Cette série couvre la configuration initiale pour mettre cette même application sur le Mac App Store (MAS) également. Les deux méthodes de distribution ne sont pas un choix exclusif. Vous pouvez gérer une seule application à travers le canal de distribution directe et le canal App Store en même temps. L’App Store confie à Apple la gestion des paiements, des remboursements et de la visibilité dans les recherches, et il bénéficie d’une plus grande confiance des utilisateurs, donc le gérer en parallèle avec la distribution directe est un choix courant.
Cette série suppose que votre application est déjà distribuée directement avec un Developer ID et dispose déjà des mises à jour automatiques Sparkle intégrées. Cette configuration a été couverte à partir de Partie 1 de la série « Distribuer soi-même une application macOS ». Si vous ne l’avez pas encore lu, je vous recommande de le parcourir d’abord.
Pourquoi MAS a besoin d’« une autre cible »
Une application distribuée directement inclut les mises à jour automatiques Sparkle — la fonctionnalité qui permet à l’application de vérifier elle-même un flux de mises à jour, de télécharger une nouvelle version et de se remplacer.
Mais les règles de validation du Mac App Store interdisent ce comportement. Une application sur l’App Store ne doit pas télécharger de code de l’extérieur pour se mettre à jour ; les mises à jour doivent se faire uniquement via l’App Store. En d’autres termes, un build destiné à MAS ne doit pas contenir Sparkle.
Le build de distribution directe, cependant, doit avoir Sparkle. Un seul artefact de build ne peut pas satisfaire les deux exigences simultanément. La solution est donc :
Un codebase, deux cibles de build.
| Canal | Cible de build | Sparkle | Distribué via |
|---|---|---|---|
| Developer ID | FocusTimer | Inclus | Distribution directe (.dmg) |
| Mac App Store | FocusTimer MAS | Exclu | App Store |
Vous partagez un codebase unique, mais vous le divisez en deux cibles de build, en liant Sparkle dans une seule d’entre elles. Cette série couvre la configuration initiale pour créer cette deuxième cible (FocusTimer MAS).
Ce que cette série construit
En trois parties, vous mettrez en place les éléments suivants.
- (Partie 1, cet article) Enregistrement d’un Bundle ID exclusif MAS + duplication de la cible de build Xcode
- (Partie 2) Les fichiers de configuration (entitlements et Info.plist) et le branchement du code qui séparent les deux canaux
- (Partie 3) Un
ExportOptions-MAS.plistpour le téléversement + enregistrement dans App Store Connect + vérification du build
À la fin de la série, vous devriez avoir :
- Un Bundle ID exclusif MAS enregistré dans l’Apple Developer Portal
- Une cible de build
FocusTimer MASavec la dépendance Sparkle supprimée - Un fichier entitlements et un fichier Info.plist exclusifs MAS
- Du code branché avec
#if canImport(Sparkle) - Un
ExportOptions-MAS.plistpour le téléversement vers l’App Store
L’application exemple — FocusTimer
Comme dans la série précédente, nous utiliserons une application macOS fictive, FocusTimer (une simple application de minuterie pour gérer les sessions de concentration), comme exemple. FocusTimer, l’identifiant de bundle com.example.FocusTimer, le Team ID ABCDE12345, et ainsi de suite sont tous des valeurs d’exemple. En pratique, remplacez-les par votre propre application et les informations de votre compte.
Cet article a été rédigé pour Xcode 26.
Étape 1 — Enregistrer un Bundle ID exclusif MAS
Pourquoi un Bundle ID séparé
Si le Bundle ID du canal de distribution directe est com.example.FocusTimer, le canal MAS utilise un Bundle ID différent.
| Canal | Bundle ID |
|---|---|
| Developer ID | com.example.FocusTimer |
| Mac App Store | com.example.FocusTimer.mas |
Vous ajoutez .mas au Bundle ID existant. Pourquoi prendre la peine de les séparer ?
- Les deux canaux peuvent coexister sur un Mac — Si les Bundle IDs sont identiques, macOS traite les deux applications comme la même et elles entrent en conflit. S’ils diffèrent, vous pouvez installer la version distribuée directement et la version App Store sur la même machine en même temps (pratique pour le développement et les tests).
- Domaines
UserDefaultsséparés — Le stockage des paramètres est partitionné par Bundle ID, donc les paramètres des deux canaux ne se mélangent pas. - Éviter les conflits Launch Services — Cela évite la confusion lorsque macOS décide à quelle application envoyer une requête comme « ouvrir cette application ».
Conservez le Bundle ID du canal de distribution directe inchangé. C’est l’identifiant de vos utilisateurs existants, il ne doit donc pas être modifié. Vous enregistrez un nouveau ID supplémentaire pour MAS.
Procédure d’enregistrement
- Connectez-vous sur developer.apple.com/account (avec votre compte Apple Developer Program)
- Certificates, Identifiers & Profiles → Identifiers dans le menu de gauche → le bouton
+ - Sélectionnez App IDs → Continue → choisissez le type App → Continue
- Description : Entrez un nom facilement reconnaissable (par ex.,
FocusTimer MAS) - Bundle ID :
- Sélectionnez Explicit
- Entrez :
com.example.FocusTimer.mas
- Capabilities : Désactivez toutes les fonctionnalités que l’application n’utilise pas. Si vous n’utilisez pas iCloud, les notifications push, les achats intégrés, Sign in with Apple, etc., vous n’avez rien besoin d’activer. (App Sandbox est géré par les entitlements côté Xcode, il n’est donc pas nécessaire de l’activer ici.)
- Continue → Register
Vérification
Si la liste Identifiers affiche une entrée pour FocusTimer MAS — com.example.FocusTimer.mas, l’enregistrement est complet.
Étape 2 — Dupliquer la cible de build Xcode
Vous allez maintenant créer une cible de build FocusTimer MAS dans le projet Xcode. La façon la plus rapide est de dupliquer la cible existante.
2-1. Dupliquer la cible
- Ouvrez
FocusTimer.xcodeprojdans Xcode - Cliquez sur l’icône du projet (bleue) en haut du Project navigator (panneau gauche)
- Dans la liste TARGETS de la zone d’édition centrale, faites un clic droit sur
FocusTimer→ Duplicate - Lorsque la boîte de dialogue apparaît, sélectionnez Duplicate Only
- La nouvelle cible est créée sous le nom
FocusTimer copy. Double-cliquez sur le nom et changez-le enFocusTimer MAS - Si la demande « Ajouter un nouveau Scheme ? » apparaît, choisissez Activate (ou ajoutez-le plus tard dans Manage Schemes)
2-2. Changer immédiatement le Bundle ID
La toute première chose à faire juste après la duplication est de remplacer le Bundle ID. Si vous le laissez tel quel, les deux cibles auront le même ID.
Changez TARGETS → FocusTimer MAS → General → Identity → Bundle Identifier par la valeur que vous avez enregistrée à l’Étape 1.
com.example.FocusTimer.mas
2-3. Un piège courant — le « fardeau de nettoyage » que laisse Duplicate
C’est la partie la plus délicate de cet article. La fonction Duplicate Target de Xcode fonctionne avec des « paramètres par défaut sûrs », mais cette sécurité même laisse du travail de nettoyage qui nécessite une attention manuelle. Juste après la duplication, vous devez vérifier les quatre points suivants.
① Faire inclure les fichiers source par la nouvelle cible
Pour des raisons de sécurité, Duplicate exclut automatiquement tous les fichiers source de la nouvelle cible. Laissée telle quelle, la cible FocusTimer MAS est une coquille vide — la builder produit un build sans aucun code. Vous devez corriger les appartenances aux cibles pour que la nouvelle cible inclue à nouveau les fichiers source existants.
② Supprimer la dépendance Sparkle de la cible MAS
Duplicate copie verbatim les dépendances Swift Package de l’original. En conséquence, Sparkle se retrouve également dans la cible FocusTimer MAS. Le point de départ de toute cette série était « le build MAS ne doit pas avoir Sparkle », donc supprimez Sparkle de la liste des dépendances de packages de la cible MAS et de la phase de build Frameworks.
③ Nettoyer le fichier Info.plist temporaire
Duplicate crée un fichier Info.plist temporaire comme FocusTimer copy-Info.plist. Puisque nous allons créer un Info.plist MAS dédié séparément en Partie 2, supprimez ces fichiers temporaires — à la fois la référence du projet et le fichier réel.
④ Mettre à jour les paramètres de build de la cible MAS
Vous devez aligner les paramètres de build tels que l’identifiant de bundle, le chemin Info.plist et le chemin entitlements pour MAS. Nous nous en occuperons tous à la fois en Partie 2, après avoir créé les fichiers de configuration dédiés.
Les points ① et ② peuvent être traités pour la plupart depuis les écrans d’appartenance aux cibles et de dépendances de packages dans l’interface Xcode, mais si les références en double laissées par le processus de duplication ne se nettoient pas proprement, vous devrez parfois regarder directement le fichier de projet (
.pbxproj). Une fois que vous pensez que le nettoyage est terminé, la façon la plus fiable de vérifier est de builder les deux cibles séparément et de vérifier siimport Sparkleéchoue dans le build de la cible MAS (la Partie 2 couvre ce branchement de code).
Récapitulatif de la Partie 1
Si vous avez suivi jusqu’ici, vous disposez maintenant des éléments suivants :
- ✅ Un Bundle ID exclusif MAS (
com.example.FocusTimer.mas) enregistré dans l’Apple Developer Portal - ✅ Une cible de build
FocusTimer MAScréée par duplication - ✅ Une compréhension du fardeau de nettoyage que laisse la duplication (appartenance aux sources, dépendance Sparkle, fichiers temporaires)
Le « conteneur » — la cible — a été créé. Mais cette cible est encore essentiellement juste une copie de FocusTimer ; elle n’est pas encore vraiment devenue « spécifique à MAS ». Un build MAS doit utiliser des entitlements différents et un Info.plist différent du build de distribution directe, et le code doit également se ramifier pour ne pas se casser sans Sparkle.
Dans la prochaine partie, nous couvrirons les fichiers de configuration et le branchement du code qui séparent les deux canaux.