← Tous les articles

Préparer votre app pour l'iPhone Duo : un exemple complet

Comment préparer une app pour l’iPhone Duo ? Compilez-la avec le SDK iOS 27.1, faites-lui parcourir chaque position dans le simulateur, corrigez ce que ce parcours révèle et organisez la soumission autour de deux dates qu’Apple n’a pas encore annoncées. L’iPhone Duo sera en vente le 23 octobre, sous iOS 27.1.1 Ce qu’une app obtient sur cet appareil dépend de la version du SDK inscrite dans son binaire : un même fichier source, lié en 26.0, en 27.0 puis en 27.1, est apparu sous la forme d’une boîte de la taille d’un téléphone, d’une fenêtre à côté du bandeau d’état, puis de l’écran entier, avec ses barres sur le côté et la pliure signalée.12 Au 2 octobre, seules les bêtas d’Apple inscrivent 27.1 ou plus (Xcode 27.1 beta, qui contient le simulateur du Duo, et Xcode 27.2 beta), et App Store Connect accepte leurs builds pour TestFlight, pas pour la boutique.8 Ce billet mène tout le travail sur Kiradex, une app de collection de cartes à échanger que nous avons dans TestFlight : ce qui est venu gratuitement, ce que le parcours a repéré et que la lecture du code n’avait pas vu, les captures d’écran pour les deux écrans, et un brief à confier à un agent de code.

L’essentiel

  • Le tampon du SDK est l’interrupteur. iOS lit la version du SDK dans le LC_BUILD_VERSION du binaire. Tamponnée 27.1, l’app sonde a obtenu l’écran entier, 466 par 678 points fermée et 951 par 669 ouverte, avec des barres verticales et des régions réservées. Tamponnée 27.0, elle s’arrêtait à 80 points du bord où se trouve le bandeau d’état, gardait des barres horizontales et ne savait rien de la pliure. Tamponnée 26.0, c’était un téléphone de 375 par 667 dans une boîte. Vérifiez la vôtre avec otool -l.12
  • Le calendrier compte deux dates inconnues. TestFlight accepte les builds du SDK 27.1 depuis le 18 septembre et ceux de la bêta 27.2 depuis le 16 septembre ; l’App Store n’accepte que les builds du SDK 27.0 ; les tailles de captures du Duo sont publiées, et leur téléversement « will be available later this year » (sera possible plus tard dans l’année).89 Une clé d’écran de lancement est désormais exigée au téléversement.10
  • Les conteneurs système ont fait l’essentiel. Un TabView, un NavigationStack dans quatre de ses cinq onglets et des éléments de barre d’outils dotés d’un titre et d’un symbole ont placé les barres de Kiradex sur le côté sans une ligne de code propre au Duo. Une seule ArrangementView a scindé l’écran ouvert et déplacé son séparateur sur la pliure en position Book. Un seul onHingeChange rejoue l’ouverture de l’app quand le téléphone se déplie.13
  • Le parcours a trouvé ce que la lecture avait manqué. Une feuille dont le seul bouton est un « Done » textuel réserve le bandeau latéral et le laisse vide. La carte plein écran passe sous la caméra externe. Pivotée en portrait, la vue scindée s’empile. Une carte restée ouverte pendant le dépliage atterrit dans la mise en page compacte, étirée. La mise en page en largeur regular, écrite pour l’écran interne, se casse sur un iPhone de 6,9 pouces en paysage.13
  • Tant que la boutique n’accepte pas 27.1, une même arborescence de sources a besoin de deux Xcode. #available n’y peut rien ; le SDK 27.0 ne contient aucune ArrangementView contre laquelle compiler. Une condition de compilation, ou #if canImport(SwiftUI, _version: 8.0.85), isole les nouveaux appels.14
  • Les captures sortent de la même exécution. Les captures du simulateur ont exactement les tailles d’App Store Connect, tout comme les ouvertures des contours du Duo fournis par Apple. Les règles d’Apple exigent toujours une vue de face, sans retouche, et aucun rendu 3D de l’appareil.911

Où en sont les choses au 2 octobre

État Date
Le téléphone Précommandes le 16 octobre, en vente le 23 octobre, « available with iOS 27.1 » (disponible avec iOS 27.1)1 9 septembre
Le SDK Xcode 27.1 beta (27A9269) contient le SDK iOS 27.1 et le simulateur de l’iPhone Duo ; le flux Releases d’Apple ne mentionne ni deuxième bêta 27.1 ni version candidate. Xcode 27.2 beta contient les mêmes API et aucun simulateur du Duo814 18 septembre ; flux lu le 2 octobre
TestFlight Ouvert aux builds de Xcode 27.1 beta et des bêtas de Xcode 27.2, en interne comme en externe8 16, 18 et 28 septembre
App Store Ouvert aux builds de Xcode 27 et du SDK 27.0. Aucune entrée ne l’ouvre au SDK 27.18 14 septembre
Captures du Duo Tailles publiées ; le téléversement « will be available later this year » (sera possible plus tard dans l’année)9 9 septembre
Écran de lancement Exigé au téléversement pour tout ce qui est compilé avec le SDK iOS 27 ou plus récent10 Note technique révisée le 14 septembre

Trois de ces lignes attendent Apple, et aucune ne bloque le travail. L’ordre qui découle du tableau : passer l’app au SDK 27.1 et la lancer dans le simulateur, lui faire parcourir chaque position, corriger ce que le parcours révèle, mettre ce build dans TestFlight, et tenir prêtes la soumission à la boutique et les captures du Duo pour le jour où chacune ouvrira.

Le point de départ d’Apple est le premier de ses six Tech Talks, long de dix minutes, et tout ce qui suit le suppose connu :

Watch on Apple Developer ↗

Première étape : le tampon du SDK décide de ce que le téléphone vous donne

La présentation s’ouvre sur une promesse de compatibilité en trois niveaux. Une app qui n’a pas été compilée avec le SDK iOS 27 fonctionne quand même : « When the device is closed, your app will use the screen space to the left of the status bar and camera. When the device is open, your app will be a familiar size and aspect ratio. » (Fermé, l’app occupe l’espace à gauche de la barre d’état et de la caméra ; ouvert, elle garde une taille et des proportions familières.) (0:36) Une app qui a adopté le SDK iOS 27 « will extend to the left of the status bar area on the inner display. » (s’étendra, sur l’écran interne, jusqu’à la gauche de la zone de la barre d’état.) (0:58) Puis : « When you build your app with the iOS 27.1 SDK, your app extends to the edge of the screen. Standard navigation and toolbar buttons now lay out vertically under the status bar. » (Compilée avec le SDK iOS 27.1, l’app s’étend jusqu’au bord de l’écran, et les boutons standard de navigation et de barre d’outils se disposent verticalement sous la barre d’état.) (1:05)3

Ces niveaux ne sont pas une propriété de votre code. Ils sont la propriété d’un seul nombre dans votre binaire, la version du SDK que l’éditeur de liens consigne dans la commande de chargement LC_BUILD_VERSION, et iOS la lit au lancement. Pour mesurer ce qui en dépend, j’ai écrit une petite app sonde, un TabView contenant un NavigationStack avec une barre d’outils de cinq éléments et une ArrangementView, compilée trois fois à partir du même fichier source. La seule différence entre les trois binaires est ce nombre : 26.0, 27.0, 27.1. Puis j’ai lancé les trois dans le simulateur de l’iPhone Duo, dans chaque position.12

La même app sonde, trois fois, sur l'écran interne ouvert du simulateur de l'iPhone Duo. Liée avec le SDK 26.0, c'est une fenêtre de la taille d'un téléphone, 375 par 667 points, sur un écran noir, avec une barre d'outils et une barre d'onglets horizontales. Liée avec le SDK 27.0, elle remplit l'écran à gauche d'un bandeau d'état noir, 871 par 669 points, avec des barres horizontales. Liée avec le SDK 27.1, elle remplit tout l'écran, 951 par 669 points, sa barre d'outils et sa barre d'onglets empilées verticalement sous l'horloge sur le bord droit, et elle signale une division et deux occultations

Un fichier source, trois tampons de SDK, ouvert et à la verticale. De gauche à droite : 26.0, 27.0, 27.1.

Position Tampon 26.0 Tampon 27.0 Tampon 27.1
Fermé 375 par 667, mis à l’échelle dans l’espace à côté du bandeau 386 par 678, à côté du bandeau 466 par 678, l’écran entier
Ouvert 375 par 667, un téléphone au milieu de l’écran 871 par 669 951 par 669
Ouvert, pivoté 375 par 667 669 par 871 669 par 951
Fermé, pivoté 667 par 375 678 par 386 678 par 466
Classe de taille en largeur, ouvert compact regular regular
Barres horizontales partout horizontales partout verticales, sauf ouvert et pivoté
toolbarVerticalEdge nil nil trailing, sauf ouvert et pivoté, où il vaut nil
Régions réservées aucune aucune la pliure, les deux caméras, la colonne d’état
Partiellement plié aucun changement aucun changement la pliure devient une division active ; les arrangements scindés y ouvrent un espace

Tailles de fenêtre en points, telles que la fenêtre de chaque build les a elle-même signalées.12

Lisez deux fois la colonne du milieu, car c’est celle avec laquelle la plupart des apps s’apprêtent à sortir. Un build issu de Xcode 27 obtient la largeur regular sur l’écran interne et la majeure partie de l’écran, un vrai progrès par rapport au téléphone en boîte de la première colonne. Il s’arrête pourtant à 80 points du bord arrière, là où se trouve le bandeau d’état, il n’obtient pas de barres verticales, et le système ne lui dit rien de la pliure ni des caméras : chaque requête de régions réservées est revenue vide, dans chaque position, quel que soit le nombre de fois où l’app sonde a posé la question.12 Pour m’assurer que le tampon était un substitut honnête, j’ai aussi compilé une version simple de l’app sonde avec Xcode 27.0 lui-même, contre son propre SDK iOS 27.0. Elle a obtenu les mêmes fenêtres : 386 par 678 fermée, 871 par 669 ouverte.12

Le guide écrit d’Apple est moins précis que la présentation sur ce point, et sa formulation a changé. Le 17 septembre, sa vue d’ensemble disait « Build your app with Xcode 27.1 or later to use all of the available screen space on iPhone Duo. In earlier versions, your app doesn’t extend under the status bar and camera. » (Compilez avec Xcode 27.1 ou plus récent pour utiliser tout l’espace disponible ; dans les versions antérieures, l’app ne s’étend pas sous la barre d’état et la caméra.) Le 19 septembre, elle disait, comme encore au 2 octobre, « Build your app with the latest version of Xcode to use all of the available screen space on iPhone Duo. When you build with Xcode 26 and earlier, your app doesn’t extend under the status bar and camera. » (Compilez avec la dernière version de Xcode pour utiliser tout l’espace ; avec Xcode 26 ou antérieur, l’app ne s’étend pas sous la barre d’état et la caméra.)2 La nouvelle phrase ne désigne comme insuffisants que Xcode 26 et les versions antérieures, et « latest version » (dernière version) ne dit pas si une bêta compte ; un lecteur pourrait donc croire qu’un build de Xcode 27.0 obtient l’écran entier. Dans le simulateur de cette bêta, ce n’est pas le cas. Il obtient le niveau intermédiaire de la présentation, et c’est l’ancienne formulation qui correspondait à mes mesures. Tant que le matériel ne dit pas le contraire, planifiez d’après le tableau.

