AI-Powered News Reader for iPhone and iPad
News Mobile is a native SwiftUI news aggregator for iOS that performs real-time sentiment analysis, named entity recognition, story clustering, and personalized feed ranking entirely on-device using Apple's NaturalLanguage framework. It pulls from 16 built-in RSS sources across 10 categories, filters ads and clickbait, syncs state over iCloud, and includes a WidgetKit home screen extension. No cloud AI services, no accounts, no telemetry.
Written by Jordan Koch (@kochj23).
+-------------------------------------------------------------------+
| NewsMobileApp |
| @main entry point -- registers background tasks, starts API |
+----------------------------+--------------------------------------+
|
+--------------v--------------+
| ContentView |
| TabView (5 tabs) |
| Breaking news overlay |
+----+----+----+----+---------+
| | | |
+-----------+ | | +-----------+
| | | | |
+----v---+ +----v-+ | +--v-------+ +----v----+
| Home | | For | | | Watch | |Settings |
| View | | You | | | Later | | View |
+--------+ +------+ | +----------+ +---------+
|
+----v----+
| Search |
| View |
+---------+
+------------------------------ Services --------------------------------+
| |
| NewsAggregator -- concurrent RSS fetch via TaskGroup |
| +-- RSSParser -- XMLParser-backed RSS/Atom decoder |
| +-- SentimentAnalyzer -- NLTagger (.sentimentScore) |
| +-- EntityExtractor -- NLTagger (.nameType) NER |
| +-- ContentFilter -- ad / clickbait / source blocklist |
| |
| PersonalizationEngine -- weighted scoring: category/source/topic |
| StoryClusterEngine -- NLTagger keyword overlap clustering |
| TrendingTopicsEngine -- named entity + proper-noun frequency |
| |
| CloudSyncManager -- NSUbiquitousKeyValueStore (iCloud KV) |
| BackgroundRefreshManager-- BGAppRefreshTask (15-min interval) |
| NotificationManager -- UNUserNotificationCenter |
| KeywordAlertManager -- user-defined keyword monitoring |
| TTSManager -- AVSpeechSynthesizer audio briefings |
| WeatherService -- CoreLocation + Open-Meteo API |
| LocalNewsService -- Google News RSS geo-search |
| CustomFeedManager -- user-added RSS feeds |
| WidgetDataManager -- App Group shared data for WidgetKit |
| SettingsManager -- Codable settings persistence |
| |
+------------------------------------------------------------------------+
+---------------------- Widget Extension --------------------------------+
| NewsMobileWidget (WidgetKit) |
| TimelineProvider -- 30-min refresh, App Group shared data |
| Small / Medium / Large widget layouts |
| Headlines + weather + trending topic + sentiment dots |
+------------------------------------------------------------------------+
+---------------------- Local API Server --------------------------------+
| NovaAPIServer (NWListener, port 37436, loopback only) |
| GET /api/status -- app status, version, uptime |
| GET /api/ping -- health check |
+------------------------------------------------------------------------+
All ML inference runs locally through Apple's NaturalLanguage framework. Nothing leaves the device.
- Sentiment Analysis -- NLTagger with
.sentimentScorescheme scores every headline and maps to positive / neutral / negative with color-coded indicators. - Named Entity Recognition -- NLTagger with
.nameTypescheme extracts people, organizations, and places from article titles. - Story Clustering -- Keyword extraction via
.lexicalClasstagging groups related articles from different sources by shared nouns and verbs, then analyzes left / center / right perspective breakdown based on source bias metadata. - Trending Topics -- Combines named entity frequency with capitalized proper-noun counts across the full article set to surface the top 15 trending topics.
- Personalization Engine -- Tracks category, source, and entity-level reading preferences weighted by dwell time. Produces a scored "For You" feed ranked by a four-factor model: category preference (40%), source preference (30%), topic interest (20%), and recency (10%). Preferences auto-normalize to prevent runaway weights.
- 16 built-in RSS sources across 10 categories (Top Stories, US, World, Business, Technology, Science, Health, Sports, Entertainment, Politics)
- Concurrent feed fetching with Swift
TaskGroup - XML parsing handles RSS 2.0 and Atom feeds, multiple date formats, media thumbnails, and HTML entity cleanup
- Source bias metadata (Left, Lean Left, Center, Lean Right, Right) and reliability scores
- Content filtering removes ads, sponsored content, clickbait patterns, and user-excluded sources
- Breaking news detection based on headline keyword matching within the last hour
- Tab-based navigation: Home, For You, Search, Saved, Settings
- Pull-to-refresh on all feed views
- In-app article WebView for full reading
- iOS share sheet integration
- Dark mode with system or manual toggle
- Configurable font sizes (Small, Medium, Large, Extra Large)
- Breaking news banner overlay
- Small, Medium, and Large home screen widgets
- Headlines with sentiment-colored dots
- Inline weather display
- Trending topic badge
- 30-minute automatic refresh via TimelineProvider
- Data shared through App Group (
group.com.jordankoch.newsmobile)
- Text-to-speech via AVSpeechSynthesizer
- Reads source attribution, headline, and description
- Play / pause / skip / previous controls
- Configurable speech rate (Slow, Normal, Fast)
- Audio session configured for background playback with duck-others policy
- iCloud key-value sync via NSUbiquitousKeyValueStore for settings and saved articles
- Background app refresh every 15 minutes via BGAppRefreshTask
- Push notification support for breaking news and keyword alerts
- Watch Later queue with read/unread tracking
- Location-based local news via Google News RSS geo-search
- Weather from Open-Meteo API (free, no key required) using CoreLocation
- 20 pre-populated US city shortcuts
A lightweight HTTP server built on NWListener binds to 127.0.0.1:37436 at app launch for integration with external tooling (Nova / OpenClaw).
| Endpoint | Method | Description |
|---|---|---|
/api/status |
GET | App name, version, port, uptime in seconds |
/api/ping |
GET | Health check (returns {"pong": "true"}) |
Loopback-only binding. No external network exposure.
| Category | Sources | Bias |
|---|---|---|
| Top Stories | Associated Press, Reuters, NPR | Center, Center, Lean Left |
| US | NY Times | Lean Left |
| World | BBC, The Guardian | Center, Lean Left |
| Business | CNBC | Center |
| Technology | TechCrunch, Ars Technica, The Verge | Center |
| Science | Science Daily | Center |
| Health | Medical News Today | Center |
| Sports | ESPN | Center |
| Entertainment | Variety | Center |
| Politics | Politico, The Hill | Center |
Users can add unlimited custom RSS feeds through the settings screen.
- iOS 17.0 or iPadOS 17.0
- iPhone or iPad
- Xcode 15.0+ (to build from source)
- iCloud account (optional, for cross-device sync)
- Location Services (optional, for local news and weather)
git clone git@github.com:kochj23/NewsMobile.git
cd NewsMobile
open NewsMobile.xcodeprojSelect your device or simulator as the run destination in Xcode and press Cmd+R.
None. The project uses only Apple first-party frameworks:
- SwiftUI
- NaturalLanguage
- BackgroundTasks
- Network (NWListener)
- AVFoundation (AVSpeechSynthesizer)
- CoreLocation
- WidgetKit
NewsMobile/
NewsMobileApp.swift -- @main entry, background task registration
ContentView.swift -- Root TabView with breaking news overlay
NovaAPIServer.swift -- Local HTTP API (port 37436)
ML/
SentimentAnalyzer.swift -- NLTagger sentiment scoring
EntityExtractor.swift -- Named entity recognition
Models/
NewsModels.swift -- All data models and enums
AIBackendManager.swift -- Local AI backend detection
AIBackendManager+Enhanced.swift
AIBackendManager+Generation.swift
AIBackendStatusMenu.swift
Services/
NewsAggregator.swift -- Concurrent RSS aggregation engine
RSSParser.swift -- XMLParser-based RSS/Atom parser
PersonalizationEngine.swift -- Reading habit personalization
StoryClusterEngine.swift -- Multi-source story grouping
TrendingTopicsEngine.swift -- Topic frequency analysis
ContentFilter.swift -- Ad and clickbait filtering
CloudSyncManager.swift -- iCloud KV sync
BackgroundRefreshManager.swift -- BGAppRefreshTask scheduling
NotificationManager.swift -- Push notifications
KeywordAlertManager.swift -- Keyword monitoring
TTSManager.swift -- Text-to-speech briefings
WeatherService.swift -- Open-Meteo weather
LocalNewsService.swift -- Geo-local news via Google News
CustomFeedManager.swift -- User-added RSS feeds
WatchLaterManager.swift -- Save-for-later queue
WidgetDataManager.swift -- App Group data for widgets
SettingsManager.swift -- Settings persistence
Views/
HomeView.swift -- Category-organized feed
ForYouView.swift -- Personalized feed
SearchView.swift -- Article search
WatchLaterView.swift -- Saved articles
SettingsView.swift -- All app settings
ArticleDetailView.swift -- Article detail
ArticleWebView.swift -- In-app web reader
AudioBriefingView.swift -- TTS playback controls
CategoryView.swift -- Single-category list
CustomFeedsView.swift -- Manage custom RSS feeds
KeywordAlertsView.swift -- Manage keyword alerts
LocalNewsView.swift -- Location-based feed
StoryClusterView.swift -- Multi-source story comparison
Components/
ArticleCard.swift -- Reusable article card
BreakingNewsBanner.swift -- Breaking news overlay
TrendingBar.swift -- Trending topics strip
WeatherWidget.swift -- Inline weather display
NewsMobileWidget/
NewsMobileWidget.swift -- WidgetKit extension (S/M/L)
- All ML processing happens on-device. No data is sent to any cloud AI service.
- No analytics, telemetry, or usage tracking.
- No sign-in required. iCloud sync is optional and uses only Apple's infrastructure.
- News is fetched directly from public RSS feeds. No intermediary servers.
- Weather uses the free Open-Meteo API with no API key and no account.
- Source code is fully open for inspection.
- No external dependencies. Only Apple first-party frameworks.
- RSS feed parsing validates all input data and strips HTML entities.
- In-app WebView restricts navigation to known trusted domains.
- No API keys, tokens, or credentials are required or stored.
- Background task handlers use safe guard-let casting instead of force casts.
- Local API server binds to loopback only (127.0.0.1) with no external exposure.
- NewsTV -- Apple TV version of this news reader
MIT License. See LICENSE for the full text.
Copyright (c) 2026 Jordan Koch. All rights reserved.
Written by Jordan Koch (@kochj23)
Disclaimer: This is a personal project created on my own time. It is not affiliated with, endorsed by, or representative of my employer.