Release 3.8.2.13: iOS Packet Tunnel client and Clash URL subscriptions.
Add SwiftUI + Network Extension (LibXray/hev), parse Clash Meta YAML from subscription URLs into vless/trojan/hy2 share links, keep the selected server on connect, and ship Navis-3.8.2.13.ipa with versioned changelog. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Executable
+184
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build Navis iOS device IPA (+ optional simulator zip).
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/build-ios.sh
|
||||
# # device IPA (unsigned if no Team) + simulator zip
|
||||
# NAVIS_IOS_TEAM_ID=XXXXXXXXXX ./scripts/build-ios.sh
|
||||
# # signed archive + exported IPA
|
||||
# NAVIS_IOS_SKIP_SIMULATOR=1 ./scripts/build-ios.sh
|
||||
# # device only
|
||||
#
|
||||
# Optional:
|
||||
# NAVIS_IOS_SIGN_IDENTITY="Apple Development: …"
|
||||
# NAVIS_IOS_EXPORT_METHOD=development|ad-hoc|enterprise|app-store
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
IOS="$ROOT/ios"
|
||||
OUT="$ROOT/dist/navis-release/ios"
|
||||
PROJECT="$IOS/Navis.xcodeproj"
|
||||
SCHEME=Navis
|
||||
CONFIG=Release
|
||||
|
||||
# Keep VERSION_FULL in sync with internal/update/update.go (also via sync-version.py).
|
||||
VERSION_FULL="$(
|
||||
python3 - <<PY
|
||||
import re
|
||||
from pathlib import Path
|
||||
text = Path(r"$ROOT/internal/update/update.go").read_text(encoding="utf-8")
|
||||
ver = re.search(r'CurrentVersion\s*=\s*"([^"]+)"', text).group(1)
|
||||
build = re.search(r"const BuildNumber\s*=\s*(\d+)", text).group(1)
|
||||
print(f"{ver}.{build}")
|
||||
PY
|
||||
)"
|
||||
# Fail early if parsing broke.
|
||||
[[ "$VERSION_FULL" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] || {
|
||||
echo "failed to parse version from update.go" >&2
|
||||
exit 1
|
||||
}
|
||||
echo "==> Navis iOS build $VERSION_FULL"
|
||||
|
||||
# Ensure Info.plist stays aligned with update.go.
|
||||
python3 "$ROOT/scripts/sync-version.py"
|
||||
|
||||
# Ensure LibXray + Hev are present
|
||||
"$ROOT/scripts/fetch-ios-cores.sh"
|
||||
|
||||
mkdir -p "$OUT"
|
||||
find "$OUT" -mindepth 1 -maxdepth 1 ! -name '.gitkeep' -exec rm -rf {} +
|
||||
|
||||
TEAM="${NAVIS_IOS_TEAM_ID:-}"
|
||||
EXPORT_METHOD="${NAVIS_IOS_EXPORT_METHOD:-development}"
|
||||
DERIVED="${TMPDIR:-/tmp}/navis-ios-derived"
|
||||
rm -rf "$DERIVED"
|
||||
mkdir -p "$DERIVED"
|
||||
|
||||
package_ipa() {
|
||||
local app_path="$1"
|
||||
local ipa_path="$2"
|
||||
local stage
|
||||
stage="$(mktemp -d)"
|
||||
mkdir -p "$stage/Payload"
|
||||
ditto "$app_path" "$stage/Payload/Navis.app"
|
||||
(
|
||||
cd "$stage"
|
||||
zip -qry "$ipa_path" Payload
|
||||
)
|
||||
rm -rf "$stage"
|
||||
}
|
||||
|
||||
# --- Device (iphoneos) ---
|
||||
echo "==> Building iOS device ($CONFIG, sdk=iphoneos)"
|
||||
DEV_ARGS=(
|
||||
-project "$PROJECT"
|
||||
-scheme "$SCHEME"
|
||||
-configuration "$CONFIG"
|
||||
-destination "generic/platform=iOS"
|
||||
-derivedDataPath "$DERIVED"
|
||||
-sdk iphoneos
|
||||
ONLY_ACTIVE_ARCH=NO
|
||||
)
|
||||
if [[ -n "$TEAM" ]]; then
|
||||
DEV_ARGS+=(DEVELOPMENT_TEAM="$TEAM")
|
||||
if [[ -n "${NAVIS_IOS_SIGN_IDENTITY:-}" ]]; then
|
||||
DEV_ARGS+=(CODE_SIGN_IDENTITY="$NAVIS_IOS_SIGN_IDENTITY")
|
||||
fi
|
||||
echo "==> Archiving (Team=$TEAM)"
|
||||
ARCHIVE="$OUT/Navis.xcarchive"
|
||||
xcodebuild "${DEV_ARGS[@]}" -archivePath "$ARCHIVE" archive
|
||||
|
||||
EXPORT_PLIST="$OUT/ExportOptions.plist"
|
||||
cat >"$EXPORT_PLIST" <<EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>method</key>
|
||||
<string>${EXPORT_METHOD}</string>
|
||||
<key>teamID</key>
|
||||
<string>${TEAM}</string>
|
||||
<key>signingStyle</key>
|
||||
<string>automatic</string>
|
||||
<key>compileBitcode</key>
|
||||
<false/>
|
||||
<key>stripSwiftSymbols</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
EXPORT_DIR="$OUT/export"
|
||||
rm -rf "$EXPORT_DIR"
|
||||
mkdir -p "$EXPORT_DIR"
|
||||
echo "==> Exporting signed IPA (method=$EXPORT_METHOD)"
|
||||
xcodebuild -exportArchive \
|
||||
-archivePath "$ARCHIVE" \
|
||||
-exportPath "$EXPORT_DIR" \
|
||||
-exportOptionsPlist "$EXPORT_PLIST"
|
||||
|
||||
IPA="$(find "$EXPORT_DIR" -name '*.ipa' | head -n1 || true)"
|
||||
if [[ -n "${IPA:-}" ]]; then
|
||||
cp "$IPA" "$OUT/Navis-${VERSION_FULL}.ipa"
|
||||
cp "$IPA" "$OUT/Navis.ipa"
|
||||
echo "wrote $OUT/Navis-${VERSION_FULL}.ipa (signed)"
|
||||
else
|
||||
echo "error: signed export produced no .ipa" >&2
|
||||
ls -la "$EXPORT_DIR" || true
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
DEV_ARGS+=(
|
||||
CODE_SIGNING_ALLOWED=NO
|
||||
CODE_SIGNING_REQUIRED=NO
|
||||
CODE_SIGN_IDENTITY=-
|
||||
EXPAND_SDK_VARIABLES=YES
|
||||
)
|
||||
xcodebuild "${DEV_ARGS[@]}" build
|
||||
|
||||
DEV_APP="$(find "$DERIVED/Build/Products" -path '*iphoneos/Navis.app' -type d | head -n1 || true)"
|
||||
if [[ -z "${DEV_APP:-}" || ! -d "$DEV_APP" ]]; then
|
||||
echo "error: device Navis.app not found under $DERIVED" >&2
|
||||
find "$DERIVED/Build/Products" -name 'Navis.app' -type d 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp -R "$DEV_APP" "$OUT/Navis-device.app"
|
||||
package_ipa "$DEV_APP" "$OUT/Navis-${VERSION_FULL}.ipa"
|
||||
cp "$OUT/Navis-${VERSION_FULL}.ipa" "$OUT/Navis.ipa"
|
||||
echo "wrote $OUT/Navis-device.app"
|
||||
echo "wrote $OUT/Navis-${VERSION_FULL}.ipa (UNSIGNED — re-sign before install)"
|
||||
echo "wrote $OUT/Navis.ipa"
|
||||
fi
|
||||
|
||||
# --- Simulator (optional) ---
|
||||
if [[ "${NAVIS_IOS_SKIP_SIMULATOR:-}" != "1" ]]; then
|
||||
echo "==> Building iOS Simulator ($CONFIG)"
|
||||
SIM_ARGS=(
|
||||
-project "$PROJECT"
|
||||
-scheme "$SCHEME"
|
||||
-configuration "$CONFIG"
|
||||
-destination "generic/platform=iOS Simulator"
|
||||
-derivedDataPath "$DERIVED"
|
||||
ONLY_ACTIVE_ARCH=NO
|
||||
)
|
||||
if [[ -n "$TEAM" ]]; then
|
||||
SIM_ARGS+=(DEVELOPMENT_TEAM="$TEAM")
|
||||
else
|
||||
SIM_ARGS+=(CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO)
|
||||
fi
|
||||
xcodebuild "${SIM_ARGS[@]}" build
|
||||
|
||||
SIM_APP="$(find "$DERIVED/Build/Products" -path '*iphonesimulator/Navis.app' -type d | head -n1 || true)"
|
||||
if [[ -n "${SIM_APP:-}" && -d "$SIM_APP" ]]; then
|
||||
cp -R "$SIM_APP" "$OUT/Navis-simulator.app"
|
||||
(
|
||||
cd "$OUT"
|
||||
ditto -c -k --sequesterRsrc --keepParent Navis-simulator.app "Navis-${VERSION_FULL}-simulator.app.zip"
|
||||
)
|
||||
echo "wrote $OUT/Navis-simulator.app"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "done → $OUT"
|
||||
ls -lh "$OUT"/*.ipa "$OUT"/*.app 2>/dev/null || ls -lh "$OUT"
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Increment BuildNumber in update.go, then sync versioninfo / macOS bat / Android."""
|
||||
"""Increment BuildNumber in update.go, then sync versioninfo / macOS bat / Android / iOS."""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
# Fetch prebuilt LibXray + HevSocks5Tunnel into ios/Vendor.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
VENDOR="$ROOT/ios/Vendor"
|
||||
mkdir -p "$VENDOR"
|
||||
cd "$VENDOR"
|
||||
|
||||
LIBXRAY_VER="${NAVIS_LIBXRAY_VERSION:-26.7.28}"
|
||||
HEV_VER="${NAVIS_HEV_VERSION:-2.10.0}"
|
||||
|
||||
if [[ ! -d LibXray.xcframework ]]; then
|
||||
echo "==> LibXray $LIBXRAY_VER"
|
||||
curl -fsSL -o LibXray.xcframework.zip \
|
||||
"https://github.com/wanliyunyan/LibXray/releases/download/${LIBXRAY_VER}/LibXray.xcframework.zip"
|
||||
unzip -qo LibXray.xcframework.zip
|
||||
rm -f LibXray.xcframework.zip
|
||||
else
|
||||
echo "LibXray.xcframework present"
|
||||
fi
|
||||
|
||||
if [[ ! -d HevSocks5Tunnel.xcframework ]]; then
|
||||
echo "==> HevSocks5Tunnel $HEV_VER"
|
||||
curl -fsSL -o HevSocks5Tunnel.xcframework.zip \
|
||||
"https://github.com/wanliyunyan/HevSocks5Tunnel/releases/download/${HEV_VER}/HevSocks5Tunnel.xcframework.zip"
|
||||
unzip -qo HevSocks5Tunnel.xcframework.zip
|
||||
rm -f HevSocks5Tunnel.xcframework.zip
|
||||
else
|
||||
echo "HevSocks5Tunnel.xcframework present"
|
||||
fi
|
||||
|
||||
echo "Vendor ready:"
|
||||
ls -d *.xcframework
|
||||
@@ -12,6 +12,11 @@ VERSIONINFO = ROOT / "versioninfo.json"
|
||||
BUILD_BAT = ROOT / "build-macos.bat"
|
||||
ANDROID_GRADLE = ROOT / "android" / "app" / "build.gradle.kts"
|
||||
INDEX_HTML = ROOT / "internal" / "appui" / "index.html"
|
||||
IOS_README = ROOT / "ios" / "README.md"
|
||||
IOS_PLISTS = (
|
||||
ROOT / "ios" / "Navis" / "Info.plist",
|
||||
ROOT / "ios" / "NavisTunnel" / "Info.plist",
|
||||
)
|
||||
|
||||
|
||||
def read_consts() -> tuple[str, int]:
|
||||
@@ -77,6 +82,42 @@ def main() -> None:
|
||||
else:
|
||||
print("index.html badge already in sync")
|
||||
|
||||
for plist in IOS_PLISTS:
|
||||
if not plist.exists():
|
||||
continue
|
||||
p = plist.read_text(encoding="utf-8")
|
||||
p2 = re.sub(
|
||||
r"(<key>CFBundleShortVersionString</key>\s*<string>)[^<]+",
|
||||
rf"\g<1>{ver}",
|
||||
p,
|
||||
count=1,
|
||||
)
|
||||
p2 = re.sub(
|
||||
r"(<key>CFBundleVersion</key>\s*<string>)[^<]+",
|
||||
rf"\g<1>{full}",
|
||||
p2,
|
||||
count=1,
|
||||
)
|
||||
if p2 != p:
|
||||
plist.write_text(p2, encoding="utf-8")
|
||||
print("updated", plist, "->", ver, full)
|
||||
else:
|
||||
print(plist.name, "already in sync")
|
||||
|
||||
if IOS_README.exists():
|
||||
r = IOS_README.read_text(encoding="utf-8")
|
||||
r2 = re.sub(
|
||||
r"(Версия:\s*\*\*)[^*]+(\*\*)",
|
||||
rf"\g<1>{display}\2",
|
||||
r,
|
||||
count=1,
|
||||
)
|
||||
if r2 != r:
|
||||
IOS_README.write_text(r2, encoding="utf-8")
|
||||
print("updated", IOS_README, "->", display)
|
||||
else:
|
||||
print("ios/README.md already in sync")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user