Communitygithub.com

byteratio/iphone-dev

Conventions pour le développement d'applications iPhone natives — SwiftUI + SwiftData local-first, génération de projet XcodeGen, boucles de build/test/déploiement en ligne de commande (simulateur par défaut, déploiement sur appareil signé via devicectl), XCTest avec couverture visible, et les pièges de la signature avec un compte personnel gratuit. À utiliser lors de la création d'une application iOS/iPhone, de l'ajout de cibles iOS ou de boucles Makefile à un projet, du débogage de problèmes de signature/approvisionnement/déploiement Xcode, ou du portage de la logique d'une application existante vers un client Swift natif.

Qu'est-ce que iphone-dev ?

Cette compétence définit les conventions pour le développement d'applications iPhone natives avec SwiftUI et SwiftData, en mettant l'accent sur une approche local-first, la génération de projet via XcodeGen (sans .xcodeproj versionné), et des boucles de développement entièrement en ligne de commande. Elle couvre l'architecture par défaut (SwiftUI + SwiftData, relations d'objets réels, déploiement cible), la génération de projet avec XcodeGen, la boucle de développement CLI avec des cibles Makefile pour le simulateur et le déploiement, les commodités de débogage (seeder de données d'exemple, sélecteurs recherchables), les tests XCTest, et les pièges de signature et déploiement avec un compte personnel gratuit (durée de validité de 7 jours, limite de 3 applications sideloadées). Elle inclut également un guide de bootstrap pour un Mac frais, des stratégies de synchronisation pour des clients compagnons (client léger, miroir instantané, boîte d'envoi limitée, synchronisation bidirectionnelle complète), et des règles d'hygiène de projet. La compétence est conçue pour les petites applications utilisant un compte Apple personnel gratuit, sans distribution sur l'App Store.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/byteratio/skills/tree/main/plugins/hechtch-skills/skills/iphone-dev

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Développement d'applications iPhone

Conventions tirées de l'expérience de livraison d'une application SwiftUI de bout en bout, du dépôt vide à une version signée fonctionnant sur un téléphone physique.

Contexte supposé : applications à petite échelle, un compte Apple personnel gratuit, aucune distribution sur l'App Store. Un compte développeur payant modifie plusieurs règles ci-dessous — la section sur la signature indique lesquelles.

Architecture par défaut

  • SwiftUI + SwiftData, local-first. Une petite application ne devrait pas nécessiter de serveur accessible. Les données résident sur l'appareil dans SwiftData ; les appels réseau sont réservés aux API publiques uniquement (https, pas d'exceptions ATS). Si l'application commence comme un client léger pour un backend existant, prévoyez le pivot « peut-on se passer du serveur ? » — portez la logique du backend en fonctions Swift pures manipulant les tableaux SwiftData plutôt que de maintenir un serveur pour un seul téléphone.
  • Modélisation SwiftData : relations d'objets réels, pas de clés étrangères entières. @Attribute(.unique) pour les clés naturelles. Les tableaux to-many de SwiftData ne préservent pas l'ordre — ajoutez un champ sortOrder et une propriété calculée sortedX lorsque l'ordre est important. Les dates sont des Date, pas des chaînes. Les énumérations sont Codable avec une valeur brute de type String.
  • Modifications de schéma sur une installation existante : l'ajout de modèles ou de propriétés optionnelles effectue une migration légère silencieuse au prochain lancement ; les renommages, suppressions ou changements de type sans SchemaMigrationPlan empêchent l'ouverture du magasin — l'application déployée plante alors au démarrage avec les données de l'utilisateur intactes mais inaccessibles. Les redéploiements (même bundle ID) n'effacent jamais le conteneur de données ; seule la suppression de l'application le fait. Prévoyez un chemin d'exportation/ sauvegarde avant que les utilisateurs n'accumulent des données réelles.
  • Les vues dialoguent directement avec @Query + modelContext. Pas de couche Store / repository à moins que quelque chose ne nécessite réellement un cache. La logique pure (correspondance, analyse, importation) vit dans des espaces de noms d'énumération (enum Foo { static func … }) — testable sans interface utilisateur.
  • Cible de déploiement : version majeure actuelle moins un sauf si une API nécessaire dit autrement. Une seule cible, TARGETED_DEVICE_FAMILY: "1", portrait sauf si l'application mérite la rotation.

