Forked from raphendyr/sailfish_install_google_services.md
Last active
February 9, 2026 21:09
-
-
Save lkraav/cde72215adfe0898f12798989f9606d8 to your computer and use it in GitHub Desktop.
Google Play Services installation to Sailfish X
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # | |
| # Install Google Apps into Sailfish OS AppSupport via bind-mounts. | |
| # Based on raphendyr's guide, updated for SFOS 5.0 / Android 13. | |
| # | |
| # Instead of patching system.img, this populates /opt/gapps-for-appsupport/ and | |
| # hooks into the AppSupport LXC container to bind-mount /product and | |
| # /system/system_ext at startup. Survives SFOS updates; uninstall by | |
| # removing the hook symlink. | |
| # | |
| set -e | |
| GAPPS_DIR=/opt/gapps-for-appsupport | |
| HOOK_DIR=/etc/appsupport.conf.d/init/prepare-hook.d | |
| SYSTEM_IMG=/opt/appsupport/system.img | |
| MINDTHEGAPPS_PATTERN='MindTheGapps-13.0.0-arm64-*.zip' | |
| log() { | |
| printf '%s\n' "$1" >&2 | |
| } | |
| find_mindthegapps_zip() { | |
| local downloads=/home/defaultuser/Downloads | |
| log "Searching for $MINDTHEGAPPS_PATTERN in $downloads" | |
| find "$downloads" -maxdepth 1 -name "$MINDTHEGAPPS_PATTERN" | sort | tail -n 1 | |
| } | |
| install() { | |
| local zip="$1" | |
| local tmp | |
| tmp="$(mktemp -d)" | |
| # shellcheck disable=SC2064 | |
| trap "rm -rf '$tmp'" EXIT | |
| log "Extracting MindTheGapps" | |
| unzip -q -o "$zip" 'system/*' -d "$tmp" | |
| # ── product ────────────────────────────────────────────────── | |
| # Stock /product is empty; we own it entirely. | |
| # | |
| # Strip non-essential bloat (the three largest after GmsCore): | |
| rm -rf "$tmp/system/product/priv-app/VelvetTitan" | |
| rm -rf "$tmp/system/product/priv-app/Velvet" | |
| rm -rf "$tmp/system/product/app/SpeechServicesByGoogle" | |
| rm -rf "$tmp/system/product/app/talkback" | |
| rm -rf "$tmp/system/product/app/MarkupGoogle" | |
| rm -rf "$tmp/system/product/priv-app/AndroidAutoStub" | |
| # addon.d is for Android recovery OTA survival, not needed here | |
| rm -rf "$tmp/system/addon.d" | |
| rm -rf "$GAPPS_DIR/product" | |
| cp -a "$tmp/system/product" "$GAPPS_DIR/product" | |
| # ── system_ext ─────────────────────────────────────────────── | |
| # Stock /system/system_ext has HAL libs, VINTF manifest, and | |
| # build.prop that must be preserved. Our merge script copies | |
| # stock first, then overlays MindTheGapps on top. | |
| # Save GApps system_ext overlay for boot-time re-merge. | |
| rm -rf "$GAPPS_DIR/system_ext.gapps" | |
| cp -a "$tmp/system/system_ext" "$GAPPS_DIR/system_ext.gapps" | |
| chown -R appsupport-root:appsupport-root "$GAPPS_DIR/system_ext.gapps" | |
| # Initial merge (--force: no stamp yet). | |
| "$GAPPS_DIR/merge-system-ext.sh" --force | |
| # ── ownership ──────────────────────────────────────────────── | |
| chown -R appsupport-root:appsupport-root "$GAPPS_DIR/product" | |
| rm -rf "$tmp" | |
| trap - EXIT | |
| } | |
| deploy_merge_script() { | |
| cat > "$GAPPS_DIR/merge-system-ext.sh" <<MERGE | |
| #!/bin/sh | |
| # | |
| # Merge stock system_ext with GApps overlay. | |
| # Skips work when system.img hasn't changed (stat-based stamp). | |
| # | |
| # Usage: merge-system-ext.sh [--force] | |
| # | |
| set -e | |
| GAPPS_DIR=$GAPPS_DIR | |
| SYSTEM_IMG=$SYSTEM_IMG | |
| STAMP="\$GAPPS_DIR/.system_img.stamp" | |
| force=false | |
| [ "\${1-}" = "--force" ] && force=true | |
| cur_stat=\$(stat -c '%s %Y' "\$SYSTEM_IMG") | |
| old_stat=\$(cat "\$STAMP" 2>/dev/null || true) | |
| if [ "\$force" = true ] || [ "\$cur_stat" != "\$old_stat" ]; then | |
| echo "Merging stock system_ext with GApps overlay" >&2 | |
| tmp=\$(mktemp -d) | |
| mount -o loop,ro "\$SYSTEM_IMG" "\$tmp" | |
| rm -rf "\$GAPPS_DIR/system_ext" | |
| cp -a "\$tmp/system/system_ext" "\$GAPPS_DIR/system_ext" | |
| umount "\$tmp" | |
| rmdir "\$tmp" | |
| cp -a "\$GAPPS_DIR/system_ext.gapps/." "\$GAPPS_DIR/system_ext/" | |
| chown -R appsupport-root:appsupport-root "\$GAPPS_DIR/system_ext" | |
| echo "\$cur_stat" > "\$STAMP" | |
| fi | |
| MERGE | |
| chmod +x "$GAPPS_DIR/merge-system-ext.sh" | |
| } | |
| create_hook() { | |
| cat > "$GAPPS_DIR/prepare-hook.sh" <<EOF | |
| #!/bin/sh | |
| # Boot-time hook for GApps in AppSupport. | |
| # Re-merges stock system_ext with GApps overlay only when system.img changes. | |
| $GAPPS_DIR/merge-system-ext.sh | |
| cat >> "\$CONTAINER_CONFIG_PATH/41-gapps_config" <<CONF | |
| lxc.mount.entry = $GAPPS_DIR/product product none rbind,nodev,nosuid,ro,create=dir 0 0 | |
| lxc.mount.entry = $GAPPS_DIR/system_ext system/system_ext none rbind,nodev,nosuid,ro,create=dir 0 0 | |
| CONF | |
| EOF | |
| chmod +x "$GAPPS_DIR/prepare-hook.sh" | |
| mkdir -p "$HOOK_DIR" | |
| ln -sf "$GAPPS_DIR/prepare-hook.sh" \ | |
| "$HOOK_DIR/61-gapps-for-appsupport.sh" | |
| } | |
| # ── main ───────────────────────────────────────────────────────── | |
| if [ "$(id -u)" -ne 0 ]; then | |
| log "Run as root (devel-su)" | |
| exit 1 | |
| fi | |
| zip="$(find_mindthegapps_zip)" | |
| if [ -z "$zip" ]; then | |
| log "MindTheGapps zip not found. Download from https://wiki.lineageos.org/gapps" | |
| exit 1 | |
| fi | |
| log "Using $zip" | |
| mkdir -p "$GAPPS_DIR" | |
| systemctl stop appsupport@defaultuser 2>/dev/null || true | |
| deploy_merge_script | |
| install "$zip" | |
| create_hook | |
| log "" | |
| log "Done. Start AppSupport — first boot will be slow (dex compilation)." | |
| log "Monitor with: appsupport-attach /system/bin/logcat" | |
| log "" | |
| log "To uninstall:" | |
| log " rm $HOOK_DIR/61-gapps-for-appsupport.sh # disable" | |
| log " rm -rf $GAPPS_DIR # remove data" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment