""" 经 SSH 在 Ubuntu 上用 adb 安装主包 + FL-Xposed 模块,并做 ROOT / Xposed 环境探测与启动主界面。 需该主机已 usb 连接设备且 adb devices 可见;APK 默认 ~/gps_build_artifacts。 环境变量: FL_SSH_PASS;或 gps 目录 fl_ssh_pass.txt(单行,已 .gitignore) 可选: FL_SKIP_BUILD=1 不同步、不编译,仅安装已有 APK """ import os import subprocess import sys import paramiko from _gps_ssh_auth import ssh_password HOST = "192.168.2.179" USER = "eric" GPS_ROOT = os.path.dirname(os.path.abspath(__file__)) REBUILT = os.path.join(GPS_ROOT, "rebuilt_app") TGZ = os.path.join(GPS_ROOT, "rebuilt_sync.tgz") REMOTE_PROJ = "/home/eric/codex_apk_recovery/rebuilt_app" REMOTE_TGZ = "/home/eric/rebuilt_sync.tgz" REMOTE_BUILD_AND_INSTALL = r"""set -e export ANDROID_HOME="${ANDROID_HOME:-$HOME/android-sdk}" if [[ -d /usr/lib/jvm/java-17-openjdk-amd64 ]]; then export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 fi cd /tmp rm -rf rebuilt_app tar xzf """ + REMOTE_TGZ + r""" rm -rf /home/eric/codex_apk_recovery/rebuilt_app mv rebuilt_app /home/eric/codex_apk_recovery/rebuilt_app chmod +x /home/eric/codex_apk_recovery/rebuilt_app/gradlew chmod +x /home/eric/codex_apk_recovery/rebuilt_app/scripts/adb_device_autosetup.sh bash /home/eric/codex_apk_recovery/rebuilt_app/scripts/ubuntu_gps_pipeline.sh """ REMOTE_INSTALL_ONLY = r"""set -e OUT="${GPS_ARTIFACT_DIR:-$HOME/gps_build_artifacts}" MAIN="$OUT/fakelocation-gps-debug.apk" XP="$OUT/FL-Xposed-gps-debug.apk" if [[ ! -f "$MAIN" || ! -f "$XP" ]]; then echo "Missing APK: $MAIN or $XP" exit 3 fi pick_serial() { adb devices | awk 'NR>1 && $2=="device" && $1 !~ /^emulator/ && $1 !~ /^127/ && $1 !~ /^localhost/ {print $1; exit}' } S=$(pick_serial) if [[ -z "$S" ]]; then echo "No USB adb device (authorized)." exit 4 fi echo "== device: $S ==" adb -s "$S" uninstall com.lerist.fakelocation 2>/dev/null || true adb -s "$S" uninstall com.lerist.fakelocation.common.xposed 2>/dev/null || true adb -s "$S" install -r "$MAIN" adb -s "$S" install -r "$XP" SETUP="/home/eric/codex_apk_recovery/rebuilt_app/scripts/adb_device_autosetup.sh" if [[ -f "$SETUP" ]]; then chmod +x "$SETUP" bash "$SETUP" "$S" else echo "Missing $SETUP — run full deploy once without FL_SKIP_BUILD" exit 5 fi echo "== done ==" """ def _ssh_run(client: paramiko.SSHClient, script: str, timeout: int = 900) -> int: stdin, stdout, stderr = client.exec_command(script, get_pty=True, timeout=timeout) for line in stdout: sys.stdout.write(line) err = stderr.read().decode(errors="replace") if err.strip(): sys.stderr.write(err) return stdout.channel.recv_exit_status() def main(): if hasattr(sys.stdout, "reconfigure"): try: sys.stdout.reconfigure(encoding="utf-8", errors="replace") except Exception: pass password = ssh_password(GPS_ROOT) if not password: print("Set FL_SSH_PASS or create fl_ssh_pass.txt in", GPS_ROOT, file=sys.stderr) sys.exit(2) skip = os.environ.get("FL_SKIP_BUILD", "").strip().lower() in ("1", "true", "yes", "on") client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(HOST, username=USER, password=password, timeout=45) if skip: code = _ssh_run(client, REMOTE_INSTALL_ONLY, timeout=120) else: if not os.path.isdir(REBUILT): print("Missing rebuilt_app", file=sys.stderr) sys.exit(2) subprocess.run( [ "tar", "-czf", TGZ, "--exclude=rebuilt_app/.gradle", "--exclude=rebuilt_app/app/build", "--exclude=rebuilt_app/build", "--exclude=rebuilt_app/fl_xposed/build", "rebuilt_app", ], cwd=GPS_ROOT, check=True, ) t = paramiko.Transport((HOST, 22)) t.connect(username=USER, password=password) sftp = paramiko.SFTPClient.from_transport(t) sftp.put(TGZ, REMOTE_TGZ) sftp.close() t.close() code = _ssh_run(client, REMOTE_BUILD_AND_INSTALL, timeout=900) client.close() sys.exit(code) if __name__ == "__main__": main()