aaf6b2aa07
Gradle 8.x supports up to Java 24. Fedora 44 ships Java 25 by default, causing "Unsupported class file major version 69" at build time. build-apk.sh now auto-detects system Java version and falls back to ~/jdk21 (Temurin 21 LTS) when Java ≥ 25 is detected. README documents the one-time JDK 21 install step. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
229 lines
6.8 KiB
Markdown
229 lines
6.8 KiB
Markdown
# PostizMobile
|
||
|
||
React Native (Expo) mobile app to control a self-hosted [Postiz](https://postiz.com) 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–24 (Java 25+ not yet supported by Gradle 8) |
|
||
| Android SDK | see below |
|
||
|
||
No expo.dev account needed for builds.
|
||
|
||
---
|
||
|
||
## Development
|
||
|
||
### Install dependencies
|
||
|
||
```bash
|
||
git clone ssh://gitea@homegit.gyozamancave.fr:2222/billisdead/Postiz-android.git
|
||
cd Postiz-android
|
||
pnpm install
|
||
```
|
||
|
||
### Start dev server (Expo Go)
|
||
|
||
```bash
|
||
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. Java 21 LTS**
|
||
|
||
Gradle 8 requires Java ≤ 24. If the system Java is 25+ (Fedora 44), install Temurin 21 locally:
|
||
|
||
```bash
|
||
wget -O /tmp/jdk21.tar.gz \
|
||
"https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.7%2B6/OpenJDK21U-jdk_x64_linux_hotspot_21.0.7_6.tar.gz"
|
||
mkdir -p ~/jdk21 && tar -xzf /tmp/jdk21.tar.gz -C ~/jdk21 --strip-components=1
|
||
```
|
||
|
||
`build-apk.sh` will use `~/jdk21` automatically if the system Java is ≥ 25.
|
||
|
||
**2. Android SDK**
|
||
|
||
```bash
|
||
cd artifacts/postiz-mobile
|
||
./install-android-sdk.sh
|
||
```
|
||
|
||
Add to `~/.bashrc` or `~/.zshrc`:
|
||
|
||
```bash
|
||
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):
|
||
|
||
```bash
|
||
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**
|
||
|
||
```bash
|
||
cp ~/.config/postiz-mobile/signing.env.example ~/.config/postiz-mobile/signing.env
|
||
$EDITOR ~/.config/postiz-mobile/signing.env
|
||
```
|
||
|
||
Fill in:
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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**:
|
||
|
||
1. **Base URL**: `https://your-postiz-instance/api/public/v1`
|
||
2. **API Key**: generated in Postiz → Settings → API Keys
|
||
3. 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.
|