Avant toute chose, vérifiez donc le tampon du build que vous testez :

otool -l Build/Products/Debug-iphonesimulator/YourApp.app/YourApp | grep -A4 LC_BUILD_VERSION

Un build de débogage issu de Xcode garde son code dans YourApp.debug.dylib, à côté d’un petit lanceur, et les deux portent la commande. Vous cherchez sdk 27.1 ou plus ; l’app sonde tamponnée 27.2, la valeur qu’écrirait le SDK de la bêta de Xcode 27.2, a reçu le même traitement que 27.1.12 Celle de Kiradex indique minos 27.0 et sdk 27.1 : l’app s’installe sous iOS 27.0 et obtient le comportement de 27.1 sur un Duo.13

J’insiste sur ce point parce que je m’y suis trompé publiquement. Mon premier compte rendu sur ce simulateur, le 21 septembre, affirmait que la barre d’outils ne devenait jamais verticale et que les régions réservées étaient vides dans chaque position. La bêta n’y était pour rien. J’avais compilé cette app sonde en appelant directement swiftc -sdk, l’étape d’édition de liens a pris pour racine le SDK macOS du même Xcode, et le binaire est sorti tamponné 27.0 : tout ce que j’ai mesuré ce jour-là, c’était la colonne du milieu. Ce billet porte désormais la correction.12 Si votre mise en page Duo semble à moitié adoptée dans le simulateur, avec des barres en travers du haut et une bande noire morte sur le côté, vérifiez le tampon avant de vérifier votre code.

L’app sur l’établi

Kiradex est une app de collection de cartes à échanger que nous avons dans TestFlight : chaque série, les cartes que vous possédez et celles que vous cherchez, leur valeur dans le temps, et chaque carte sous forme d’objet 3D que vous pouvez retourner. Elle est gratuite, réservée à l’iPhone, fonctionne sous iOS 27.0 et versions ultérieures, et conserve les listes d’un collectionneur dans son propre iCloud, sans aucun serveur à nous entre les deux.13 Elle n’est pas terminée. Le scanner n’a jamais rencontré de vraie caméra, et jusqu’à cette semaine personne n’avait regardé l’app sur un Duo ouvert : à côté de la mise en page pour l’écran interne, sa feuille de route portait la ligne « Seen on the open Duo’s inner display only by the column maths; the simulator was folded shut. » (Vue sur l’écran interne du Duo ouvert uniquement par le calcul des colonnes ; le simulateur était resté fermé.)13 Cela en fait un test honnête. Le travail Duo qu’elle contient a été écrit d’après la documentation d’Apple et jamais vérifié sur un écran.

Ce qu’elle fait pour le Duo est modeste, et mérite d’être énuméré justement parce que si peu relève du code propre au Duo :

  • La navigation appartient au système. Un TabView à cinq onglets, dont un avec le rôle de recherche, et un NavigationStack dans quatre d’entre eux ; le scanner est une vue caméra sans barre propre. Les éléments de barre d’outils sont des Label avec un titre et un symbole, attachés par .toolbar. Il n’y a de barre personnalisée nulle part.
  • La mise en page suit la classe de taille. La largeur compact reçoit une page de classeur à trois colonnes et pousse l’inspecteur d’une carte sur la pile. La largeur regular, qui pour une app réservée à l’iPhone désigne surtout l’écran interne du Duo, reçoit un mur de cartes en nombre pair de colonnes ; en choisir une partage l’écran entre la page et l’inspecteur.
  • Deux appels issus du SDK 27.1. Le partage est une ArrangementView de style .split, avec un HStack comme solution de repli sous iOS 27.1. Et onHingeChange rejoue l’animation d’ouverture de l’app, un appareil rouge qui s’ouvre, quand le téléphone passe de fermé à n’importe quel autre état.
  • Aucun verrouillage d’orientation, et un écran de lancement. Info.plist liste le portrait et les deux paysages, et déclare UILaunchScreen.13

C’est toute la liste : deux vérifications de disponibilité dans deux fichiers. Tout le reste de ce que le téléphone fait à l’app, il le fait à n’importe quelle app construite de cette façon.

Les images de ce billet montrent l’app telle qu’elle tourne, avec des visuels de cartes issus du catalogue public qu’elle lit. Kiradex est un outil indépendant pour collectionneurs, sans lien avec Nintendo, Creatures Inc., GAME FREAK inc. ou The Pokémon Company ni approuvé par eux, et les visuels des cartes appartiennent à leurs propriétaires.

Deuxième étape : parcourir chaque position

Le guide d’Apple présente le parcours sous forme de quatre vérifications :2

  • « Confirm your views resize well in each supported orientation and pose. » (Vérifiez que vos vues se redimensionnent bien dans chaque orientation et position prises en charge.)
  • « Inspect how the system presents your app’s navigation bars, toolbars, and tab bars vertically on the side of the display. » (Examinez comment le système présente verticalement, sur le côté de l’écran, les barres de navigation, barres d’outils et barres d’onglets de votre app.)
  • « Identify any views, sheets, or popovers that position awkwardly when you fold or open iPhone Duo. » (Repérez les vues, feuilles ou popovers qui se placent mal quand vous pliez ou ouvrez l’iPhone Duo.)
  • « Identify elements or controls in your views that appear in the fold, and are difficult to see or interact with. » (Repérez les éléments ou commandes qui tombent dans la pliure et deviennent difficiles à voir ou à manipuler.)

Ses recommandations de conception disent combien de mises en page cela devrait demander : « A compact width layout for the outer display and a regular width layout for the inner display give you the fundamentals for every pose. » (Une mise en page en largeur compact pour l’écran externe et une en largeur regular pour l’écran interne vous donnent les bases de chaque position.)7

Les positions sont des boutons dans Device Hub : Closed, Book, Open et Rotate Right, et chaque combinaison donne un écran différent. Le guide de SwiftLee ajoute un réglage plus fin dont je n’ai pas eu besoin : « Holding Option ⌥ reveals a slider that you can use to control the hinge angle of the device with precision » (Maintenir la touche Option ⌥ fait apparaître un curseur qui permet de régler précisément l’angle de la charnière).17 Avant de regarder l’app, il est utile de savoir ce que le système remet à n’importe quelle app dans chacune. Voici les relevés de l’app sonde avec le tampon 27.1 :12

Position Fenêtre, points Classes de taille (largeur, hauteur) Barres Régions réservées signalées
Fermé 466 par 678 compact, regular verticales, bord arrière caméra externe, 37 par 37, active ; colonne d’état, 84 par 170, active
Fermé, pivoté 678 par 466 compact, compact verticales, bord arrière caméra externe, active ; zone d’état, 84 par 82, active
Ouvert 951 par 669 regular, regular verticales, bord arrière pliure, 40 de large de x 455 à 495, inactive ; caméra interne, 58 par 37, inactive ; colonne d’état, 84 par 120, active
Book 951 par 669 regular, regular verticales, bord arrière les trois mêmes, pliure active
Ouvert, pivoté 669 par 951 regular, regular horizontales pliure, 40 de haut de y 455 à 495, inactive ; caméra interne, inactive ; zone d’état, 134 par 82, active
Book, pivoté 669 par 951 regular, regular horizontales les trois mêmes, pliure active

Trois écrans du simulateur de l'iPhone Duo dessinés à l'échelle avec les régions que le système signale à une app compilée avec le SDK 27.1. Fermé, 466 par 678 points : une zone de contenu de 382 points de large, un bandeau de 84 points à droite qui accueille la colonne d'état, la caméra et les barres. Ouvert, 951 par 669 points : une zone de contenu de 867 points de large, le même bandeau, une bande de 40 points au milieu pour la pliure et, à sa droite près du haut, la caméra interne. Ouvert et pivoté, 669 par 951 points : des barres horizontales en haut et en bas, la pliure sous forme de bande de 40 points en travers du milieu

Trois éléments de ce tableau ont façonné tout ce qui a suivi.

La fenêtre ne change pas quand le téléphone se plie. Book et Open signalent la même taille. La seule différence que l’app peut voir, c’est que la division de la pliure passe d’inactive à active, et que la charnière se déclare partiellement ouverte à 127 degrés là où elle se déclarait entièrement ouverte à 180. Une app qui ne lit que sa taille n’apprend jamais que le téléphone a été plié.

La pliure est toujours là, et elle est étroite. Elle est signalée ouvert comme plié, pile au milieu, et le cadre que renvoie l’API mesure 40 points de large dans les deux états, avec 20 points de marge de chaque côté. La présentation d’Apple dit de la région de la pliure : « When flat, it’s inactive and has a width of zero. » (À plat, elle est inactive et sa largeur est nulle.) (7:32) Le simulateur ne renvoie pas de cadre de largeur nulle. Les notes de terrain d’Artem Novichkov décrivent le même relevé comme « 40 pt wide, with 20 pt margins on each side of a zero-width fold line, » (40 pt de large, avec 20 pt de marge de chaque côté d’une ligne de pliure de largeur nulle)17 et je lis le zéro de la présentation de la même façon, comme la ligne entre les marges ; c’est une lecture, pas ce que dit le texte d’Apple. La présentation fait aussi la remarque pratique : « By default, only active ones will be returned, but you can query for inactive ones » (Par défaut, seules les régions actives sont renvoyées, mais vous pouvez demander les inactives) et « in grid-like layouts, you could prefer even numbers of columns when a division region is present regardless of its active state. » (Dans les mises en page en grille, vous pouvez préférer un nombre pair de colonnes dès qu’une région de division est présente, qu’elle soit active ou non.) (7:16, 7:41)5

Les régions arrivent tard. À chaque lancement, les premières évaluations de l’app sonde ne lisaient aucune région, et toutes les évaluations suivantes lisaient l’ensemble complet. Une vue qui pose la question une seule fois, lors de sa première passe de mise en page, met en cache un tableau vide. Lisez-les dans le body de la vue, à chaque évaluation ; l’app sonde se réévaluait sur un minuteur d’une seconde, et les notes d’Artem Novichkov énoncent la règle sans détour : « Read them in the GeometryReader body so the view updates when they arrive. Don’t cache them. » (Lisez-les dans le body du GeometryReader pour que la vue se mette à jour à leur arrivée. Ne les mettez pas en cache.)1217

