Lorsqu’une équipe débogue une app iOS depuis un Mac dans le cloud, elle peut facilement conclure trop vite qu’un import a réussi : elle sélectionne un PDF dans Fichiers, l’aperçu s’ouvre, et elle considère l’opération terminée. Pourtant, l’app n’a peut-être fait que lire temporairement un fichier externe. Au lancement suivant, si le chemin d’origine n’est plus accessible, l’entrée de la bibliothèque ne s’ouvre plus. Il ne suffit donc pas de vérifier que le sélecteur de fichiers s’affiche : il faut examiner les droits d’accès, la propriété du fichier et sa durée de vie une fois qu’il est transmis à l’app par un fournisseur externe.
Prenons le cas d’un PDF importé pour être lu durablement. Le Mac de développement peut être accessible à distance, mais les règles d’accès aux fichiers restent celles de l’appareil iOS qui exécute l’app. Il faut d’abord distinguer l’implémentation de l’import des tests automatisés : la première traite l’URL réellement remise par le sélecteur, les seconds vérifient la copie appartenant à l’app et les cas d’échec.
Définir ce qui constitue un import terminé
Ouvrir un fichier ne signifie pas en posséder une copie. Avec UIDocumentPickerViewController(forOpeningContentTypes: [.pdf], asCopy: false), l’URL reçue dans le rappel désigne l’emplacement fourni par le sélecteur. Elle ne doit pas être enregistrée directement comme chemin permanent dans la bibliothèque de lecture. Si le fichier doit rester accessible au prochain lancement, l’app doit lire l’original tant que l’accès est valide, le copier dans son propre répertoire persistant, puis faire pointer l’entrée de la bibliothèque vers cette nouvelle copie.
Définissons d’abord trois résultats observables : annuler la sélection ne crée aucune entrée ; un échec de copie ne crée aucune entrée indiquée comme réussie ; après un import réussi, l’app peut toujours ouvrir sa copie au redémarrage, même si l’original a été déplacé. Un répertoire temporaire convient pour une opération d’import ponctuelle, pas pour une bibliothèque à conserver. Si l’entrée doit être durable, la copie temporaire validée doit ensuite être déplacée vers un répertoire persistant de l’app, tel qu’Application Support.
Il faut déclarer l’import réussi après l’écriture et la validation de la copie, et non au moment où le sélecteur renvoie une URL.
Coordonner la copie tant que l’accès est valide
Après avoir reçu l’URL dans le rappel du sélecteur, commencez par activer l’accès à la ressource à portée de sécurité, puis coordonnez la lecture avec NSFileCoordinator. La fonction suivante montre uniquement la mise en attente d’un PDF unique et de petite taille. Il revient encore au code appelant de décider comment valider le contenu, déplacer le fichier vers un répertoire persistant et mettre à jour la bibliothèque. Cet exemple utilise l’ouverture avec asCopy: false ; ce n’est pas une fonction de copie générique qui traiterait systématiquement toutes les sources comme des fichiers externes soumis à autorisation.
func stagePickedPDF(_ url: URL) throws -> URL {
guard url.startAccessingSecurityScopedResource() else {
throw CocoaError(.fileReadNoPermission)
}
defer { url.stopAccessingSecurityScopedResource() }
let destination = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension("pdf")
var coordinationError: NSError?
var copyError: Error?
NSFileCoordinator().coordinate(
readingItemAt: url,
options: [],
error: &coordinationError
) { readableURL in
do {
try FileManager.default.copyItem(
at: readableURL,
to: destination
)
} catch {
copyError = error
}
}
if let coordinationError { throw coordinationError }
if let copyError { throw copyError }
return destination
}
coordinate est un appel synchrone : évitez qu’une copie volumineuse bloque longtemps le thread de l’interface. Dans une implémentation réelle, toute la séquence « activer l’accès — coordonner la lecture — arrêter l’accès » peut être exécutée dans une tâche en arrière-plan. N’arrêtez pas l’accès dans le rappel avant de transmettre l’URL externe à cette tâche. L’accès doit aussi être arrêté en cas d’erreur ; ici, defer est plus facile à contrôler que des appels de fermeture dispersés.
Transformer le fichier temporaire en entrée récupérable
Une fois la copie effectuée, vérifiez que le fichier existe, que sa taille est plausible et qu’un analyseur PDF parvient à l’ouvrir. L’extension .pdf ne suffit pas à prouver que son contenu est valide. Si la validation réussit, déplacez le fichier dans le répertoire persistant de l’app et enregistrez son chemin relatif sous un identifiant généré par l’app. Si la validation ou le déplacement échoue, supprimez le fichier temporaire, affichez une erreur permettant à l’utilisateur de réessayer et n’ajoutez rien à la liste de lecture.
La persistance doit aussi tenir compte d’un échec intermédiaire où « le fichier a été écrit, mais pas l’entrée correspondante ». Une solution consiste à créer d’abord une entrée en attente de validation, puis à la marquer comme disponible après le déplacement. Au démarrage, l’app peut rechercher les entrées inachevées, vérifier les fichiers correspondants et nettoyer les éléments résiduels. La stratégie transactionnelle précise dépend du stockage utilisé par l’app, mais l’objectif reste le même : aucune entrée de la liste ne doit pointer vers un fichier inexistant.
Ne concaténez pas directement le nom affiché par le sélecteur au chemin de destination. Utilisez un nom de fichier généré par l’app et conservez le nom d’origine dans un champ destiné à l’affichage. Vous éviterez ainsi d’écraser un fichier homonyme et réduirez les problèmes liés aux caractères utilisés dans les chemins. Si le produit doit toujours lire l’original externe plutôt que conserver une copie, il s’agit d’un autre contrat d’accès : il faut prévoir séparément une nouvelle autorisation et l’interface à afficher lorsque la source est indisponible, sans réutiliser l’état « importé en local ».
Vérifier chaque couche sur le Mac dans le cloud
Commencez par fournir à la logique post-import des PDF de test situés dans le sandbox de l’app au moyen de XCTest. Vérifiez qu’un document valide est analysé, qu’un fichier endommagé produit une erreur, que des fichiers homonymes ne s’écrasent pas et que la liste pointe toujours vers la copie persistante après la suppression du fichier temporaire. Ces tests ne doivent pas être présentés comme une validation de l’autorisation d’accès à portée de sécurité : les fichiers du sandbox ne reproduisent généralement pas les conditions d’accès d’un véritable fournisseur de fichiers.
Parcourez ensuite toute l’interface dans le simulateur. Préparez un PDF visible dans le sélecteur Fichiers, puis testez séparément la sélection et l’annulation. Après l’import, quittez et relancez l’app pour vérifier que l’entrée de la bibliothèque s’ouvre. Essayez ensuite de déplacer le fichier source visible dans le sélecteur afin de constater si l’app lit bien sa propre copie. Consignez comme vérifications manuelles les comportements des fournisseurs impossibles à piloter de façon fiable par automatisation ; n’utilisez pas une attente d’un nombre fixe de secondes pour masquer cette incertitude.
Enfin, revérifiez les autorisations et le comportement de téléchargement sur l’appareil cible, avec les fournisseurs de fichiers réellement utilisés. Certains documents ne sont pas encore entièrement disponibles en local au moment de leur sélection. Si la lecture échoue, l’interface doit conserver l’erreur et permettre une nouvelle sélection, plutôt que de créer une copie vide. Il s’agit ici de valider le traitement des erreurs, pas de promettre un délai de téléchargement au nom du fournisseur.
Terminer par une matrice des échecs
| Action | Résultat attendu |
|---|---|
| Annuler la sélection | La liste de lecture reste inchangée et aucun fichier temporaire ne subsiste |
| Source illisible | Une erreur explicite s’affiche et aucune entrée indiquée comme réussie n’est créée |
| Échec de la validation de la copie | Le fichier temporaire est supprimé et l’utilisateur peut réessayer |
| Déplacer la source après l’import | La copie de l’app reste accessible après son redémarrage |
| Interrompre l’app pendant l’import | Au prochain lancement, l’app détecte et traite l’entrée inachevée |
Il est préférable de joindre au compte rendu de validation le type de fichier utilisé, la catégorie de la source, les versions du système et du build de l’app, ainsi que le résultat réel de chaque action. Lorsqu’elle reproduit un problème sur le bureau distant, l’équipe peut ainsi déterminer d’abord si l’échec concerne l’autorisation, la lecture coordonnée, la copie, la validation ou l’enregistrement de l’entrée, plutôt que de sélectionner sans cesse le même fichier.
Questions fréquentes
Peut-on conserver le chemin fourni par le sélecteur de documents ?
Pas comme référence durable. Si le document doit rester disponible, coordonnez sa lecture pendant que l’accès est autorisé, copiez-le dans le conteneur de l’app, puis utilisez cette copie.
Le simulateur suffit-il pour valider l’import de fichiers ?
Non. Il aide à tester la copie, l’analyse et les erreurs, mais il faut aussi vérifier le sélecteur et un fournisseur de fichiers réel, notamment l’annulation et le déplacement du document.
Besoin d’un Mac physique dédié accessible à distance ?
Comparez les configurations, les emplacements et les périodes de facturation de M4 Start, M4 Work et M4 Pro, puis choisissez l’offre adaptée à vos besoins.