NetDesk 1.5.0 — source release
This commit is contained in:
commit
40318aafdd
227 files changed
+80798
No files matched your search
@@ -0,0 +1,241 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# NetDesk by Akronlogic -- iOS build (Flutter + Rust core).
|
||||
#
|
||||
# Runs on macOS ONLY (needs Xcode + the iOS SDKs). It:
|
||||
# 1. adds the Rust iOS targets (aarch64-apple-ios + aarch64-apple-ios-sim)
|
||||
# 2. builds the Rust core static lib for device AND simulator
|
||||
# 3. assembles NetDeskCore.xcframework (xcodebuild -create-xcframework)
|
||||
# 4. ensures ui/ios/ exists (flutter create --platforms=ios .)
|
||||
# 5. wires the xcframework into the Flutter iOS project (CocoaPods podspec)
|
||||
# 6. flutter build ipa (signed with your Apple team)
|
||||
#
|
||||
# The Rust FFI static lib comes from the workspace `core` crate
|
||||
# (package netdesk-core, lib netdesk_core -> libnetdesk_core.a). When the
|
||||
# Phase-3 flutter_rust_bridge wrapper crate lands under a different name
|
||||
# (e.g. "netdesk-frb"), point the script at it with:
|
||||
# CORE_CRATE=netdesk-frb LIB_NAME=netdesk_frb ./build-ios.sh ...
|
||||
#
|
||||
# See docs/build-ios.md for prerequisites (Apple Developer Program, signing
|
||||
# cert + provisioning profile) and the full walkthrough.
|
||||
#
|
||||
# Usage:
|
||||
# packaging/build-ios.sh --team ABCDE12345
|
||||
# packaging/build-ios.sh --team ABCDE12345 --method ad-hoc --org com.akronlogic
|
||||
# packaging/build-ios.sh --skip-ipa # just build the xcframework
|
||||
# packaging/build-ios.sh --help
|
||||
#
|
||||
# Env overrides: CORE_CRATE LIB_NAME DEVICE_TARGET SIM_TARGET IOS_MIN
|
||||
# FLUTTER TEAM_ID EXPORT_METHOD FLUTTER_ORG
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
# ---- configuration (env-overridable) ---------------------------------------
|
||||
CORE_CRATE="${CORE_CRATE:-netdesk-core}" # cargo package to build
|
||||
LIB_NAME="${LIB_NAME:-netdesk_core}" # -> lib<LIB_NAME>.a
|
||||
DEVICE_TARGET="${DEVICE_TARGET:-aarch64-apple-ios}"
|
||||
SIM_TARGET="${SIM_TARGET:-aarch64-apple-ios-sim}" # Intel Macs: x86_64-apple-ios
|
||||
IOS_MIN="${IOS_MIN:-13.0}"
|
||||
FLUTTER="${FLUTTER:-flutter}"
|
||||
FLUTTER_ORG="${FLUTTER_ORG:-space.netdesk}" # -> bundle id <org>.netdesk
|
||||
EXPORT_METHOD="${EXPORT_METHOD:-app-store}" # app-store | ad-hoc | development | enterprise
|
||||
TEAM_ID="${TEAM_ID:-${DEVELOPMENT_TEAM:-}}" # 10-char Apple Team ID
|
||||
XCFRAMEWORK="NetDeskCore.xcframework"
|
||||
|
||||
SKIP_IPA=0
|
||||
|
||||
# ---- args ------------------------------------------------------------------
|
||||
usage() { sed -n '3,29p' "$0" | sed 's/^# \{0,1\}//'; exit "${1:-0}"; }
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--team) TEAM_ID="${2:?--team needs an Apple Team ID}"; shift 2 ;;
|
||||
--method) EXPORT_METHOD="${2:?--method needs a value}"; shift 2 ;;
|
||||
--org) FLUTTER_ORG="${2:?--org needs a value}"; shift 2 ;;
|
||||
--skip-ipa|--xcframework-only) SKIP_IPA=1; shift ;;
|
||||
-h|--help) usage 0 ;;
|
||||
*) echo "unknown argument: $1" >&2; usage 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ---- paths -----------------------------------------------------------------
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
UI="$ROOT/ui"
|
||||
IOSDIR="$UI/ios"
|
||||
TEMPLATES="$SCRIPT_DIR/ios"
|
||||
DIST="$SCRIPT_DIR/dist/ios"
|
||||
DEV_LIB="$ROOT/target/$DEVICE_TARGET/release/lib$LIB_NAME.a"
|
||||
SIM_LIB="$ROOT/target/$SIM_TARGET/release/lib$LIB_NAME.a"
|
||||
|
||||
say() { printf '\033[36m==> %s\033[0m\n' "$*"; }
|
||||
ok() { printf '\033[32m %s\033[0m\n' "$*"; }
|
||||
die() { printf '\033[31mERROR: %s\033[0m\n' "$*" >&2; exit 1; }
|
||||
|
||||
cat <<BANNER
|
||||
=== NetDesk iOS build (Akronlogic) ===
|
||||
root : $ROOT
|
||||
crate : $CORE_CRATE (lib$LIB_NAME.a)
|
||||
targets: $DEVICE_TARGET + $SIM_TARGET
|
||||
flutter: $FLUTTER org: $FLUTTER_ORG ios-min: $IOS_MIN
|
||||
ipa : $([ "$SKIP_IPA" = 1 ] && echo "SKIPPED (--skip-ipa)" || echo "method=$EXPORT_METHOD team=${TEAM_ID:-<unset>}")
|
||||
BANNER
|
||||
|
||||
# ---- 0. preflight ----------------------------------------------------------
|
||||
say "0/6 preflight"
|
||||
[ "$(uname -s)" = "Darwin" ] || die "iOS builds require macOS. Run this on the Mac."
|
||||
command -v rustup >/dev/null || die "rustup not found. Install Rust: https://rustup.rs"
|
||||
command -v cargo >/dev/null || die "cargo not found on PATH (try: source \$HOME/.cargo/env)"
|
||||
command -v xcrun >/dev/null || die "xcrun not found. Install Xcode + command line tools (xcode-select --install)."
|
||||
xcode-select -p >/dev/null 2>&1 || die "no active Xcode. Run: sudo xcode-select -s /Applications/Xcode.app"
|
||||
command -v "$FLUTTER" >/dev/null || die "flutter not found. Install the Flutter SDK and add it to PATH (or set FLUTTER=/path/to/flutter)."
|
||||
if [ "$SKIP_IPA" = 0 ] && [ -z "$TEAM_ID" ]; then
|
||||
die "no Apple Team ID. Pass --team ABCDE12345 (or TEAM_ID=...), or use --skip-ipa to only build the xcframework."
|
||||
fi
|
||||
ok "macOS $(sw_vers -productVersion 2>/dev/null || true), Xcode $(xcodebuild -version 2>/dev/null | head -1 || true)"
|
||||
|
||||
# ---- 1. rust ios targets ---------------------------------------------------
|
||||
say "1/6 rustup targets"
|
||||
rustup target add "$DEVICE_TARGET" "$SIM_TARGET"
|
||||
ok "$DEVICE_TARGET, $SIM_TARGET installed"
|
||||
|
||||
# ---- 2. build the rust core static lib for both targets --------------------
|
||||
say "2/6 cargo build (release, staticlib) for device + simulator"
|
||||
# Match Flutter's deployment target so the slices are link-compatible.
|
||||
export IPHONEOS_DEPLOYMENT_TARGET="$IOS_MIN"
|
||||
( cd "$ROOT" && cargo build --release -p "$CORE_CRATE" --target "$DEVICE_TARGET" )
|
||||
( cd "$ROOT" && cargo build --release -p "$CORE_CRATE" --target "$SIM_TARGET" )
|
||||
[ -f "$DEV_LIB" ] || die "expected device lib not found: $DEV_LIB"
|
||||
[ -f "$SIM_LIB" ] || die "expected simulator lib not found: $SIM_LIB"
|
||||
ok "device: $DEV_LIB"
|
||||
ok "sim : $SIM_LIB"
|
||||
|
||||
# ---- 3. assemble the xcframework -------------------------------------------
|
||||
say "3/6 assemble $XCFRAMEWORK"
|
||||
mkdir -p "$DIST"
|
||||
rm -rf "$DIST/$XCFRAMEWORK" # xcodebuild refuses to overwrite
|
||||
# No -headers yet: the C ABI header (cbindgen over core/src/ffi.rs) is Phase 3.
|
||||
# When it exists, add: -headers "$ROOT/target/include" to each -library pair.
|
||||
xcodebuild -create-xcframework \
|
||||
-library "$DEV_LIB" \
|
||||
-library "$SIM_LIB" \
|
||||
-output "$DIST/$XCFRAMEWORK"
|
||||
ok "built $DIST/$XCFRAMEWORK"
|
||||
|
||||
if [ "$SKIP_IPA" = 1 ]; then
|
||||
# Still stage it into ui/ios if that project already exists, so a later
|
||||
# `flutter build ipa` picks up the fresh binary.
|
||||
if [ -d "$IOSDIR" ]; then
|
||||
cp -R "$DIST/$XCFRAMEWORK" "$IOSDIR/"
|
||||
ok "staged into $IOSDIR/$XCFRAMEWORK"
|
||||
fi
|
||||
say "done (--skip-ipa). xcframework at: $DIST/$XCFRAMEWORK"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ---- 4. ensure the Flutter iOS project exists ------------------------------
|
||||
say "4/6 ensure ui/ios Flutter project"
|
||||
if [ ! -d "$IOSDIR" ]; then
|
||||
ok "ui/ios missing — generating with flutter create"
|
||||
( cd "$UI" && "$FLUTTER" create --org "$FLUTTER_ORG" --project-name netdesk --platforms=ios . )
|
||||
else
|
||||
ok "ui/ios already present — leaving it in place"
|
||||
fi
|
||||
( cd "$UI" && "$FLUTTER" pub get )
|
||||
|
||||
# ---- 5. wire the xcframework into ui/ios (CocoaPods) -----------------------
|
||||
say "5/6 wire xcframework into the iOS project"
|
||||
cp -R "$DIST/$XCFRAMEWORK" "$IOSDIR/"
|
||||
ok "copied $XCFRAMEWORK into ui/ios"
|
||||
|
||||
cp "$TEMPLATES/netdesk_core.podspec" "$IOSDIR/netdesk_core.podspec"
|
||||
ok "installed ui/ios/netdesk_core.podspec"
|
||||
|
||||
# Podfile: install the template if there is none, otherwise inject the pod line.
|
||||
if [ ! -f "$IOSDIR/Podfile" ]; then
|
||||
cp "$TEMPLATES/Podfile" "$IOSDIR/Podfile"
|
||||
ok "installed ui/ios/Podfile (from template)"
|
||||
else
|
||||
# Uncomment any commented `platform :ios` line so it matches the xcframework.
|
||||
if grep -qE '^\s*#\s*platform :ios' "$IOSDIR/Podfile"; then
|
||||
sed -i '' -E "s/^\s*#\s*platform :ios.*/platform :ios, '$IOS_MIN'/" "$IOSDIR/Podfile"
|
||||
fi
|
||||
# Inject the netdesk_core pod into the Runner target if it is not there yet.
|
||||
if ! grep -q "pod 'netdesk_core'" "$IOSDIR/Podfile"; then
|
||||
awk '
|
||||
/target '\''Runner'\'' do/ && !done {
|
||||
print
|
||||
print " # NetDesk Rust core (added by packaging/build-ios.sh)."
|
||||
print " pod '\''netdesk_core'\'', :path => '\''.'\''"
|
||||
done = 1
|
||||
next
|
||||
}
|
||||
{ print }
|
||||
' "$IOSDIR/Podfile" > "$IOSDIR/Podfile.tmp" && mv "$IOSDIR/Podfile.tmp" "$IOSDIR/Podfile"
|
||||
ok "injected pod 'netdesk_core' into existing Podfile"
|
||||
else
|
||||
ok "Podfile already references netdesk_core"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Signing for the archive step: set the team + automatic signing via the
|
||||
# Flutter xcconfig layer (applies because a fresh Runner target has no explicit
|
||||
# DEVELOPMENT_TEAM in project.pbxproj). Idempotent.
|
||||
for cfg in Release Debug; do
|
||||
XC="$IOSDIR/Flutter/$cfg.xcconfig"
|
||||
[ -f "$XC" ] || continue
|
||||
if ! grep -q '^DEVELOPMENT_TEAM' "$XC"; then
|
||||
{
|
||||
echo ""
|
||||
echo "// NetDesk signing (added by packaging/build-ios.sh)"
|
||||
echo "DEVELOPMENT_TEAM = $TEAM_ID"
|
||||
echo "CODE_SIGN_STYLE = Automatic"
|
||||
} >> "$XC"
|
||||
ok "set DEVELOPMENT_TEAM in Flutter/$cfg.xcconfig"
|
||||
else
|
||||
sed -i '' -E "s/^DEVELOPMENT_TEAM.*/DEVELOPMENT_TEAM = $TEAM_ID/" "$XC"
|
||||
ok "updated DEVELOPMENT_TEAM in Flutter/$cfg.xcconfig"
|
||||
fi
|
||||
done
|
||||
|
||||
# ExportOptions.plist consumed by `flutter build ipa` for the export phase.
|
||||
cat > "$IOSDIR/ExportOptions.plist" <<PLIST
|
||||
<?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_ID</string>
|
||||
<key>signingStyle</key><string>automatic</string>
|
||||
<key>uploadSymbols</key><true/>
|
||||
<key>stripSwiftSymbols</key><true/>
|
||||
<key>destination</key><string>export</string>
|
||||
</dict>
|
||||
</plist>
|
||||
PLIST
|
||||
ok "wrote ui/ios/ExportOptions.plist (method=$EXPORT_METHOD)"
|
||||
|
||||
# Resolve pods now so any CocoaPods error surfaces before the long archive.
|
||||
if command -v pod >/dev/null; then
|
||||
( cd "$IOSDIR" && pod install )
|
||||
ok "pod install complete"
|
||||
else
|
||||
ok "CocoaPods 'pod' not on PATH — flutter will run it during the build (sudo gem install cocoapods to install)"
|
||||
fi
|
||||
|
||||
# ---- 6. flutter build ipa --------------------------------------------------
|
||||
say "6/6 flutter build ipa"
|
||||
( cd "$UI" && "$FLUTTER" build ipa --release --export-options-plist=ios/ExportOptions.plist )
|
||||
|
||||
IPA="$(ls -t "$UI/build/ios/ipa/"*.ipa 2>/dev/null | head -1 || true)"
|
||||
echo ""
|
||||
echo "=== DONE ==="
|
||||
echo "xcframework : $DIST/$XCFRAMEWORK (also staged in ui/ios/)"
|
||||
if [ -n "$IPA" ]; then
|
||||
echo "ipa : $IPA"
|
||||
echo ""
|
||||
echo "Upload to App Store Connect / TestFlight with:"
|
||||
echo " xcrun altool --upload-app -f \"$IPA\" -t ios --apiKey <KEY_ID> --apiIssuer <ISSUER_ID>"
|
||||
echo "or open ui/build/ios/archive/Runner.xcarchive in Xcode > Organizer > Distribute App."
|
||||
else
|
||||
echo "ipa : (not found under ui/build/ios/ipa — check the flutter output above)"
|
||||
fi
|
||||
Reference in new issue
Block a user