Une remarque pratique avant l’app. Le runtime de simulateur iOS 27.1 de cette bêta prend en charge un seul type d’appareil, l’iPhone Duo ; lui demander un iPhone 18 Pro Max échoue avec « Incompatible device ». La comparaison ci-dessous, le même build sur un iPhone ordinaire, a donc tourné sur le runtime iOS 27.0, ce qui est aussi un moyen rapide de confirmer que les solutions de repli #available fonctionnent.12

Kiradex affiche la même série de cartes sur trois écrans à partir d'un seul build. Sur un iPhone de 6,9 pouces : trois colonnes de cartes, une barre de navigation en haut et une barre d'onglets en bas. Sur l'iPhone Duo fermé : trois colonnes, avec le bouton retour, un bouton de filtre et cinq boutons d'onglets empilés dans un bandeau le long du bord droit, sous l'horloge. Sur l'iPhone Duo ouvert : six colonnes de cartes et le même bandeau à droite

Un seul build de Kiradex sur un iPhone de 6,9 pouces, le Duo fermé et le Duo ouvert. Rien dans le code de l’app ne place les barres sur le côté.

Ce que le parcours a trouvé

Un test d’interface a fait passer le build 5 par huit types d’écran dans chacune des six positions (sept avec le téléphone fermé et pivoté, où le bouton Réglages était passé dans le menu de débordement), pendant qu’un script capturait les deux écrans à chaque arrêt : 1398 par 2034 pixels à l’extérieur, 2853 par 2007 à l’intérieur, les tailles qu’indique App Store Connect.13 À l’aune des quatre vérifications d’Apple, l’app a réussi plus de points que je ne l’attendais et a échoué à des endroits qu’aucune lecture du code n’avait signalés.

Ce qui est venu gratuitement

Les barres. Fermé, la barre d’outils et les cinq onglets se dressent dans le bandeau sous l’horloge ; ouvert, de même ; ouvert et pivoté, ils retournent en haut et en bas. Rien dans l’app ne le demande. La deuxième présentation explique pourquoi les barres faites main restent à la traîne : « When used to build custom bars, content from sub-components like UIToolbar, UINavigationBar, or UITabBar won’t be considered. » (Quand on s’en sert pour construire des barres personnalisées, le contenu de sous-composants comme UIToolbar, UINavigationBar ou UITabBar n’est pas pris en compte.) (2:52)4 Et comme chaque élément de barre d’outils des écrans principaux est un Label, chacun a un symbole pour le bandeau et un titre pour le menu de débordement, ce qui est l’autre condition du guide : « If your item has a title and doesn’t have an icon, the system doesn’t present it vertically. » (Si votre élément a un titre mais pas d’icône, le système ne le présente pas verticalement.)2

Watch on Apple Developer ↗

La pliure. Ouvert, les cartes d’une série s’alignent par six, un nombre pair, si bien qu’aucune carte ne se trouve au milieu de l’écran. Choisissez-en une, et l’écran se partage entre la page et l’inspecteur de la carte au milieu de la zone de contenu de l’app, à x 433. C’est 42 points à gauche de la pliure, parce que le bandeau retire 84 points sur le côté droit, et tant que le téléphone est à plat, cela n’a aucune importance. En position Book, la vue d’arrangement déplace le séparateur sur la pliure et laisse vide la bande de 40 points : l’inspecteur qui commençait à x 433 commence maintenant à 495. L’app n’a aucun code pour la position Book ; c’est ArrangementView qui fait ce que décrit la présentation, « moving, resizing, or reorganizing what’s already there. » (déplacer, redimensionner ou réorganiser ce qui est déjà là.) (6:04)513

Kiradex sur l'écran interne ouvert avec une carte sélectionnée, deux fois. À plat : à gauche une page de cartes sur trois colonnes, à droite la scène 3D et les détails de la carte choisie, qui se rejoignent au milieu de la zone de contenu, un peu à gauche du centre de l'écran. En position Book : les deux mêmes volets séparés par une bande verticale vide à l'emplacement de la pliure, la page un peu plus large et l'inspecteur plus étroit

Ouvert et à plat, puis en position Book. L’espace dans la seconde image est la pliure, et ce n’est pas l’app qui l’a placé là.

Les feuilles, une fois ouvert. Sur l’écran interne, une feuille arrive centrée et son bouton Done reste horizontal ; en position Book, la feuille de l’app sonde s’est déplacée d’elle-même du côté leading (le côté de tête) de la pliure.12

La charnière, en tant qu’événement. Dépliez le téléphone pendant que l’app tourne et son ouverture se rejoue sur l’écran interne : l’appareil rouge, fermé, puis s’ouvrant sur l’app. C’est un seul gestionnaire onHingeChange qui se déclenche quand l’état quitte closed, et c’est exactement la répartition des rôles que demande la quatrième présentation : « Hinge data is observed live, and is ideal for driving interactions or effects. For layout, use the arrangement and region APIs. » (Les données de charnière s’observent en direct et conviennent parfaitement pour piloter des interactions ou des effets ; pour la mise en page, utilisez les API d’arrangement et de régions.) (2:34)6

Quatre images de l'écran interne de l'iPhone Duo capturées pendant que le simulateur se déplie avec Kiradex en cours d'exécution : un appareil portable rouge fermé sur un fond rouge sombre, l'appareil qui s'ouvre et montre un petit écran vert où s'affiche KIRADEX, l'appareil ouvert qui se fond dans l'app, et l'écran Dex de l'app

Dépliage avec l’app en cours d’exécution : l’ouverture est l’appareil propre à l’app, dessiné par l’app, rejoué par la charnière.

Ce qui lui a échappé

Une feuille avec un seul bouton textuel réserve le bandeau et le laisse vide. Fermé, la feuille Réglages cède le long de son bord arrière une bande pour une barre verticale, puis n’y met rien : le seul élément de barre d’outils est un « Done » doté d’un titre et sans symbole, et un élément purement textuel reste horizontal. Le formulaire est comprimé dans ce qui reste. L’app sonde a mesuré le coût : 374 points de largeur de contenu avec le bandeau réservé, 450 avec la barre verticale désactivée.12 La présentation d’Apple nomme précisément ce cas : « if a sheet is control-heavy with only one item, like the close button here, consider disabling a vertical bar so it doesn’t reduce available space. » (Si une feuille est chargée en commandes avec un seul élément, comme ce bouton de fermeture, envisagez de désactiver la barre verticale pour ne pas réduire l’espace disponible.) (14:37)4 Il existe deux réparations, et l’app sonde a essayé les deux. Donnez un symbole au bouton, Button("Done", systemImage: "checkmark"), et il passe dans le bandeau sous forme de coche mise en avant ; ou ajoutez .toolbarVerticalBehavior(.disabled) au contenu de la feuille, et le bandeau disparaît, au prix d’une feuille plus courte.

Quatre captures de l'écran externe fermé. La feuille Réglages de Kiradex avec un bouton Done textuel en haut et, à droite, une bande vide qui ne contient que l'horloge. La feuille de l'app sonde avec un Done textuel : la même bande vide. La feuille de l'app sonde avec un symbole de coche sur Done : le bouton se loge dans la bande sous forme de cercle bleu sous l'horloge. La feuille de l'app sonde avec la barre verticale désactivée : la feuille occupe toute la largeur et est plus courte, avec Done en haut à droite

De gauche à droite : la feuille de l’app, puis l’app sonde avec un Done purement textuel, avec un symbole, et avec la barre verticale désactivée.

La carte plein écran passe sous la caméra. La pièce maîtresse de l’app est une carte sur une scène noire, barres masquées, et sa scène ignore la zone sûre sur tous les bords. Sur l’écran externe, cela envoie le coin supérieur de la carte sous la caméra. Le système signale cette caméra à toute vue qui le demande, sous forme d’occultation active de 37 points de côté, et sa position correspond à un point et demi près à la découpe des visuels de contour d’Apple.1112 Les recommandations de conception d’Apple autorisent le traitement pleine largeur « as long as nothing conflicts with the Dynamic Island or the status bar. » (tant que rien n’entre en conflit avec la Dynamic Island ou la barre d’état.)7 La réparation consiste à garder le fond noir à fond perdu et à ramener la carte elle-même à l’intérieur : soit en laissant la scène respecter la zone sûre arrière et supérieure sur cet écran, soit en lisant reservedRegions(kind: .occlusion) et en cadrant la carte à l’écart de ce qui est renvoyé.

La visionneuse de cartes plein écran de Kiradex capturée sur l'écran externe fermé et placée dans le contour d'iPhone Duo fourni par Apple : la carte remplit l'écran et son coin supérieur droit passe sous la caméra, dans l'angle de l'écran, à côté du bouton de fermeture de la visionneuse

La capture de la visionneuse dans le contour d’Apple pour l’écran externe. La capture du simulateur n’a pas de trou ; le téléphone, si.

Pivotés, les deux volets s’empilent. Ouvert et pivoté en portrait, l’écran mesure 669 points de large et reste en largeur regular, donc l’app continue de partager. Mais une vue d’arrangement qui remplit un espace plus haut que large partage en haut et en bas, selon le guide d’Apple : « it places the primary view on top and the secondary view below it when the containing view is taller than it is wide. » (elle place la vue principale en haut et la vue secondaire en dessous quand la vue conteneur est plus haute que large.)2 Le résultat est une bande qui montre une rangée de cartes et le haut d’une deuxième, au-dessus d’un inspecteur. Le commentaire de l’app sur cette ligne précise que la paire « is only useful side by side, » (n’est utile que côte à côte), et rien ne l’imposait. Restreindre le style avec .split.axes(.horizontal) est la commande documentée,16 avec un piège que la présentation détaille : « If the split arrangement cannot split among an axis, and it’s the primary axis, the arrangement view chooses to only show a single view. » (Si l’arrangement scindé ne peut pas partager le long d’un axe et qu’il s’agit de l’axe principal, la vue d’arrangement choisit de n’afficher qu’une seule vue.) (12:44)5 L’app sonde confirme les deux moitiés : en remplissant l’écran pivoté, un partage simple s’est empilé, et le partage limité à l’horizontale a montré le volet principal et rien d’autre.12 Pour cette app, cela masquerait l’inspecteur ; la correction honnête est donc une décision, pas un modificateur : quand l’espace est plus haut que large, poussez l’inspecteur sur la pile comme le fait la mise en page compacte.

Kiradex sur l'écran interne pivoté en portrait. À gauche, une série affichée en quatre colonnes de cartes sous une barre de navigation horizontale, avec une barre d'onglets flottante en bas. À droite, avec une carte sélectionnée : une rangée de cartes et le haut d'une deuxième en travers du haut, la scène et les détails de la carte choisie en dessous

