Imagine an elderly parishioner trying to listen to a sermon on an iPhone 6s. Audio cuts off when switching to another app, the font is too small, and a notification about the upcoming service never arrives. This scenario results from a lack of proper handling of background audio, Dynamic Type, and push notifications. We've accumulated solutions to these challenges for church apps that run on devices 5–7 years old.
How the Schedule and Notifications Work
The service schedule is a calendar with recurring events and exceptions. A local copy in Core Data (iOS) or Room (Android) syncs on launch. Recurring events (iCalendar RRULE semantics) are better stored as a rule plus an exception list rather than as N separate entries.
Push notifications an hour before the service are sent via FCM or APNs. On the client side, local notifications via UNUserNotificationCenter (iOS) or AlarmManager + NotificationCompat (Android) serve as a fallback for users without stable internet.
Local Notifications: Step by Step
- Request permission:
UNUserNotificationCenter.current().requestAuthorization(options:). - Create content:
UNMutableNotificationContent()with title and body. - Set trigger:
UNCalendarNotificationTrigger(dateMatching:repeats:). - Add request:
UNUserNotificationCenter.current().add(request).
On Android — NotificationCompat.Builder + AlarmManager.setExact().
How the Sermon Media Library Works
Audio and video sermons are the primary content. Video via HLS from CDN (AVPlayer with AVAsset(url: m3u8URL)), audio — AVAudioPlayer or AVPlayer depending on format. Background audio is mandatory: users listen while commuting.
Background audio on iOS: AVAudioSession with category .playback, UIBackgroundModes: audio in Info.plist, MPRemoteCommandCenter for control from Control Center and AirPods (play/pause, next track, seek). Without MPRemoteCommandCenter, the notification doesn't appear in the system player, and AirPods don't control playback. For proper operation, MPRemoteCommandCenter must be configured — see Apple documentation for details.
On Android — MediaSessionCompat + MediaBrowserServiceCompat + notification with MediaStyle. ExoPlayer in ForegroundService for background playback. PlayerNotificationManager from ExoPlayer automatically creates a media notification with controls.
Sermon search — full-text search via API. Filter by speaker, date, series. Offline access for downloaded materials — stored in FileManager (iOS) or getExternalFilesDir() (Android).
Community Chat: Ready SDK or Custom Solution?
A general chat can be implemented either via a third-party SDK (Stream Chat, SendBird) or a custom WebSocket-based solution. For small communities (up to 500 people), ready SDKs with freemium models are more cost-effective in terms of development time and cost. Stream Chat SDK for iOS and Android provides a ready-made UI — ChatChannelVC / ChannelListFragment — with customization options.
| Criterion | Stream Chat | Custom Implementation |
|---|---|---|
| Integration time | 1–2 days | 2–4 weeks |
| Cost | Free tier up to 10k MAU | Server costs + development |
| Features | Moderation, reactions, files | Full control, but more complex |
Content moderation — admin and moderator roles. Message deletion, user blocking. This is a mandatory feature for a religious community.
How Donations Are Handled
In-app donations are the most regulated part. On iOS, you cannot simply embed your own payment form for digital goods/services — Apple requires StoreKit. However, donations for non-profits/religious organizations are not a digital content purchase, so a WebView with an external payment form (Stripe, PayPal) is acceptable. This must be explicitly stated in the app's purpose during review — otherwise risk rejection under guideline 3.1.1.
On Android, restrictions are fewer — native Stripe SDK (com.stripe:stripe-android) with PaymentSheet provides a ready UI for card entry.
Recurring donations — subscriptions via Stripe Billing. Manage from the app: cancel, change amount. The savings on Stripe's commission compared to a custom payment gateway can be significant.
Supporting Older Devices: What to Watch For
Minimum iOS 14 (covers over 95% of active devices). Android minimum API 26 (Android 8). On iOS 14 there is no AsyncImage — use Kingfisher. Without @Observable (iOS 17) — use ObservableObject + @Published.
Font — Dynamic Type (UIFont.preferredFont(forTextStyle:), sp units on Android). Elderly users often increase the font size in system settings — the app must respond correctly without text overflow.
| What devices we test on? |
|---|
| iPhone 6s (iOS 14), iPhone 8, iPhone X, iPod touch 7, Samsung Galaxy S8 (Android 8), Galaxy J5, Xiaomi Redmi Note 5. On each device we check font scaling, background playback, push notifications. |
What's Included in the Work? (Deliverables)
| Stage | Result |
|---|---|
| Analysis | Technical specification, architecture diagram, UX prototype |
| Design | Pixel Perfect mockups for iOS and Android, Dynamic Type adaptation |
| Development | Native code in Swift/Kotlin, API integration, push certificates |
| Testing | QA on real devices, UI tests, load testing |
| Publication | Upload to App Store Connect and Google Play Console, navigating guidelines |
| Support | 3 months of bug fixes and consultations after release |
Timelines and Cost
Schedule + media library with background audio + push notifications — 4–6 weeks. Chat + donations + offline — 2–3 months. Cost is calculated after requirements analysis. Contact us for a project estimate — we'll prepare a commercial proposal within 2 days.
Guarantees and Experience
We guarantee passing App Store Review and Google Play Review, compliance with guidelines (Section 4.2, 5.1), and personal data protection. 5+ years in mobile development, 30+ releases. Get a consultation on your app architecture today.