Génération de projet — XcodeGen, jamais de .xcodeproj versionné

ios/project.yml est la source de vérité ; le bundle .xcodeproj est généré et gitignoré (gitignore aussi ios/build/ et le Info.plist généré). Régénérez après avoir ajouté ou supprimé des fichiers — xcodegen parcourt le répertoire des sources, donc les modifications de fichiers existants ne nécessitent rien.

  • Installez xcodegen depuis l'archive zip de GitHub (PREFIX=~/.local ./install.sh) — pas besoin de Homebrew, fonctionne sur un Mac restreint.
  • Les cibles de tests unitaires nécessitent GENERATE_INFOPLIST_FILE: YES sinon le bundle de test échoue à la signature.
  • Définissez le schéma dans project.yml avec gatherCoverageData: true et la cible de test attachée, sinon xcodebuild test n'a rien à exécuter.

La boucle de développement — CLI uniquement, simulateur par défaut

Chaque projet iOS obtient ces cibles Makefile. Paramétrez le nom du simulateur, l'ID de l'appareil et l'ID de l'équipe avec des variables ?= afin que rien ne soit codé en dur pour une machine spécifique :

CibleQuoi
ios-projectgénération xcodegen + ouverture dans Xcode
ios-simbuild non signé pour simulateur, démarrage du sim, installation, lancement — la boucle par défaut ; zéro signature, zéro demande de mot de passe
ios-sim-seedios-sim, puis relancement avec --seed-demo
ios-testxcodebuild test dans le simulateur + rapport de couverture xccov par cible
ios-deploybuild signé pour le téléphone branché + installation devicectl + lancement

ios-test affiche la couverture à chaque exécution — la règle de la maison est que make test montre toujours le nombre, sans seuil fixe attaché.

Builds pour simulateur : CODE_SIGNING_ALLOWED=NO convient pour les vérifications de compilation generic/platform=iOS ; les destinations simulateur n'ont besoin d'aucune signature. Rappelez-vous que le simulateur et le téléphone ont des bases de données séparées.

Commodités de débogage qui paient toujours

  • Seeder de données d'exemple (DemoData.swift, #if DEBUG) : jeu de données organisé avec des champs de date/expiration calculés relativement à .now, idempotent (une ré-exécution n'ajoute rien), exposé de trois manières — un bouton dans la section « Développeur » des Réglages, un argument de lancement --seed-demo vérifié via ProcessInfo.processInfo.arguments, et la cible ios-sim-seed. Ajoutez un test vérifiant que la seed exerce les principaux états de l'application afin qu'elle ne pourrisse pas silencieusement.
  • Sélecteurs recherchables plutôt que des sélecteurs à roue dès qu'une liste peut dépasser quelques dizaines d'entrées (les ensembles de données importés garantissent cela).
  • Fonctionnalités appareil photo/scanner : vérifiez DataScannerViewController.isSupported && .isAvailable et fournissez une solution de repli pour la saisie manuelle — cela se dégrade gracieusement aussi dans le simulateur.

Tests

  • XCTest dans le simulateur ; lors du portage de logique depuis une autre pile, portez aussi la suite de tests de référence afin que la sémantique soit figée entre les langages.
  • Aide partagée : makeInMemoryContext() construisant un ModelContainer avec isStoredInMemoryOnly: true ; classes de test @MainActor avec setUp() async throws.
  • Lisez le résultat succès/échec depuis le bundle de résultats : xcrun xcresulttool get test-results summary --path build/test.xcresult.