Pivoté : des barres horizontales, comme le prévoient les recommandations d’Apple, et un partage parti dans le mauvais sens pour cette paire de vues.

Une carte restée ouverte pendant le dépliage n’atterrit dans aucune des deux mises en page. Fermé, choisir une carte pousse son inspecteur sur la pile de navigation. Dépliez alors que cet inspecteur est affiché, et la carte est toujours là, ce qui est la partie facile à rater. Mais c’est toujours un écran poussé, désormais large de 951 points : la scène à gauche, les détails dans une boîte blanche à la dérive sur le noir, un bouton Retour dans le bandeau. Ce que l’app prévoit pour cet écran, c’est le mur avec la carte à côté, et le seul moyen d’y parvenir est de revenir en arrière et de choisir à nouveau la carte. Une même sélection pilote les deux mises en page ; un même chemin de navigation, non. La réparation consiste à détecter le passage de la largeur compact à la largeur regular avec une carte sélectionnée et à retirer l’écran poussé, pour que le partage prenne le relais.

Kiradex avec une carte ouverte, avant et après le dépliage. Sur l'écran externe fermé : la carte sur une scène noire au-dessus de ses détails. Sur l'écran interne ouvert : la même carte en grand à gauche d'un écran noir, ses détails dans un rectangle blanc à droite et un bouton Retour en haut du bandeau

La même carte avant et après le dépliage. L’état a survécu ; la mise en page est la compacte, étirée.

La largeur regular n’est pas « le Duo ». L’app traite la largeur regular comme l’écran interne : mur, colonnes en nombre pair, partage. Un iPhone de 6,9 pouces couché sur le côté est lui aussi en largeur regular, avec une hauteur compact, et l’app ne verrouille pas l’orientation. Exécutée là, la même branche produit une page en retrait du bord gauche, un inspecteur dont la colonne de détails est trop étroite pour le nom de la carte, et des boutons d’action coupés au bas de l’écran. Rien de tout cela n’est nouveau dans iOS 27, et cela n’est apparu dans aucune position du Duo que j’ai testée ; le travail sur le Duo l’a mis au jour parce que c’était la première fois que quelqu’un parcourait la mise en page en largeur regular sur chaque écran qui la signale. Ce qui distingue les deux cas, c’est l’autre classe de taille : l’écran interne est regular dans les deux dimensions, et la présentation d’Apple donne l’écran externe couché sur le côté comme compact dans les deux.3 Une mise en page qui a besoin de place dans deux directions devrait interroger les deux.

Kiradex sur un iPhone de 6,9 pouces en paysage avec une carte sélectionnée : la page de cartes ne commence qu'à environ un cinquième de la largeur de l'écran, la scène de la carte se trouve à côté, et le panneau de détails à droite est si étroit que le nom de la carte se coupe sur trois lignes et que les boutons Have et Want sont tronqués au bas de l'écran

La mise en page en largeur regular sur un téléphone qui n’est pas un Duo : un iPhone de 6,9 pouces couché, iOS 27.0.

Le clavier recouvre le bandeau. Clavier affiché sur l’écran externe, les onglets du bas du bandeau passent derrière. C’est la mise en page du système, pas un défaut ; la présentation dit que la barre peut devoir déborder « as other competing UI appears, like the keyboard » (à mesure qu’apparaissent d’autres éléments d’interface concurrents, comme le clavier) (11:50).4 Il figure sur cette liste parce qu’il a cassé l’outillage : mon premier parcours a touché « Collection » avec le clavier de recherche affiché, et le toucher est tombé sur la lettre P. Les tests d’interface qui supposent qu’une barre d’onglets est toujours accessible échouent ici en premier.

Deux points plus mineurs. L’app choisit un nombre pair de colonnes d’après la classe de taille en largeur, là où la présentation suggère de se fier à la région propre de la pliure, présente ou non. Et un point qui n’a rien à voir avec le pliage : ouverte quatre fois de suite sur le simulateur de 6,9 pouces, la visionneuse plein écran a montré la carte la première fois et un écran noir vide les trois suivantes. Ni l’un ni l’autre ne bloque un build TestFlight. Tous deux sont restés invisibles jusqu’à ce que l’app soit sur un écran et que quelque chose appuie sur ses boutons dans l’ordre.

Ce que le simulateur ne pouvait pas montrer

Le scanner. Il ouvre la caméra grand-angle arrière et utilise déjà un coordinateur de rotation, ce que demande la présentation consacrée à la caméra : « On iPhone Duo, the rotation coordinator will update when your app moves displays. » (Sur l’iPhone Duo, le coordinateur de rotation se met à jour quand votre app change d’écran.) (8:19)6 Savoir si la session survit au passage d’un écran à l’autre est une question pour le matériel ; le simulateur n’a aucune caméra. Les notes de version d’Apple ajoutent StandBy et la plupart des extensions d’app à ce que ce runtime ne peut pas exécuter, et les notes de Xcode 27.2 beta 2 en ajoutent une pour quiconque automatise les captures : « Screenshots and recordings in iPhone Duo may be black for up to a few minutes after booting the device. » (Les captures et enregistrements dans l’iPhone Duo peuvent rester noirs jusqu’à quelques minutes après le démarrage de l’appareil.)20

Une arborescence de sources, deux Xcode

Le calendrier crée un problème. Le build qu’accepte la boutique vient de Xcode 27 et du SDK 27.0 ; le build qui se comporte correctement sur l’iPhone Duo vient du SDK 27.1. Tant qu’Apple n’ouvre pas la boutique au second, une app qui veut publier une mise à jour tout en continuant de travailler sa mise en page Duo doit compiler avec les deux.

if #available(iOS 27.1, *) ne suffit pas. La disponibilité est une question d’exécution ; le compilateur doit tout de même trouver le symbole. Kiradex enveloppe ses deux appels Duo exactement de cette façon, et sa cible de déploiement est 27.0, si bien que le build s’installe sur un téléphone qui n’a pas été mis à jour. Avec le SDK 27.1, cela compile. Avec Xcode 27.0, un fichier qui fait la même chose s’arrête sur error: cannot find 'ArrangementView' in scope, parce que le SDK 27.0 ne contient pas ce type.14 Kiradex n’est pas encore sur la boutique, il peut donc simplement rester sur la chaîne d’outils bêta ; une app qui a des clients ne le peut pas.

Les conditions documentées de Swift ne distinguent pas non plus les deux SDK. #if compiler(>=6.4) est vrai dans les deux cas : Xcode 27.0, Xcode 27.1 beta et Xcode 27.2 beta affichent tous le même Apple Swift version 6.4 (swiftlang-6.4.0.34.1 clang-2100.3.34.1).14 Restent deux clôtures, et j’ai essayé les deux.

Une condition de compilation que vous définissez vous-même. C’est la voie documentée. Définissez un drapeau uniquement dans la configuration que vous compilez avec la bêta (dans Xcode, SWIFT_ACTIVE_COMPILATION_CONDITIONS = DUO_SDK ; en ligne de commande, -D DUO_SDK) et clôturez avec lui le code propre à 27.1 :

struct Pair<Primary: View, Secondary: View>: View {
    @ViewBuilder var primary: Primary
    @ViewBuilder var secondary: Secondary

    var body: some View {
        #if DUO_SDK
        if #available(iOS 27.1, *) {
            ArrangementView { primary } secondary: { secondary }
                .arrangementViewStyle(.split)
        } else {
            HStack(spacing: 0) { primary; secondary }
        }
        #else
        HStack(spacing: 0) { primary; secondary }
        #endif
    }
}

Sans le drapeau, ce fichier passe la vérification de types sous Xcode 27.0 et sous la bêta 27.1. Avec le drapeau, il la passe sous la bêta et échoue sous 27.0 avec la même erreur de symbole introuvable : la mauvaise combinaison ne compile pas.14

La version propre du SDK, lue par le compilateur. canImport accepte un second argument préfixé d’un trait de soulignement, comparé à la version d’un module, et la version du module SwiftUI diffère d’un SDK à l’autre : 8.0.84.1.104 dans le SDK 27.0, 8.0.85.27 dans le SDK 27.1, 8.1.6.1.101 dans le SDK de la bêta 27.2.14 Ceci ne demande donc aucun réglage de build :

#if canImport(SwiftUI, _version: 8.0.85)
// ArrangementView, reservedRegions, onHingeChange, toolbarVerticalBehavior
#else
// what the app did before
#endif

J’ai placé un #warning dans chaque branche et compilé avec les trois Xcode : 27.0 a pris la seconde branche, la bêta 27.1 et la bêta 27.2 ont pris la première.14 La prudence tient au trait de soulignement. La grammaire de cette condition dans le livre Swift est canImport(import-path) et rien de plus ; _version: est donc une fonctionnalité du compilateur sans contrat documenté, et le nombre 8.0.85 est une valeur que j’ai lue dans deux SDK, pas une valeur publiée par Apple.14 Utilisez-la tant que la boutique est fermée à 27.1 si un réglage de build est malcommode dans votre configuration ; prenez le drapeau si vous voulez quelque chose que vous pouvez défendre.

Dans les deux cas, la clôture est temporaire. Le jour où App Store Connect acceptera les builds d’un Xcode qui contient le SDK 27.1, supprimez-la et gardez les vérifications #available, car ce sont elles qui protègent un téléphone encore sous iOS 27.0.

Soumettre : ce qu’App Store Connect accepte aujourd’hui

TestFlight accepte le build 27.1. Les notes de version d’App Store Connect du 18 septembre : « You can now submit apps built with Xcode 27.1 beta using the SDK for iOS 27.1 beta or iPadOS 27.1 beta for internal and external testing. » (Vous pouvez désormais soumettre aux tests internes et externes des apps compilées avec Xcode 27.1 beta et le SDK d’iOS 27.1 beta ou d’iPadOS 27.1 beta.) Les entrées du 16 et du 28 septembre disent la même chose pour Xcode 27.2 beta et beta 2.8 Kiradex passe par là ; son cinquième build, celui que teste ce billet, a été téléversé le 2 octobre, et App Store Connect l’indique comme valide.13

L’App Store, pas encore. L’entrée la plus récente qui ouvre la boutique date du 14 septembre : « You can now upload apps built with Xcode 27 using the SDK for iOS 27.0, iPadOS 27.0, macOS 27.0, tvOS 27.0, visionOS 27.0, and watchOS 27.0 for the App Store, and for internal and external testing through TestFlight. » (Vous pouvez désormais téléverser des apps compilées avec Xcode 27 et les SDK 27.0 pour l’App Store, ainsi que pour les tests internes et externes via TestFlight.)8 Rien après elle ne mentionne 27.1 et la boutique dans la même phrase, et le flux Releases d’Apple, dont les éléments les plus récents datent du 28 septembre, ne liste qu’un build de Xcode 27.1, la bêta du 18 septembre.8 Apple n’a pas dit quand cela changera. L’appareil sera en vente le 23 octobre.1

