React Native repo for the FindOut Media Mastodon instance, an ongoing project designed to rebuild the place for honest, real conversations.
This documentation serves as a comprehensive guide for developers, covering environment setup, project structure, building and releasing for iOS and Android, and configuring essential services like Push Notifications and Sentry.
- 1. Prerequisites
- 2. Setup
- 3. Running in Development
- 4. Useful Scripts
- 5. Cleaning & Cache Reset
- 6. Building Android (Release)
- 7. Building-iOS (Release / App Store)
- 8. Push Notifications Setup
- 9. Stallion and Sentry Setup
- 10. Troubleshooting
- 11. CI/CD Setup
- 12. Further Reading
- macOS (recommended β supports iOS + Android)
- Windows/Linux (Android only)
| Tool | Version / Notes |
|---|---|
| Node.js | LTS (v18+ recommended) |
| Yarn or npm | Yarn preferred |
| Git | latest |
| Java JDK | JDK 17 recommended |
| Android Studio | latest stable |
| Xcode (macOS only) | latest stable |
| Cocoapods | sudo gem install cocoapods |
Notice: This project uses Yarn for all installation, setup, development, and scripts. Please prefer yarn commands instead of npm to avoid dependency inconsistencies.
- `src/` β All application code (screens, components, hooks, services)
- `src/components/` β Custom reusable components
- `src/context/` β Global state & providers
- `src/hooks/` β Custom reusable hooks
- `src/navigation/` β Navigation stacks, tabs, routes
- `src/serivces/` - Service files for API fetching
- `src/store/` - Global state
- `src/translations/` - Translations
- `src/types/` - Queries types, navigation types, project API response types
- `src/utils/` β Helper utilities
- `assets/` β Images, fonts, icons
- `android/` β Native Android project
- `ios/` β Native iOS project
This section helps new developers understand what each folder is responsible for and where to place new code.
Main application source code. All core logic lives here.
Reusable UI components:
- Buttons
- Inputs
- Cards
- Shared layout elements
Keep components small and stateless when possible.
React Context providers.
Used for global state that must be accessible throughout the app.
Custom reusable hooks:
- API hooks (ex:
useAccountInfo) - UI hooks (ex:
useGradualAnimation) - Logic hooks (ex:
useStatus)
All navigation setup:
- Stack navigators
- Tab navigators
- Navigation types
- App entry navigation flow
Business logic modules:
- API service calls
- Formatting/parsing API data
Keep API functions organized by feature (ex:auth.service.ts,profile.service.ts).
Global state management Store files should contain:
- App-wide state
- Actions
- Selectors
All translation JSON files.
Organized per language (ex: en/translation.json, fr/translation.json, etc.).
TypeScript types:
- API response types
- Navigation types
- Shared utility types
Helper utilities, formatting functions:
- Date/time helpers
- String helpers
- Validation helpers
Static assets:
- Images
- Icons
- Fonts
Native platform-specific code and build configuration.
Clone the repo:
git clone https://github.com/patchwork-hub/findout-app
cd findout-appInstall dependencies
yarnInstall iOS pods (macOS only):
cd ios
pod install
cd ..Setup environment variables:
Create a .env file at the project root:
# URL of your Mastodon instance
# -----------------------
API_URL: https://findout-media.social
# URL of Patchwork Dashboard (optional)
# This key is optional if you havenβt set up Patchwork Dashboard.
# -----------------------
DASHBOARD_API_URL: https://dashboard.channel.org
# Environment
# -----------------------
ENV_TYPE: production
# Client key and secret of Mastodon application
# Log in with the instance owner account and go to the /settings/applications page of your Mastodon instance.
# Create a new application with the scopes: read, profile, write, follow, and push.
# The βClient keyβ value is used as the CLIENT_ID.
# The βClient secret' value is used as the CLIENT_SECRET_TOKEN.
# -----------------------
CLIENT_ID: YOUR_CLIENT_ID
CLIENT_SECRET_TOKEN: YOUR_CLIENT_SECRET
# Application monitoring tool
# Create an account on sentry.io and retrieve your API key.
# -----------------------
SENTRY_DSN: https://07f1a2a85e@o43dd22288.ingest.us.sentry.io/13727228
# GIF keyboard
# Create an account on tenor.com and retrieve your API key.
# -----------------------
TENOR_API_KEY: AIdusk8k28339md89229kdskdh
Make sure to restart the app after editing environment variables.
yarn start --reset-cache
OS (macOS only)
Start Metro (if it doesn't auto-start):
yarn start
Run iOS app:
yarn ios
# or
npx react-native run-ios
Android
Run Android app:
yarn android
# or
npx react-native run-android
yarn format # Auto-format using Prettier
yarn clean:android # Custom script for Android cleanup
yarn clean:ios # Custom script for iOS cleanup
Reset Metro cache
yarn start --reset-cache
Android clean build
cd android
./gradlew clean
cd ..
iOS clean
cd ios
xcodebuild clean
cd ..
Full cleanup
rm -rf node_modules
rm -rf android/.gradle android/app/build
rm -rf ios/Pods ios/Podfile.lock
yarn
cd ios && pod install && cd ..
Note: You can also run cleaning commands directly from package.json scripts, such as:
yarn clean:iosyarn clean:androidyarn clean:gradleyarn clean:yarnTip: Most build issues in React Native can be fixed by doing a full cleanup. Perform this especially after dependency or native module updates.
- Generate a Keystore (run once per project)
keytool -genkey -v -keystore app-release.keystore -alias release -keyalg RSA -keysize 2048 -validity 10000
Move it to:
android/app/app-release.keystore
Add your keystore configuration inside android/app/build.gradle under android { signingConfigs { release { ... } } }:
android {
signingConfigs {
release {
storeFile file("app-release.keystore")
storePassword "<YOUR_KEYSTORE_PASSWORD>"
keyAlias "release"
keyPassword "<YOUR_KEY_PASSWORD>"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
}
}
}- Build Release APK
cd android
./gradlew assembleRelease
APK path:
android/app/build/outputs/apk/release/app-release.apk
- Build AAB (Play Store)
./gradlew bundleRelease
AAB path:
android/app/build/outputs/bundle/release/app-release.aab
Archive with Xcode
Open workspace:
open ios/FindOutMedia.xcworkspace
Make sure the correct Apple Developer Account is selected:
- Open Xcode β Settings β Accounts
- Add your Apple ID if not already added
- Select your Team for signing
Select Any iOS Device (arm64) as the build target.
Check signing settings:
- Go to
FindOutMediaproject (top of Project Navigator) - Select
FindOutMediatarget β Signing & Capabilities - Ensure the correct Team is selected
- Ensure the Bundle Identifier matches the one registered in Apple Developer Console
- Ensure Automatically Manage Signing is enabled (recommended)
Then archive:
Product β Archive
Export or Upload via Organizer
Steps for preparing push notifications, FCM integration, and backend-triggered notifications.
- Go to Firebase Console β https://console.firebase.google.com
- Click Add project
- Enter project name (ex:
FindOut Media Production) - Disable Google Analytics unless required
- Finish project creation
- In Firebase β Project Settings β General
- Under Your Apps, choose Android
- Add:
- Package name β must match the app bundle id: com.findoutmedia.social
- Download the generated
google-services.json - Place it in:
android/app/google-services.json
- Rebuild Android app
- In Firebase β Project Settings β General
- Choose iOS
- Add:
- com.qlub.social β must match Xcode β target β Signing & Capabilities
- Download
GoogleService-Info.plist - Place it in:
ios/GoogleService-Info.plist
- Rebuild iOS app
- Go to Apple Developer β Certificates, Identifiers & Profiles
- Open Keys
- Press Create
- Enable Apple Push Notification service (APNs)
- Download:
AuthKey_XXXXXX.p8
- Go to Firebase β Project Settings β Cloud Messaging
- Under APNs Authentication Key:
- Upload
.p8 - Enter Key ID
- Enter Team ID
- Upload
Firebase will handle both Development & Production APNs using the single .p8 key.
Important: The
.p8key is sensitive. Do not commit it to the repository.
- Firebase β Cloud Messaging
- Ensure FCM API is enabled inside Google Cloud Console
This key is used by backend to send notifications to FCM.
This is sensitive, do not share it with anyone.
Steps:
-
Firebase Console β Project Settings
-
Open Service Accounts
-
Choose Firebase Admin SDK
-
Click Generate New Private Key
-
Download
project-admin-sdk.json -
Upload this JSON to the backend system (server)
-
Backend uses:
- project_id
- private_key
to trigger FCM push notifications
β οΈ Note:
Theproject_idused by the backend must match the same Firebase project that the frontend (Android/iOS apps) are using.
If the backend uses a different Firebase project, push notifications will not be delivered because FCM tokens from the frontend belong to a different project.
| Platform | File | Purpose |
|---|---|---|
| iOS | GoogleService-Info.plist |
Firebase iOS config |
| iOS | AuthKey_XXXXXX.p8 |
APNs push key |
| Android | google-services.json |
Firebase Android config |
| Backend | firebase-admin-sdk.json |
Backend push trigger key |
- Create project on Stallion Dashboard.
- Get projectID: On project info page, copy
project_id. - Generate
app_token: Navigate to Project > Project Settings > Access Tokens, and select Generate or Regenerate App Token to create a new token. - Add StallionProjectId & StallionAppToken as shown below (example) -
- iOS: Add the copied App Token and projectId to info.plist
<plist version="1.0">
<dict>
<!-- ...other configs... -->
<key>StallionProjectId</key>
<string>YOUR_STALLION_PROJECT_ID</string>
<key>StallionAppToken</key>
<string>YOUR_STALLION_APP_TOKEN</string>
<!-- ...other configs... -->
</dict>
</plist>
- Android: Add the copied App Token and projectId to strings.xml
<resources>
<string name="app_name">my_app</string>
<!-- make sure app token starts with spb_... and is 46 characters long -->
<string name="StallionProjectId">YOUR_STALLION_PROJECT_ID</string>
<string name="StallionAppToken">YOUR_STALLION_APP_TOKEN</string>
</resources>
For ref: Installion: https://learn.stalliontech.io/docs/sdk/installation Publish Bundle Usage & API Reference: https://learn.stalliontech.io/docs/cli/usage-api-reference
- Go to the Sentry Dashboard: https://sentry.io
- Log in or create an account.
- On the left sidebar, click Projects.
- Click Create Project.
- Select React Native as the platform. Set your alert frequency.
- Enter the project name (example:
FindOut Media App). - Choose or create an Organization.
- Click Create Project.
- After creating the project, Sentry will present two setup options: Automatic Configuration and Manual Configuration. For this project, continue with Manual Configuration, as other setup steps have already been completed.
Copy DSN value and inside .env, add your Sentry DSN
SENTRY_DSN=YOUR_SENTRY_DSN
After changing values in
.env, please always runyarn start --reset-cache.
- Run
yarn start --reset-cache
- Try
cd android && ./gradlew clean
- Run
sudo gem install cocoapods - Then run
cd ios && pod repo update && pod install
- Ensure environment variables are set correctly
- Reinstall app after major changes (
yarn ios/yarn android)
This project uses GitHub Actions and Fastlane to automate testing and deployment.
- Action:
release - Steps:
- Build Release Bundle (
bundleRelease). - Upload to Play Store (
internaltrack).
- Build Release Bundle (
- Required Env Vars:
ANDROID_KEYSTORE_PASSWORD,ANDROID_KEY_ALIAS,ANDROID_KEY_PASSWORD.
- Action:
release - Steps:
- Increment build number.
- Build App (
FindOutMediascheme). - Upload to App Store.
To enable the CI/CD pipeline, the following secrets must be set in your GitHub repository:
| Secret Name | Description |
|---|---|
ANDROID_KEYSTORE_FILE_BASE64 |
Base64 encoded release.keystore file. |
ANDROID_JSON_KEY_FILE_BASE64 |
Base64 encoded Google Play Service Account JSON. |
ANDROID_KEYSTORE_PASSWORD |
Password for the Android keystore. |
ANDROID_KEY_ALIAS |
Alias name for the key. |
ANDROID_KEY_PASSWORD |
Password for the key alias. |
APPLE_ID |
Apple ID email address. |
ITC_TEAM_ID |
iTunes Connect Team ID. |
TEAM_ID |
Apple Developer Team ID. |
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD |
App-specific password for Apple ID. |
MATCH_PASSWORD |
Password for the match repo (if using fastlane match). |
ASC_KEY_ID |
App Store Connect API Key ID. |
ASC_ISSUER_ID |
App Store Connect API Issuer ID. |
ASC_KEY_CONTENT_BASE64 |
App Store Connect API Key content (Base64). |
Note: For iOS automation, ensure you have set up
MATCH_PASSWORDandASC_KEY_ID/ASC_ISSUER_IDif using Match, or manually configured signing secrets if extending the workflow.
React Native CLI Docs https://reactnative.dev/docs/environment-setup
Android Build System https://developer.android.com/studio/build
Xcode App Distribution https://developer.apple.com/documentation/xcode/distributing-your-app-for-testing-and-release
React Navigation https://reactnavigation.org/