Signature & déploiement — les pièges (chacun a coûté du temps réel)

  • L'ID d'équipe n'est PAS la parenthèse dans security find-identity — c'est l'ID du certificat lui-même. Obtenez le vrai ID d'équipe depuis un profil d'approvisionnement (security cms -D -i <profile> → le préfixe application-identifier) ou le volet Comptes d'Xcode. Le mauvais ID donne une erreur trompeuse « No Account for Team ».
  • -allowProvisioningUpdates ne voit pas la session Apple ID depuis un terminal simple. Créez le profil d'approvisionnement une fois dans l'interface graphique d'Xcode (Signing & Capabilities → définir l'équipe → Try Again) ; après cela, les builds purement CLI fonctionnent avec DEVELOPMENT_TEAM=<id> CODE_SIGN_STYLE=Automatic.
  • Première danse avec l'appareil : activez le mode développeur sur le téléphone (Réglages → Confidentialité et sécurité ; l'interrupteur n'apparaît qu'après qu'Xcode a parlé à l'appareil ; redémarrages) → faites confiance à l'ordinateur → après la première installation, faites confiance au certificat développeur (Réglages → Général → VPN et gestion des appareils). L'erreur « your team has no devices » d'Xcode signifie généralement que la tentative d'enregistrement a eu lieu pendant que le téléphone redémarrait ou était verrouillé — sélectionnez le téléphone comme destination d'exécution et réessayez.
  • Invitations du trousseau à chaque build : cliquez sur Always Allow dans la boîte de dialogue du trousseau de codesign une fois ; les invites de mot de passe par build s'arrêtent.
  • Limites du compte personnel gratuit : les installations expirent après 7 jours (redéployez pour re-signer), maximum 3 applications sideloadées, pas de notifications push, pas de groupes d'applications. Un compte payant lève les quatre — si l'application a besoin de push ou de groupes d'applications, c'est le déclencheur pour en obtenir un.
  • CLI de déploiement/lancement : xcrun devicectl list devices, xcrun devicectl device install app --device <id> <path>.app, … device process launch --device <id> <bundle-id>.

Bootstrap Mac frais (compatible sans tête)

  1. Xcode depuis l'App Store (ouvrez macappstore://apps.apple.com/app/id497799835).
  2. sudo xcode-select -s /Applications/Xcode.app && sudo xcodebuild -license accept && sudo xcodebuild -runFirstLaunch — nécessite un administrateur ; sur un compte standard, corrigez d'abord l'appartenance admin (su admin -c 'sudo dseditgroup -o edit -a <user> -t user admin').
  3. xcodebuild -downloadPlatform iOS — le SDK iOS + l'environnement d'exécution du simulateur est un téléchargement séparé de plusieurs Go depuis Xcode 15 ; les builds échouent avec « iOS X.Y is not installed » sans cela.
  4. DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer fonctionne comme une substitution par commande avant que xcode-select ne soit corrigé.
  5. xcodegen depuis l'archive zip dans ~/.local (voir ci-dessus).

Clients compagnons pour un serveur existant — niveaux de synchronisation