À moins qu’Apple n’ouvre la boutique au SDK 27.1 avant le 23 octobre, le build que vos clients auront depuis la boutique le jour du lancement sera au mieux un build du SDK 27.0, et la comparaison ci-dessus dit ce qu’il obtient dans le simulateur, la présentation d’Apple décrivant le même niveau intermédiaire : l’écran à côté du bandeau d’état, des barres horizontales, aucune pliure. C’est une app utilisable si elle se redimensionne bien, et c’est l’argument pour publier dès maintenant, avec Xcode 27, le travail de redimensionnement.

Un écran de lancement est désormais obligatoire. Ce n’est pas une règle propre au Duo, mais elle arrive avec le même SDK et elle échoue au téléversement, pas à la revue. La note technique d’Apple : « Starting in iOS 27 and iPadOS 27, App Store Connect requires your app to include a launch screen configuration in its Info.plist, » (À partir d’iOS 27 et d’iPadOS 27, App Store Connect exige que votre app inclue une configuration d’écran de lancement dans son Info.plist), et sans l’une des clés UILaunchStoryboardName, UILaunchStoryboards, UILaunchScreen ou UILaunchScreens, le téléversement est refusé avec « ITMS-90870: Missing launch screen. »10 Kiradex déclare UILaunchScreen avec une couleur, le rouge de sa couverture, si bien que le lancement enchaîne directement sur l’animation d’ouverture.13

Les emplacements de captures existent sur le papier. Les spécifications de captures d’écran d’App Store Connect listent l’iPhone Duo depuis le 9 septembre, en deux paires : 1398 par 2034 ou 2034 par 1398 pixels pour l’écran externe, et 2007 par 2853 ou 2853 par 2007 pour l’écran interne, avec la mention « Support for uploading assets for this device in App Store Connect will be available later this year. » (La prise en charge du téléversement de ressources pour cet appareil dans App Store Connect arrivera plus tard dans l’année.)9 Les règles habituelles s’appliquent : « You can upload one to 10 screenshots in .jpeg, .jpg, and .png formats, » (Vous pouvez téléverser de une à 10 captures aux formats .jpeg, .jpg et .png) et « Images can’t include alpha channels or transparencies. » (Les images ne peuvent pas contenir de couche alpha ni de transparence.)9

Une phrase de la page de téléversement décide de la manière de s’organiser : « Once your app is submitted for review and approved, you must create a new version to update the screenshots. » (Une fois votre app soumise à la revue et approuvée, vous devez créer une nouvelle version pour mettre à jour les captures.)9 Les captures du Duo ne peuvent pas être glissées plus tard toutes seules ; quand les emplacements ouvriront, elles voyageront avec une version.

Mis bout à bout, voici l’enchaînement que je suivrais, et que je suis pour Kiradex :

  1. Le build 27.1 dans TestFlight dès maintenant, avec les constats du parcours corrigés au fil de l’eau.
  2. Pour une app déjà sur la boutique : une mise à jour compilée avec Xcode 27 qui embarque toutes les corrections n’exigeant pas le SDK 27.1. Des classes de taille plutôt que des tests d’idiome et d’orientation, des zones sûres par bord, des barres détenues par des conteneurs système, un titre et un symbole sur chaque élément de barre d’outils.
  3. Des captures aux tailles du Duo, prises dès maintenant dans le simulateur, et conservées.
  4. Une version tenue prête pour le jour où deux conditions seront réunies : un Xcode doté du SDK 27.1 est accepté pour la boutique, et les emplacements du Duo acceptent les téléversements. Jusqu’ici, Apple a publié chaque changement de ce type dans les notes de version d’App Store Connect, parmi lesquelles l’entrée du 14 septembre qui a ouvert la boutique à la version finale de Xcode 27 et celle du 9 septembre qui a ajouté les spécifications de captures du Duo ; c’est donc la page à surveiller, avec à côté la page des actualités pour les développeurs.8

Une autre exigence se profile plus loin. À partir d’avril 2027, « iOS and iPadOS apps must be built with the iOS 27 & iPadOS 27 SDK or later » (les apps iOS et iPadOS doivent être compilées avec le SDK d’iOS 27 et d’iPadOS 27 ou plus récent) pour pouvoir être téléversées.18 Une app encore compilée avec un SDK iOS 26 obtient sur un Duo la plus petite des trois images ci-dessus, et à partir d’avril 2027 elle ne peut plus téléverser de mise à jour tant qu’elle n’est pas passée au SDK iOS 27.

Des captures pour deux écrans

Le parcours a déjà produit la matière première : chaque arrêt a été capturé en 1398 par 2034 et 2853 par 2007 pixels, et une fois pivoté en 2034 par 1398 et 2007 par 2853, soit les quatre tailles de la ligne iPhone Duo d’App Store Connect.913 Reste à décider ce qui les entoure, et c’est là qu’un téléphone pliable invite à l’erreur.

L’image que tout le monde veut, c’est le téléphone à demi ouvert, de biais, l’app qui se déverse par-dessus la pliure. Les directives marketing d’Apple l’excluent ligne par ligne. Pour les images d’appareils d’Apple elle-même : « Use Apple product images ‘as is’ and without modification. Modifications include adding reflections, shadows, highlights, or graphic elements that appear to enter or come out of the product screen; cropping, tilting, or obstructing any part of the images; animating, flipping, or spinning the images » (Utilisez les images de produits Apple telles quelles, sans modification ; sont des modifications l’ajout de reflets, d’ombres, de brillances ou d’éléments graphiques qui semblent entrer dans l’écran ou en sortir, le recadrage, l’inclinaison ou le masquage d’une partie des images, ainsi que leur animation, leur retournement ou leur rotation). Pour les visuels que vous créez vous-même : « Straight-on product shots are preferred. Don’t use extreme angles or alter an Apple product in any way. » (Les prises de vue de face sont préférées ; n’utilisez pas d’angles extrêmes et ne modifiez en rien un produit Apple.) Et sous « Unauthorized Uses » (utilisations non autorisées), en tête de liste : « Rendering in 3D or creating any simulation of an Apple product » (le rendu en 3D ou toute simulation d’un produit Apple).11 Mon billet sur les captures d’écran examine comment les lauréats traitent ces règles et à quoi ressemble une série qui les respecte ; une charnière n’y change rien.

Ce qu’Apple vous donne à la place, c’est un kit de contours pour ce téléphone, en deux finitions et cinq vues : le téléphone fermé en portrait et en paysage, l’écran interne ouvert en paysage et en portrait, et le téléphone ouvert vu de dos, avec l’écran externe à côté des caméras. Les ouvertures de ces fichiers ont exactement les tailles des captures, si bien qu’une capture du simulateur s’y insère sans mise à l’échelle.11 Il n’y a ni vue à demi pliée ni vue de biais.

Les visuels ci-dessous sont donc construits à partir de trois éléments : un fond aux couleurs de l’app, une courte ligne de texte, et la capture dans le contour d’Apple, entière et droite, sans rien par-dessus. La variété vient du fond, de la taille de l’appareil, et d’un visuel par série qui ne montre aucun appareil : la carte plein écran de l’app sur fond noir, qui est la 3D de l’app elle-même et le matériel de personne.

Trois rangées de captures App Store pour Kiradex. Six visuels pour un iPhone de 6,9 pouces, cinq pour l'écran externe de l'iPhone Duo, cinq pour son écran interne en paysage. Chaque visuel porte un court titre comme Your collection. In your hands. ou Open it. The binder fills the wall., un fond rouge, vert ou sombre, et l'écran de l'app dans un contour d'appareil Apple vu de face ; un visuel de la première et de la troisième rangée montre une seule carte à échanger sur fond noir avec le titre Turn it over.

Trois séries composées par script à partir des captures du parcours, en 1320 par 2868, 1398 par 2034 et 2853 par 2007 pixels. Elles montrent la méthode, pas la fiche : ces captures portent des cartes du catalogue, et ce que montrera la série de la boutique est la question ouverte de la troisième remarque ci-dessous.

Trois remarques pratiques tirées de leur fabrication.

Composer par script. Les séries ci-dessus sortent d’un seul fichier Python qui prend une capture, un titre et un fond, et écrit un PNG à la taille exacte, sans couche alpha. Quand l’app change, et celle-ci a changé deux fois le jour où je l’ai capturée, le parcours se relance et les visuels se reconstruisent.

Capturer ce que le téléphone ajoute. La page de téléversement d’Apple dit qu’une série en 6,9 pouces suffit quand l’interface est la même sur toutes les tailles : « provide only the highest resolution screenshots required. They automatically scale down to smaller device sizes. » (Fournissez uniquement les captures de plus haute résolution requises ; elles sont automatiquement réduites pour les appareils plus petits.)9 Sur ce téléphone, elle n’est pas la même : le mur de cartes et l’inspecteur scindé n’existent que sur l’écran interne. Ce sont les deux visuels qui ouvrent la série interne.

Faire attention à ce qui est à l’écran. Les mêmes directives disent : « You are responsible for securing the rights to all materials used in screen content within your app. » (Il vous incombe d’obtenir les droits sur tous les éléments utilisés dans le contenu affiché par votre app.)11 Une app de collection montre par nature les œuvres d’autres personnes, et une fiche de boutique relève du marketing, ce qui n’est pas la même chose que ce que l’app affiche à l’usage. Nous n’avons pas encore tranché cette question pour Kiradex, et les visuels ci-dessus ne seront pas soumis en l’état. C’est pour cette raison que le parcours a un second mode qui tourne sur six cartes inventées ; elles n’ont pas encore d’illustrations, donc soumettre une série implique de concevoir des substituts ou de régler la question des droits.

Kiradex n’a pas encore de fiche. Quand elle en aura une, elle commencera par une série en 6,9 pouces, et les séries du Duo attendront, avec une version à elles, le jour où App Store Connect les acceptera.

Confier le travail à un agent de code

L’essentiel de ce travail est du genre qu’un agent fait bien, à condition qu’il puisse voir l’app. Deux moitiés, et Apple fournit l’une d’elles.

