init
This commit is contained in:
116
build/ios/Assets.xcassets
Normal file
116
build/ios/Assets.xcassets
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "icon-20@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-20@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-29@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-29@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-40@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-40@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-60@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-60@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-20.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-20@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-29.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-29@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-40.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-40@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-76.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-76@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-83.5@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-1024.png",
|
||||
"idiom" : "ios-marketing",
|
||||
"scale" : "1x",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
]
|
||||
}
|
||||
62
build/ios/Info.dev.plist
Normal file
62
build/ios/Info.dev.plist
Normal file
@@ -0,0 +1,62 @@
|
||||
<?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>CFBundleExecutable</key>
|
||||
<string>mesh-drop</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.example.meshdrop.dev</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>My Product (Dev)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>My Product (Dev)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1.0-dev</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>15.0</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<!-- Development mode enabled -->
|
||||
<key>WailsDevelopmentMode</key>
|
||||
<true/>
|
||||
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>© 2026, My Company</string>
|
||||
|
||||
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>This is a comment</string>
|
||||
|
||||
</dict>
|
||||
</plist>
|
||||
59
build/ios/Info.plist
Normal file
59
build/ios/Info.plist
Normal file
@@ -0,0 +1,59 @@
|
||||
<?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>CFBundleExecutable</key>
|
||||
<string>mesh-drop</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.example.meshdrop</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>My Product</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>My Product</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>15.0</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<false/>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>© 2026, My Company</string>
|
||||
|
||||
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>This is a comment</string>
|
||||
|
||||
</dict>
|
||||
</plist>
|
||||
53
build/ios/LaunchScreen.storyboard
Normal file
53
build/ios/LaunchScreen.storyboard
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="My Product" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
|
||||
<rect key="frame" x="0.0" y="397" width="393" height="43"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="A mesh-drop application" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="MN2-I3-ftu">
|
||||
<rect key="frame" x="0.0" y="448" width="393" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
|
||||
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/2" constant="-20" id="moa-c2-u7t"/>
|
||||
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="x7j-FC-K8j"/>
|
||||
|
||||
<constraint firstItem="MN2-I3-ftu" firstAttribute="top" secondItem="GJd-Yh-RWb" secondAttribute="bottom" constant="8" symbolic="YES" id="cPy-rs-vsC"/>
|
||||
<constraint firstItem="MN2-I3-ftu" firstAttribute="centerX" secondItem="Bcu-3y-fUS" secondAttribute="centerX" id="OQL-iM-xY6"/>
|
||||
<constraint firstItem="MN2-I3-ftu" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="Dti-5h-tvW"/>
|
||||
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
293
build/ios/Taskfile.yml
Normal file
293
build/ios/Taskfile.yml
Normal file
@@ -0,0 +1,293 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
common: ../Taskfile.yml
|
||||
|
||||
vars:
|
||||
BUNDLE_ID: '{{.BUNDLE_ID | default "com.wails.app"}}'
|
||||
# SDK_PATH is computed lazily at task-level to avoid errors on non-macOS systems
|
||||
# Each task that needs it defines SDK_PATH in its own vars section
|
||||
|
||||
tasks:
|
||||
install:deps:
|
||||
summary: Check and install iOS development dependencies
|
||||
cmds:
|
||||
- go run build/ios/scripts/deps/install_deps.go
|
||||
env:
|
||||
TASK_FORCE_YES: '{{if .YES}}true{{else}}false{{end}}'
|
||||
prompt: This will check and install iOS development dependencies. Continue?
|
||||
|
||||
# Note: Bindings generation may show CGO warnings for iOS C imports.
|
||||
# These warnings are harmless and don't affect the generated bindings,
|
||||
# as the generator only needs to parse Go types, not C implementations.
|
||||
build:
|
||||
summary: Creates a build of the application for iOS
|
||||
deps:
|
||||
- task: generate:ios:overlay
|
||||
- task: generate:ios:xcode
|
||||
- task: common:go:mod:tidy
|
||||
- task: generate:ios:bindings
|
||||
vars:
|
||||
BUILD_FLAGS:
|
||||
ref: .BUILD_FLAGS
|
||||
- task: common:build:frontend
|
||||
vars:
|
||||
BUILD_FLAGS:
|
||||
ref: .BUILD_FLAGS
|
||||
PRODUCTION:
|
||||
ref: .PRODUCTION
|
||||
- task: common:generate:icons
|
||||
cmds:
|
||||
- echo "Building iOS app {{.APP_NAME}}..."
|
||||
- go build -buildmode=c-archive -overlay build/ios/xcode/overlay.json {{.BUILD_FLAGS}} -o {{.OUTPUT}}.a
|
||||
vars:
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production,ios -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-tags ios,debug -buildvcs=false -gcflags=all="-l"{{end}}'
|
||||
DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
|
||||
OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
|
||||
SDK_PATH:
|
||||
sh: xcrun --sdk iphonesimulator --show-sdk-path
|
||||
env:
|
||||
GOOS: ios
|
||||
CGO_ENABLED: 1
|
||||
GOARCH: '{{.ARCH | default "arm64"}}'
|
||||
PRODUCTION: '{{.PRODUCTION | default "false"}}'
|
||||
CGO_CFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator -mios-simulator-version-min=15.0'
|
||||
CGO_LDFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator'
|
||||
|
||||
compile:objc:
|
||||
summary: Compile Objective-C iOS wrapper
|
||||
vars:
|
||||
SDK_PATH:
|
||||
sh: xcrun --sdk iphonesimulator --show-sdk-path
|
||||
cmds:
|
||||
- xcrun -sdk iphonesimulator clang -target arm64-apple-ios15.0-simulator -isysroot {{.SDK_PATH}} -framework Foundation -framework UIKit -framework WebKit -o {{.BIN_DIR}}/{{.APP_NAME}} build/ios/main.m
|
||||
- codesign --force --sign - "{{.BIN_DIR}}/{{.APP_NAME}}"
|
||||
|
||||
package:
|
||||
summary: Packages a production build of the application into a `.app` bundle
|
||||
deps:
|
||||
- task: build
|
||||
vars:
|
||||
PRODUCTION: "true"
|
||||
cmds:
|
||||
- task: create:app:bundle
|
||||
|
||||
create:app:bundle:
|
||||
summary: Creates an iOS `.app` bundle
|
||||
cmds:
|
||||
- rm -rf "{{.BIN_DIR}}/{{.APP_NAME}}.app"
|
||||
- mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.app"
|
||||
- cp "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}.app/"
|
||||
- cp build/ios/Info.plist "{{.BIN_DIR}}/{{.APP_NAME}}.app/"
|
||||
- |
|
||||
# Compile asset catalog and embed icons in the app bundle
|
||||
APP_BUNDLE="{{.BIN_DIR}}/{{.APP_NAME}}.app"
|
||||
AC_IN="build/ios/xcode/main/Assets.xcassets"
|
||||
if [ -d "$AC_IN" ]; then
|
||||
TMP_AC=$(mktemp -d)
|
||||
xcrun actool \
|
||||
--compile "$TMP_AC" \
|
||||
--app-icon AppIcon \
|
||||
--platform iphonesimulator \
|
||||
--minimum-deployment-target 15.0 \
|
||||
--product-type com.apple.product-type.application \
|
||||
--target-device iphone \
|
||||
--target-device ipad \
|
||||
--output-partial-info-plist "$APP_BUNDLE/assetcatalog_generated_info.plist" \
|
||||
"$AC_IN"
|
||||
if [ -f "$TMP_AC/Assets.car" ]; then
|
||||
cp -f "$TMP_AC/Assets.car" "$APP_BUNDLE/Assets.car"
|
||||
fi
|
||||
rm -rf "$TMP_AC"
|
||||
if [ -f "$APP_BUNDLE/assetcatalog_generated_info.plist" ]; then
|
||||
/usr/libexec/PlistBuddy -c "Merge $APP_BUNDLE/assetcatalog_generated_info.plist" "$APP_BUNDLE/Info.plist" || true
|
||||
fi
|
||||
fi
|
||||
- codesign --force --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.app"
|
||||
|
||||
deploy-simulator:
|
||||
summary: Deploy to iOS Simulator
|
||||
deps: [package]
|
||||
cmds:
|
||||
- xcrun simctl terminate booted {{.BUNDLE_ID}} 2>/dev/null || true
|
||||
- xcrun simctl uninstall booted {{.BUNDLE_ID}} 2>/dev/null || true
|
||||
- xcrun simctl install booted "{{.BIN_DIR}}/{{.APP_NAME}}.app"
|
||||
- xcrun simctl launch booted {{.BUNDLE_ID}}
|
||||
|
||||
compile:ios:
|
||||
summary: Compile the iOS executable from Go archive and main.m
|
||||
deps:
|
||||
- task: build
|
||||
vars:
|
||||
SDK_PATH:
|
||||
sh: xcrun --sdk iphonesimulator --show-sdk-path
|
||||
cmds:
|
||||
- |
|
||||
MAIN_M=build/ios/xcode/main/main.m
|
||||
if [ ! -f "$MAIN_M" ]; then
|
||||
MAIN_M=build/ios/main.m
|
||||
fi
|
||||
xcrun -sdk iphonesimulator clang \
|
||||
-target arm64-apple-ios15.0-simulator \
|
||||
-isysroot {{.SDK_PATH}} \
|
||||
-framework Foundation -framework UIKit -framework WebKit \
|
||||
-framework Security -framework CoreFoundation \
|
||||
-lresolv \
|
||||
-o "{{.BIN_DIR}}/{{.APP_NAME | lower}}" \
|
||||
"$MAIN_M" "{{.BIN_DIR}}/{{.APP_NAME}}.a"
|
||||
|
||||
generate:ios:bindings:
|
||||
internal: true
|
||||
summary: Generates bindings for iOS with proper CGO flags
|
||||
sources:
|
||||
- "**/*.go"
|
||||
- go.mod
|
||||
- go.sum
|
||||
generates:
|
||||
- frontend/bindings/**/*
|
||||
vars:
|
||||
SDK_PATH:
|
||||
sh: xcrun --sdk iphonesimulator --show-sdk-path
|
||||
cmds:
|
||||
- wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true
|
||||
env:
|
||||
GOOS: ios
|
||||
CGO_ENABLED: 1
|
||||
GOARCH: '{{.ARCH | default "arm64"}}'
|
||||
CGO_CFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator -mios-simulator-version-min=15.0'
|
||||
CGO_LDFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator'
|
||||
|
||||
ensure-simulator:
|
||||
internal: true
|
||||
summary: Ensure iOS Simulator is running and booted
|
||||
silent: true
|
||||
cmds:
|
||||
- |
|
||||
if ! xcrun simctl list devices booted | grep -q "Booted"; then
|
||||
echo "Starting iOS Simulator..."
|
||||
# Get first available iPhone device
|
||||
DEVICE_ID=$(xcrun simctl list devices available | grep "iPhone" | head -1 | grep -o "[A-F0-9-]\{36\}" || true)
|
||||
if [ -z "$DEVICE_ID" ]; then
|
||||
echo "No iPhone simulator found. Creating one..."
|
||||
RUNTIME=$(xcrun simctl list runtimes | grep iOS | tail -1 | awk '{print $NF}')
|
||||
DEVICE_ID=$(xcrun simctl create "iPhone 15 Pro" "iPhone 15 Pro" "$RUNTIME")
|
||||
fi
|
||||
# Boot the device
|
||||
echo "Booting device $DEVICE_ID..."
|
||||
xcrun simctl boot "$DEVICE_ID" 2>/dev/null || true
|
||||
# Open Simulator app
|
||||
open -a Simulator
|
||||
# Wait for boot (max 30 seconds)
|
||||
for i in {1..30}; do
|
||||
if xcrun simctl list devices booted | grep -q "Booted"; then
|
||||
echo "Simulator booted successfully"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# Final check
|
||||
if ! xcrun simctl list devices booted | grep -q "Booted"; then
|
||||
echo "Failed to boot simulator after 30 seconds"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
preconditions:
|
||||
- sh: command -v xcrun
|
||||
msg: "xcrun not found. Please run 'wails3 task ios:install:deps' to install iOS development dependencies"
|
||||
|
||||
generate:ios:overlay:
|
||||
internal: true
|
||||
summary: Generate Go build overlay and iOS shim
|
||||
sources:
|
||||
- build/config.yml
|
||||
generates:
|
||||
- build/ios/xcode/overlay.json
|
||||
- build/ios/xcode/gen/main_ios.gen.go
|
||||
cmds:
|
||||
- wails3 ios overlay:gen -out build/ios/xcode/overlay.json -config build/config.yml
|
||||
|
||||
generate:ios:xcode:
|
||||
internal: true
|
||||
summary: Generate iOS Xcode project structure and assets
|
||||
sources:
|
||||
- build/config.yml
|
||||
- build/appicon.png
|
||||
generates:
|
||||
- build/ios/xcode/main/main.m
|
||||
- build/ios/xcode/main/Assets.xcassets/**/*
|
||||
- build/ios/xcode/project.pbxproj
|
||||
cmds:
|
||||
- wails3 ios xcode:gen -outdir build/ios/xcode -config build/config.yml
|
||||
|
||||
run:
|
||||
summary: Run the application in iOS Simulator
|
||||
deps:
|
||||
- task: ensure-simulator
|
||||
- task: compile:ios
|
||||
cmds:
|
||||
- rm -rf "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
|
||||
- mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
|
||||
- cp "{{.BIN_DIR}}/{{.APP_NAME | lower}}" "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/{{.APP_NAME | lower}}"
|
||||
- cp build/ios/Info.dev.plist "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Info.plist"
|
||||
- |
|
||||
# Compile asset catalog and embed icons for dev bundle
|
||||
APP_BUNDLE="{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
|
||||
AC_IN="build/ios/xcode/main/Assets.xcassets"
|
||||
if [ -d "$AC_IN" ]; then
|
||||
TMP_AC=$(mktemp -d)
|
||||
xcrun actool \
|
||||
--compile "$TMP_AC" \
|
||||
--app-icon AppIcon \
|
||||
--platform iphonesimulator \
|
||||
--minimum-deployment-target 15.0 \
|
||||
--product-type com.apple.product-type.application \
|
||||
--target-device iphone \
|
||||
--target-device ipad \
|
||||
--output-partial-info-plist "$APP_BUNDLE/assetcatalog_generated_info.plist" \
|
||||
"$AC_IN"
|
||||
if [ -f "$TMP_AC/Assets.car" ]; then
|
||||
cp -f "$TMP_AC/Assets.car" "$APP_BUNDLE/Assets.car"
|
||||
fi
|
||||
rm -rf "$TMP_AC"
|
||||
if [ -f "$APP_BUNDLE/assetcatalog_generated_info.plist" ]; then
|
||||
/usr/libexec/PlistBuddy -c "Merge $APP_BUNDLE/assetcatalog_generated_info.plist" "$APP_BUNDLE/Info.plist" || true
|
||||
fi
|
||||
fi
|
||||
- codesign --force --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
|
||||
- xcrun simctl terminate booted "com.wails.{{.APP_NAME | lower}}.dev" 2>/dev/null || true
|
||||
- xcrun simctl uninstall booted "com.wails.{{.APP_NAME | lower}}.dev" 2>/dev/null || true
|
||||
- xcrun simctl install booted "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
|
||||
- xcrun simctl launch booted "com.wails.{{.APP_NAME | lower}}.dev"
|
||||
|
||||
xcode:
|
||||
summary: Open the generated Xcode project for this app
|
||||
cmds:
|
||||
- task: generate:ios:xcode
|
||||
- open build/ios/xcode/main.xcodeproj
|
||||
|
||||
logs:
|
||||
summary: Stream iOS Simulator logs filtered to this app
|
||||
cmds:
|
||||
- |
|
||||
xcrun simctl spawn booted log stream \
|
||||
--level debug \
|
||||
--style compact \
|
||||
--predicate 'senderImagePath CONTAINS[c] "{{.APP_NAME | lower}}.app/" OR composedMessage CONTAINS[c] "{{.APP_NAME | lower}}" OR eventMessage CONTAINS[c] "{{.APP_NAME | lower}}" OR process == "{{.APP_NAME | lower}}" OR category CONTAINS[c] "{{.APP_NAME | lower}}"'
|
||||
|
||||
logs:dev:
|
||||
summary: Stream logs for the dev bundle (used by `task ios:run`)
|
||||
cmds:
|
||||
- |
|
||||
xcrun simctl spawn booted log stream \
|
||||
--level debug \
|
||||
--style compact \
|
||||
--predicate 'senderImagePath CONTAINS[c] ".dev.app/" OR subsystem == "com.wails.{{.APP_NAME | lower}}.dev" OR process == "{{.APP_NAME | lower}}"'
|
||||
|
||||
logs:wide:
|
||||
summary: Wide log stream to help discover the exact process/bundle identifiers
|
||||
cmds:
|
||||
- |
|
||||
xcrun simctl spawn booted log stream \
|
||||
--level debug \
|
||||
--style compact \
|
||||
--predicate 'senderImagePath CONTAINS[c] ".app/"'
|
||||
10
build/ios/app_options_default.go
Normal file
10
build/ios/app_options_default.go
Normal file
@@ -0,0 +1,10 @@
|
||||
//go:build !ios
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/wailsapp/wails/v3/pkg/application"
|
||||
|
||||
// modifyOptionsForIOS is a no-op on non-iOS platforms
|
||||
func modifyOptionsForIOS(opts *application.Options) {
|
||||
// No modifications needed for non-iOS platforms
|
||||
}
|
||||
11
build/ios/app_options_ios.go
Normal file
11
build/ios/app_options_ios.go
Normal file
@@ -0,0 +1,11 @@
|
||||
//go:build ios
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/wailsapp/wails/v3/pkg/application"
|
||||
|
||||
// modifyOptionsForIOS adjusts the application options for iOS
|
||||
func modifyOptionsForIOS(opts *application.Options) {
|
||||
// Disable signal handlers on iOS to prevent crashes
|
||||
opts.DisableDefaultSignalHandler = true
|
||||
}
|
||||
72
build/ios/build.sh
Normal file
72
build/ios/build.sh
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Build configuration
|
||||
APP_NAME="mesh-drop"
|
||||
BUNDLE_ID="com.example.meshdrop"
|
||||
VERSION="0.1.0"
|
||||
BUILD_NUMBER="0.1.0"
|
||||
BUILD_DIR="build/ios"
|
||||
TARGET="simulator"
|
||||
|
||||
echo "Building iOS app: $APP_NAME"
|
||||
echo "Bundle ID: $BUNDLE_ID"
|
||||
echo "Version: $VERSION ($BUILD_NUMBER)"
|
||||
echo "Target: $TARGET"
|
||||
|
||||
# Ensure build directory exists
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
||||
# Determine SDK and target architecture
|
||||
if [ "$TARGET" = "simulator" ]; then
|
||||
SDK="iphonesimulator"
|
||||
ARCH="arm64-apple-ios15.0-simulator"
|
||||
elif [ "$TARGET" = "device" ]; then
|
||||
SDK="iphoneos"
|
||||
ARCH="arm64-apple-ios15.0"
|
||||
else
|
||||
echo "Unknown target: $TARGET"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get SDK path
|
||||
SDK_PATH=$(xcrun --sdk $SDK --show-sdk-path)
|
||||
|
||||
# Compile the application
|
||||
echo "Compiling with SDK: $SDK"
|
||||
xcrun -sdk $SDK clang \
|
||||
-target $ARCH \
|
||||
-isysroot "$SDK_PATH" \
|
||||
-framework Foundation \
|
||||
-framework UIKit \
|
||||
-framework WebKit \
|
||||
-framework CoreGraphics \
|
||||
-o "$BUILD_DIR/$APP_NAME" \
|
||||
"$BUILD_DIR/main.m"
|
||||
|
||||
# Create app bundle
|
||||
echo "Creating app bundle..."
|
||||
APP_BUNDLE="$BUILD_DIR/$APP_NAME.app"
|
||||
rm -rf "$APP_BUNDLE"
|
||||
mkdir -p "$APP_BUNDLE"
|
||||
|
||||
# Move executable
|
||||
mv "$BUILD_DIR/$APP_NAME" "$APP_BUNDLE/"
|
||||
|
||||
# Copy Info.plist
|
||||
cp "$BUILD_DIR/Info.plist" "$APP_BUNDLE/"
|
||||
|
||||
# Sign the app
|
||||
echo "Signing app..."
|
||||
codesign --force --sign - "$APP_BUNDLE"
|
||||
|
||||
echo "Build complete: $APP_BUNDLE"
|
||||
|
||||
# Deploy to simulator if requested
|
||||
if [ "$TARGET" = "simulator" ]; then
|
||||
echo "Deploying to simulator..."
|
||||
xcrun simctl terminate booted "$BUNDLE_ID" 2>/dev/null || true
|
||||
xcrun simctl install booted "$APP_BUNDLE"
|
||||
xcrun simctl launch booted "$BUNDLE_ID"
|
||||
echo "App launched on simulator"
|
||||
fi
|
||||
21
build/ios/entitlements.plist
Normal file
21
build/ios/entitlements.plist
Normal file
@@ -0,0 +1,21 @@
|
||||
<?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>
|
||||
<!-- Development entitlements -->
|
||||
<key>get-task-allow</key>
|
||||
<true/>
|
||||
|
||||
<!-- App Sandbox -->
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
|
||||
<!-- Network access -->
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
|
||||
<!-- File access (read-only) -->
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
3
build/ios/icon.png
Normal file
3
build/ios/icon.png
Normal file
@@ -0,0 +1,3 @@
|
||||
# iOS Icon Placeholder
|
||||
# This file should be replaced with the actual app icon (1024x1024 PNG)
|
||||
# The build process will generate all required icon sizes from this base icon
|
||||
23
build/ios/main.m
Normal file
23
build/ios/main.m
Normal file
@@ -0,0 +1,23 @@
|
||||
//go:build ios
|
||||
// Minimal bootstrap: delegate comes from Go archive (WailsAppDelegate)
|
||||
#import <UIKit/UIKit.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// External Go initialization function from the c-archive (declare before use)
|
||||
extern void WailsIOSMain();
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
// Disable buffering so stdout/stderr from Go log.Printf flush immediately
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
// Start Go runtime on a background queue to avoid blocking main thread/UI
|
||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
|
||||
WailsIOSMain();
|
||||
});
|
||||
|
||||
// Run UIApplicationMain using WailsAppDelegate provided by the Go archive
|
||||
return UIApplicationMain(argc, argv, nil, @"WailsAppDelegate");
|
||||
}
|
||||
}
|
||||
24
build/ios/main_ios.go
Normal file
24
build/ios/main_ios.go
Normal file
@@ -0,0 +1,24 @@
|
||||
//go:build ios
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"C"
|
||||
)
|
||||
|
||||
// For iOS builds, we need to export a function that can be called from Objective-C
|
||||
// This wrapper allows us to keep the original main.go unmodified
|
||||
|
||||
//export WailsIOSMain
|
||||
func WailsIOSMain() {
|
||||
// DO NOT lock the goroutine to the current OS thread on iOS!
|
||||
// This causes signal handling issues:
|
||||
// "signal 16 received on thread with no signal stack"
|
||||
// "fatal error: non-Go code disabled sigaltstack"
|
||||
// iOS apps run in a sandboxed environment where the Go runtime's
|
||||
// signal handling doesn't work the same way as desktop platforms.
|
||||
|
||||
// Call the actual main function from main.go
|
||||
// This ensures all the user's code is executed
|
||||
main()
|
||||
}
|
||||
222
build/ios/project.pbxproj
Normal file
222
build/ios/project.pbxproj
Normal file
@@ -0,0 +1,222 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {};
|
||||
objectVersion = 56;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
C0DEBEEF0000000000000001 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000002 /* main.m */; };
|
||||
C0DEBEEF00000000000000F1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000101 /* UIKit.framework */; };
|
||||
C0DEBEEF00000000000000F2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000102 /* Foundation.framework */; };
|
||||
C0DEBEEF00000000000000F3 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000103 /* WebKit.framework */; };
|
||||
C0DEBEEF00000000000000F4 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000104 /* Security.framework */; };
|
||||
C0DEBEEF00000000000000F5 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000105 /* CoreFoundation.framework */; };
|
||||
C0DEBEEF00000000000000F6 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000106 /* libresolv.tbd */; };
|
||||
C0DEBEEF00000000000000F7 /* My Product.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000107 /* My Product.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
C0DEBEEF0000000000000002 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
C0DEBEEF0000000000000003 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
C0DEBEEF0000000000000004 /* My Product.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "My Product.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C0DEBEEF0000000000000101 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
C0DEBEEF0000000000000102 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
C0DEBEEF0000000000000103 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
|
||||
C0DEBEEF0000000000000104 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||
C0DEBEEF0000000000000105 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
|
||||
C0DEBEEF0000000000000106 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.text-based-dylib-definition; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
|
||||
C0DEBEEF0000000000000107 /* My Product.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "My Product.a"; path = ../../../bin/My Product.a; sourceTree = SOURCE_ROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
C0DEBEEF0000000000000010 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C0DEBEEF0000000000000020 /* Products */,
|
||||
C0DEBEEF0000000000000045 /* Frameworks */,
|
||||
C0DEBEEF0000000000000030 /* main */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C0DEBEEF0000000000000020 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C0DEBEEF0000000000000004 /* My Product.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C0DEBEEF0000000000000030 /* main */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C0DEBEEF0000000000000002 /* main.m */,
|
||||
C0DEBEEF0000000000000003 /* Info.plist */,
|
||||
);
|
||||
path = main;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
C0DEBEEF0000000000000045 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C0DEBEEF0000000000000101 /* UIKit.framework */,
|
||||
C0DEBEEF0000000000000102 /* Foundation.framework */,
|
||||
C0DEBEEF0000000000000103 /* WebKit.framework */,
|
||||
C0DEBEEF0000000000000104 /* Security.framework */,
|
||||
C0DEBEEF0000000000000105 /* CoreFoundation.framework */,
|
||||
C0DEBEEF0000000000000106 /* libresolv.tbd */,
|
||||
C0DEBEEF0000000000000107 /* My Product.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
C0DEBEEF0000000000000040 /* My Product */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = C0DEBEEF0000000000000070 /* Build configuration list for PBXNativeTarget "My Product" */;
|
||||
buildPhases = (
|
||||
C0DEBEEF0000000000000055 /* Prebuild: Wails Go Archive */,
|
||||
C0DEBEEF0000000000000050 /* Sources */,
|
||||
C0DEBEEF0000000000000056 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "My Product";
|
||||
productName = "My Product";
|
||||
productReference = C0DEBEEF0000000000000004 /* My Product.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
C0DEBEEF0000000000000060 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1500;
|
||||
ORGANIZATIONNAME = "My Company";
|
||||
TargetAttributes = {
|
||||
C0DEBEEF0000000000000040 = {
|
||||
CreatedOnToolsVersion = 15.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = C0DEBEEF0000000000000080 /* Build configuration list for PBXProject "main" */;
|
||||
compatibilityVersion = "Xcode 15.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = C0DEBEEF0000000000000010;
|
||||
productRefGroup = C0DEBEEF0000000000000020 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
C0DEBEEF0000000000000040 /* My Product */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
C0DEBEEF0000000000000056 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C0DEBEEF00000000000000F7 /* My Product.a in Frameworks */,
|
||||
C0DEBEEF00000000000000F1 /* UIKit.framework in Frameworks */,
|
||||
C0DEBEEF00000000000000F2 /* Foundation.framework in Frameworks */,
|
||||
C0DEBEEF00000000000000F3 /* WebKit.framework in Frameworks */,
|
||||
C0DEBEEF00000000000000F4 /* Security.framework in Frameworks */,
|
||||
C0DEBEEF00000000000000F5 /* CoreFoundation.framework in Frameworks */,
|
||||
C0DEBEEF00000000000000F6 /* libresolv.tbd in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
C0DEBEEF0000000000000055 /* Prebuild: Wails Go Archive */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Prebuild: Wails Go Archive";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "set -e\nAPP_ROOT=\"${PROJECT_DIR}/../../..\"\nSDK_PATH=$(xcrun --sdk iphonesimulator --show-sdk-path)\nexport GOOS=ios\nexport GOARCH=arm64\nexport CGO_ENABLED=1\nexport CGO_CFLAGS=\"-isysroot ${SDK_PATH} -target arm64-apple-ios15.0-simulator -mios-simulator-version-min=15.0\"\nexport CGO_LDFLAGS=\"-isysroot ${SDK_PATH} -target arm64-apple-ios15.0-simulator\"\ncd \"${APP_ROOT}\"\n# Ensure overlay exists\nif [ ! -f build/ios/xcode/overlay.json ]; then\n wails3 ios overlay:gen -out build/ios/xcode/overlay.json -config build/config.yml || true\nfi\n# Build Go c-archive if missing or older than sources\nif [ ! -f bin/My Product.a ]; then\n echo \"Building Go c-archive...\"\n go build -buildmode=c-archive -overlay build/ios/xcode/overlay.json -o bin/My Product.a\nfi\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
C0DEBEEF0000000000000050 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C0DEBEEF0000000000000001 /* main.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
C0DEBEEF0000000000000090 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
INFOPLIST_FILE = main/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.example.meshdrop";
|
||||
PRODUCT_NAME = "My Product";
|
||||
CODE_SIGNING_ALLOWED = NO;
|
||||
SDKROOT = iphonesimulator;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
C0DEBEEF00000000000000A0 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
INFOPLIST_FILE = main/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.example.meshdrop";
|
||||
PRODUCT_NAME = "My Product";
|
||||
CODE_SIGNING_ALLOWED = NO;
|
||||
SDKROOT = iphonesimulator;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
C0DEBEEF0000000000000070 /* Build configuration list for PBXNativeTarget "My Product" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
C0DEBEEF0000000000000090 /* Debug */,
|
||||
C0DEBEEF00000000000000A0 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
C0DEBEEF0000000000000080 /* Build configuration list for PBXProject "main" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
C0DEBEEF0000000000000090 /* Debug */,
|
||||
C0DEBEEF00000000000000A0 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Debug;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = C0DEBEEF0000000000000060 /* Project object */;
|
||||
}
|
||||
319
build/ios/scripts/deps/install_deps.go
Normal file
319
build/ios/scripts/deps/install_deps.go
Normal file
@@ -0,0 +1,319 @@
|
||||
// install_deps.go - iOS development dependency checker
|
||||
// This script checks for required iOS development tools.
|
||||
// It's designed to be portable across different shells by using Go instead of shell scripts.
|
||||
//
|
||||
// Usage:
|
||||
// go run install_deps.go # Interactive mode
|
||||
// TASK_FORCE_YES=true go run install_deps.go # Auto-accept prompts
|
||||
// CI=true go run install_deps.go # CI mode (auto-accept)
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Dependency struct {
|
||||
Name string
|
||||
CheckFunc func() (bool, string) // Returns (success, details)
|
||||
Required bool
|
||||
InstallCmd []string
|
||||
InstallMsg string
|
||||
SuccessMsg string
|
||||
FailureMsg string
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("Checking iOS development dependencies...")
|
||||
fmt.Println("=" + strings.Repeat("=", 50))
|
||||
fmt.Println()
|
||||
|
||||
hasErrors := false
|
||||
dependencies := []Dependency{
|
||||
{
|
||||
Name: "Xcode",
|
||||
CheckFunc: func() (bool, string) {
|
||||
// Check if xcodebuild exists
|
||||
if !checkCommand([]string{"xcodebuild", "-version"}) {
|
||||
return false, ""
|
||||
}
|
||||
// Get version info
|
||||
out, err := exec.Command("xcodebuild", "-version").Output()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
if len(lines) > 0 {
|
||||
return true, strings.TrimSpace(lines[0])
|
||||
}
|
||||
return true, ""
|
||||
},
|
||||
Required: true,
|
||||
InstallMsg: "Please install Xcode from the Mac App Store:\n https://apps.apple.com/app/xcode/id497799835\n Xcode is REQUIRED for iOS development (includes iOS SDKs, simulators, and frameworks)",
|
||||
SuccessMsg: "✅ Xcode found",
|
||||
FailureMsg: "❌ Xcode not found (REQUIRED)",
|
||||
},
|
||||
{
|
||||
Name: "Xcode Developer Path",
|
||||
CheckFunc: func() (bool, string) {
|
||||
// Check if xcode-select points to a valid Xcode path
|
||||
out, err := exec.Command("xcode-select", "-p").Output()
|
||||
if err != nil {
|
||||
return false, "xcode-select not configured"
|
||||
}
|
||||
path := strings.TrimSpace(string(out))
|
||||
|
||||
// Check if path exists and is in Xcode.app
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return false, "Invalid Xcode path"
|
||||
}
|
||||
|
||||
// Verify it's pointing to Xcode.app (not just Command Line Tools)
|
||||
if !strings.Contains(path, "Xcode.app") {
|
||||
return false, fmt.Sprintf("Points to %s (should be Xcode.app)", path)
|
||||
}
|
||||
|
||||
return true, path
|
||||
},
|
||||
Required: true,
|
||||
InstallCmd: []string{"sudo", "xcode-select", "-s", "/Applications/Xcode.app/Contents/Developer"},
|
||||
InstallMsg: "Xcode developer path needs to be configured",
|
||||
SuccessMsg: "✅ Xcode developer path configured",
|
||||
FailureMsg: "❌ Xcode developer path not configured correctly",
|
||||
},
|
||||
{
|
||||
Name: "iOS SDK",
|
||||
CheckFunc: func() (bool, string) {
|
||||
// Get the iOS Simulator SDK path
|
||||
cmd := exec.Command("xcrun", "--sdk", "iphonesimulator", "--show-sdk-path")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return false, "Cannot find iOS SDK"
|
||||
}
|
||||
sdkPath := strings.TrimSpace(string(output))
|
||||
|
||||
// Check if the SDK path exists
|
||||
if _, err := os.Stat(sdkPath); err != nil {
|
||||
return false, "iOS SDK path not found"
|
||||
}
|
||||
|
||||
// Check for UIKit framework (essential for iOS development)
|
||||
uikitPath := fmt.Sprintf("%s/System/Library/Frameworks/UIKit.framework", sdkPath)
|
||||
if _, err := os.Stat(uikitPath); err != nil {
|
||||
return false, "UIKit.framework not found"
|
||||
}
|
||||
|
||||
// Get SDK version
|
||||
versionCmd := exec.Command("xcrun", "--sdk", "iphonesimulator", "--show-sdk-version")
|
||||
versionOut, _ := versionCmd.Output()
|
||||
version := strings.TrimSpace(string(versionOut))
|
||||
|
||||
return true, fmt.Sprintf("iOS %s SDK", version)
|
||||
},
|
||||
Required: true,
|
||||
InstallMsg: "iOS SDK comes with Xcode. Please ensure Xcode is properly installed.",
|
||||
SuccessMsg: "✅ iOS SDK found with UIKit framework",
|
||||
FailureMsg: "❌ iOS SDK not found or incomplete",
|
||||
},
|
||||
{
|
||||
Name: "iOS Simulator Runtime",
|
||||
CheckFunc: func() (bool, string) {
|
||||
if !checkCommand([]string{"xcrun", "simctl", "help"}) {
|
||||
return false, ""
|
||||
}
|
||||
// Check if we can list runtimes
|
||||
out, err := exec.Command("xcrun", "simctl", "list", "runtimes").Output()
|
||||
if err != nil {
|
||||
return false, "Cannot access simulator"
|
||||
}
|
||||
// Count iOS runtimes
|
||||
lines := strings.Split(string(out), "\n")
|
||||
count := 0
|
||||
var versions []string
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "iOS") && !strings.Contains(line, "unavailable") {
|
||||
count++
|
||||
// Extract version number
|
||||
if parts := strings.Fields(line); len(parts) > 2 {
|
||||
for _, part := range parts {
|
||||
if strings.HasPrefix(part, "(") && strings.HasSuffix(part, ")") {
|
||||
versions = append(versions, strings.Trim(part, "()"))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if count > 0 {
|
||||
return true, fmt.Sprintf("%d runtime(s): %s", count, strings.Join(versions, ", "))
|
||||
}
|
||||
return false, "No iOS runtimes installed"
|
||||
},
|
||||
Required: true,
|
||||
InstallMsg: "iOS Simulator runtimes come with Xcode. You may need to download them:\n Xcode → Settings → Platforms → iOS",
|
||||
SuccessMsg: "✅ iOS Simulator runtime available",
|
||||
FailureMsg: "❌ iOS Simulator runtime not available",
|
||||
},
|
||||
}
|
||||
|
||||
// Check each dependency
|
||||
for _, dep := range dependencies {
|
||||
success, details := dep.CheckFunc()
|
||||
if success {
|
||||
msg := dep.SuccessMsg
|
||||
if details != "" {
|
||||
msg = fmt.Sprintf("%s (%s)", dep.SuccessMsg, details)
|
||||
}
|
||||
fmt.Println(msg)
|
||||
} else {
|
||||
fmt.Println(dep.FailureMsg)
|
||||
if details != "" {
|
||||
fmt.Printf(" Details: %s\n", details)
|
||||
}
|
||||
if dep.Required {
|
||||
hasErrors = true
|
||||
if len(dep.InstallCmd) > 0 {
|
||||
fmt.Println()
|
||||
fmt.Println(" " + dep.InstallMsg)
|
||||
fmt.Printf(" Fix command: %s\n", strings.Join(dep.InstallCmd, " "))
|
||||
if promptUser("Do you want to run this command?") {
|
||||
fmt.Println("Running command...")
|
||||
cmd := exec.Command(dep.InstallCmd[0], dep.InstallCmd[1:]...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Printf("Command failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("✅ Command completed. Please run this check again.")
|
||||
} else {
|
||||
fmt.Printf(" Please run manually: %s\n", strings.Join(dep.InstallCmd, " "))
|
||||
}
|
||||
} else {
|
||||
fmt.Println(" " + dep.InstallMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for iPhone simulators
|
||||
fmt.Println()
|
||||
fmt.Println("Checking for iPhone simulator devices...")
|
||||
if !checkCommand([]string{"xcrun", "simctl", "list", "devices"}) {
|
||||
fmt.Println("❌ Cannot check for iPhone simulators")
|
||||
hasErrors = true
|
||||
} else {
|
||||
out, err := exec.Command("xcrun", "simctl", "list", "devices").Output()
|
||||
if err != nil {
|
||||
fmt.Println("❌ Failed to list simulator devices")
|
||||
hasErrors = true
|
||||
} else if !strings.Contains(string(out), "iPhone") {
|
||||
fmt.Println("⚠️ No iPhone simulator devices found")
|
||||
fmt.Println()
|
||||
|
||||
// Get the latest iOS runtime
|
||||
runtimeOut, err := exec.Command("xcrun", "simctl", "list", "runtimes").Output()
|
||||
if err != nil {
|
||||
fmt.Println(" Failed to get iOS runtimes:", err)
|
||||
} else {
|
||||
lines := strings.Split(string(runtimeOut), "\n")
|
||||
var latestRuntime string
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "iOS") && !strings.Contains(line, "unavailable") {
|
||||
// Extract runtime identifier
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) > 0 {
|
||||
latestRuntime = parts[len(parts)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if latestRuntime == "" {
|
||||
fmt.Println(" No iOS runtime found. Please install iOS simulators in Xcode:")
|
||||
fmt.Println(" Xcode → Settings → Platforms → iOS")
|
||||
} else {
|
||||
fmt.Println(" Would you like to create an iPhone 15 Pro simulator?")
|
||||
createCmd := []string{"xcrun", "simctl", "create", "iPhone 15 Pro", "iPhone 15 Pro", latestRuntime}
|
||||
fmt.Printf(" Command: %s\n", strings.Join(createCmd, " "))
|
||||
if promptUser("Create simulator?") {
|
||||
cmd := exec.Command(createCmd[0], createCmd[1:]...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Printf(" Failed to create simulator: %v\n", err)
|
||||
} else {
|
||||
fmt.Println(" ✅ iPhone 15 Pro simulator created")
|
||||
}
|
||||
} else {
|
||||
fmt.Println(" Skipping simulator creation")
|
||||
fmt.Printf(" Create manually: %s\n", strings.Join(createCmd, " "))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Count iPhone devices
|
||||
count := 0
|
||||
lines := strings.Split(string(out), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "iPhone") && !strings.Contains(line, "unavailable") {
|
||||
count++
|
||||
}
|
||||
}
|
||||
fmt.Printf("✅ %d iPhone simulator device(s) available\n", count)
|
||||
}
|
||||
}
|
||||
|
||||
// Final summary
|
||||
fmt.Println()
|
||||
fmt.Println("=" + strings.Repeat("=", 50))
|
||||
if hasErrors {
|
||||
fmt.Println("❌ Some required dependencies are missing or misconfigured.")
|
||||
fmt.Println()
|
||||
fmt.Println("Quick setup guide:")
|
||||
fmt.Println("1. Install Xcode from Mac App Store (if not installed)")
|
||||
fmt.Println("2. Open Xcode once and agree to the license")
|
||||
fmt.Println("3. Install additional components when prompted")
|
||||
fmt.Println("4. Run: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer")
|
||||
fmt.Println("5. Download iOS simulators: Xcode → Settings → Platforms → iOS")
|
||||
fmt.Println("6. Run this check again")
|
||||
os.Exit(1)
|
||||
} else {
|
||||
fmt.Println("✅ All required dependencies are installed!")
|
||||
fmt.Println(" You're ready for iOS development with Wails!")
|
||||
}
|
||||
}
|
||||
|
||||
func checkCommand(args []string) bool {
|
||||
if len(args) == 0 {
|
||||
return false
|
||||
}
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
err := cmd.Run()
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func promptUser(question string) bool {
|
||||
// Check if we're in a non-interactive environment
|
||||
if os.Getenv("CI") != "" || os.Getenv("TASK_FORCE_YES") == "true" {
|
||||
fmt.Printf("%s [y/N]: y (auto-accepted)\n", question)
|
||||
return true
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Printf("%s [y/N]: ", question)
|
||||
|
||||
response, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
response = strings.ToLower(strings.TrimSpace(response))
|
||||
return response == "y" || response == "yes"
|
||||
}
|
||||
Reference in New Issue
Block a user