Lorsque l'application iPhone rejoint une application qui a déjà un serveur + une application web (le serveur reste la source unique de vérité), choisissez le niveau le moins coûteux que le cas d'utilisation du téléphone permet. Demandez d'abord « le téléphone doit-il fonctionner hors du réseau du serveur ? » et « capture ou édition complète ? » :

  1. Client léger — pas de stockage local ; le téléphone appelle l'API existante. Approprié lorsque la connectivité est acquise.
  2. Miroir instantané — cache SwiftData reconstruit en bloc à partir d'une extraction JSON complète (les bases de données mono-utilisateur sont petites). Pas de fusion → pas de pierres tombales, pas d'horodatages par ligne, pas de moteur de conflit ; les suppressions/modifications côté serveur arrivent gratuitement. Les photos se chargent paresseusement via le cache d'URL.
  3. Boîte d'envoi limitée — création hors ligne limitée aux enfants d'enregistrements qui existent déjà (journaux, notes, photos contre des parents connus). Les parents portent de vrais IDs serveur, donc la relecture est de simples appels API — les schémas avec clé primaire entière n'ont besoin d'aucune migration UUID. Un événement de synchronisation = pousser la boîte d'envoi, puis tirer le miroir (les propres captures reviennent confirmées). Affichez les orphelins 404 (« N n'a pas pu se synchroniser »), ne les supprimez jamais silencieusement. Montrez un badge en attente + un horodatage de dernière synchro. Synchronisation automatique uniquement lorsque l'adresse serveur épinglée de l'utilisateur répond — ne sondez jamais des réseaux étrangers.
  4. Synchronisation bidirectionnelle complète (UUID, pierres tombales, points de terminaison delta, LWW/CRDT) — seulement avec la preuve que les niveaux 1 à 3 ne suffisent pas ; le remaniement commence côté serveur (UUID créés par le client, upserts idempotents, changes?since= + pierres tombales) avant qu'aucun Swift ne soit écrit.

Les niveaux 2 et 3 se combinent bien : un miroir instantané pour les lectures plus une boîte d'envoi limitée pour les captures couvre « fonctionne à la maison, capture n'importe où » sans aucun des mécanismes du niveau 4.

Hygiène de projet

  • Les faits spécifiques à la machine et à l'appareil (ID d'équipe, UDID de l'appareil, nom du simulateur) vont dans les variables ?= du Makefile ou dans les notes du projet — jamais codés en dur dans les scripts, et jamais dans cette compétence.
  • Conservez un document plans/<sujet>.md pour chaque tranche de travail en cours et un CHANGELOG.md de haut niveau pour ce qui est livré ; déplacez un plan vers plans/done/<sujet>.md avec un en-tête « Livré dans — » une fois qu'il est terminé.
  • Dimensionnez chaque tranche de plan pour qu'elle se termine par quelque chose d'exécutable sur un téléphone ou un simulateur. Une tranche iOS qui ne peut pas être lancée ne peut pas être revue.

Individual skills in this repo

This repo contains 5 individual skills — each has its own dedicated page.

byteratio/example-skill

Template skill for this marketplace. Use as a starting point when adding a new skill — copy this plugin directory, rename it, and replace this description with the specific trigger conditions for your skill (what the user says or does that should invoke it).

byteratio/kanban-plans

Track multi-session plans on a locally-running kanban board (github.com/hechtch/kanban) via its agent REST API. Claim a plan, move it through todo/doing/blocked/awaiting_merge/done, leave notes, and set the git branch. Use at the start of any non-trivial multi-session plan, when resuming such a plan, or when the user asks what's on the board or where a plan stands.

byteratio/password-generator

Generates secure, memorable passwords using 3 random dictionary words with leet-speak substitutions. Use when the user asks to generate a password, create a new password, or needs a secure passphrase.

byteratio/security-sweep

Investigate whether a project (or every repo on the machine) is exposed to known and actively-exploited dependency vulnerabilities. Combines a deterministic per-ecosystem audit (npm audit, govulncheck, pip-audit, osv-scanner) with live web research into recent/active supply-chain incidents, then checks each project's lockfiles directly — the leading-indicator check that `npm audit` misses. Use when the user asks to "investigate security", "check for vulnerable dependencies", "are we affected by <a named CVE / package compromise>", "scan the projects for supply-chain issues", or wants a recurring security sweep.

byteratio/ux-agents

Scaffold persona-based UX testing agents for a web app — project-scoped .claude/agents/<persona>-ux.md files that drive a real browser via Playwright, walk user journeys as a specific persona, and report tagged friction findings. Use when setting up UX review automation, when the user asks what a specific user segment would think of the app, or after the user accepts an offer to add persona testing.

Skills associés