La moitié statique appartient à Apple. Le premier Tech Talk se termine sur elle : « During the talk, Modernize Your UIKit App, we introduced a new app modernization skill. With Xcode 27.1, this skill has a new name: App Resizability. It now supports SwiftUI and iPhone Duo. » (Lors de la présentation Modernize Your UIKit App, nous avons présenté une nouvelle compétence de modernisation d’app ; avec Xcode 27.1, elle s’appelle désormais App Resizability et prend en charge SwiftUI et l’iPhone Duo.) (9:19)3 Cette compétence est un ensemble de fichiers texte brut à l’intérieur de la bêta : dans Xcode 27.1 beta, Contents/PlugIns/IDEIntelligenceChat.framework/Versions/A/Resources/app-resizability.idechatprompttemplate et cinq fichiers de référence à côté.15 Ses instructions disent jusqu’où ratisser : « Treat a request about the foldable iPhone Duo as a request for every task in the Task Registry, because a screen that changes size exposes all of them at once. » (Traitez une demande portant sur l’iPhone Duo pliable comme une demande portant sur chaque tâche du Task Registry, car un écran qui change de taille les expose toutes à la fois.)15

Elle vaut d’être lue même si vous ne l’exécutez jamais, car c’est la liste de contrôle d’Apple mise par écrit. Elle vérifie trois réglages du projet sans en modifier aucun (une clé d’écran de lancement, la déclaration d’orientations iPad, UIRequiresFullScreen), puis traque cinq motifs : UIScreen.main, une mise en page décidée par l’orientation de l’interface, une mise en page décidée par userInterfaceIdiom, un cycle de vie d’application là où devrait se trouver un cycle de vie de scène, et du code de zone sûre qui suppose que les deux côtés sont identiques. Le fichier sur la zone sûre contient la phrase qui explique la moitié de ce qui tourne mal sur ce téléphone : « Asymmetric horizontal insets are the normal case. Where a vertical bar is present, one horizontal edge usually carries the whole inset and the other carries zero. » (Des marges horizontales asymétriques sont le cas normal ; en présence d’une barre verticale, un bord porte généralement toute la marge et l’autre zéro.)15

Kiradex est une app SwiftUI écrite cette année, et ces cinq recherches n’y trouvent rien.13 Chaque constat ci-dessus est venu de son exécution. C’est la limite de la moitié statique : elle lit le source, et la pliure, le bandeau et le clavier ne sont visibles que sur un écran.

L’autre moitié est un parcours que l’agent peut lancer et regarder. Ce qui a rendu possible l’audit ci-dessus, ce sont trois petites pièces, dont aucune n’est propre à cette app :

  1. Un test d’interface qui visite chaque type d’écran et s’arrête sur chacun. Pas d’assertions ; une visite guidée. La nôtre ouvre le Dex, une série, une carte, une feuille, la liste de la collection, une carte de la collection, la visionneuse plein écran et la recherche avec le clavier affiché : huit arrêts.13
  2. Une capture qui se fait sur le Mac, pas dans le test. La capture d’un test d’interface ne couvre qu’un écran. simctl atteint les deux :
xcrun simctl io "$UDID" screenshot --type=png --display=primary   outer.png
xcrun simctl io "$UDID" screenshot --type=png --display=primary-1 inner.png

Le test écrit un fichier vide nommé d’après l’arrêt ; une boucle shell sur le Mac le voit, capture les deux écrans et répond par un second fichier ; le test l’attend puis poursuit. La capture externe mesure 1398 par 2034 pixels téléphone fermé et l’interne 2853 par 2007 téléphone ouvert, si bien que les images de l’audit et les captures pour la boutique sortent de la même exécution.913 3. Un moyen de changer de position sans toucher la souris. simctl n’a pas de commande de position et les frameworks de test d’interface de cette bêta n’ont aucun appel lié à la charnière que j’aie pu trouver ; le script appuie donc sur les boutons Closed, Book, Open et Rotate Right de Device Hub via l’API d’accessibilité, ce qui fonctionne même quand Device Hub est en arrière-plan.13

Avec cela, vérifier l’app dans chaque position cesse d’être une demande d’avis adressée à l’agent et devient un dossier d’images par position, que lui comme vous pouvez lire. Le brief ci-dessous est celui que je confierais. Il est écrit pour être collé tel quel.

Goal: make this app correct on iPhone Duo in every pose, without device checks.

0. Toolchain. Build with Xcode 27.1 beta. Confirm the binary is stamped with the 27.1 SDK:
   otool -l <App>.app/<App> | grep -A4 LC_BUILD_VERSION      (debug builds: <App>.debug.dylib)
   If "sdk" is lower than 27.1, stop: nothing below will reproduce.

1. Static pass. Report every use, with file and line, of:
   UIScreen.main / UIScreen.mainScreen; userInterfaceIdiom; interface orientation used for layout;
   a UIApplicationDelegate doing scene work; one safe-area inset applied to both sides;
   a bare ignoresSafeArea() on anything a person reads or taps; fixed widths tied to a phone size;
   toolbars or tab bars built by hand instead of owned by NavigationStack, NavigationSplitView or TabView;
   toolbar items with a title and no symbol, or a symbol and no title.
   Confirm Info.plist has a launch screen key and no orientation lock the design does not need.

2. Walk. Run the screenshot tour in each pose and capture BOTH displays at every stop:
   closed; closed and turned; open; open and turned; partly folded; partly folded and turned.
   If no tour exists, write a UI test that stops at each kind of screen and signals a host script, and have
   the script capture with:  xcrun simctl io <udid> screenshot --display=primary     (outer)
                             xcrun simctl io <udid> screenshot --display=primary-1   (inner)
   Poses are buttons in Device Hub (Closed, Book, Open, Rotate Right); simctl has no pose command.

3. Read every capture and answer, per pose:
   - Are the bars where the system puts them (down the side closed and in open landscape, across the top
     and bottom in open portrait)? Is any toolbar item missing from the bar and from the overflow menu?
   - Does any sheet reserve the side rail and leave it empty?
   - With the keyboard up, what is covered? Can every tab still be reached once it is dismissed?
   - Does anything sit under the outer camera corner or the status column?
   - Open: does a grid have an even number of columns? Does any control or line of text cross the middle?
   - Partly folded: does content move off the fold? Do sheets and alerts land on one side?
   - Turned: did a two-pane layout stack when it should have stayed side by side, or the reverse?
   - Is the same selection, scroll position and navigation path still there after the pose changed?

4. Fix with, in this order: a system container that already adapts; size classes; ArrangementView for a
   custom two-pane layout; reservedRegions for hand-placed content. Never branch on the device model,
   the idiom, the orientation, or the raw hinge angle to decide layout.

5. Guard everything from the 27.1 SDK with `if #available(iOS 27.1, *)` and a fallback that keeps both
   panes reachable. If the same source must also build with Xcode 27.0, fence it at compile time.

6. Report what could not be checked in the simulator: cameras, StandBy, extensions, haptics, real reach.

La documentation d’Apple, dans l’ordre où je l’utiliserais

Tout ce qu’Apple a publié pour cet appareil se rattache à une seule page, Get ready for iPhone Duo.19 Dans l’ordre de travail :

Quoi Pourquoi l’ouvrir
Prepare your app for iPhone Duo (Tech Talk) Les trois niveaux de SDK, les classes de taille, les zones sûres. Commencez ici
Preparing your app for iPhone Duo (guide) Le même terrain sous forme de texte, avec chaque API nommée. Les quatre vérifications de « Address common layout and resizing considerations » forment la liste d’audit2
Raise the bar with iPhone Duo Les barres verticales : ce qui y entre, ce qui reste dehors, le débordement
Strike a pose with adaptive layouts on iPhone Duo La pliure : déplacement, régions réservées, vues d’arrangement
Designing for iPhone Duo (HIG) et Design for iPhone Duo Les règles qu’un designer vous opposera7
Leverage multiple displays and scenes on iPhone Duo La charnière, Split View, une seconde scène sur l’écran externe
Build a great camera experience for iPhone Duo Seulement si vous capturez : deux caméras frontales et l’orientation de chacune6
Enregistrements des Group Labs, jour 1 et jour 2, et les questions-réponses du forum pour SwiftUI, UIKit et Photos and Camera Des ingénieurs d’Apple répondent aux questions des développeurs19
Apple Design Resources Kits Figma et Sketch, et les contours de produits pour le marketing11
Hors d’Apple : le guide du simulateur de SwiftLee, iPhone Duo by Examples, la liste de contrôle de BleepingSwift, le guide d’Adapty Une liste de tests et le curseur de charnière ; un exemple exécutable par API, avec des notes de terrain ; une courte liste de contrôle ; le seul que j’aie trouvé qui traite d’un paywall de bout en bout17
Ateliers En personne. SwiftLee précise qu’ils viennent « with the opportunity to test your app on a physical device, » (avec la possibilité de tester votre app sur un appareil physique), ce qui, avant le 23 octobre, est le seul moyen de vérifier une caméra1719

Je n’ai lu ni la synthèse des questions-réponses des Group Labs ni les fils du forum : les pages du forum d’Apple répondent à une récupération automatisée par une page de vérification humaine, et je ne l’ai pas contournée.

Points clés à retenir

  • Si vous publiez une app aujourd’hui : publiez dès maintenant le travail de redimensionnement, compilé avec Xcode 27. C’est ce que vos clients auront sur un Duo le 23 octobre si la boutique est encore fermée au SDK 27.1 ce jour-là, et rien de tout cela n’a besoin de la bêta.
  • Si vous adoptez les API du Duo : compilez avec Xcode 27.1 beta, confirmez sdk 27.1 ou plus avec otool, gardez le build dans TestFlight, et clôturez les appels propres à 27.1 si le même source doit encore compiler pour la boutique.
  • Si vous testez : ne lisez pas le code, parcourez les positions. Fermé, ouvert, partiellement plié, chacune pivotée, une feuille, le clavier, une vue plein écran, et un écran resté ouvert pendant le dépliage. Capturez les deux écrans à chaque fois.
  • Si vous préparez la fiche de la boutique : capturez dès maintenant aux tailles du Duo, composez par script, utilisez les contours d’Apple de face, et gardez une version prête pour le jour où les emplacements ouvriront.
  • Si vous confiez cela à un agent : donnez-lui le parcours, pas seulement les fichiers. La compétence App Resizability d’Apple couvre ce qui se trouve en lisant ; tout ce qui figure dans les constats ci-dessus a été trouvé en regardant.

Questions fréquentes

Mon app actuelle fonctionne-t-elle sur l’iPhone Duo sans modification ?

Oui. La présentation d’Apple le promet pour n’importe quel SDK, et le simulateur le confirme : un build tamponné avec le SDK iOS 26 a tourné dans une fenêtre de 375 par 667 points, et un build tamponné 27.0 a rempli l’écran à côté du bandeau d’état avec des barres horizontales. Aucun des deux n’obtient de barres verticales ni de régions réservées.312

Quel Xcode faut-il pour la mise en page complète de l’iPhone Duo ?

