From e051ce8e7f78746d0a7b3378de9079d8cfc26fdc Mon Sep 17 00:00:00 2001 From: billisdead Date: Sun, 7 Jun 2026 20:48:44 +0200 Subject: [PATCH] docs: rewrite README for local build workflow, drop EAS references - 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 --- artifacts/postiz-mobile/README.md | 429 ++++++++++-------------------- artifacts/postiz-mobile/app.json | 7 +- artifacts/postiz-mobile/eas.json | 11 + 3 files changed, 156 insertions(+), 291 deletions(-) create mode 100644 artifacts/postiz-mobile/eas.json diff --git a/artifacts/postiz-mobile/README.md b/artifacts/postiz-mobile/README.md index 21c87cc..01f812a 100644 --- a/artifacts/postiz-mobile/README.md +++ b/artifacts/postiz-mobile/README.md @@ -1,22 +1,8 @@ # PostizMobile -React Native (Expo) mobile app to control a self-hosted **Postiz** instance from your Android or iOS device. +React Native (Expo) mobile app to control a self-hosted [Postiz](https://postiz.com) instance from Android. ---- - -## Table of Contents - -1. [Features](#features) -2. [Prerequisites](#prerequisites) -3. [Installation & Development](#installation--development) -4. [App Configuration](#app-configuration) -5. [Project Architecture](#project-architecture) -6. [Postiz API](#postiz-api) -7. [Android APK Build (EAS)](#android-apk-build-eas) -8. [iOS Build (Expo Launch)](#ios-build-expo-launch) -9. [Pushing Changes to Gitea](#pushing-changes-to-gitea) -10. [Environment Variables & Secrets](#environment-variables--secrets) -11. [Troubleshooting](#troubleshooting) +Build is fully local — no expo.dev account or EAS cloud required. --- @@ -24,344 +10,207 @@ React Native (Expo) mobile app to control a self-hosted **Postiz** instance from | Screen | Description | |--------|-------------| -| **Calendar** | Monthly view with color dots per day (indigo = scheduled, green = published, red = error). Tap a day to see its posts. | -| **Posts** | Filtered list (All / Queue / Published / Draft / Error) with pull-to-refresh and swipe left to delete. | -| **Compose** | Text editor, channel picker, date/time picker, gallery image import + upload, publish now or schedule. | -| **Settings** | API key and base URL input, connection test, secure storage (SecureStore). | -| **Notifications** | Automatic local alerts when a post transitions to PUBLISHED or ERROR (polling every 15 minutes). | +| **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 (`userInterfaceStyle: dark`). -**Authentication**: API key stored in `expo-secure-store`, never hardcoded. +**Theme**: forced dark. **Auth**: API key in `expo-secure-store`, never hardcoded. --- ## Prerequisites -| Tool | Minimum version | -|------|----------------| +| Tool | Version | +|------|---------| | Node.js | 20 LTS | | pnpm | 10+ | -| Expo Go (phone) | SDK 54 compatible | -| EAS account (for APK) | free on expo.dev | +| Java (JDK) | 17+ | +| Android SDK | see below | -```bash -npm install -g pnpm -npm install -g eas-cli -``` +No expo.dev account needed for builds. --- -## Installation & Development +## Development -### 1. Clone the repository +### Install dependencies ```bash git clone ssh://gitea@homegit.gyozamancave.fr:2222/billisdead/Postiz-android.git cd Postiz-android -``` - -### 2. Install dependencies - -```bash pnpm install ``` -### 3. Start the development server +### Start dev server (Expo Go) ```bash pnpm --filter @workspace/postiz-mobile run dev ``` -The terminal displays a QR code. Scan it with **Expo Go** (Android) or the **Camera** app (iOS) to see the app live. - -### 4. Open in the browser (web preview) - -``` -http://localhost: -``` - -The port is dynamically assigned by the Replit environment. +Scan the QR code with Expo Go on Android to preview the app live. --- -## App Configuration +## Building an APK (local, no EAS) -On first launch, the **Settings** screen is shown because no key is configured yet. +### First-time setup -1. **Base URL**: `https://your-postiz-instance.fr/public/v1` -2. **API Key**: generated from your Postiz instance → *Settings → API Keys* -3. Tap **Test Connection** to validate -4. Tap **Save Settings** +**1. Android SDK** -The key is encrypted and stored locally via `expo-secure-store`. It is never sent to a third-party service. +```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="" +KEYSTORE_STORE_PASSWORD="" +KEYSTORE_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 +``` --- -## Project Architecture +## 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, notifications +│ ├── _layout.tsx # Root layout: providers, fonts, 401 handler │ └── (tabs)/ -│ ├── _layout.tsx # Tab bar (NativeTabs iOS 26+ / Tabs classique) -│ ├── index.tsx # Écran Calendrier -│ ├── posts.tsx # Écran Liste des posts -│ ├── compose.tsx # Écran Composer -│ └── settings.tsx # Écran Paramètres +│ ├── _layout.tsx # Tab bar +│ ├── index.tsx # Calendar screen +│ ├── posts.tsx # Post list screen +│ ├── compose.tsx # Compose screen +│ └── settings.tsx # Settings screen ├── components/ -│ ├── ChannelChip.tsx # Chip de sélection de canal -│ ├── ErrorBoundary.tsx # Gestionnaire d'erreurs global -│ ├── PostCard.tsx # Carte post avec swipe-to-delete -│ └── StatusBadge.tsx # Badge QUEUE / PUBLISHED / ERROR / DRAFT -├── constants/ -│ └── colors.ts # Palette dark theme +│ ├── ChannelChip.tsx # Channel selector chip +│ ├── ErrorBoundary.tsx +│ ├── PostCard.tsx # Swipe-to-delete / swipe-to-reschedule +│ └── StatusBadge.tsx ├── context/ -│ └── PostizContext.tsx # Client axios + SecureStore (apiKey, baseUrl) +│ └── PostizContext.tsx # axios client + SecureStore + 401 interceptor ├── hooks/ -│ ├── useColors.ts # Tokens couleur selon le thème -│ └── useNotifications.ts # Permissions + polling + notifications locales -├── assets/ -│ └── images/ -│ └── icon.png # Icône générée par IA -└── app.json # Config Expo (permissions, plugins, thème) +│ ├── 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 ``` -### Main dependencies +### Key dependencies -| Package | Usage | -|---------|-------| +| Package | Role | +|---------|------| | `expo-router` | File-based navigation | -| `axios` | HTTP client for the Postiz API | -| `expo-secure-store` | Encrypted API key storage | -| `react-native-calendars` | Monthly calendar view | -| `@react-native-community/datetimepicker` | Date/time picker in Compose | -| `expo-image-picker` | Gallery photo access | +| `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 | -| `expo-task-manager` | Background task for polling | -| `@tanstack/react-query` | API data cache and refetch | +| `@tanstack/react-query` | API cache + refetch | --- ## Postiz API -Base URL configured by the user (e.g. `https://postiz.example.com/public/v1`). - | Method | Endpoint | Usage | |--------|----------|-------| -| `GET` | `/integrations` | List channels (Twitter, LinkedIn, etc.) | +| `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) | -### POST /posts payload example - -```json -{ - "type": "schedule", - "date": "2025-01-15T10:00:00.000Z", - "content": [ - { - "content": "Mon super post 🚀", - "image": [{ "id": "upload-id", "path": "/uploads/photo.jpg" }] - } - ], - "integrations": ["integration-id-twitter", "integration-id-linkedin"] -} -``` - -To publish immediately, use `"type": "now"`. - ---- - -## Android APK Build (EAS) - -> **Prerequisites**: free account on [expo.dev](https://expo.dev) and `eas-cli` installed. - -### 1. Log in to EAS - -```bash -npx eas login -``` - -### 2. Initialize EAS in the project - -```bash -cd artifacts/postiz-mobile -npx eas init -``` - -This generates a `projectId` in `app.json`. - -### 3. Create the EAS configuration file - -Create `artifacts/postiz-mobile/eas.json`: - -```json -{ - "cli": { - "version": ">= 16.0.0" - }, - "build": { - "preview": { - "android": { - "buildType": "apk" - } - }, - "production": { - "android": { - "buildType": "app-bundle" - } - } - }, - "submit": { - "production": {} - } -} -``` - -### 4. Start the APK build - -```bash -# APK de test (sideload) -npx eas build --platform android --profile preview - -# AAB pour le Play Store -npx eas build --platform android --profile production -``` - -The build runs in the EAS cloud. You receive a download link at the end (~10-15 min). - -### 5. Install the APK on your phone - -```bash -# Via adb -adb install postiz-mobile.apk - -# Ou scannez le QR code affiché par EAS -``` - -### Declared Android permissions - -```xml -READ_EXTERNAL_STORAGE -WRITE_EXTERNAL_STORAGE -READ_MEDIA_IMAGES -RECEIVE_BOOT_COMPLETED -VIBRATE -``` - ---- - -## iOS Build (Expo Launch) - -> Available only via **Replit Expo Launch** (automated App Store submission). - -1. In Replit, click the **Publish** button -2. Select **Expo Launch** -3. Follow the wizard (Apple Developer account required) - -**Note**: Google Play publishing is not yet supported by Expo Launch — use EAS for Android. - ---- - -## Pushing Changes to Gitea - -The remote repository is: `ssh://gitea@homegit.gyozamancave.fr:2222/billisdead/Postiz-android.git` - -The SSH key used is stored in the `GITEA_SSH_KEY` environment variable (on the Replit side). - -### Push from your local machine - -```bash -# Ajouter le remote (une seule fois) -git remote add gitea ssh://gitea@homegit.gyozamancave.fr:2222/billisdead/Postiz-android.git - -# Pousser -git push gitea main -``` - -Make sure your public SSH key is added in Gitea → *User Settings → SSH / GPG Keys*. - -### Push from Replit (via script) - -From Replit, direct `git push` commands are restricted. Use the bundle script: - -```bash -# Créer le bundle -git bundle create /tmp/postiz.bundle main - -# Cloner le bundle et pousser -git clone /tmp/postiz.bundle /tmp/repo_push -cd /tmp/repo_push -git remote add gitea ssh://gitea@homegit.gyozamancave.fr:2222/billisdead/Postiz-android.git -GIT_SSH_COMMAND="ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no -p 2222" \ - git push --force gitea main -``` - ---- - -## Environment Variables & Secrets - -| Variable | Storage | Description | -|----------|---------|-------------| -| `GITEA_SSH_KEY` | Replit Secrets (shared) | Private SSH key for pushing to Gitea | -| `SESSION_SECRET` | Replit Secrets | Session secret (API server) | - -App-side variables (Postiz API key, URL) are **entered by the user** in the Settings screen and stored in `expo-secure-store` — they never pass through the source code. - --- ## Troubleshooting -### The app shows "Not Configured" on all screens +**"Not Configured" on all screens** → Settings tab → enter API key and URL → Test Connection. -→ Go to the **Settings** tab, enter your API key and URL, then tap **Test Connection**. +**"Connection failed"** → URL must end with `/api/public/v1` — check Postiz is reachable. -### "Connection failed" in Settings +**No notifications** → Accept permissions on first launch. Polling runs every 15 min. -- Check that the URL ends with `/public/v1` -- Check that the API key is valid (generated in Postiz → API Keys) -- Check that your Postiz instance is accessible from the internet +**Build fails at Gradle** → Make sure `ANDROID_HOME` is set and `./gradlew` is executable (`chmod +x android/gradlew`). -### No notifications received - -- Accept notification permissions on first launch -- Polling runs every 15 minutes — wait for a full cycle -- On Android, check that the app's notifications are not disabled in system settings - -### Metro error "module not found" - -```bash -pnpm install -# Puis redémarrer le workflow Expo -``` - -### Calendar does not load posts - -- Check that the Postiz API supports `startDate` / `endDate` parameters on `GET /posts` -- Check network logs: in Expo Go, shake the device → *Open Debugger* - -### EAS build fails - -```bash -# Vérifier la version Expo -npx expo --version - -# Vérifier la cohérence des packages -npx expo install --check -``` - ---- - -## Contributing - -1. Fork on Gitea: `https://homegit.gyozamancave.fr/billisdead/Postiz-android` -2. Create a feature branch: `git checkout -b feature/my-feature` -3. Commit your changes -4. Push and open a Pull Request - ---- - -*Generated with ❤️ on Replit — PostizMobile v1.0.0* +**`expo prebuild` fails** → Run `pnpm install` from the repo root first. diff --git a/artifacts/postiz-mobile/app.json b/artifacts/postiz-mobile/app.json index e4b28ee..ff63ac8 100644 --- a/artifacts/postiz-mobile/app.json +++ b/artifacts/postiz-mobile/app.json @@ -47,11 +47,16 @@ "color": "#6366F1", "sounds": [] } - ], + ] ], "experiments": { "typedRoutes": true, "reactCompiler": true + }, + "extra": { + "eas": { + "projectId": "aeaaa2bd-3a27-4771-8e39-f2e14fe0e030" + } } } } diff --git a/artifacts/postiz-mobile/eas.json b/artifacts/postiz-mobile/eas.json new file mode 100644 index 0000000..d412d35 --- /dev/null +++ b/artifacts/postiz-mobile/eas.json @@ -0,0 +1,11 @@ +{ + "cli": { + "version": ">= 16.0.0" + }, + "build": { + "preview": { + "android": { "buildType": "apk" }, + "ios": { "simulator": true } + } + } +}