Sakinah
Application compagnon pour musulmans : horaires de prière, mushaf du Coran, Qibla et parcours guidés, en EN/AR/FR


En bref
- Plateformes
- iOS 26+ (SwiftUI), Android (Kotlin, Jetpack Compose, minSdk 26)
- Calendrier
- De juillet 2026 à aujourd'hui
- Équipe
- Seul : produit, intégration du design, iOS, Android
- Langues
- Anglais, arabe (RTL, chiffres orientaux ou occidentaux), français
- Base de code
- Environ 320 fichiers source Swift et 81 fichiers de test sur iOS ; Android découpé en 9 modules core et 15 modules de fonctionnalités
- Tests
- Environ 1 460 méthodes XCTest sur iOS
Vue d'ensemble
Sakinah est une application compagnon gratuite pour musulmans, développée nativement pour iPhone en SwiftUI, avec un portage Android en Kotlin et Jetpack Compose. Elle réunit dans une seule app les horaires de prière avec notifications d'adhan, un lecteur du Coran avec récitation, la Qibla, une bibliothèque de du'a et d'adhkar, les masjids à proximité et des parcours guidés pour le wudu, la salah et la Omra, en anglais, en arabe (RTL) et en français. Je l'ai conçue et développée seul.
Le défi
Une application de pratique religieuse laisse moins de place à l'erreur que la plupart des applications grand public. Un horaire de prière faux, un adhan qui ne se déclenche jamais, un compteur de tasbih perdu ou un texte religieux mal retranscrit sont de vrais échecs pour l'utilisateur. iOS supprime silencieusement toute notification locale en attente au-delà de 64 par app, et avec toutes les alertes activées, une seule journée en demande 18 : la limite est donc atteinte en moins de quatre jours. La bibliothèque open source de calcul des horaires, épinglée à une version fixe, ne sait pas calculer le calendrier officiel de chaque autorité régionale (la méthode du ministère marocain en est un exemple). L'arabe devait être une vraie mise en page RTL avec le choix entre chiffres orientaux et occidentaux, pas un simple remplacement de chaînes. Tout cela devait fonctionner hors ligne, s'appuyer sur des contenus issus de sources citables, puis être reconstruit une seconde fois sur Android.
Mon rôle
Je porte l'ensemble du produit : je l'ai lancé en juillet 2026 et je suis depuis le seul ingénieur sur l'app iOS. Sur iOS, j'ai construit le squelette de l'app (la TabView système à cinq onglets, avec une pile de navigation par onglet), un module de design system avec tokens et trois apparences (clair, nuit et noir pur OLED), les moteurs d'horaires de prière et de notifications, un journal SQLite en ajout seul pour les données de pratique religieuse, le texte du Coran et l'audio des récitations, 29 dossiers de fonctionnalités, les abonnements de soutien et dons StoreKit 2, AdMob avec le parcours de consentement UMP de Google, ainsi que Firebase Crashlytics et Analytics. J'ai aussi écrit les scripts Python d'ingestion de contenu et une suite XCTest d'environ 1 460 méthodes de test. Pour Android, j'ai rédigé neuf spécifications de portage et construit une app Kotlin et Compose multi-module avec des flavors de préproduction et de production, Play Billing, AdMob avec UMP, et un convertisseur qui génère les ressources de chaînes Android à partir des String Catalogs iOS.
Architecture
Clients
App iOS
Swift, SwiftUI, XcodeGen, iOS 26
La TabView système à cinq onglets (Today, Qur'an, Qiblah, Dhikr, More), une NavigationStack par onglet et 29 dossiers de fonctionnalités.
App Android
Kotlin, Jetpack Compose, Gradle multi-module
Un portage natif construit à partir de neuf spécifications écrites, avec un unique NavHost typé et un graphe imbriqué par onglet, le flou d'arrière-plan Haze sur API 31+, et des flavors de préproduction et de production d'un même application id.
Services
Moteur d'horaires de prière
Adhan (Swift) 1.5.0, CoreLocation
Calcule les horaires de prière sur l'appareil et choisit l'autorité régionale selon la position de l'utilisateur ; une façade choisit entre un calendrier officiel vérifié en cache et le moteur local, sans aucun appel réseau sur le chemin de lecture.
Planificateur d'adhan et de rappels
UserNotifications
Maintient une fenêtre glissante de 7 jours de notifications ponctuelles, adhans en priorité, et la complète chaque fois que l'app revient au premier plan.
Média
Audio de récitation et d'adhan
AVFoundation
Télécharge un MP3 par ayah dans un cache sur disque depuis des miroirs épinglés, garde trois ayat en file d'avance, et s'appuie sur une table embarquée des durées d'ayah par récitateur pour une barre de lecture couvrant toute la sourate.
Données
Journal de pratique
SQLite3 C API (WAL, synchronous FULL)
Un journal d'événements en ajout seul pour les compteurs de tasbih, les suivis de prière et les positions de lecture ; des triggers rejettent les mises à jour et les suppressions, et chaque ligne porte un identifiant d'événement et d'appareil pour que les journaux puissent être fusionnés.
Contenu embarqué
Python ingest scripts, JSON, String Catalogs
Le texte du Coran, les traductions et le tafsir, Hisn al-Muslim (132 chapitres, 267 adhkar) et les textes des parcours guidés sont ingérés depuis des fichiers sources épinglés, vérifiés et embarqués pour fonctionner hors ligne.
Services tiers
Calendriers officiels
AlAdhan API over HTTPS
Couvre les autorités que la bibliothèque embarquée ne sait pas calculer : un mois est récupéré en une seule requête, mis en cache sur disque pour une position ancrée, et réutilisé hors ligne.
Cartes et lieux
MapKit (MKLocalSearch, MKDirections)
Nearby & Drive trouve les masjids, affiche les temps de trajet et ouvre la fiche lieu native d'Apple pour les horaires et les détails.
Monétisation et diagnostics
StoreKit 2, Google Play Billing, Google Mobile Ads, UMP, Firebase
Abonnements de soutien et dons ponctuels, publicités derrière un parcours de consentement, 7 jours sans publicité à la première installation, et remontée des crashs via Crashlytics.
Infrastructure
Site d'assistance et de confidentialité
Firebase Hosting
Une page d'assistance statique, une politique de confidentialité et un app-ads.txt pour les fiches des stores.
Décisions clés
- 01
Fenêtre glissante de 7 jours, adhans en priorité
iOS ne conserve que 64 notifications locales en attente par app et supprime le reste sans erreur, et avec toutes les alertes activées une journée en demande 18. Mon planificateur maintient une fenêtre glissante de 7 jours d'adhans ponctuels (35 au maximum), remplit le reste du budget avec les rappels les plus proches d'abord, et la recharge dès que l'app revient au premier plan : un rappel n'évince donc jamais un adhan. La contrepartie : si l'app n'est pas ouverte, les rappels s'épuisent quelques jours avant les adhans.
- 02
Moteur hors ligne et calendriers officiels en cache
La plupart des régions sont calculées sur l'appareil avec la bibliothèque Adhan épinglée. Pour les autorités qu'elle ne sait pas calculer, l'app récupère un calendrier mensuel officiel et le met en cache pour une position ancrée qui ne bouge que lorsque l'utilisateur se déplace ; ainsi, les variations du GPS et les relancements retrouvent toujours le mois en cache. Si une méthode n'a ni équivalent local ni mois en cache, l'app affiche un état d'attente au lieu d'utiliser discrètement les horaires d'une autre autorité.
- 03
Journal SQLite en ajout seul pour les données de pratique
Les compteurs de tasbih, les suivis de prière et les positions de lecture sont écrits dans un journal en ajout seul, sur l'API C SQLite3 du système en mode WAL avec synchronous=FULL : une écriture ne rend la main qu'une fois sur un stockage stable. L'app lit un état dérivé du journal, et les identifiants d'événement et d'appareil permettent de fusionner deux journaux par union. Les enregistrements modifiables, comme les notes et les plans, ont ensuite reçu des horodatages de création/mise à jour et des tombstones, pour qu'un futur backend puisse distinguer une suppression d'un enregistrement manquant.
- 04
Réseau cloisonné, contenu épinglé
Seuls cinq fichiers sources nommés peuvent faire des appels HTTP : téléchargement des éditions du Coran, calendriers officiels, audio des récitations, audio des adhkar, et cours de l'or et de l'argent pour le nisab de la zakat. Un test parcourt l'arborescence du code et échoue si du code réseau apparaît ailleurs. Les fichiers fixes proviennent de miroirs identiques à l'octet près, et les téléchargements d'éditions et d'audio d'adhkar sont vérifiés par rapport aux tailles et aux empreintes SHA-256 embarquées dans l'app.
- 05
RTL arabe, chiffres et texte source comme règles vérifiées
L'interface se met en miroir en RTL, et l'arabe peut utiliser les chiffres orientaux ou occidentaux. Chaque nombre passe par un formateur de chiffres, et un test échoue si une chaîne arabe contient un chiffre saisi en dur. Les scripts d'ingestion n'écrivent le texte des parcours guidés que si chaque ligne est retrouvée lettre par lettre dans l'une des trois extractions indépendantes du PDF de l'éditeur, et l'arabe est en outre vérifié mot par mot avec ses signes vocaliques.
- 06
Chaînes Android générées depuis les catalogues iOS
Plutôt que de traduire deux fois, j'ai écrit un convertisseur Python qui transforme les String Catalogs iOS en ressources Android, placeholders et pluriels compris, et son mode vérification échoue lorsque la sortie commitée n'est plus à jour. Les modules Android suivent neuf spécifications de portage écrites, si bien que les deux apps restent cohérentes dans leur comportement et leurs formulations.
Résultats
- Construite et en phase de test avant publication (pas encore sur l'App Store ni sur Google Play).
- Une app iOS à cinq onglets et 29 domaines fonctionnels : horaires de prière, adhan et rappels, index et lecteur du Coran avec récitation, Qibla, bibliothèque de du'a et d'adhkar, les 99 Noms, Ruqyah, calendrier musulman, calculateur de zakat, Nearby & Drive, parcours de hifz, et guides du wudu, de la salah, de la Omra et de la janazah.
- Notifications d'adhan avec audio embarqué, rappels par prière et d'adhkar qui continuent de se déclencher pendant une semaine sans ouvrir l'app.
- Localisation complète en anglais, arabe (RTL) et français, avec le choix entre chiffres arabes orientaux et occidentaux.
- Une suite de tests iOS d'environ 1 460 méthodes XCTest, dont des règles vérifiées dans le code : le cloisonnement réseau, l'absence de chiffres saisis en dur dans les chaînes arabes et la durabilité du journal de pratique.
- Un portage Android multi-module en Kotlin et Jetpack Compose avec Play Billing, AdMob avec consentement UMP, et des flavors de préproduction et de production distincts.
- Monétisation sur les deux plateformes sans aucune fonctionnalité de pratique derrière un paywall : abonnements de soutien optionnels et dons ponctuels (qui suppriment les publicités), publicités derrière un parcours de consentement, et 7 jours sans publicité après l'installation.
Stack
- iOS
- SwiftSwiftUIXcodeGenStoreKit 2MapKitCoreLocationUserNotificationsAVFoundationSQLite3Adhan (Swift)
- Android
- KotlinJetpack ComposeNavigation ComposeGradle multi-moduleDataStoreGoogle Play BillingHaze
- Services et SDK
- Google Mobile AdsGoogle UMPFirebase CrashlyticsFirebase AnalyticsGoogle Tag ManagerAlAdhan APIFirebase Hosting
- Outillage
- XCTestPython content-ingest scriptsString CatalogsiOS-to-Android string converter
