mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-28 18:06:09 +02:00
linux and android builds
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
name: Release
|
||||
|
||||
# Builds the macOS and Windows desktop apps on the self-hosted Mac runner
|
||||
# and publishes them as a GitHub Release.
|
||||
# Builds the macOS, Windows, and Linux desktop apps plus an Android APK
|
||||
# on the self-hosted Mac runner, and publishes them as a GitHub Release.
|
||||
#
|
||||
# Versioning:
|
||||
# - First ever release is 0.1.0.
|
||||
@@ -152,14 +152,20 @@ jobs:
|
||||
echo "Identities available to codesign:"
|
||||
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
|
||||
|
||||
- name: Build macOS + Windows
|
||||
- name: Build macOS + Windows + Linux
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Sign in-build (identity auto-detected from the temp keychain);
|
||||
# notarize separately below so it uses secret credentials, not a
|
||||
# login-keychain profile.
|
||||
# login-keychain profile. "all" also builds the Linux AppImage,
|
||||
# which needs no signing/notarization.
|
||||
scripts/build.sh all --version "${{ steps.ver.outputs.version }}" --no-notarize
|
||||
|
||||
- name: Build Android
|
||||
run: |
|
||||
set -euo pipefail
|
||||
scripts/build_android.sh --version "${{ steps.ver.outputs.version }}"
|
||||
|
||||
- name: Notarize & staple macOS app
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -204,6 +210,10 @@ jobs:
|
||||
mkdir -p "$outdir"
|
||||
cp "dist/mac/PokemonRed-macos.zip" "$outdir/PokemonRed-${v}-macos.zip"
|
||||
cp "dist/win/PokemonRed-win64.zip" "$outdir/PokemonRed-${v}-windows.zip"
|
||||
cp "dist/linux/PokemonRed-linux.zip" "$outdir/PokemonRed-${v}-linux.zip"
|
||||
apk="$(find dist/android/debug -name '*.apk' | head -1)"
|
||||
[ -n "$apk" ] || { echo "::error::no Android APK found under dist/android/debug"; exit 1; }
|
||||
cp "$apk" "$outdir/PokemonRed-${v}-android.apk"
|
||||
ls -lh "$outdir"
|
||||
|
||||
- name: Publish GitHub Release
|
||||
@@ -254,7 +264,9 @@ jobs:
|
||||
--title "$v" \
|
||||
--notes "$notes" \
|
||||
"dist/release/PokemonRed-${v}-macos.zip" \
|
||||
"dist/release/PokemonRed-${v}-windows.zip"
|
||||
"dist/release/PokemonRed-${v}-windows.zip" \
|
||||
"dist/release/PokemonRed-${v}-linux.zip" \
|
||||
"dist/release/PokemonRed-${v}-android.apk"
|
||||
|
||||
echo "Published release $tag"
|
||||
|
||||
|
||||
+15
-19
@@ -27,17 +27,17 @@ refresh is safe, just rebuild.
|
||||
## Build
|
||||
|
||||
```bash
|
||||
# Debug APK (default Android debug keystore)
|
||||
# Build the APK
|
||||
scripts/build_android.sh
|
||||
|
||||
# Release APK (signing is manual, see below)
|
||||
scripts/build_android.sh --release
|
||||
# Build the APK, setting app.version_name/app.version_code to match a release
|
||||
scripts/build_android.sh --version 0.2.5
|
||||
|
||||
# Zip game.love + branding only (no Android SDK required)
|
||||
scripts/build_android.sh --package-only
|
||||
```
|
||||
|
||||
Or via `scripts/build.sh android`.
|
||||
Or via `scripts/build.sh android [--version X.Y.Z]`.
|
||||
|
||||
The embedded `game.love` deliberately excludes `data/generated/`,
|
||||
`assets/generated/`, and any ROM. It contains the first-boot Lua importer and
|
||||
@@ -59,12 +59,10 @@ Set `ANDROID_SDK_ROOT` (or `ANDROID_HOME`), or let the script write
|
||||
`local.properties` when it finds `~/Library/Android/sdk`.
|
||||
|
||||
Gradle flavor used: **`embedNoRecord`** (game fused into the APK, no microphone).
|
||||
Build task: `assembleEmbedNoRecordDebug`.
|
||||
|
||||
- Debug task: `assembleEmbedNoRecordDebug`
|
||||
- Release task: `assembleEmbedNoRecordRelease`
|
||||
|
||||
APKs land under `app/build/outputs/apk/embedNoRecord/{debug,release}/`.
|
||||
`scripts/build_android.sh` also copies the built APK(s) to `dist/android/{debug,release}/`.
|
||||
The APK lands under `app/build/outputs/apk/embedNoRecord/debug/`.
|
||||
`scripts/build_android.sh` also copies it to `dist/android/debug/`.
|
||||
|
||||
### Payload path
|
||||
|
||||
@@ -79,17 +77,15 @@ scripts, tests, and mobile build sources are excluded.
|
||||
| `app.application_id` | `com.theboisclub.pokemonred` |
|
||||
| `app.name` | Pokemon Red |
|
||||
| `app.orientation` | `portrait` |
|
||||
| `app.version_name` / `app.version_code` | set from `--version X.Y.Z` (code = major*10000 + minor*100 + patch); left as-is if `--version` is omitted |
|
||||
| Permissions | INTERNET / RECORD_AUDIO / WRITE_EXTERNAL_STORAGE stripped; VIBRATE + BLUETOOTH kept |
|
||||
|
||||
## Releases
|
||||
|
||||
`.github/workflows/release.yml` builds the APK with `--version` set to the
|
||||
release version and publishes it alongside the macOS/Windows/Linux builds as
|
||||
`PokemonRed-<version>-android.apk`.
|
||||
|
||||
## Signing
|
||||
|
||||
- **Debug**: default Android debug keystore (no setup).
|
||||
- **Release**: out-of-band. Create a keystore yourself and wire it into
|
||||
`app/build.gradle`, **do not commit keystores or passwords**.
|
||||
|
||||
Example (placeholder only):
|
||||
|
||||
```bash
|
||||
keytool -genkey -v -keystore /path/to/pokemonred-release.jks \
|
||||
-alias pokemonred -keyalg RSA -keysize 2048 -validity 10000
|
||||
```
|
||||
Signed with the default Android keystore (no setup required).
|
||||
|
||||
+45
-14
@@ -1,15 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
# Packages the LÖVE2D Pokémon Red port into distributable macOS and
|
||||
# Windows builds. Runs entirely on macOS (no cross-compiling needed,
|
||||
# the Windows build reuses LÖVE's prebuilt win64 binaries).
|
||||
# Packages the LÖVE2D Pokémon Red port into distributable macOS, Windows,
|
||||
# and Linux builds. Runs entirely on macOS (no cross-compiling needed,
|
||||
# the Windows and Linux builds reuse LÖVE's prebuilt win64 / AppImage
|
||||
# binaries, fusing our game.love onto them the same way love.exe does).
|
||||
#
|
||||
# Usage: scripts/build.sh [mac|win|android|ios|all] [--version X.Y.Z] [--identity "Developer ID Application: ..."]
|
||||
# Usage: scripts/build.sh [mac|win|linux|android|ios|all] [--version X.Y.Z] [--identity "Developer ID Application: ..."]
|
||||
# [--notary-profile NAME] [--no-notarize]
|
||||
# [--release] # android/ios: release config instead of debug
|
||||
# [--release] # ios only: release config instead of debug
|
||||
#
|
||||
# Output: dist/mac/PokemonRed-macos.zip
|
||||
# dist/win/PokemonRed-win64.zip
|
||||
# dist/android/{debug,release}/*.apk (full gradle output stays under
|
||||
# dist/linux/PokemonRed-linux.zip (fused x86_64 AppImage)
|
||||
# dist/android/debug/*.apk (full gradle output stays under
|
||||
# mobile/android/app/build/outputs/apk/embedNoRecord/)
|
||||
# dist/ios/<Config>-<sdk>/PokemonRed.app (full xcodebuild output stays
|
||||
# under mobile/ios/build/Build/Products/)
|
||||
@@ -27,11 +29,11 @@ APP_NAME="PokemonRed"
|
||||
BUNDLE_ID="com.theboisclub.pokemonred"
|
||||
LOVE_VERSION="11.5"
|
||||
VERSION="$(git -C "$ROOT" rev-parse --short HEAD 2>/dev/null || echo dev)"
|
||||
VERSION_EXPLICIT=false
|
||||
IDENTITY=""
|
||||
TARGET="all"
|
||||
NOTARY_PROFILE="notary-profile"
|
||||
NOTARIZE=true
|
||||
ANDROID_RELEASE=false
|
||||
IOS_RELEASE=false
|
||||
|
||||
say() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
|
||||
@@ -40,18 +42,18 @@ fail() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
mac|win|android|ios|all) TARGET="$1" ;;
|
||||
--version) VERSION="$2"; shift ;;
|
||||
mac|win|linux|android|ios|all) TARGET="$1" ;;
|
||||
--version) VERSION="$2"; VERSION_EXPLICIT=true; shift ;;
|
||||
--identity) IDENTITY="$2"; shift ;;
|
||||
--notary-profile) NOTARY_PROFILE="$2"; shift ;;
|
||||
--no-notarize) NOTARIZE=false ;;
|
||||
--release) ANDROID_RELEASE=true; IOS_RELEASE=true ;;
|
||||
--release) IOS_RELEASE=true ;;
|
||||
*) fail "unknown argument: $1" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
mkdir -p "$CACHE" "$WORK" "$DIST/mac" "$DIST/win"
|
||||
mkdir -p "$CACHE" "$WORK" "$DIST/mac" "$DIST/win" "$DIST/linux"
|
||||
|
||||
# --------------------------------------------------------------- game.love
|
||||
say "packing game.love"
|
||||
@@ -167,12 +169,40 @@ build_win() {
|
||||
say "Windows build: $zip_out"
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------- Linux
|
||||
build_linux() {
|
||||
say "building Linux (x86_64 AppImage) app"
|
||||
local appimage_name="love-$LOVE_VERSION-x86_64.AppImage"
|
||||
local love_appimage="$CACHE/$appimage_name"
|
||||
if [ ! -f "$love_appimage" ]; then
|
||||
say "downloading LÖVE $LOVE_VERSION Linux AppImage"
|
||||
curl -fL --progress-bar \
|
||||
"https://github.com/love2d/love/releases/download/$LOVE_VERSION/$appimage_name" \
|
||||
-o "$love_appimage" || fail "download failed, check LOVE_VERSION or your network"
|
||||
fi
|
||||
chmod +x "$love_appimage"
|
||||
|
||||
# Same fusion trick as the Windows exe: love looks for a zip appended to
|
||||
# its own running binary, and an AppImage is just an ELF executable, so
|
||||
# concatenating game.love onto it works the same way `cat love.exe
|
||||
# game.love` does on Windows.
|
||||
local out_bin="$WORK/$APP_NAME-x86_64.AppImage"
|
||||
rm -f "$out_bin"
|
||||
cat "$love_appimage" "$LOVE_FILE" > "$out_bin"
|
||||
chmod +x "$out_bin"
|
||||
|
||||
local zip_out="$DIST/linux/$APP_NAME-linux.zip"
|
||||
rm -f "$zip_out"
|
||||
(cd "$WORK" && zip -q -9 -j "$zip_out" "$(basename "$out_bin")")
|
||||
say "Linux build: $zip_out"
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------- Android
|
||||
build_android() {
|
||||
say "building Android (delegating to scripts/build_android.sh)"
|
||||
local args=()
|
||||
if [ "$ANDROID_RELEASE" = true ]; then
|
||||
args+=(--release)
|
||||
if [ "$VERSION_EXPLICIT" = true ]; then
|
||||
args+=(--version "$VERSION")
|
||||
fi
|
||||
"$ROOT/scripts/build_android.sh" ${args[@]+"${args[@]}"}
|
||||
}
|
||||
@@ -190,9 +220,10 @@ build_ios() {
|
||||
case "$TARGET" in
|
||||
mac) build_mac ;;
|
||||
win) build_win ;;
|
||||
linux) build_linux ;;
|
||||
android) build_android ;;
|
||||
ios) build_ios ;;
|
||||
all) build_mac; build_win ;;
|
||||
all) build_mac; build_win; build_linux ;;
|
||||
esac
|
||||
|
||||
case "$TARGET" in
|
||||
|
||||
+28
-30
@@ -1,11 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
# Packages the LÖVE2D Pokémon Red port into an Android APK via love-android 11.5a.
|
||||
#
|
||||
# Usage: scripts/build_android.sh [--release] [--package-only]
|
||||
# Usage: scripts/build_android.sh [--version X.Y.Z] [--package-only]
|
||||
#
|
||||
# (default) assembleEmbedNoRecordDebug (debug keystore)
|
||||
# --release assembleEmbedNoRecordRelease (requires out-of-band signing)
|
||||
# --package-only zip game.love + apply branding; skip gradle
|
||||
# --version X.Y.Z set app.version_name / app.version_code (else left as-is)
|
||||
# --package-only zip game.love + apply branding; skip gradle
|
||||
#
|
||||
# Prerequisites:
|
||||
# - mobile/android vendored love-android tree at tag 11.5a (in-repo; see mobile/ANDROID.md)
|
||||
@@ -13,9 +12,8 @@
|
||||
# - JDK 17
|
||||
#
|
||||
# Output (after gradle):
|
||||
# dist/android/{debug,release}/*.apk (convenience copy)
|
||||
# dist/android/debug/*.apk (convenience copy)
|
||||
# mobile/android/app/build/outputs/apk/embedNoRecord/debug/*.apk
|
||||
# mobile/android/app/build/outputs/apk/embedNoRecord/release/*.apk
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -29,7 +27,7 @@ APPLICATION_ID="com.theboisclub.pokemonred"
|
||||
LOVE_ANDROID_VERSION="11.5a"
|
||||
NDK_VERSION="25.2.9519653"
|
||||
|
||||
RELEASE=false
|
||||
VERSION=""
|
||||
PACKAGE_ONLY=false
|
||||
|
||||
say() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
|
||||
@@ -38,17 +36,29 @@ fail() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--release) RELEASE=true ;;
|
||||
--version) VERSION="$2"; shift ;;
|
||||
--package-only) PACKAGE_ONLY=true ;;
|
||||
-h|--help)
|
||||
sed -n '2,20p' "$0"
|
||||
exit 0
|
||||
;;
|
||||
*) fail "unknown argument: $1 (try --release or --package-only)" ;;
|
||||
*) fail "unknown argument: $1 (try --version X.Y.Z or --package-only)" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
VERSION_CODE=""
|
||||
if [ -n "$VERSION" ]; then
|
||||
if ! printf '%s' "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
|
||||
fail "invalid --version '$VERSION' (expected X.Y.Z)"
|
||||
fi
|
||||
major="${VERSION%%.*}"
|
||||
rest="${VERSION#*.}"
|
||||
minor="${rest%%.*}"
|
||||
patch="${rest##*.}"
|
||||
VERSION_CODE=$((major * 10000 + minor * 100 + patch))
|
||||
fi
|
||||
|
||||
# --------------------------------------------------------------- preconditions
|
||||
if [ ! -f "$ANDROID_DIR/settings.gradle" ] || [ ! -f "$ANDROID_DIR/gradlew" ]; then
|
||||
fail "love-android not found at mobile/android/.
|
||||
@@ -74,10 +84,10 @@ apply_android_branding() {
|
||||
|
||||
say "applying Android branding (gradle.properties + permission trim)"
|
||||
|
||||
python3 - "$props" "$APPLICATION_ID" "$APP_NAME" <<'PY'
|
||||
python3 - "$props" "$APPLICATION_ID" "$APP_NAME" "$VERSION" "$VERSION_CODE" <<'PY'
|
||||
import pathlib, re, sys
|
||||
path = pathlib.Path(sys.argv[1])
|
||||
app_id, name = sys.argv[2], sys.argv[3]
|
||||
app_id, name, version, version_code = sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]
|
||||
text = path.read_text()
|
||||
|
||||
def set_prop(text, key, value):
|
||||
@@ -92,6 +102,9 @@ text = re.sub(r"(?m)^app\.name_byte_array=.*\n?", "", text)
|
||||
text = set_prop(text, "app.name", name)
|
||||
text = set_prop(text, "app.application_id", app_id)
|
||||
text = set_prop(text, "app.orientation", "portrait")
|
||||
if version:
|
||||
text = set_prop(text, "app.version_name", version)
|
||||
text = set_prop(text, "app.version_code", version_code)
|
||||
path.write_text(text)
|
||||
PY
|
||||
|
||||
@@ -178,16 +191,8 @@ require_android_sdk() {
|
||||
|
||||
# --------------------------------------------------------------- gradle
|
||||
run_gradle() {
|
||||
local task
|
||||
if $RELEASE; then
|
||||
task="assembleEmbedNoRecordRelease"
|
||||
say "building release APK ($task)"
|
||||
warn "release signing is out-of-band, see mobile/ANDROID.md (Signing)."
|
||||
warn "without a signingConfig, assembleRelease may produce an unsigned APK or fail."
|
||||
else
|
||||
task="assembleEmbedNoRecordDebug"
|
||||
say "building debug APK ($task), uses the default Android debug keystore"
|
||||
fi
|
||||
local task="assembleEmbedNoRecordDebug"
|
||||
say "building APK ($task)"
|
||||
|
||||
if ! (
|
||||
cd "$ANDROID_DIR"
|
||||
@@ -199,19 +204,12 @@ run_gradle() {
|
||||
You can still iterate on the .love payload with: scripts/build_android.sh --package-only"
|
||||
fi
|
||||
|
||||
local out_dir
|
||||
if $RELEASE; then
|
||||
out_dir="$ANDROID_DIR/app/build/outputs/apk/embedNoRecord/release"
|
||||
else
|
||||
out_dir="$ANDROID_DIR/app/build/outputs/apk/embedNoRecord/debug"
|
||||
fi
|
||||
local out_dir="$ANDROID_DIR/app/build/outputs/apk/embedNoRecord/debug"
|
||||
if [ -d "$out_dir" ]; then
|
||||
say "APK output:"
|
||||
find "$out_dir" -name '*.apk' -exec ls -lh {} \;
|
||||
|
||||
local flavor="debug"
|
||||
$RELEASE && flavor="release"
|
||||
local dist_dir="$DIST/$flavor"
|
||||
local dist_dir="$DIST/debug"
|
||||
rm -rf "$dist_dir"
|
||||
mkdir -p "$dist_dir"
|
||||
find "$out_dir" -name '*.apk' -exec cp {} "$dist_dir/" \;
|
||||
|
||||
Reference in New Issue
Block a user