Xcode 27.1 beta (27A9269), qui contient le SDK iOS 27.1 et le seul simulateur de l’iPhone Duo. Son runtime de simulateur 27.1 ne prend en charge que le type d’appareil iPhone Duo, si bien que les autres iPhone se testent sur le runtime 27.0. Le SDK de la bêta de Xcode 27.2 contient les mêmes API, et une app sonde tamponnée 27.2 s’est comportée comme 27.1 dans le simulateur, mais ce Xcode n’a aucun Duo sur lequel tourner.81214

Puis-je soumettre aujourd’hui un build pour l’iPhone Duo à l’App Store ?

Pas un build compilé avec le SDK 27.1, au 2 octobre 2026. App Store Connect accepte les builds des bêtas de Xcode 27.1 et 27.2 pour les tests TestFlight internes et externes, et les builds de Xcode 27 pour la boutique. Apple n’a pas daté le changement.8

Quelles tailles de captures App Store Connect demande-t-il pour l’iPhone Duo ?

1398 par 2034 ou 2034 par 1398 pixels pour l’écran externe, et 2007 par 2853 ou 2853 par 2007 pour l’écran interne, de une à dix images sans couche alpha. Leur téléversement est annoncé pour « later this year » (plus tard dans l’année).9

Comment capturer les deux écrans du simulateur de l’iPhone Duo ?

xcrun simctl io <udid> screenshot --display=primary pour l’écran externe et --display=primary-1 pour l’écran interne. La capture propre d’un test d’interface ne couvre qu’un écran.13

Pourquoi les barres de mon app sont-elles encore horizontales dans le simulateur de l’iPhone Duo ?

Trois causes, dans l’ordre où les vérifier. Le binaire n’est pas tamponné avec le SDK 27.1. Les barres sont faites main au lieu d’appartenir à un TabView, un NavigationStack ou un NavigationSplitView. Ou l’écran interne est en portrait, où Apple garde les barres horizontales par conception.2712

Faut-il une mise en page pour chaque position ?

Non. Les recommandations d’Apple prévoient deux mises en page, largeur compact et largeur regular, plus une réaction à la pliure là où du contenu la traverserait. Kiradex a ces deux-là et une vue d’arrangement ; la position Book n’a demandé aucun code.713

À lire aussi sur ce site : le billet sur le simulateur donne les étapes d’installation, le profil de l’appareil et les mesures corrigées par position ; concevoir pour l’iPhone Duo lit les recommandations de conception d’Apple comme des règles ; le billet Duo pour les développeurs donne les chiffres du matériel et l’historique daté ; le billet sur les captures d’écran défend ce qu’une série doit dire ; la liste de contrôle de l’iPhone redimensionnable est le travail Xcode 27 que ce billet vous conseille de publier en premier ; et le hub Xcode 27 suit la chaîne d’outils.

