Let the iOS project open and run in Xcode straight from a clone.

The build script now extracts content.json into derived data and copies
it into the app bundle, so no generated file is referenced from the
project or written into the repository. Signing is explicit: ad hoc for
the simulator, automatic with your own team for a device.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pepaskopec-blip 2026-09-18 15:46:58 +02:00
commit 2eec46329a
5 changed files with 25 additions and 15 deletions

1
.gitignore vendored
View file

@ -39,5 +39,4 @@ android/app/src/main/assets/content.json
ios/DerivedData/
ios/build/
ios/Payload/
ios/Maturita/content.json
ios/**/xcuserdata/

View file

@ -163,12 +163,14 @@ nebo z kořene `make android`.
iOS ze zdroje (Xcode 26, iOS 26+ / Liquid Glass):
```bash
python3 scripts/extract-android-content.py
open ios/Maturita.xcodeproj
# Signing: vlastní Team, Run na iPhone
# Simulátor: vyber iPhone a Run, nic dalšího není potřeba (obsah se
# vytáhne z C zdrojů při buildu). Na iPhone: v Signing vyber svůj Team.
# nebo: make ios # unsigned IPA v dist-ios/maturita-ios.ipa
```
Projekt musí zůstat v `ios/` uvnitř repozitáře – build čte `../src` a `../scripts`.
Licence: [GPL-3.0](LICENSE).
---
@ -331,10 +333,12 @@ or `make android` from the repo root.
iOS from source (Xcode 26, iOS 26+ / Liquid Glass):
```bash
python3 scripts/extract-android-content.py
open ios/Maturita.xcodeproj
# Signing: your Team, Run on iPhone
# Simulator: pick an iPhone and Run, nothing else needed (content is
# extracted from the C sources during the build). Device: pick your Team.
# or: make ios # unsigned IPA at dist-ios/maturita-ios.ipa
```
Keep the project inside `ios/` in the checkout – the build reads `../src` and `../scripts`.
License: [GPL-3.0](LICENSE).

View file

@ -22,7 +22,6 @@
A101000000000000000014 /* Exercises.swift in Sources */ = {isa = PBXBuildFile; fileRef = A201000000000000000014 /* Exercises.swift */; };
A101000000000000000015 /* ExercisesMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A201000000000000000015 /* ExercisesMore.swift */; };
A101000000000000000016 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A201000000000000000016 /* Assets.xcassets */; };
A101000000000000000017 /* content.json in Resources */ = {isa = PBXBuildFile; fileRef = A201000000000000000017 /* content.json */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -41,7 +40,6 @@
A201000000000000000014 /* Exercises.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Exercises.swift; sourceTree = "<group>"; };
A201000000000000000015 /* ExercisesMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExercisesMore.swift; sourceTree = "<group>"; };
A201000000000000000016 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A201000000000000000017 /* content.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = content.json; sourceTree = "<group>"; };
A201000000000000000018 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A301000000000000000001 /* Maturita.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Maturita.app; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@ -75,7 +73,6 @@
A501000000000000000004 /* Update */,
A501000000000000000005 /* UI */,
A201000000000000000016 /* Assets.xcassets */,
A201000000000000000017 /* content.json */,
A201000000000000000018 /* Info.plist */,
);
path = Maturita;
@ -128,10 +125,10 @@
isa = PBXNativeTarget;
buildConfigurationList = A801000000000000000002 /* Build configuration list for PBXNativeTarget "Maturita" */;
buildPhases = (
A701000000000000000004 /* Extract content */,
A701000000000000000001 /* Sources */,
A401000000000000000001 /* Frameworks */,
A701000000000000000002 /* Resources */,
A701000000000000000004 /* Extract content */,
);
buildRules = (
);
@ -182,7 +179,6 @@
buildActionMask = 2147483647;
files = (
A101000000000000000016 /* Assets.xcassets in Resources */,
A101000000000000000017 /* content.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -203,11 +199,12 @@
outputFileListPaths = (
);
outputPaths = (
"$(SRCROOT)/Maturita/content.json",
"$(DERIVED_FILE_DIR)/content.json",
"$(TARGET_BUILD_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/content.json",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "python3 \"${SRCROOT}/../scripts/extract-android-content.py\"\n";
shellScript = "# Pull the exercises out of the C sources and drop the JSON into the app\n# bundle. Nothing generated is kept in the repository, so a fresh clone opens\n# and runs in Xcode without extra steps.\nset -eu\nextract=\"${SRCROOT}/../scripts/extract-android-content.py\"\nif [ ! -f \"$extract\" ]; then\n echo \"error: ${extract} not found. Keep ios/ inside the maturita.c checkout.\" >&2\n exit 1\nfi\nout=\"${DERIVED_FILE_DIR}/content.json\"\nmkdir -p \"${DERIVED_FILE_DIR}\"\npython3 \"$extract\" --out \"$out\"\nmkdir -p \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\"\ncp \"$out\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/content.json\"\n";
};
/* End PBXShellScriptBuildPhase section */
@ -338,7 +335,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
"CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = "-";
COMMIT = dev;
DEVELOPMENT_TEAM = "";
CURRENT_PROJECT_VERSION = 1;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@ -371,7 +371,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
"CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = "-";
COMMIT = dev;
DEVELOPMENT_TEAM = "";
CURRENT_PROJECT_VERSION = 1;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;

View file

@ -6,8 +6,7 @@ set -eu
root=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)
cd "$root"
python3 scripts/extract-android-content.py
# The Xcode target extracts content.json itself during the build.
export DEVELOPER_DIR="${DEVELOPER_DIR:-/Applications/Xcode.app/Contents/Developer}"
COMMIT="${COMMIT:-$(git -C "$root" rev-parse HEAD 2>/dev/null || echo dev)}"
dd="$root/ios/DerivedData"

View file

@ -10,10 +10,15 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "src"
# Default target is the Android asset; Xcode passes `--out` and copies the
# file into the app bundle itself, so nothing generated lives under ios/.
OUTS = [
ROOT / "android" / "app" / "src" / "main" / "assets" / "content.json",
ROOT / "ios" / "Maturita" / "content.json",
]
if "--out" in sys.argv:
OUTS = [Path(a) for a in sys.argv[sys.argv.index("--out") + 1:] if a]
if not OUTS:
sys.exit("usage: extract-android-content.py [--out PATH ...]")
OUT = OUTS[0]
IDENT = re.compile(r"[A-Za-z_][A-Za-z0-9_]*")