Repository navigation
Expand file tree
/
Copy pathipabuild.sh
More file actions
executable file
·214 lines (185 loc) · 7.05 KB
/
Copy pathipabuild.sh
File metadata and controls
executable file
·214 lines (185 loc) · 7.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/bin/bash
set -e
cd "$(dirname "$0")"
WORKING_LOCATION="$(pwd)"
PROJECT_NAME="Eclipse"
APPLICATION_NAME="Eclipse"
PLATFORM=${1:-ios}
case "$PLATFORM" in
ios|iOS)
PLATFORM="ios"
SCHEME="$PROJECT_NAME"
SDK="iphoneos"
XCODE_DESTINATION="generic/platform=iOS"
OUTPUT_SUFFIX=""
;;
tvos|tvOS)
PLATFORM="tvos"
SCHEME="$PROJECT_NAME-tvOS"
SDK="appletvos"
XCODE_DESTINATION="generic/platform=tvOS"
OUTPUT_SUFFIX="-tvOS"
;;
*)
echo "Error: Invalid platform '$PLATFORM'"
echo "Usage: $0 [ios|tvos]"
echo " ios - Build for iOS (default)"
echo " tvos - Build for tvOS"
exit 1
;;
esac
mkdir -p build
cd build
BUILD_INVOCATION_DIR=$(mktemp -d "$WORKING_LOCATION/build/.ipa-$PLATFORM.XXXXXX")
trap 'rm -rf "$BUILD_INVOCATION_DIR"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
DERIVED_DATA_PATH="$BUILD_INVOCATION_DIR/DerivedData"
SOURCE_PACKAGES_DIR="$BUILD_INVOCATION_DIR/SourcePackages"
XCODE_CONTAINER=(-project "$WORKING_LOCATION/$PROJECT_NAME.xcodeproj")
MPVKIT_CHECKOUT="$WORKING_LOCATION/../MPVKit"
MPVKIT_LOCAL_RUNTIME="$MPVKIT_CHECKOUT/dist/release"
if [ -d "$MPVKIT_LOCAL_RUNTIME/Libmpv.xcframework" ] \
|| [ -d "$MPVKIT_LOCAL_RUNTIME/xcframework/Libmpv.xcframework" ]; then
# MPVKit's manifest can auto-discover this directory, but SwiftPM's manifest
# cache does not observe artifact contents. Bind resolution and archive to
# the same reviewed local runtime that the native-export audit examines.
export MPVKIT_LOCAL_ARTIFACTS_DIR="dist/release"
fi
xcodebuild -resolvePackageDependencies \
"${XCODE_CONTAINER[@]}" \
-scheme "$SCHEME" \
-derivedDataPath "$DERIVED_DATA_PATH" \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
-skipPackagePluginValidation \
-skipMacroValidation
if [ "$PLATFORM" = "ios" ]; then
LIBMPV_SLICE='*Libmpv.xcframework/ios-arm64/Libmpv.framework/Libmpv'
else
LIBMPV_SLICE='*Libmpv.xcframework/tvos-arm64_arm64e/Libmpv.framework/Libmpv'
fi
LIBMPV_BINARY=""
for ARTIFACT_ROOT in "$MPVKIT_CHECKOUT/dist/release" "$SOURCE_PACKAGES_DIR/artifacts"; do
if [ ! -d "$ARTIFACT_ROOT" ]; then
continue
fi
LIBMPV_BINARY="$(find "$ARTIFACT_ROOT" -path "$LIBMPV_SLICE" -type f -print -quit)"
if [ -n "$LIBMPV_BINARY" ]; then
break
fi
done
if [ -z "$LIBMPV_BINARY" ]; then
echo "Error: The resolved MPVKit runtime does not contain the $PLATFORM Libmpv device slice."
exit 1
fi
LIBMPV_SYMBOLS="$BUILD_INVOCATION_DIR/libmpv-symbols.txt"
xcrun nm -gU "$LIBMPV_BINARY" > "$LIBMPV_SYMBOLS" 2>/dev/null || true
for SYMBOL in \
mpv_apple_pip_api_version \
mpv_apple_pip_get_capabilities \
mpv_apple_pip_set_callback \
mpv_apple_pip_set_mode \
mpv_apple_pip_submit_target \
mpv_apple_pip_disable_and_drain \
mpv_apple_audiounit_recovery_count
do
if ! grep -Eq "[[:space:]]_?${SYMBOL}$" "$LIBMPV_SYMBOLS"; then
echo "Error: The resolved $PLATFORM Libmpv artifact is missing required native export '$SYMBOL'."
echo "Rebuild the reviewed private MPVKit runtime in ../MPVKit/dist/release before packaging."
exit 1
fi
done
rm -f "$LIBMPV_SYMBOLS"
# Create archive (required for proper IPA structure)
ARCHIVE_PATH="$BUILD_INVOCATION_DIR/$APPLICATION_NAME.xcarchive"
rm -rf "$ARCHIVE_PATH"
xcodebuild archive \
"${XCODE_CONTAINER[@]}" \
-scheme "$SCHEME" \
-configuration Release \
-archivePath "$ARCHIVE_PATH" \
-destination "$XCODE_DESTINATION" \
-sdk "$SDK" \
-derivedDataPath "$DERIVED_DATA_PATH" \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
-disableAutomaticPackageResolution \
-skipPackagePluginValidation \
-skipMacroValidation \
CODE_SIGN_IDENTITY="" \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGNING_ALLOWED=NO \
'SWIFT_ACTIVE_COMPILATION_CONDITIONS=$(inherited) ECLIPSE_UNSIGNED_BUILD' \
ENABLE_USER_SCRIPT_SANDBOXING=NO
# Verify archive was created
if [ ! -d "$ARCHIVE_PATH" ]; then
echo "Error: Archive failed to create at $ARCHIVE_PATH"
exit 1
fi
# Extract app from archive (correct path: Products/Applications)
APP_PATH="$ARCHIVE_PATH/Products/Applications/$PROJECT_NAME.app"
if [ ! -d "$APP_PATH" ]; then
APP_PATH="$(find "$ARCHIVE_PATH/Products/Applications" -maxdepth 1 -type d -name "*.app" 2>/dev/null | head -n 1)"
if [ -z "$APP_PATH" ] || [ ! -d "$APP_PATH" ]; then
echo "Error: App not found at $ARCHIVE_PATH/Products/Applications"
echo "Contents of archive:"
find "$ARCHIVE_PATH" -type d -name "*.app" 2>/dev/null || echo "No app bundles found"
exit 1
fi
fi
if [ "$PLATFORM" = "ios" ]; then
"$WORKING_LOCATION/scripts/validate-ios-privacy-manifest.sh" "$APP_PATH"
else
MANIFEST_PATH="$APP_PATH/PrivacyInfo.xcprivacy"
if [ ! -f "$MANIFEST_PATH" ]; then
echo "Error: PrivacyInfo.xcprivacy is missing from the tvOS app bundle."
exit 1
fi
plutil -lint "$MANIFEST_PATH" >/dev/null
python3 - "$MANIFEST_PATH" <<'PY'
import plistlib
import sys
with open(sys.argv[1], "rb") as handle:
manifest = plistlib.load(handle)
if manifest.get("NSPrivacyTracking") is not False:
raise SystemExit("error: tvOS privacy manifest must declare NSPrivacyTracking=false.")
if manifest.get("NSPrivacyCollectedDataTypes") != []:
raise SystemExit("error: tvOS privacy manifest must contain an empty NSPrivacyCollectedDataTypes array.")
required = {
"NSPrivacyAccessedAPICategoryUserDefaults": {"CA92.1"},
"NSPrivacyAccessedAPICategorySystemBootTime": {"35F9.1"},
"NSPrivacyAccessedAPICategoryFileTimestamp": {"C617.1"},
"NSPrivacyAccessedAPICategoryDiskSpace": {"E174.1"},
}
declared = {
entry.get("NSPrivacyAccessedAPIType"): set(entry.get("NSPrivacyAccessedAPITypeReasons", []))
for entry in manifest.get("NSPrivacyAccessedAPITypes", [])
if isinstance(entry, dict)
}
for category, reasons in required.items():
missing = reasons - declared.get(category, set())
if missing:
raise SystemExit(
f"error: tvOS privacy manifest is missing {category} reason(s) {', '.join(sorted(missing))}."
)
PY
echo "tvOS privacy manifest validation passed"
fi
# Create Payload directory and copy app
cd "$BUILD_INVOCATION_DIR"
mkdir Payload
cp -r "$APP_PATH" "Payload/$APPLICATION_NAME.app"
# Strip binary to reduce size
if [ -f "Payload/$APPLICATION_NAME.app/$PROJECT_NAME" ]; then
strip "Payload/$APPLICATION_NAME.app/$PROJECT_NAME" 2>/dev/null || true
elif [ -f "Payload/$APPLICATION_NAME.app/$APPLICATION_NAME" ]; then
strip "Payload/$APPLICATION_NAME.app/$APPLICATION_NAME" 2>/dev/null || true
fi
# Remove code signature
rm -rf "Payload/$APPLICATION_NAME.app/_CodeSignature" 2>/dev/null || true
rm -f "Payload/$APPLICATION_NAME.app/embedded.mobileprovision" 2>/dev/null || true
# Create IPA (preserve symlinks with -y, recursive with -r)
zip -qry "$APPLICATION_NAME$OUTPUT_SUFFIX.ipa" Payload
mv -f "$APPLICATION_NAME$OUTPUT_SUFFIX.ipa" "$WORKING_LOCATION/build/$APPLICATION_NAME$OUTPUT_SUFFIX.ipa"
# Cleanup
rm -rf Payload
rm -rf "$ARCHIVE_PATH"