From 20226caef4198faafe92e481dc2a0a23c4022b6e Mon Sep 17 00:00:00 2001 From: billisdead Date: Sun, 7 Jun 2026 20:32:18 +0200 Subject: [PATCH] build: remove expo.dev/EAS dependency, add local Android build pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Delete eas.json and strip extra.eas.projectId from app.json - Add plugins/withAndroidReleaseSigning.js — Expo config plugin that injects release signingConfig into the generated build.gradle during expo prebuild - Add build-apk.sh — self-contained build script (expo prebuild + Gradle) Reads keystore credentials from ~/.config/postiz-mobile/signing.env Outputs APK/AAB to dist/, wipes credentials from gradle.properties after build - Add install-android-sdk.sh — one-time Android SDK cmdline-tools bootstrap - Remove unused expo-task-manager dependency - Update .gitignore: android/, ios/, static-build/ excluded (generated) Build workflow: 1. eas credentials --platform android # export keystore once 2. ./install-android-sdk.sh # first time only 3. ./build-apk.sh # → dist/postiz-mobile-YYYYMMDD-HHMM.apk Co-Authored-By: Claude Sonnet 4.6 --- artifacts/postiz-mobile/.gitignore | 6 +- artifacts/postiz-mobile/app.json | 8 +- artifacts/postiz-mobile/build-apk.sh | 115 ++++++++++++++++++ artifacts/postiz-mobile/eas.json | 24 ---- .../postiz-mobile/install-android-sdk.sh | 46 +++++++ artifacts/postiz-mobile/package.json | 1 - .../plugins/withAndroidReleaseSigning.js | 38 ++++++ 7 files changed, 206 insertions(+), 32 deletions(-) create mode 100755 artifacts/postiz-mobile/build-apk.sh delete mode 100644 artifacts/postiz-mobile/eas.json create mode 100755 artifacts/postiz-mobile/install-android-sdk.sh create mode 100644 artifacts/postiz-mobile/plugins/withAndroidReleaseSigning.js diff --git a/artifacts/postiz-mobile/.gitignore b/artifacts/postiz-mobile/.gitignore index 621de6b..e89a15f 100644 --- a/artifacts/postiz-mobile/.gitignore +++ b/artifacts/postiz-mobile/.gitignore @@ -9,16 +9,20 @@ dist/ web-build/ expo-env.d.ts -# Native +# Native — generated by expo prebuild, never committed ios/ android/ *.orig.* *.jks +*.keystore *.p8 *.p12 *.key *.mobileprovision +# Local build output +static-build/ + # Metro .metro-health-check* diff --git a/artifacts/postiz-mobile/app.json b/artifacts/postiz-mobile/app.json index ff63ac8..2c6aba2 100644 --- a/artifacts/postiz-mobile/app.json +++ b/artifacts/postiz-mobile/app.json @@ -47,16 +47,12 @@ "color": "#6366F1", "sounds": [] } - ] + ], + "./plugins/withAndroidReleaseSigning" ], "experiments": { "typedRoutes": true, "reactCompiler": true - }, - "extra": { - "eas": { - "projectId": "aeaaa2bd-3a27-4771-8e39-f2e14fe0e030" - } } } } diff --git a/artifacts/postiz-mobile/build-apk.sh b/artifacts/postiz-mobile/build-apk.sh new file mode 100755 index 0000000..6cebd85 --- /dev/null +++ b/artifacts/postiz-mobile/build-apk.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash +# build-apk.sh — Build a signed release APK locally without expo.dev / EAS. +# +# Prerequisites (first time only): +# 1. Export EAS keystore: +# eas credentials --platform android +# → "Download existing keystore" → save to ~/.config/postiz-mobile/postiz-mobile.jks +# 2. Fill in signing credentials: +# cp ~/.config/postiz-mobile/signing.env.example ~/.config/postiz-mobile/signing.env +# editor ~/.config/postiz-mobile/signing.env +# 3. Install Android SDK (if not already): +# ./install-android-sdk.sh +# +# Usage: +# ./build-apk.sh # APK goes to dist/ +# ./build-apk.sh --aab # AAB (Play Store) instead of APK + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SIGNING_ENV="$HOME/.config/postiz-mobile/signing.env" +DIST_DIR="$SCRIPT_DIR/dist" +BUILD_TYPE="${1:-}" + +# ─── Colours ─────────────────────────────────────────────────────────────── +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' +info() { echo -e "${GREEN}[build]${NC} $*"; } +warn() { echo -e "${YELLOW}[warn]${NC} $*"; } +abort() { echo -e "${RED}[error]${NC} $*" >&2; exit 1; } + +# ─── 1. Signing credentials ──────────────────────────────────────────────── +if [ ! -f "$SIGNING_ENV" ]; then + abort "Missing signing.env.\n\n cp ~/.config/postiz-mobile/signing.env.example ~/.config/postiz-mobile/signing.env\n # then fill in your keystore path and passwords" +fi +# shellcheck source=/dev/null +source "$SIGNING_ENV" + +[ -z "${KEYSTORE_PATH:-}" ] && abort "KEYSTORE_PATH not set in signing.env" +[ -z "${KEYSTORE_ALIAS:-}" ] && abort "KEYSTORE_ALIAS not set in signing.env" +[ -z "${KEYSTORE_STORE_PASSWORD:-}" ] && abort "KEYSTORE_STORE_PASSWORD not set in signing.env" +[ -z "${KEYSTORE_KEY_PASSWORD:-}" ] && abort "KEYSTORE_KEY_PASSWORD not set in signing.env" + +KEYSTORE_PATH_EXPANDED="${KEYSTORE_PATH/#\$HOME/$HOME}" +KEYSTORE_PATH_EXPANDED="${KEYSTORE_PATH_EXPANDED/#~/$HOME}" + +[ ! -f "$KEYSTORE_PATH_EXPANDED" ] && abort "Keystore not found: $KEYSTORE_PATH_EXPANDED\n\nExport it from EAS:\n eas credentials --platform android\n → Download existing keystore → save to $KEYSTORE_PATH_EXPANDED" + +# ─── 2. Android SDK ──────────────────────────────────────────────────────── +if [ -z "${ANDROID_HOME:-}" ]; then + # Try common locations + for candidate in "$HOME/android-sdk" "$HOME/Android/Sdk" "/opt/android-sdk"; do + if [ -d "$candidate/platform-tools" ]; then + export ANDROID_HOME="$candidate" + break + fi + done +fi + +if [ -z "${ANDROID_HOME:-}" ]; then + abort "Android SDK not found.\n\nRun: ./install-android-sdk.sh\nOr set ANDROID_HOME manually in your shell." +fi + +export PATH="$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/cmdline-tools/latest/bin" +info "Android SDK: $ANDROID_HOME" + +# ─── 3. expo prebuild ────────────────────────────────────────────────────── +info "Running expo prebuild (Android)…" +cd "$SCRIPT_DIR" +pnpm exec expo prebuild --platform android --clean --no-install + +# ─── 4. Inject signing into gradle.properties ────────────────────────────── +info "Injecting signing credentials into gradle.properties…" +GRADLE_PROPS="$SCRIPT_DIR/android/gradle.properties" + +# Remove any previous signing block written by this script +sed -i '/^# --- postiz-mobile release signing/,/^# --- end signing/d' "$GRADLE_PROPS" 2>/dev/null || true + +cat >> "$GRADLE_PROPS" << EOF + +# --- postiz-mobile release signing (injected by build-apk.sh) +MYAPP_UPLOAD_STORE_FILE=$KEYSTORE_PATH_EXPANDED +MYAPP_UPLOAD_STORE_PASSWORD=$KEYSTORE_STORE_PASSWORD +MYAPP_UPLOAD_KEY_ALIAS=$KEYSTORE_ALIAS +MYAPP_UPLOAD_KEY_PASSWORD=$KEYSTORE_KEY_PASSWORD +# --- end signing +EOF + +# ─── 5. Gradle build ─────────────────────────────────────────────────────── +cd "$SCRIPT_DIR/android" + +if [ "$BUILD_TYPE" = "--aab" ]; then + info "Building AAB (release)…" + ./gradlew bundleRelease + ARTIFACT="app/build/outputs/bundle/release/app-release.aab" + EXT="aab" +else + info "Building APK (release)…" + ./gradlew assembleRelease + ARTIFACT="app/build/outputs/apk/release/app-release.apk" + EXT="apk" +fi + +# ─── 6. Copy to dist/ ────────────────────────────────────────────────────── +mkdir -p "$DIST_DIR" +TIMESTAMP="$(date +%Y%m%d-%H%M)" +OUTPUT="$DIST_DIR/postiz-mobile-$TIMESTAMP.$EXT" +cp "$ARTIFACT" "$OUTPUT" + +echo "" +info "Build complete!" +echo -e " ${GREEN}→ $OUTPUT${NC}" +echo "" + +# Wipe signing credentials from gradle.properties for safety +sed -i '/^# --- postiz-mobile release signing/,/^# --- end signing/d' "$GRADLE_PROPS" diff --git a/artifacts/postiz-mobile/eas.json b/artifacts/postiz-mobile/eas.json deleted file mode 100644 index 1b89ea1..0000000 --- a/artifacts/postiz-mobile/eas.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "cli": { - "version": ">= 16.0.0" - }, - "build": { - "preview": { - "distribution": "internal", - "android": { - "buildType": "apk" - } - }, - "production": { - "android": { - "buildType": "app-bundle" - }, - "ios": { - "resourceClass": "m-medium" - } - } - }, - "submit": { - "production": {} - } -} diff --git a/artifacts/postiz-mobile/install-android-sdk.sh b/artifacts/postiz-mobile/install-android-sdk.sh new file mode 100755 index 0000000..1504c55 --- /dev/null +++ b/artifacts/postiz-mobile/install-android-sdk.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# install-android-sdk.sh — Install Android SDK command-line tools only (no Android Studio). +# Installs to ~/android-sdk. Run once; takes ~1 GB of disk space. + +set -euo pipefail + +SDK_DIR="$HOME/android-sdk" +CMDLINE_TOOLS_URL="https://dl.google.com/android/repository/commandlinetools-linux-12266719_latest.zip" +CMDLINE_ZIP="/tmp/android-cmdline-tools.zip" + +GREEN='\033[0;32m'; NC='\033[0m' +info() { echo -e "${GREEN}[sdk-install]${NC} $*"; } + +if [ -d "$SDK_DIR/cmdline-tools/latest/bin" ]; then + info "Android SDK already installed at $SDK_DIR" + exit 0 +fi + +info "Downloading Android command-line tools…" +wget -q --show-progress -O "$CMDLINE_ZIP" "$CMDLINE_TOOLS_URL" + +info "Extracting…" +mkdir -p "$SDK_DIR/cmdline-tools" +unzip -q "$CMDLINE_ZIP" -d "$SDK_DIR/cmdline-tools" +mv "$SDK_DIR/cmdline-tools/cmdline-tools" "$SDK_DIR/cmdline-tools/latest" +rm "$CMDLINE_ZIP" + +export ANDROID_HOME="$SDK_DIR" +export PATH="$PATH:$SDK_DIR/cmdline-tools/latest/bin:$SDK_DIR/platform-tools" + +info "Accepting licenses…" +yes | sdkmanager --licenses > /dev/null 2>&1 || true + +info "Installing SDK components (platform-tools, build-tools 35, NDK 28)…" +sdkmanager \ + "platform-tools" \ + "platforms;android-35" \ + "build-tools;35.0.0" \ + "ndk;28.0.12433566" + +info "Done. Add this to your ~/.bashrc or ~/.zshrc:" +echo "" +echo ' export ANDROID_HOME="$HOME/android-sdk"' +echo ' export PATH="$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools"' +echo "" +info "Then reload your shell: source ~/.bashrc" diff --git a/artifacts/postiz-mobile/package.json b/artifacts/postiz-mobile/package.json index ad72d74..b30d271 100644 --- a/artifacts/postiz-mobile/package.json +++ b/artifacts/postiz-mobile/package.json @@ -61,7 +61,6 @@ "expo-clipboard": "~8.0.8", "expo-notifications": "~0.32.17", "expo-secure-store": "~15.0.8", - "expo-task-manager": "~14.0.9", "react-native-calendars": "^1.1314.0" } } diff --git a/artifacts/postiz-mobile/plugins/withAndroidReleaseSigning.js b/artifacts/postiz-mobile/plugins/withAndroidReleaseSigning.js new file mode 100644 index 0000000..6035f90 --- /dev/null +++ b/artifacts/postiz-mobile/plugins/withAndroidReleaseSigning.js @@ -0,0 +1,38 @@ +const { withAppBuildGradle } = require("@expo/config-plugins"); + +// Injects a proper release signingConfig into the generated build.gradle. +// Reads credentials from gradle.properties (populated by build-apk.sh at build time). +// This plugin runs during `expo prebuild` so android/ doesn't need to be committed. +module.exports = function withAndroidReleaseSigning(config) { + return withAppBuildGradle(config, (mod) => { + let contents = mod.modResults.contents; + + if (contents.includes("MYAPP_UPLOAD_STORE_FILE")) { + return mod; // already patched + } + + const releaseBlock = ` release { + if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) { + storeFile file(MYAPP_UPLOAD_STORE_FILE) + storePassword MYAPP_UPLOAD_STORE_PASSWORD + keyAlias MYAPP_UPLOAD_KEY_ALIAS + keyPassword MYAPP_UPLOAD_KEY_PASSWORD + } + }`; + + // Insert release signingConfig after the closing brace of the debug block + contents = contents.replace( + /(signingConfigs\s*\{[\s\S]*?debug\s*\{[\s\S]*?\})/, + `$1\n${releaseBlock}` + ); + + // Switch the release buildType from debug signing to release signing + contents = contents.replace( + /(buildTypes[\s\S]*?release\s*\{[\s\S]*?)signingConfig\s+signingConfigs\.debug/, + "$1signingConfig signingConfigs.release" + ); + + mod.modResults.contents = contents; + return mod; + }); +};