- Remove EAS/expo.dev from prerequisites and build sections - Document build-apk.sh workflow step by step - Document first-time setup (Android SDK + keystore export + signing.env) - Update architecture tree (add lib/extractError.ts, remove expo-task-manager) - Remove Replit-specific sections (dev server, push via bundle, env vars) - Keep minimal eas.json (needed only for one-time keystore export via eas credentials) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PostizMobile
React Native (Expo) mobile app to control a self-hosted Postiz instance from Android.
Build is fully local — no expo.dev account or EAS cloud required.
Features
| Screen | Description |
|---|---|
| Calendar | Monthly view with color dots per day (indigo = scheduled, green = published, red = error). Tap a day post to copy or edit it. |
| Posts | Filtered list (All / Queue / Published / Draft / Error) with post counts, sort toggle (newest/oldest, persisted), pull-to-refresh, swipe left to delete, swipe right to reschedule. |
| Compose | Text editor with per-network character limit, channel picker, date/time picker, gallery image pick + upload, publish now or schedule. Local draft save/restore. |
| Settings | API key and base URL, connection test, secure storage. 401 auto-redirect to Settings. |
| Notifications | Local alerts when a post transitions to PUBLISHED or ERROR (polling every 15 min). |
Theme: forced dark. Auth: API key in expo-secure-store, never hardcoded.
Prerequisites
| Tool | Version |
|---|---|
| Node.js | 20 LTS |
| pnpm | 10+ |
| Java (JDK) | 17+ |
| Android SDK | see below |
No expo.dev account needed for builds.
Development
Install dependencies
git clone ssh://gitea@homegit.gyozamancave.fr:2222/billisdead/Postiz-android.git
cd Postiz-android
pnpm install
Start dev server (Expo Go)
pnpm --filter @workspace/postiz-mobile run dev
Scan the QR code with Expo Go on Android to preview the app live.
Building an APK (local, no EAS)
First-time setup
1. Android SDK
cd artifacts/postiz-mobile
./install-android-sdk.sh
Add to ~/.bashrc or ~/.zshrc:
export ANDROID_HOME="$HOME/android-sdk"
export PATH="$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/35.0.0"
2. Signing keystore
The release keystore is stored at ~/.config/postiz-mobile/postiz-mobile.jks (not in the repo).
To export it from EAS (one-time):
cd artifacts/postiz-mobile
eas credentials --platform android
# → Keystore: Manage everything → Download existing keystore
# Note the key alias and passwords shown during export
3. Signing credentials
cp ~/.config/postiz-mobile/signing.env.example ~/.config/postiz-mobile/signing.env
$EDITOR ~/.config/postiz-mobile/signing.env
Fill in:
KEYSTORE_PATH="$HOME/.config/postiz-mobile/postiz-mobile.jks"
KEYSTORE_ALIAS="<alias shown during export>"
KEYSTORE_STORE_PASSWORD="<store password>"
KEYSTORE_KEY_PASSWORD="<key password>"
Build
cd artifacts/postiz-mobile
./build-apk.sh # → dist/postiz-mobile-YYYYMMDD-HHMM.apk
./build-apk.sh --aab # → dist/postiz-mobile-YYYYMMDD-HHMM.aab (Play Store)
The script runs expo prebuild, patches android/app/build.gradle for release signing, runs Gradle, copies the artifact to dist/, then wipes the credentials from gradle.properties.
Install on device
adb install dist/postiz-mobile-*.apk
How the build works
build-apk.sh
├── source ~/.config/postiz-mobile/signing.env
├── expo prebuild --platform android --clean
│ └── generates android/ from app.json + plugins
├── python3 patch: injects release signingConfig into build.gradle
├── append MYAPP_UPLOAD_* to gradle.properties
├── ./gradlew assembleRelease (or bundleRelease)
├── wipe signing block from gradle.properties
└── copy APK → dist/
The android/ directory is not committed (gitignored). It is regenerated on each build.
App configuration
On first launch, go to Settings:
- Base URL:
https://your-postiz-instance/api/public/v1 - API Key: generated in Postiz → Settings → API Keys
- Tap Test Connection, then Save Settings
The key is encrypted locally via expo-secure-store and never sent to third parties.
Architecture
artifacts/postiz-mobile/
├── app/
│ ├── _layout.tsx # Root layout: providers, fonts, 401 handler
│ └── (tabs)/
│ ├── _layout.tsx # Tab bar
│ ├── index.tsx # Calendar screen
│ ├── posts.tsx # Post list screen
│ ├── compose.tsx # Compose screen
│ └── settings.tsx # Settings screen
├── components/
│ ├── ChannelChip.tsx # Channel selector chip
│ ├── ErrorBoundary.tsx
│ ├── PostCard.tsx # Swipe-to-delete / swipe-to-reschedule
│ └── StatusBadge.tsx
├── context/
│ └── PostizContext.tsx # axios client + SecureStore + 401 interceptor
├── hooks/
│ ├── useColors.ts
│ └── useNotifications.ts # Permission + polling + local notifications
├── lib/
│ └── extractError.ts # Shared axios/fetch error formatter
├── build-apk.sh # Local build script
└── install-android-sdk.sh # One-time Android SDK bootstrap
Key dependencies
| Package | Role |
|---|---|
expo-router |
File-based navigation |
axios |
Postiz API HTTP client |
expo-secure-store |
Encrypted key storage |
react-native-calendars |
Calendar view |
@react-native-community/datetimepicker |
Date/time picker |
expo-image-picker |
Gallery access |
expo-notifications |
Local status notifications |
@tanstack/react-query |
API cache + refetch |
Postiz API
| Method | Endpoint | Usage |
|---|---|---|
GET |
/integrations |
List channels |
GET |
/posts?startDate=&endDate= |
Posts over a date range |
POST |
/posts |
Create / schedule a post |
DELETE |
/posts/:id |
Delete a post |
POST |
/upload |
Upload an image (multipart) |
Troubleshooting
"Not Configured" on all screens → Settings tab → enter API key and URL → Test Connection.
"Connection failed" → URL must end with /api/public/v1 — check Postiz is reachable.
No notifications → Accept permissions on first launch. Polling runs every 15 min.
Build fails at Gradle → Make sure ANDROID_HOME is set and ./gradlew is executable (chmod +x android/gradlew).
expo prebuild fails → Run pnpm install from the repo root first.