Sources


  1. Apple Newsroom, Apple unveils iPhone Duo, 9 septembre 2026, consulté le 2 octobre 2026 : « Pre-orders begin Friday, October 16, with availability beginning Friday, October 23. » (Précommandes à partir du vendredi 16 octobre, disponibilité à partir du vendredi 23 octobre.) et « iPhone Duo will be available with iOS 27.1. » (L’iPhone Duo sera disponible avec iOS 27.1.) ↩↩↩

  2. Apple, Preparing your app for iPhone Duo, Technology Overviews, consulté via le point de terminaison JSON de la documentation le 2 octobre 2026 ; sont cités la vue d’ensemble et les sections « Address common layout and resizing considerations », « Organize items in your bars » et « Arrange views in different poses ». La phrase de la vue d’ensemble sur les versions de Xcode était formulée autrement quand ce site l’a citée le 17 septembre 2026 (« Build your app with Xcode 27.1 or later to use all of the available screen space on iPhone Duo. In earlier versions, your app doesn’t extend under the status bar and camera. ») ; le billet Duo pour les développeurs de ce site a consigné la formulation actuelle le 19 septembre. La page ne porte aucune mention de révision. ↩↩↩↩↩↩

  3. Apple Developer Tech Talk, Prepare your app for iPhone Duo, David Jackson, UI Frameworks. Citations tirées de la piste de sous-titres anglais de la présentation, aux instants indiqués. ↩↩↩↩

  4. Apple Developer Tech Talk, Raise the bar with iPhone Duo, Anna, ingénieure UI Frameworks, et Maria, Human Interface Designer. Citations tirées de la piste de sous-titres anglais de la présentation, aux instants indiqués. ↩↩↩

  5. Apple Developer Tech Talk, Strike a pose with adaptive layouts on iPhone Duo, Maria, Human Interface Designer, et Harry, ingénieur UI Frameworks. Citations tirées de la piste de sous-titres anglais de la présentation, aux instants indiqués. ↩↩↩

  6. Apple Developer Tech Talks, Leverage multiple displays and scenes on iPhone Duo et Build a great camera experience for iPhone Duo, citations tirées des pistes de sous-titres anglais aux instants indiqués ; Apple, Choosing a camera by the direction it faces, AVKit, consulté le 2 octobre 2026. ↩↩↩

  7. Apple, Designing for iPhone Duo, Human Interface Guidelines, consulté via le point de terminaison JSON de la documentation le 2 octobre 2026 ; sont citées les sections « Device poses » et « Vertical controls ». ↩↩↩↩↩

  8. Apple, App Store Connect release notes, consulté le 2 octobre 2026 : sont citées les entrées datées du 14 et du 18 septembre 2026 ; l’entrée datée du 9 septembre ajoute les spécifications de captures pour l’iPhone Duo et indique que leur téléversement « will be available later this year », la phrase que reprend la page des spécifications ; les entrées datées du 16 et du 28 septembre ouvrent TestFlight à Xcode 27.2 beta et beta 2 sous la même forme, pour six plateformes ; aucune entrée postérieure au 18 septembre ne mentionne Xcode 27.1 ni le SDK iOS 27.1. Apple, Releases, flux RSS consulté le 2 octobre 2026, dernière date de génération Mon, 28 Sep 2026 14:00:00 PDT : un seul élément mentionne Xcode 27.1, « Xcode 27.1 beta (27A9269) » daté du Fri, 18 Sep 2026 ; l’élément Xcode le plus récent est « Xcode 27.2 beta 2 (27B5028f) » daté du Mon, 28 Sep 2026. ↩↩↩↩↩↩↩↩↩↩↩

  9. Apple, Screenshot specifications et Upload app previews and screenshots, aide d’App Store Connect, consultés le 2 octobre 2026, cités. ↩↩↩↩↩↩↩↩↩↩

  10. Apple, TN3208: Preparing your app’s launch screen to meet App Store requirements, consulté le 2 octobre 2026, cité ; historique des révisions : « 2026-09-14 Updated the ITMS-90870 error message to reflect the iOS 27 launch screen requirement. » et « 2026-06-08 First published. » ↩↩↩

  11. Apple, Marketing Resources and Identity Guidelines, sections « Apple Product Images », « Unauthorized Uses », « Screen Content » et « Custom Photography and Video », consulté le 2 octobre 2026, cité. Apple, Apple Design Resources, Product Bezels, iPhone Duo (Photoshop et PNG), consulté le 2 octobre 2026. Les mesures des contours sont de l’auteur, à partir des fichiers PNG du Bezel-iPhone-Duo.dmg d’Apple : « Outer Closed Portrait » mesure 1574 par 2194 pixels avec une ouverture transparente de 1398 par 2034 ; « Inner Open Landscape » mesure 3093 par 2247 avec une ouverture de 2853 par 2007 ; le kit contient aussi « Inner Open Portrait », « Outer Closed Landscape » et « Outer Open », chacun en Star White et Night Sky. La découpe de la caméra dans « Outer Closed Portrait », mesurée à l’intérieur de l’ouverture à trois pixels par point, s’étend de 400,3 à 436,3 points en largeur et de 29,7 à 65,7 en hauteur ; l’occultation de caméra de l’app sonde s’étend de 399 à 436 et de 30 à 67. ↩↩↩↩↩↩

  12. Exécutions de l’auteur le 2 octobre 2026 : macOS 27.0 (26A428), Xcode 27.1 beta (27A9269), le runtime de simulateur iOS 27.1 (24A94401) et un simulateur créé à partir du type d’appareil iPhone Duo. L’app sonde, DuoProbe2, est un seul fichier Swift : un TabView dont le premier onglet contient un NavigationStack avec cinq éléments de barre d’outils, un affichage de la taille du GeometryProxy, des classes de taille, de toolbarVerticalEdge, de onHingeChange et des reservedRegions des deux types avec .includeInactive, lu à chaque évaluation du body et réévalué une fois par seconde, une ArrangementView de style split, et une vue UIKit qui journalise sa fenêtre, l’écran de la scène de sa fenêtre, UIScreen.main et le trait verticalBarEdge. Elle a été compilée trois fois à partir de ce fichier avec swiftc contre le SDK de simulateur 27.1, cible de déploiement 27.1, en indiquant à l’éditeur de liens quelle version de SDK consigner (-Xlinker -platform_version -Xlinker ios-simulator -Xlinker 27.1 -Xlinker <26.0, 27.0 or 27.1>) ; otool -l sur chaque binaire a affiché la valeur sdk correspondante. Les positions ont été réglées avec les boutons Closed, Book, Open et Rotate Right de Device Hub, actionnés via l’API d’accessibilité. Lignes de console, tampon 27.1, fermé : size=382x562 ... h=compact v=regular verticalEdge=trailing safe=EdgeInsets(top: 82.0, leading: 0.0, bottom: 34.0, trailing: 84.0) divisions=0 occlusions=2, occlusion[0] active=true frame=(399,-52 37x37), occlusion[1] active=true frame=(382,-82 84x170), window=(466.0, 678.0), verticalBarEdge=2 ; ouvert : size=867x553 ... h=regular v=regular verticalEdge=trailing ... divisions=1 occlusions=2, division[0] active=false frame=(455,-82 40x669) margins=EdgeInsets(top: 0.0, leading: 20.0, bottom: 0.0, trailing: 20.0), occlusion[0] active=false frame=(677,-61 58x37), occlusion[1] active=true frame=(867,-82 84x120), window=(951.0, 669.0), hinge=fullyOpen 180 deg ; Book : les mêmes avec division[0] active=true et hinge=partiallyOpen 127 deg ; ouvert et pivoté : size=669x734 ... verticalEdge=nil ... divisions=1 occlusions=2, division[0] active=false frame=(0,321 669x40), window=(669.0, 951.0), mainScreen=(466.0, 678.0), verticalBarEdge=0 ; fermé et pivoté : size=594x350 ... h=compact v=compact verticalEdge=trailing, window=(678.0, 466.0). Les cadres sont exprimés dans les coordonnées de la vue d’affichage, dont l’origine se situe 82 ou 134 points sous le haut de la fenêtre. Tampon 27.0 : window=(386.0, 678.0) fermé, (871.0, 669.0) ouvert, (669.0, 871.0) ouvert et pivoté, (678.0, 386.0) fermé et pivoté, avec verticalEdge=nil et divisions=0 occlusions=0 sur chaque ligne dans chaque position. Tampon 26.0 : window=(375.0, 667.0) fermé, ouvert, en Book et ouvert et pivoté, et (667.0, 375.0) fermé et pivoté, avec h=compact partout. À chaque lancement en 27.1, les six à neuf premières évaluations ont journalisé divisions=0 occlusions=0 avant l’apparition des régions, dont trois avant que la vue ait une taille. Les positions des volets en Open et en Book ont été mesurées sur les captures : à plat, volet principal de x 8 à 433,7 et volet secondaire de 433,7 à 859 ; en Book, volet principal jusqu’à 455,7, une bande vide jusqu’à 495,7, volet secondaire jusqu’à 859. Feuilles, fermé : contenu 374x562 avec un Done textuel, idem avec un symbole sur Done, 450x428 et verticalEdge=nil avec .toolbarVerticalBehavior(.disabled) ; ouvert : 653x501 centré avec h=compact ; Book : 459x501 au bord de tête. Avec la vue d’arrangement remplissant la zone de contenu (une option de lancement), un .split simple a placé le volet principal au-dessus du secondaire sur l’écran pivoté et .split.axes(.horizontal) a montré le volet principal seul ; ouvert et à plat, la même vue a partagé côte à côte, et en Book elle a laissé vide la bande de la pliure. Une app sonde compilée comme le décrit le billet du 21 septembre (swiftc -sdk avec SDKROOT non défini) a affiché clang: warning: using sysroot for 'macOS 27.0' but targeting 'arm64-apple-ios27.1.0-simulator' et a été tamponnée sdk 27.0. Deux builds supplémentaires ont tourné fermé et ouvert. PlainProbe, avec le même tab view, la même pile de navigation et la même barre d’outils et rien qui vienne du SDK 27.1, compilée par Xcode 27.0 (27A266a) contre son propre SDK iOS 27.0 (otool : minos 27.0, sdk 27.0) : window=(386.0, 678.0) fermé et (871.0, 669.0) ouvert. DuoProbe2 tamponnée sdk 27.2 : les mêmes lignes qu’avec le tampon 27.1 dans les deux positions. simctl list runtimes -j donne pour le runtime 27.1 une seule entrée dans supportedDeviceTypes, iPhone Duo, et simctl create avec le type iPhone 18 Pro Max sur ce runtime échoue avec « Incompatible device ». ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  13. Kiradex est l’app de l’auteur (941 Apps), version 1.0, build 5, téléversée sur TestFlight le 2 octobre 2026 et indiquée comme valide par App Store Connect le même jour. Les éléments du projet proviennent de son code source à ce build : cible de déploiement iOS 27.0, compilée avec le SDK 27.1 (otool -l sur le binaire de l’app : minos 27.0, sdk 27.1), UILaunchScreen avec une couleur, portrait et les deux paysages, un TabView à cinq onglets, et deux emplacements #available(iOS 27.1, *), l’un autour d’ArrangementView et l’autre autour d’onHingeChange. La ligne de la feuille de route est citée d’après les notes du projet. Le parcours est un test d’interface qui s’arrête sur huit types d’écran et demande à un script hôte de capturer le simulateur avec simctl io <udid> screenshot --display=primary et --display=primary-1 ; il a tourné dans six positions sur le simulateur de l’iPhone Duo (runtime iOS 27.1), avec les huit arrêts dans cinq d’entre elles et sept fermé et pivoté, ainsi que sur un simulateur d’iPhone 18 Pro Max (runtime iOS 27.0, portrait et paysage). Tailles de capture : 1398 par 2034 et 2034 par 1398 (externe), 2853 par 2007 et 2007 par 2853 (interne), 1320 par 2868 (6,9 pouces). Le bord gauche de l’inspecteur a été mesuré sur les captures de l’écran interne à x 433,7 à plat et à 495,7 en position Book. Le test de dépliage a lancé l’app fermée, capturé l’écran interne en continu et appuyé sur Open ; quatre images consécutives montrent l’ouverture. Le test de la carte restée ouverte a ouvert une carte en position fermée, appuyé sur Open et capturé vingt secondes plus tard. Le test de la visionneuse a ouvert la visionneuse plein écran quatre fois dans une même session sur le simulateur de 6,9 pouces et mesuré chaque capture : la première comptait 52 % de pixels non noirs, les trois autres 0,3 %. Une recherche textuelle dans les frameworks XCTest et XCUIAutomation de la plateforme simulateur de la bêta de Xcode 27.1 pour « hinge », « posture », « DevicePose » et « foldState » n’a rien trouvé, et simctl ne liste aucune commande de position. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  14. Test de l’auteur le 2 octobre 2026. Un fichier utilisant ArrangementView derrière if #available(iOS 27.1, *) a été vérifié avec swiftc -typecheck contre le SDK de simulateur de chaque Xcode installé : Xcode 27.0 (27A266a) a échoué avec error: cannot find 'ArrangementView' in scope ; Xcode 27.1 beta (27A9269) et Xcode 27.2 beta (27B5019j) ont réussi. Le même fichier clôturé par #if DUO_SDK a réussi sous 27.0 sans le drapeau et sous la bêta 27.1 avec et sans, et a échoué sous 27.0 avec -D DUO_SDK. Clôturé par #if canImport(SwiftUI, _version: 8.0.85), il a réussi sous les trois, et un #warning dans chaque branche a montré que 27.0 compilait la solution de repli et les deux bêtas la branche 27.1. xcrun swift --version affiche Apple Swift version 6.4 (swiftlang-6.4.0.34.1 clang-2100.3.34.1) sous les trois. Les versions du module SwiftUI sont les valeurs -user-module-version du SwiftUI.swiftinterface de chaque SDK. La bêta 27.2 installée ici est la bêta 1 (27B5019j) ; son runtime de simulateur iOS 27.2 (24B5084k) ne liste pas le type d’appareil iPhone Duo, et les notes 27.2 d’Apple renvoient les développeurs vers la bêta 27.1 pour celui-ci. La grammaire de la condition provient de The Swift Programming Language, Statements, « Conditional Compilation Block », consulté le 2 octobre 2026 : « platform-condition → canImport ( import-path ) ». ↩↩↩↩↩↩↩↩↩

  15. Xcode 27.1 beta (27A9269), Contents/PlugIns/IDEIntelligenceChat.framework/Versions/A/Resources/ : app-resizability.idechatprompttemplate et app-resizability-ref-uiscreen-task.md.packaged, -orientation-task, -scene-lifecycle-task, -safe-area-task et -idiom-task, lus le 2 octobre 2026 ; les citations proviennent de la section « When to Use » du modèle et de la règle 6 de la référence sur la zone sûre ; les trois vérifications du projet correspondent à son tableau « Prerequisites » et les cinq motifs à son « Task Registry ». Xcode 27.0 (27A266a) contient uikit-app-modernization.idechatprompttemplate et quatre fichiers de référence dans le même dossier. ↩↩↩

  16. Apple, documentation consultée via le point de terminaison JSON le 2 octobre 2026 : ArrangementView, reservedRegions(kind:options:layoutDirectionBehavior:), onHingeChange(isEnabled:_:), toolbarVerticalBehavior(_:) et toolbarVerticalEdge. ↩

  17. Antoine van der Lee, iPhone Duo Simulator: Testing and optimizing your SwiftUI app, SwiftLee, 22 septembre 2026, cité. Artem Novichkov, iPhone Duo by Examples, README GitHub, « Good to Know », consulté le 2 octobre 2026 : « Its frame is the same in both states: 40 pt wide, with 20 pt margins on each side of a zero-width fold line. », « Reserved regions arrive after the first layout pass. » et « When folded, the outer display has no reserved regions at all, not even inactive ones. » Les deux premiers concordent avec l’app sonde ; le troisième non, puisque l’app sonde a lu deux occultations actives sur l’écran externe fermé. Mick MacCallum, How to Get Your App Ready for iPhone Duo, BleepingSwift, 18 septembre 2026. Yurii Kleimenov, How to adapt your iOS app to iPhone Duo, Adapty, publié le 11 septembre 2026 et marqué comme mis à jour le 15 septembre. ↩↩↩↩↩

  18. Apple, « App Store submissions now open for the latest OS releases », actualités pour les développeurs, 9 septembre 2026 : à partir d’avril 2027, les apps téléversées sur App Store Connect « need to meet the following minimum requirements » (doivent satisfaire aux exigences minimales suivantes), dont la première est « iOS and iPadOS apps must be built with the iOS 27 & iPadOS 27 SDK or later ». ↩

  19. Apple, Get ready for iPhone Duo, consulté le 2 octobre 2026 : six Tech Talks, deux enregistrements de Group Labs, un lien vers les questions-réponses des Group Labs, des questions-réponses de forum pour Photos and Camera, SwiftUI et UIKit, Xcode 27.1 beta, les recommandations et ressources de conception, le guide de préparation et des ateliers en personne. La page de questions-réponses des Group Labs et les fils du forum n’ont pas été lus ; les requêtes vers eux ont renvoyé une page de vérification humaine. ↩↩↩

  20. Apple, Xcode 27.1 Beta Release Notes, consulté via le point de terminaison JSON de la documentation le 2 octobre 2026, Simulator, Known Issues : « StandBy is unavailable in the iPhone Duo Simulator runtime. (187708663) » et « Running and debugging most app extensions is unavailable in the iPhone Duo Simulator runtime. (187708767) ». Apple, Xcode 27.2 Beta 2 Release Notes, consulté de la même façon le 2 octobre 2026 : Overview, « Download Xcode 27.1 beta to get the iOS SDK and simulator support for iPhone Duo. » ; General, Known Issues, 187146039, cité. ↩

Articles connexes

Xcode 27.1 beta : votre app dans le simulateur iPhone Duo

Xcode 27.1 beta apporte le premier SDK iOS 27.1 et un simulateur iPhone Duo : ce que contient le SDK, ce que dit le prof…

46 min de lecture

arm64e.x1 : la slice d'Apple pour l'arithmétique de pointeurs vérifiée

Les notes de version d'iOS 27 RC ajoutent arm64e.x1 : arithmétique de pointeurs vérifiée (CPA2) sur A20 Pro, M6 et S11. …

22 min de lecture

Concevoir pour l'iPhone Duo : ce qui bouge, ce qui se divise et ce qui reste

Le guide de design d'Apple pour l'iPhone Duo et trois Tech Talks, lus comme des règles : deux classes de taille plutôt q…

27 min de lecture