The Idea
It was November 2024, and I had just wrapped up another intense week of .NET development work. I was sitting at my desk, thinking about a conversation I'd had with my wife, Daniela, about wanting to start our day with scripture but always forgetting to open the Bible app on our phones.
That's when it hit me: What if there was a dead-simple app that just showed you a random Bible verse every time you opened it? No accounts, no complexity, no distractions—just you and the Word.
I'd been wanting to publish something to the App Store for a while, partly to diversify my technical portfolio beyond web development, and partly because I was curious about the mobile app publishing process. This felt like the perfect project: simple enough to actually finish, useful enough to be meaningful, and focused enough to ship quickly.
The Problem I Wanted to Solve:
- Existing Bible apps were overwhelming (thousands of features, reading plans, social features)
- People wanted quick spiritual refreshment, not commitment
- Language barrier for Spanish speakers (most apps were English-first)
- Privacy concerns (too many apps collecting data)
My Goals:
- Ship my first mobile app to the App Store
- Learn React Native and Expo
- Create something genuinely useful for daily spiritual life
- Make it bilingual (English/Spanish) from day one
- Keep it 100% free with no ads or tracking
The Technical Stack
I chose React Native with Expo for a few strategic reasons:
Why React Native:
- Write once, deploy to both iOS and Android
- JavaScript/TypeScript (already familiar from my Angular work)
- Huge ecosystem and community
- Hot reload for fast development
Why Expo:
- Managed workflow (no need for Xcode/Android Studio initially)
- Over-the-air updates
- Easy push notifications setup
- EAS Build for cloud builds (no Mac needed for iOS builds!)
Full Stack:
Frontend: React Native 0.81
Language: TypeScript 5.1
Framework: Expo 54
State Management: React Hooks (useState, useEffect)
Storage: AsyncStorage (for offline data)
API: Bolls.life Bible API (free, no auth)
Navigation: Expo Router
Why These Choices Matter:
TypeScript: Type safety prevents stupid bugs. In a solo project, you ARE the QA team.
AsyncStorage: All user data (favorites, downloaded books, preferences) stored locally. Zero backend costs, maximum privacy.
Bolls.life API: After researching 5+ Bible APIs, this one was perfect:
- Free and unlimited
- Multiple translations
- Simple REST endpoints
- No authentication required
- Support for verse-by-verse fetching (crucial for my offline feature)
Expo Managed Workflow: I could build iOS apps from my Windows PC using EAS Build. Game-changer.
The Development Journey
Week 1: MVP (16 hours)
Day 1-2: Core Functionality
I started with the absolute minimum:
// The heart of the app - fetch a random verse
const fetchVerse = async () => {
const response = await fetch(
`https://bolls.life/get-random-verse/WEB/`
);
const data = await response.json();
const cleanText = data.text.replace(/<[^>]*>/g, ''); // Strip HTML tags
setVerse({
text: cleanText,
reference: `${data.book} ${data.chapter}:${data.verse}`,
translation_id: 'WEB'
});
};
Key Decision: Strip HTML tags from API responses. The API returns formatted text with and tags. I wanted plain text for simplicity.
Day 3: UI/UX Design
I'm not a designer, so I kept it minimal:
- Clean typography (large, readable text)
- Warm color palette (sage green, warm brown, off-white)
- Dark mode from day one
- One main action: "New Verse" button
Design Philosophy: Remove everything that doesn't serve the core experience.
Day 4-5: Essential Features
Added three critical features:
- Favorites: Long-press to save verses
- Share: Export verses to social media
- Copy: Quick clipboard copy
const toggleFavorite = async () => {
const verseId = `${verse.reference}-${verse.translation_id}`;
const newFavorite: SavedVerse = {
...verse,
id: verseId,
savedAt: Date.now()
};
await saveFavorites([newFavorite, ...favorites]);
};
Learning: React Native's Share API is beautiful—one line of code works on both platforms:
await Share.share({
message: `${verse.text}\n\n— ${verse.reference}`
});
Week 2: Going Bilingual (12 hours)
The Spanish Challenge:
I wanted Spanish support from day one because:
- My family in Venezuela would use it
- 50+ million Spanish speakers in the US
- Most Bible apps treat Spanish as an afterthought
Implementation:
const translations = {
en: {
title: "Daily Bible Verse",
newVerse: "New Verse",
share: "Share",
copy: "Copy"
},
es: {
title: "Versículo Bíblico Diario",
newVerse: "Nuevo Versículo",
share: "Compartir",
copy: "Copiar"
}
};
Supported Translations:
- English: WEB (World English Bible), KJV (King James), ASV (American Standard)
- Spanish: RVR1960 (Reina-Valera), LBLA (La Biblia de las Américas), NVI (Nueva Versión Internacional)
UI Challenge: Language switcher needed to be intuitive. I used flag emojis (🇺🇸/🇪🇸) with a dropdown. Simple, visual, works everywhere.
Week 3-4: The Offline Feature (20 hours)
This was the hardest part—and the most rewarding.
The Problem: Users wanted to read complete books offline (imagine flights, camping, poor signal areas).
The Challenge: Download entire books verse-by-verse without overwhelming the API.
My Solution:
const downloadBook = async (book: Book) => {
const allVerses: BibleVerse[] = [];
// Loop through each chapter
for (let ch = 1; ch <= book.chapters; ch++) {
let v = 1;
let chapterComplete = false;
while (!chapterComplete && v <= 250) {
const url = `https://bolls.life/get-verse/${translation}/${bookId}/${ch}/${v}/`;
const res = await fetch(url);
if (!res.ok) {
chapterComplete = true; // 404 = end of chapter
break;
}
const data = await res.json();
allVerses.push({
text: data.text.replace(/<[^>]*>/g, ''),
reference: `${bookName} ${ch}:${v}`,
// ... more fields
});
v++;
await new Promise(r => setTimeout(r, 50)); // Polite 50ms delay
}
// Update progress bar
setProgress((ch / book.chapters) * 100);
}
// Save to AsyncStorage
await AsyncStorage.setItem(`book_${bookName}`, JSON.stringify(allVerses));
};
Why This Approach:
- Polite crawling: 50ms delay between requests (don't abuse the free API!)
- Chapter-by-chapter: Show progress, allow pause/resume
- 404 detection: API returns 404 when verses run out (graceful ending)
- Local storage: Once downloaded, completely offline
Result: Users can download any of the 66 Bible books. Genesis = 1,533 verses, stored in ~300KB. The entire Bible = ~31,000 verses, ~6MB.
UI Polish:
- Real-time progress bar
- Verse count updates as download progresses
- Can read what's downloaded while download continues
- Delete button to free up space
Week 5: Polish & Testing (8 hours)
Responsive Design:
Had to support:
- Small phones (iPhone SE - 375px wide)
- Regular phones (iPhone 14 - 390px)
- Tablets (iPad - 768px+)
const [dimensions, setDimensions] = useState(Dimensions.get('window'));
useEffect(() => {
const subscription = Dimensions.addEventListener('change', ({ window }) => {
setDimensions(window);
});
return () => subscription?.remove();
}, []);
const isSmallDevice = dimensions.width < 375;
const isTablet = dimensions.width >= 768;
Dark Mode:
System-aware dark mode with manual override:
const [themeMode, setThemeMode] = useState<'light' | 'dark' | 'system'>('system');
const isDark = themeMode === 'dark' ||
(themeMode === 'system' && useColorScheme() === 'dark');
Performance Optimization:
- Lazy loading for favorites (only load when tab opens)
- Memoized components for verse display
- Debounced search in downloaded books
- Image optimization for app icon/splash
Week 6: App Store Submission
The Requirements:
For Apple App Store:
- Apple Developer account ($99/year)
- App icons (1024x1024 PNG)
- Screenshots (6.7" iPhone, 12.9" iPad)
- Privacy policy
- App description, keywords, category
- Age rating (I chose 4+)
For Google Play:
- Google Play Console ($25 one-time)
- Feature graphic (1024x500)
- Screenshots (phone + tablet)
- Privacy policy
- Store listing
- Content rating
The Submission Process:
Building the iOS App:
# Configure EAS
eas build:configure
# Build for iOS (cloud build, no Mac needed!)
eas build --platform ios
# Submit to App Store Connect
eas submit --platform ios
The Review Process:
Apple: Submitted November 18, 2024
- Initial review: 24 hours
- Rejected once (missing age rating explanation)
- Fixed and resubmitted
- Approved November 20, 2024
- Total time: 2 days
Google Play: Currently in closed testing
- 12 testers (friends, family, church members)
- Running for 5 days
- Collecting feedback before public launch
What I Learned About App Review:
- Apple is stricter but faster: Clear guidelines, quick turnaround
- Privacy policy is non-negotiable: Even if you collect zero data, you need one
- Screenshots matter: I got feedback that mine could be more compelling
- Keywords are limited: Apple allows 100 characters total. Choose wisely.
The Technical Challenges
Challenge #1: HTML in API Responses
Problem: The API returns verses with HTML formatting:
"For God <em>so</em> loved the world..."
Solution: Regex to strip tags:
const cleanText = text.replace(/<[^>]*>/g, '');
Why not parse HTML? React Native doesn't have a built-in HTML parser, and I didn't want to add a dependency for this simple use case.
Challenge #2: Verse Numbering Inconsistencies
Problem: Different translations have different verse counts (some split verses, some combine them).
Solution: The 404 detection pattern. When the API returns 404, that chapter is done. No hardcoded verse counts needed.
Challenge #3: AsyncStorage Limits
Problem: AsyncStorage has a 6MB limit on Android (10MB on iOS).
Solution:
- Compress data (remove whitespace from JSON)
- Store books separately (not one giant object)
- Warn users when approaching limit
- Provide "clear all downloads" option
Challenge #4: Building iOS Without a Mac
Problem: I develop on Windows. Xcode requires macOS.
Solution: Expo EAS Build is magic. Upload your code, they build it on their servers, you get back an IPA file ready for App Store Connect.
eas build --platform ios
# ☁️ Builds in the cloud
# 📧 Email notification when done
# 📦 Download IPA or submit directly
Cost: $29/month for EAS priority builds (well worth it).
Challenge #5: Keeping App Size Small
Target: Under 25MB (psychological threshold for cellular downloads)
Strategies:
- No external fonts (use system fonts)
- Optimized PNG icons (use TinyPNG)
- No bundled images beyond icons
- Tree-shaking unused Expo modules
Result: 23.8 MB final app size ✅
The Results
App Store Metrics (First 6 Weeks)
Downloads:
- Total Units: 31 downloads
- Impressions: 396 (154% increase week-over-week)
- Conversion Rate: 7.8%
User Engagement:
- Sessions: 18 active sessions
- Retention: Users open app 3.2 times/week on average
- Crashes: 0 (zero crashes! 🎉)
Revenue: $0 (completely free, no monetization)
Rating: ⭐⭐⭐⭐⭐ 5.0 stars
Google Play (Closed Testing)
Testers: 12 people (friends, family, church members)
Feedback Highlights:
- "Love how simple it is - no distractions"
- "Spanish support is perfect for my parents"
- "Dark mode is beautiful"
- "Offline books are a game-changer for flights"
Requested Features:
- Search function (most requested)
- Daily notifications (set time for daily verse)
- Reading plans (structured Bible reading)
- Bookmarks (mark position in downloaded books)
- Verse highlighting/notes
Open Source Impact
GitHub Stats:
- Stars: 3 ⭐
- Forks: 1
- Watchers: 2
- Issues: 0 (no bugs reported!)
Why Open Source:
- Portfolio showcase (proves I ship code)
- Community contributions (future features)
- Learning resource for other devs
- Transparency (users can verify privacy claims)
Repository: https://github.com/gilricardo-com/daily-bible-verse
What I Learned
Technical Lessons
1. React Native Is Production-Ready
Coming from Angular/web development, I was skeptical. But React Native works. The performance is good, the ecosystem is mature, and Expo removes most of the pain.
2. Mobile UX Is Different
Things I took for granted on web:
- Hover states don't exist (use press states)
- Back button means different things (Android vs iOS)
- Safe areas matter (notch, home indicator)
- Touch targets need to be 44x44pt minimum
- Loading states are critical (poor connections common)
3. Offline-First Is Complex
I massively underestimated the offline feature. Edge cases everywhere:
- What if download interrupted?
- How to handle partial data?
- How to clear/update cached data?
- Storage limits?
- Progress indication?
4. APIs Can Be Simple
The Bolls.life API is beautiful in its simplicity:
GET /get-random-verse/WEB/ → Random verse
GET /get-verse/WEB/1/1/1/ → Genesis 1:1
No authentication, no rate limits, no complexity. Sometimes simple is best.
Business Lessons
1. Scope Ruthlessly
My original feature list had 20+ items. I shipped with 6 core features. The rest can wait.
MVP mindset: What's the ONE thing this app must do well?
2. Publish Fast, Iterate Later
I waited too long perfecting things before submitting. Could have launched 2 weeks earlier and gotten real user feedback sooner.
3. App Store Optimization Matters
Bad keyword choices: "bible verse generator" (high competition)
Good keyword choices: "daily bible verse offline" (specific, less competition)
Bad screenshot: Just showing the app
Good screenshot: Showing the benefit ("Read the Bible offline, anytime")
4. Free Apps Can Succeed Without Monetization
I have zero ads, no subscriptions, no freemium model. Just a useful tool.
Why?
- Builds trust and credibility
- Portfolio piece (showcases skills)
- Aligns with my values (faith-based content should be accessible)
- Could monetize later if I want (donations, premium features)
Personal Lessons
1. Shipping Feels Amazing
There's something uniquely satisfying about seeing your app on the App Store. "I made this, and now strangers can use it."
2. Imposter Syndrome Never Goes Away
Even after building web apps professionally for 6+ years, I felt like a fraud publishing a mobile app. "Who am I to do this?"
Do it anyway.
3. Side Projects Are Worth It
This project:
- Taught me React Native
- Gave me portfolio material
- Led to interesting conversations with recruiters
- Connected me with other Christian developers
- Created something useful for people I care about
ROI: Priceless.
4. Start Where You Are
I didn't wait until I was an "expert" in mobile development. I had a need, researched for 2 days, and started building.
6 weeks later, I had a published app.
The Tech Stack Deep Dive
Let me break down some key technical decisions:
Why Expo Over Pure React Native?
Expo Pros:
- Managed workflow (less configuration)
- OTA updates (fix bugs without app store review)
- EAS Build (build iOS on Windows)
- Push notifications setup is 5 lines of code
- Expo modules are well-maintained
Expo Cons:
- Slightly larger app size (~5MB overhead)
- Some native modules not available
- Less control over native code (can eject if needed)
Verdict: For 95% of apps, Expo is the right choice. I can always eject later if needed.
State Management: Why No Redux/MobX?
Simple truth: This app doesn't need it.
State I manage:
- Current verse (useState)
- Favorites list (useState + AsyncStorage)
- Downloaded books (useState + AsyncStorage)
- UI state (modals, loading)
React hooks handle this perfectly. Adding Redux would be overengineering.
When I'd use Redux:
- Complex state shared across 10+ components
- Time-travel debugging needed
- Middleware requirements (logging, crash reporting)
Navigation: Expo Router
I use Expo Router (file-based routing):
app/
index.tsx → Main screen
favorites.tsx → Favorites view
book-detail.tsx → Single book view
settings.tsx → Settings
Why file-based routing?
- Familiar (works like Next.js)
- Deep linking built-in
- Type-safe navigation
- Less boilerplate than React Navigation
Styling: StyleSheet vs Styled Components?
I use plain StyleSheet.create:
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: isDark ? '#1C1C1C' : '#F5F5F0'
},
verseText: {
fontSize: isSmallDevice ? 20 : 24,
lineHeight: 1.5,
fontFamily: 'System'
}
});
Why not styled-components?
- StyleSheet is optimized by React Native
- No runtime parsing
- Better performance
- Smaller bundle size
Trade-off: Less flexible, more verbose. But performance > convenience for mobile.
The Features Breakdown
Let me walk you through each feature's implementation:
Feature #1: Random Verse
How it works:
- Call API:
GET https://bolls.life/get-random-verse/WEB/ - Parse JSON response
- Strip HTML tags
- Display verse + reference
Code:
const fetchVerse = async () => {
setLoading(true);
try {
const url = `https://bolls.life/get-random-verse/${selectedVersion[language]}/`;
const response = await fetch(url);
const data = await response.json();
setVerse({
text: data.text.replace(/<[^>]*>/g, ''),
reference: `${data.book} ${data.chapter}:${data.verse}`,
translation_id: selectedVersion[language]
});
} catch (error) {
setError(true);
} finally {
setLoading(false);
}
};
Error handling:
- Network error → Show "Try Again" button
- API timeout → Show error message
- Still allow access to offline content (favorites, downloaded books)
Feature #2: Favorites
Storage structure:
interface SavedVerse {
id: string; // "John 3:16-WEB"
text: string;
reference: string;
translation_id: string;
savedAt: number; // timestamp
}
Persisted in AsyncStorage:
await AsyncStorage.setItem('favorites', JSON.stringify(favorites));
UI features:
- Heart icon (filled when favorited)
- Long-press on any verse to favorite
- Swipe-to-delete in favorites list
- Sort by date (newest first)
Feature #3: Share & Copy
Share (native):
const handleShare = async () => {
await Share.share({
message: `${verse.text}\n\n— ${verse.reference} (${verse.translation_id})`
});
};
Copy (clipboard):
import * as Clipboard from 'expo-clipboard';
const handleCopy = async () => {
await Clipboard.setStringAsync(
`${verse.text}\n\n— ${verse.reference}`
);
Alert.alert('✓', 'Copied to clipboard');
};
Why both? Share opens system share sheet (WhatsApp, Instagram, etc.). Copy gives quick access for pasting elsewhere.
Feature #4: Multi-Translation Support
Available translations:
English:
- WEB (World English Bible) - Modern, public domain
- KJV (King James Version) - Traditional, poetic
- ASV (American Standard Version) - Literal translation
Spanish:
- RVR1960 (Reina-Valera 1960) - Most popular in Latin America
- LBLA (La Biblia de las Américas) - Modern, accurate
- NVI (Nueva Versión Internacional) - Contemporary
Switching translations:
const changeVersion = async (versionCode: string) => {
setSelectedVersion(prev => ({
...prev,
[language]: versionCode
}));
await AsyncStorage.setItem(`version_${language}`, versionCode);
// Reload current verse in new translation
if (verse) {
fetchSpecificVerse(verse.book, verse.chapter, verse.verse);
}
};
UX detail: When switching translation, keep the same verse (re-fetch with new translation). Users can compare translations side-by-side.
Feature #5: Offline Book Downloads
The algorithm:
const downloadBook = async (book: Book) => {
const bookId = bibleBooks.findIndex(b => b.name === book.name) + 1;
const allVerses: BibleVerse[] = [];
for (let chapter = 1; chapter <= book.chapters; chapter++) {
let verse = 1;
let chapterComplete = false;
while (!chapterComplete) {
const url = `https://bolls.life/get-verse/${translation}/${bookId}/${chapter}/${verse}/`;
const response = await fetch(url);
if (!response.ok) {
chapterComplete = true; // 404 = no more verses
continue;
}
const data = await response.json();
allVerses.push({
text: data.text.replace(/<[^>]*>/g, ''),
reference: `${book.name} ${chapter}:${verse}`,
chapter,
verse
});
verse++;
await sleep(50); // Polite delay
}
// Update progress
setProgress((chapter / book.chapters) * 100);
}
// Save to storage
const downloadedBook: DownloadedBook = {
bookName: book.name,
translation,
verses: allVerses,
downloadedAt: Date.now()
};
await AsyncStorage.setItem(
`book_${book.name}_${translation}`,
JSON.stringify(downloadedBook)
);
};
Progress indication:
const progress = (currentChapter / totalChapters) * 100;
// Show progress bar: 0-100%
// Also show verse count updating in real-time
Memory management:
- Download one book at a time
- Allow cancellation mid-download
- Clean up partial downloads if canceled
Feature #6: Dark Mode
Implementation:
const [themeMode, setThemeMode] = useState<'light' | 'dark' | 'system'>('system');
const isDark =
themeMode === 'dark' ||
(themeMode === 'system' && useColorScheme() === 'dark');
const styles = createStyles(isDark);
Color palette:
Light Mode:
- Background:
#F5F5F0(warm off-white) - Text:
#2C2C2C(dark gray) - Button:
#4A5D4E(sage green) - Accent:
#8B7355(warm brown)
Dark Mode:
- Background:
#1C1C1C(true black) - Text:
#E5E5E5(light gray) - Button:
#6B7C6E(muted sage) - Accent:
#A89378(light brown)
Why not pure black? OLED burn-in concerns. Also, pure black (#000000) looks harsh. Slightly off-black is more comfortable.
The App Store Optimization (ASO) Strategy
Title & Subtitle
Title: "Daily Random Bible Verse"
Why this works:
- Contains main keyword: "Bible Verse"
- Explains core function: "Daily" + "Random"
- Short enough to display fully (under 30 chars)
Subtitle (iOS): "Scripture Inspiration & Offline Reading"
Why this works:
- Secondary keywords: "Scripture", "Inspiration", "Offline"
- Benefit-focused, not feature-focused
Keywords (100 character limit)
My choices:
bible,verse,daily,scripture,offline,spanish,devotional,christian,faith,quotes,king james,rv1960
Research process:
- Used App Store search suggestions
- Checked competitor keywords (Bible Gateway, YouVersion)
- Prioritized low-competition, high-intent keywords
- Included Spanish terms (bilingual advantage)
Avoided:
- Generic terms: "app", "free", "best"
- Brand names: Can't rank for "YouVersion"
- Duplicates: Title already contains "daily bible verse"
Screenshots (6.7" iPhone)
Screenshot 1 - Hero Shot:
- Shows main screen with verse
- Overlay text: "Daily Scripture Inspiration"
- Clean, beautiful, immediately understandable
Screenshot 2 - Dark Mode:
- Same layout in dark mode
- Overlay: "Beautiful in Any Light"
Screenshot 3 - Offline Feature:
- Downloaded books list
- Overlay: "Complete Bible Books Offline"
Screenshot 4 - Bilingual:
- Spanish interface
- Overlay: "Disponible en Español"
Screenshot 5 - Features:
- List of features with icons
- No text overlay (let features speak)
Design principles:
- Use real app UI (not marketing mockups)
- Overlay text readable from thumbnail
- Show benefits, not features
- Demonstrate actual use
App Description
First 170 characters (preview):
Start each day with inspiration from the Bible. Daily Random Bible Verse delivers Scripture in English or Spanish, with complete offline reading.
Why this works:
- Benefit first: "Start each day with inspiration"
- Keywords naturally included
- Addresses pain point: "complete offline reading"
Full description structure:
- Hook (2 sentences): What it does, who it's for
- Key features (bullet list): 6 main features
- Translations (paragraph): Detail language support
- Privacy (paragraph): No data collection, no ads
- Open source (paragraph): Link to GitHub
- Call to action: "Download now and start your daily journey with Scripture"
Category Selection
Primary: Books & Reference
Secondary: Lifestyle
Why not "Reference" only? Too competitive. "Lifestyle" has less competition in Bible app space.
Pricing
Free (no IAP, no subscriptions)
Why?
- Removes barrier to download
- Aligns with mission (make Scripture accessible)
- Portfolio piece (doesn't need to make money)
- Could add donations later if desired
Localization
Languages supported:
- English (US)
- Spanish (Latin America)
Localized elements:
- App name
- Description
- Screenshots
- Keywords
Impact: Shows up in Spanish App Store searches, appeals to bilingual users.
Roadmap: What's Next
Based on tester feedback and my vision, here's what's coming:
Phase 2: Core Enhancements (Q1 2025)
1. Search Functionality ⭐ Most requested
Find specific verses by:
- Book, chapter, verse (e.g., "John 3:16")
- Keywords (e.g., "love", "faith")
- Topic (e.g., "hope", "forgiveness")
Technical approach:
- Index all downloaded books locally
- Use fuzzy matching for keywords
- Highlight search terms in results
2. Daily Notifications
Push notification at user-selected time:
- "Good morning! Here's today's verse..."
- Customizable time
- Randomized verse from user's preferred translation
Technical approach:
- Expo Notifications API
- Local notifications (no server needed)
- Permission request with clear explanation
3. Reading Plans
Structured Bible reading:
- "Read the Bible in a Year"
- "Gospels in 30 Days"
- "Psalms & Proverbs Monthly"
UI:
- Progress tracking
- Checkmarks for completed readings
- Reminder notifications
Phase 3: Community Features (Q2 2025)
4. Verse of the Day (Community)
See what verse other users are reading:
- Global VOTD (voted by community)
- Most favorited verses this week
- Trending verses
Privacy: Anonymous voting, no personal data
5. Sharing Improvements
Enhanced sharing:
- Instagram Stories integration (beautiful templates)
- Verse images (generated on-device)
- Quote-style formatting
6. Reading Streaks
Gamification (light touch):
- Track consecutive days opened
- Milestone achievements
- No pressure, just encouragement
Phase 4: Premium Features (Q3 2025)
7. Advanced Study Tools
For serious Bible students:
- Cross-references
- Commentaries (public domain)
- Original language tools (Hebrew/Greek)
- Word studies
Monetization: $2.99/month or $19.99/year
Why premium? Advanced features require:
- Larger datasets
- More complex UI
- Server costs (for syncing notes)
8. Cloud Sync
Sync across devices:
- Favorites
- Reading progress
- Notes (if added)
- Downloaded books
Backend: Firebase (free tier sufficient for thousands of users)
Long-Term Vision
The Goal: Not to compete with YouVersion or Bible Gateway (they're amazing).
Instead: Be the simplest, most beautiful, most accessible Bible app for daily inspiration.
Core principles:
- ✅ Remain free for core features
- ✅ No ads, ever
- ✅ Privacy-first
- ✅ Open source
- ✅ Multilingual
- ✅ Offline-first
For Aspiring App Developers
If you're thinking about building your first mobile app, here's my advice:
1. Start Stupid Simple
Your first app should do ONE thing well. Don't build the next Instagram.
Good first apps:
- Random quote generator
- Tip calculator
- Unit converter
- Daily reminder app
- Simple timer
Bad first apps:
- Social network
- Complex game
- E-commerce platform
- Anything requiring complex backend
2. Use Expo
Seriously. Don't fight me on this.
Yes, you give up some control. Yes, the app is slightly larger. But you'll ship 10x faster.
Start here:
npx create-expo-app my-first-app
cd my-first-app
npm start
In 2 minutes, you're running an app on your phone.
3. Ship Fast, Learn Faster
My timeline:
- Week 1-2: Build MVP
- Week 3-4: Polish + testing
- Week 5: Submit to stores
- Week 6: Iterate based on feedback
Your timeline should be similar.
Don't spend 6 months perfecting before launch. Ship in 4-6 weeks. Get real users. Learn. Iterate.
4. Read These First
Essential reading:
- React Native Docs - Start here
- Expo Docs - Your best friend
- App Store Review Guidelines - Read before building
- Play Store Policies - Same
Helpful tutorials:
- React Native basics (Traversy Media)
- Expo crash course (Programming with Mosh)
5. Tools I Used
Development:
- VS Code (with React Native extension)
- Expo Go app (for testing on real device)
- React Native Debugger
Design:
- Figma (mockups/wireframes)
- Coolors.co (color palette generator)
- TinyPNG (image compression)
Icon/Splash:
- Figma (design)
- Icon.kitchen (iOS icons from one image)
- App Icon Generator (Android adaptive icons)
Testing:
- iPhone 14 (physical device)
- Expo Go (quick testing)
- TestFlight (iOS beta testing)
Deployment:
- EAS CLI (build + submit)
- App Store Connect (Apple)
- Google Play Console (Android)
6. Budget Reality Check
Costs to publish an app:
One-time:
- Google Play: $25 (lifetime)
- Apple Developer: $99/year
- Domain (optional): $12/year
Monthly (if using Expo EAS):
- Free tier: 30 builds/month (plenty for solo dev)
- Paid tier: $29/month (unlimited builds + priority)
Total first year: $136-$484
My spending: $205 (Apple $99 + Google $25 + Expo $29x3 months)
7. Common Mistakes to Avoid
Mistake #1: Not testing on real devices
Simulators lie. Test on actual phones. Beg, borrow, or rent if you must.
Mistake #2: Ignoring platform differences
iOS and Android are different. Especially:
- Navigation patterns
- Back button behavior
- Push notification permissions
- Status bar handling
Mistake #3: Over-engineering
You don't need:
- Redux (probably)
- Complex folder structure
- Microservices
- Advanced testing setup (for v1)
You DO need:
- Basic error handling
- Loading states
- Offline behavior
- Good UX
Mistake #4: Perfectionism
Ship the 80% solution. Iterate.
Perfect is the enemy of done.
Mistake #5: Not reading guidelines
Apple and Google reject apps for stupid reasons:
- Missing privacy policy
- Crashes on launch
- Incomplete functionality
- Misleading descriptions
Read. The. Guidelines.
8. Your Launch Checklist
Pre-launch (1 week before):
- App tested on 3+ devices
- All features work offline
- Error states handled
- Loading states everywhere
- Privacy policy written
- Screenshots designed
- App description written
- Keywords researched
Launch day:
- Submit to both stores
- Share on Twitter/LinkedIn
- Post in relevant subreddits (respectfully!)
- Tell friends/family
- Add to portfolio/resume
- Update GitHub README
Post-launch (first week):
- Monitor crash reports
- Read user reviews
- Fix critical bugs ASAP
- Plan v1.1 features
- Respond to user feedback
Conclusion
Building and publishing my first mobile app was one of the most rewarding experiences of my development career. It combined:
- Technical learning (React Native, mobile UX, app stores)
- Product thinking (what do users actually need?)
- Execution (shipping something real)
Total time invested: ~60 hours over 6 weeks
Total cost: $205
Result: A published iOS app with real users, open source code showcasing my skills, and invaluable learning experience.
Most importantly: I created something useful. People use it daily for spiritual inspiration. That matters more than downloads or revenue.
Your Turn
Whether you're a seasoned web developer curious about mobile, a bootcamp grad building your portfolio, or someone with an idea and no technical background—you can do this.
Mobile app development is more accessible than ever:
- Tools are better (Expo, React Native)
- APIs are free (Bolls.life, and thousands of others)
- Documentation is excellent
- Community is helpful
You don't need:
- A Mac (EAS Build handles iOS)
- Years of experience
- A big budget
- A team
You DO need:
- An idea
- Willingness to learn
- 4-6 weeks of focused work
- $136 (minimum)
That's it.
Links & Resources
App:
- 📱 Download on App Store
- 🤖 Google Play (coming soon - in closed testing)
Code:
- 💻 GitHub Repository
- 📋 MIT License (open source!)
API:
- 📖 Bolls.life Bible API (free, no auth)
Tools:
- ⚛️ React Native
- 📦 Expo
- 🏗️ EAS Build
Contact:
About the Author:
Ricardo Gil is a Full Stack Software Engineer with 6+ years of experience specializing in C#/.NET Core, Angular, and PostgreSQL. Originally from Venezuela, he immigrated to the United States in 2015 and has built scalable applications for healthcare, hospitality, and e-commerce industries. "Daily Random Bible Verse" is his first published mobile application, combining his technical expertise with his faith to create a tool for daily spiritual inspiration.
If you found this helpful, please star the GitHub repo and share this post with other aspiring app developers. Your support means the world!
Have questions about the app or mobile development in general? Leave a comment or email me at contact@gilricardo.com.
Related Posts
Building with Angular + Firebase? Check out my Photography E-Commerce Platform that combines Firebase auth with Stripe payments and AWS S3 storage.
Self-hosting your projects? Learn how I host production apps on a Raspberry Pi with PM2, Nginx, and Tailscale.
About the Author: Ricardo Gil is a full-stack software engineer specializing in .NET/C#, Angular, and cloud platforms. Read more or subscribe for updates.
