| .. | ||
| Card2vcf | ||
| Card2vcfTests | ||
| .gitignore | 114 B | |
| README.md | 7 kB | |
| project.yml | 1 kB |
README.md
PicLead — iOS
Portage natif Swift/SwiftUI de l'application Android (voir le
README racine pour la description fonctionnelle :
scan de carte de visite → OCR local → brouillon éditable → carnet
local → export .vcf, sync PicLead optionnelle).
Rebranding au même niveau qu'Android : nom affiché PicLead et
bundle id fr.ebii.piclead (miroir de l'applicationId) ; le module,
la cible Xcode et les identifiants internes restent Card2vcf/
card2vcf (miroir du namespace Android — clés, schéma, préfixe
card2vcf:serverId= partagés avec l'existant).
Comme sur Android, l'OCR et le carnet restent 100 % sur l'appareil : aucune dépendance tierce, aucun service cloud — uniquement les frameworks Apple embarqués. Le réseau ne sert qu'à la sync optionnelle.
Build
Prérequis : Xcode 16+ (testé Xcode 26.6), XcodeGen.
cd ios xcodegen generate open Card2vcf.xcodeproj # ou : xcodebuild -project Card2vcf.xcodeproj -scheme Card2vcf \ -destination 'platform=iOS Simulator,name=iPhone 17 Pro' build
Tests (mêmes suites que les tests JUnit Android, portées en XCTest) :
xcodebuild -project Card2vcf.xcodeproj -scheme Card2vcf \ -destination 'platform=iOS Simulator,name=iPhone 17 Pro' test
Cible : iOS 16+, iPhone et iPad. Le .xcodeproj est généré (non
versionné) ; la vérité est project.yml.
Correspondances Android ↔ iOS
| Fonction | Android | iOS |
|---|---|---|
| Capture + correction perspective | CameraX + OpenCV | VisionKit VNDocumentCameraViewController (import photo : VNDetectRectanglesRequest + CIPerspectiveCorrection) |
| OCR (7 langues, on-device) | Tesseract4Android | Vision VNRecognizeTextRequest (boucle d'orientation identique) |
| Structuration heuristique | ContactHeuristicParser (Kotlin) | port Swift 1:1 (mêmes regex) |
| Carnet local + FTS | Room v3 + FTS4 | SQLite3 natif (acteur Swift) + FTS5 external-content, mêmes tables/colonnes |
| Import/Export VCF | VCardParser/VCardSerializer | ports Swift 1:1 (vCard 3.0/4.0 en lecture, 3.0 en écriture) |
| Contact système | ACTION_INSERT | CNContactViewController (Contacts) |
| Stockage clé API chiffrée | EncryptedSharedPreferences + Argon2id/XChaCha20 | Keychain + port Swift byte-compatible (Argon2id RFC 9106 + XChaCha20-Poly1305 via CryptoKit) |
| Client sync | OkHttp + kotlinx-serialization | URLSession + Codable (mêmes endpoints, mêmes JSON) |
| Pont Agenda | CalendarProvider (calendriers locaux) | EventKit (calendriers EKSource locaux) |
| Planification des tâches (jours ouvrés, teintes d'étiquette) | planning/ (Kotlin, java.time.LocalDate) | Planning/ (port Swift 1:1 + DateCivile, Foundation n'offrant pas de date sans fuseau) |
| UI | Jetpack Compose | SwiftUI (mêmes écrans, chaîne graphique design.md) |
Structure
ios/ ├── project.yml # définition XcodeGen (2 cibles : app + tests) ├── Card2vcf/ │ ├── App/ # point d'entrée SwiftUI │ ├── Contact/ # ContactCard, parseur heuristique, vCard │ ├── CRM/ # normalisation, doublons, fusion, tri, abcédaire │ ├── OCR/ # OcrResult, post-traitement, moteur Vision │ ├── Planning/ # calendrier ouvré, teintes d'étiquette, aperçu de tâche │ ├── Scan/ # caméra document, recadrage, pipeline scan→brouillon │ ├── Data/ # entités, protocoles DAO, dépôt, images │ │ └── Sqlite/ # implémentation SQLite3 + FTS5 (schéma Room v3) │ ├── Sync/ # client Ailiance, moteur LWW, crypto, agenda EventKit │ ├── Kanban/ # filtres kanban │ └── UI/ # écrans SwiftUI (carnet, fiche, scan, projets, réglages) └── Card2vcfTests/ # suites XCTest portées des tests JUnit
Écarts connus vs Android
- Modèles hors-ligne téléchargeables (Android
modeles/, saveursfdroid/direct) : sans objet sur iOS, et c'est volontaire. L'OCR passe par Vision et la transcription parSFSpeechRecognizer: les modèles sont fournis et mis à jour par le système, il n'y a rien à télécharger, donc ni catalogue, ni dépôt de modèles, ni section « Modèles hors-ligne » dans les Réglages. Le chantier F-Droid répondait à une contrainte de taille d'APK (Tesseract + Vosk embarqués) qui n'existe pas ici. - Planification des tâches : portée (dates, durée en jours ouvrés, étiquettes colorées, sous-tâches, repère de retard, édition depuis la carte kanban). Restent hors périmètre des deux plateformes : diagramme de Gantt sur téléphone, édition des dépendances et du regroupement, réglage de l'échéance et du rythme du projet — tous réservés au web. Comme sur Android, la date de début se saisit en texte ISO, pas par un sélecteur graphique.
- Langues OCR : Vision ne propose pas de correction linguistique
pol/nldsur iOS 16 ; le texte latin reste reconnu (recognizer latin), sans correction spécifique à ces deux langues. - Note du contact système : le champ note de
CNContactexige l'entitlement restreintcom.apple.developer.contacts.notes— non renseigné à la création du contact système (la note reste dans le carnet Card2vcf). - Rotation manuelle de l'image de carte (bouton 90° Android) : non portée (le recadrage VisionKit redresse déjà la capture).
- Migrations : additives depuis v3 (v3→v4 : colonne
lastErrorsursync_ops, miroir de RoomMIGRATION_3_4) ; toute version plus ancienne reste réinitialisée (filet destructif, comme sur Android). - Prétraitement contraste (CLAHE) : non porté — spécifique Tesseract ; Vision gère nativement les cartes colorées. L'extraction spatiale (BlockGrouper, champs douteux) est portée ; la confiance Vision (0-1, ramenée à 0-100) est plus grossière que celle de Tesseract, le seuil « à vérifier » (70) peut donc marquer un peu plus large.
- Refonte cosmétique Material 3 (coins arrondis,
ChampTexte, chevrons de menus) : non répliquée à l'identique — iOS conserve son système éditorial carré ; la palette PicLead (menthe, rouge erreur, gris froids) et les signaux fonctionnels (pastilles de synchro, textes d'erreur, « À vérifier ») sont repris. - HTTP clair : refusé par défaut (
ServerUrlPolicy), la case « Autoriser HTTP » reste nécessaire ; l'exception ATS globale duInfo.plistn'est effective qu'une fois cette case cochée. - Source locale masquée par iCloud (sans équivalent Android, où le
compte agenda local existe toujours) : quand iCloud Agenda est actif,
iOS n'expose plus le stockage local. À l'activation d'une liaison,
un dialogue laisse le choix : créer le calendrier dans le compte
iCloud de l'utilisateur (synchronisé sur ses appareils), ou annuler
(calendrier 100 % local possible en désactivant iCloud Agenda).
findCalendarretrouve les calendriers des deux sources pour éviter les doublons au ré-appairage.
GitRust