Simple install guide and one-step install.sh
- README rewritten as a step-by-step guide for non-developers - install.sh: build, install and copy data with plain error messages - build_native.py: bundle identifier from the user's provisioning profile (Xcode project named factorio), version check on every build, friendly errors
This commit is contained in:
1 parent
51d085e865
commit
30b961c923
4 files changed
+227
-133
No files matched your search
@@ -1,114 +1,135 @@
|
||||
# Factorio on iPhone (personal port)
|
||||
# Factorio on iPhone
|
||||
|
||||
Run your own copy of **Factorio 2.0.77** natively on an iPhone. The original macOS ARM64 game
|
||||
code from your local install runs unchanged on iOS; this repository supplies the glue: a Mach-O
|
||||
retargeting step, a small set of shims for the macOS APIs iOS lacks, touch and keyboard
|
||||
controls, and build/sign/install tooling.
|
||||
Play your own copy of **Factorio** on your iPhone. You build the app on your Mac from the
|
||||
Factorio you already own on Steam, and install it on your phone with a cable.
|
||||
|
||||
**This repository contains no game files.** You need a legitimately owned copy of Factorio for
|
||||
macOS (the Steam build). The build reads the executable and data from your local install and
|
||||
installs them only on your own device. This is an unofficial, personal project and is not
|
||||
affiliated with or endorsed by Wube Software.
|
||||
This project contains **no game files**. Everything comes from your own installed copy. It is an
|
||||
unofficial fan project, not made or supported by Wube Software.
|
||||
|
||||
## Status
|
||||
---
|
||||
|
||||
Tested on an iPhone 15 Pro (iOS 27.0.1) with Xcode 26.6 (iOS SDK 26.5), using the Steam macOS
|
||||
build of Factorio 2.0.77 (base game).
|
||||
## What you need
|
||||
|
||||
| Area | State |
|
||||
| --- | --- |
|
||||
| Startup to main menu | ~16 s |
|
||||
| Rendering | Metal, native panel resolution (2556×1179 on iPhone 15 Pro) |
|
||||
| New game, playing, autosave | Working |
|
||||
| Audio | Working (plays with the silent switch on, mixes with other apps) |
|
||||
| Touch controls, on-screen overlay | Working |
|
||||
| Hardware keyboard, iOS keyboard with extra keys | Working |
|
||||
| Loading saves, long sessions, large factories | Not yet verified |
|
||||
| Mods, multiplayer, Space Age | Not tested |
|
||||
- A **Mac** (tested on Apple Silicon).
|
||||
- **Factorio 2.0.77 for Mac, bought on Steam** and installed.
|
||||
- An **iPhone** (tested on iPhone 15 Pro) and its **cable**.
|
||||
- A free or paid **Apple account**.
|
||||
- About **3 GB** of free space on the phone.
|
||||
|
||||
No JIT and no emulation: the game's own ARM64 machine code runs natively, signed with your
|
||||
developer certificate.
|
||||
---
|
||||
|
||||
## Requirements
|
||||
## Install, step by step
|
||||
|
||||
- A Mac (tested on Apple Silicon) with **Xcode**, including the iOS platform, and **Python 3**.
|
||||
- **Factorio 2.0.77 for macOS from Steam**, installed at the default Steam location (or pass
|
||||
`--game`). The build checks the exact executable hash and refuses other versions.
|
||||
- An iPhone with an A-series chip that supports Metal, **Developer Mode** enabled, paired with
|
||||
the Mac.
|
||||
- An Apple developer account signed into Xcode, with a development provisioning profile that
|
||||
covers the app's bundle identifier (a wildcard team profile works). See
|
||||
[docs/building.md](docs/building.md#signing).
|
||||
### Step 1: Install Xcode
|
||||
|
||||
## Quick start
|
||||
1. Open the **App Store** on your Mac, search for **Xcode** and install it (it is large and takes
|
||||
a while).
|
||||
2. Open Xcode once. When it asks which platforms to install, choose **iOS**.
|
||||
|
||||
### Step 2: Sign in to Xcode with your Apple account
|
||||
|
||||
1. In Xcode open **Xcode → Settings → Accounts**.
|
||||
2. Click **+**, choose **Apple ID** and sign in.
|
||||
|
||||
### Step 3: Connect your iPhone
|
||||
|
||||
1. Plug the iPhone into the Mac, unlock it, and tap **Trust**.
|
||||
2. On the iPhone open **Settings → Privacy & Security → Developer Mode**, turn it **on**, and let
|
||||
the phone restart. (If you don't see **Developer Mode** yet, do Step 4 first and come back.)
|
||||
|
||||
### Step 4: Let Xcode set up signing (one time only)
|
||||
|
||||
Your iPhone only runs apps signed with your Apple account. A tiny empty Xcode project sets this
|
||||
up once:
|
||||
|
||||
1. In Xcode choose **File → New → Project… → iOS → App → Next**.
|
||||
2. Fill in:
|
||||
- **Product Name:** `factorio`
|
||||
- **Team:** your Apple account
|
||||
- **Organization Identifier:** `com.` followed by your name, for example `com.alexsmith`
|
||||
3. Click **Next** and save it anywhere.
|
||||
4. At the top of the Xcode window, pick your **iPhone** as the run destination and press
|
||||
**▶ (Run)**. A blank white app appears on the phone; that means it worked. If the phone says
|
||||
**Untrusted Developer**, open **Settings → General → VPN & Device Management**, tap your
|
||||
account and choose **Trust**, then press **▶** again.
|
||||
|
||||
You can now close Xcode and delete that project. The real Factorio app will replace the blank one.
|
||||
|
||||
### Step 5: Download this project
|
||||
|
||||
Open the **Terminal** app on your Mac and run:
|
||||
|
||||
```sh
|
||||
# 1. Build, sign and install the app; copy the game data (~1.5 GB) into the app once.
|
||||
python3 tools/build_native.py --install --push-data
|
||||
|
||||
# 2. Launch with the console attached (or tap the Factorio icon on the home screen).
|
||||
python3 tools/build_native.py --no-build --launch
|
||||
git clone https://git.entityseven.com/entityseven/factorio-ios.git
|
||||
cd factorio-ios
|
||||
```
|
||||
|
||||
Later rebuilds only need `python3 tools/build_native.py --install`. Game data and saves live in
|
||||
the app's Documents folder and survive reinstalls. Full instructions, options and
|
||||
troubleshooting: [docs/building.md](docs/building.md).
|
||||
### Step 6: Install Factorio on the phone
|
||||
|
||||
## Controls
|
||||
Keep the iPhone **plugged in and unlocked**, then run:
|
||||
|
||||
| Input | Action |
|
||||
```sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
This builds the app, installs it, and copies the game data (about 1.5 GB) to the phone. It takes
|
||||
a few minutes. When it says **Done**, the **Factorio** icon is on your home screen.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Playing
|
||||
|
||||
- **Tap** = left click. **Hold** = right click (hold on ore or trees to mine them).
|
||||
- **Two-finger drag** = zoom and scroll.
|
||||
- **Left stick** = walk. Buttons **E Q R F M T**, **Esc**, **Tab**, **⇧**, **Ctrl** = the same keys
|
||||
as on a computer.
|
||||
- **⌨︎** opens the keyboard. **◐** hides the on-screen buttons.
|
||||
- A Bluetooth keyboard works too.
|
||||
|
||||
The text is small at first: in the game open **Settings → Interface** and set **UI scale** to
|
||||
about **175–200 %**.
|
||||
|
||||
The game takes about 15 seconds to start. Your saves stay on the phone, also when you update the
|
||||
app.
|
||||
|
||||
All controls: [docs/controls.md](docs/controls.md).
|
||||
|
||||
---
|
||||
|
||||
## Updating
|
||||
|
||||
```sh
|
||||
cd factorio-ios
|
||||
git pull
|
||||
./install.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Problems?
|
||||
|
||||
| What you see | What to do |
|
||||
| --- | --- |
|
||||
| Tap / drag | Left mouse button |
|
||||
| Long press (hold) | Right mouse button held: mining, removing; drag to keep going |
|
||||
| Two-finger drag | Mouse wheel (zoom, scroll lists) |
|
||||
| Left stick | W A S D movement |
|
||||
| E Q R F M T buttons | Inventory, pipette, rotate, pick up, map, technologies |
|
||||
| ⇧ and Ctrl buttons | Sticky modifiers for the next click or key |
|
||||
| Esc, Tab | Escape and Tab |
|
||||
| ⌨︎ | iOS keyboard plus a bar with Esc, Tab, Ctrl, Alt, ⇧, arrows, Home/End, PgUp/PgDn, F1–F12 |
|
||||
| ◐ | Hide or show the on-screen controls |
|
||||
| `Factorio not found` | Install Factorio from Steam on this Mac and let it finish downloading. |
|
||||
| `wrong Factorio version` | This version of the port needs Factorio **2.0.77**. In Steam, open the game's **Properties** and keep it on that version. |
|
||||
| `no provisioning profile found` | Do **Step 4** again. The Xcode project must be named `factorio`. |
|
||||
| `no iPhone found` | Plug in the phone, unlock it, tap **Trust**, and check **Developer Mode** (Step 3). |
|
||||
| `Xcode is not installed` / `iOS platform is missing` | Do **Step 1**. |
|
||||
| `device was not unlocked` | Unlock the phone and run `./install.sh` again. |
|
||||
| App says **Game data missing** | Run `./install.sh` again with the phone unlocked. |
|
||||
| App stops opening after 7 days | Free Apple accounts sign apps for 7 days. Run `./install.sh` again; your saves are kept. |
|
||||
| The game closes while playing | Run `python3 tools/build_native.py --no-build --launch` and send the output as a bug report. |
|
||||
|
||||
A Bluetooth or USB keyboard works directly with Factorio's normal key bindings. Details:
|
||||
[docs/controls.md](docs/controls.md).
|
||||
---
|
||||
|
||||
Factorio's interface is small at native resolution; set **Settings → Interface → UI scale** to
|
||||
around 175–200 %.
|
||||
## More information
|
||||
|
||||
## How it works
|
||||
- [docs/building.md](docs/building.md): advanced build options and troubleshooting.
|
||||
- [docs/native-port.md](docs/native-port.md): how the port works.
|
||||
- [docs/research/](docs/research/static-translation.md): earlier research (ARM64 → WASM
|
||||
translation).
|
||||
|
||||
1. `tools/retarget.py` turns the unmodified macOS executable into an iOS-loadable dynamic
|
||||
library by editing only Mach-O header fields (platform, file type, page-zero size,
|
||||
framework paths). It verifies that no byte after the header changes.
|
||||
2. `platform/native/shim/` implements the ~150 macOS symbols iOS lacks: an AppKit layer on
|
||||
UIKit sized to the SDL 2.24 Cocoa backend Factorio links statically, CoreGraphics display
|
||||
and CoreAudio device models, PNG decoding through Wuffs, Metal device properties, and
|
||||
stubs for Steam, Carbon, ForceFeedback, OpenCL and LDAP.
|
||||
3. A small host app starts UIKit, loads the game library and calls its original `main` on the
|
||||
main thread with a larger stack.
|
||||
|
||||
The design, every shim, and the verification behind it are described in
|
||||
[docs/native-port.md](docs/native-port.md).
|
||||
|
||||
## Repository layout
|
||||
|
||||
| Path | Contents |
|
||||
| --- | --- |
|
||||
| `tools/build_native.py` | Build, sign, install, copy data, launch |
|
||||
| `tools/retarget.py` | Header-only Mach-O retargeting of the game executable |
|
||||
| `tools/native_audit.py` | Lists game imports that iOS lacks (needs shims) |
|
||||
| `tools/symbolize_native.py` | Symbolizes crash reports against the game's debug symbols |
|
||||
| `tools/make_icon.m` | Builds the app icon from the game's own icon |
|
||||
| `platform/native/` | iOS host app and macOS API shims |
|
||||
| `tests/native/` | PNG decoder parity test against macOS ImageIO |
|
||||
| `docs/` | Build guide, controls, architecture |
|
||||
| `docs/research/`, `runtime/`, `tests/*.py`, other `tools/` | Earlier static-translation research (ARM64 → WASM → native), kept for reference |
|
||||
|
||||
## Third-party software
|
||||
|
||||
- [Wuffs](https://github.com/google/wuffs) v0.3.4 (Apache-2.0): PNG decoding. Downloaded at
|
||||
build time into `third_party/` and checked against a pinned SHA-256; not vendored.
|
||||
- [SDL](https://github.com/libsdl-org/SDL) 2.24 (zlib): statically linked inside the game
|
||||
binary; its source was used as a reference for the AppKit shim and is not included.
|
||||
- [WABT](https://github.com/WebAssembly/wabt) (Apache-2.0): used only by the research track.
|
||||
|
||||
Factorio is a trademark of Wube Software Ltd. All game code and assets remain theirs.
|
||||
**Third-party software:** [Wuffs](https://github.com/google/wuffs) (Apache-2.0) is downloaded
|
||||
during the build to decode PNG images. Factorio itself uses [SDL](https://github.com/libsdl-org/SDL)
|
||||
(zlib). Factorio is a trademark of Wube Software Ltd.; all game code and assets belong to them.
|
||||
+22
-17
@@ -32,28 +32,33 @@ The default game location is
|
||||
## Signing
|
||||
|
||||
The app is signed with your **Apple Development** certificate and a development provisioning
|
||||
profile. The build script picks them automatically:
|
||||
profile from `~/Library/Developer/Xcode/UserData/Provisioning Profiles`. The build chooses:
|
||||
|
||||
- it looks in `~/Library/Developer/Xcode/UserData/Provisioning Profiles` for a profile whose
|
||||
App ID is exactly the app's bundle identifier, or a wildcard (`TEAMID.*`) profile;
|
||||
- it signs with the keychain identity whose certificate is embedded in that profile;
|
||||
- the team ID comes from the profile (override with `--team` / `FX_TEAM`).
|
||||
1. with `--bundle-id` (or `FX_BUNDLE_ID`): a profile for exactly that App ID, else a wildcard
|
||||
(`TEAMID.*`) profile;
|
||||
2. otherwise: the newest profile whose App ID contains `factorio`, and that App ID becomes the
|
||||
app's bundle identifier;
|
||||
3. otherwise: a wildcard profile, with bundle identifier `local.factorio.native`.
|
||||
|
||||
If you have no suitable profile yet, let Xcode create one: create any new iOS App project, set
|
||||
its bundle identifier to `local.factorio.native` (or your own identifier, then pass the same one
|
||||
to `--bundle-id`), choose your team under *Signing & Capabilities* with automatic signing, select
|
||||
your iPhone and build it once. Xcode then downloads a profile that the script can use.
|
||||
It signs with the keychain identity whose certificate is embedded in the chosen profile; the team
|
||||
comes from the profile (override with `--team` / `FX_TEAM`). Expired profiles are ignored.
|
||||
|
||||
Free Apple accounts can sign apps for their own devices, but the installed app expires after
|
||||
seven days and has to be reinstalled. This has only been tested with a paid account.
|
||||
The README's step 4 creates a suitable profile: an empty Xcode iOS App project named `factorio`,
|
||||
with automatic signing for your team, run once on the iPhone. Its App ID
|
||||
(`com.<you>.factorio`) is unique to you, which Apple requires for explicit App IDs.
|
||||
|
||||
Free Apple accounts work the same way, but the installed app expires after seven days and has to
|
||||
be reinstalled with `./install.sh` (saves are kept). This has been tested with a paid account
|
||||
only.
|
||||
|
||||
## 3. Build and install
|
||||
|
||||
```sh
|
||||
python3 tools/build_native.py --install --push-data
|
||||
./install.sh # same as: python3 tools/build_native.py --install --push-data
|
||||
```
|
||||
|
||||
What happens:
|
||||
`install.sh` runs the steps below with short progress messages and writes the full output to
|
||||
`build/install.log`. What happens:
|
||||
|
||||
1. **Inputs.** The ARM64 slice of the game executable is extracted with `lipo` into
|
||||
`build/factorio.arm64`. The Wuffs PNG decoder source (v0.3.4) is downloaded into
|
||||
@@ -90,7 +95,7 @@ installing takes the longest; the main menu normally appears after about 16 seco
|
||||
| --- | --- | --- |
|
||||
| `--game PATH` | `FX_GAME` | Steam location (see above) |
|
||||
| `--team ID` | `FX_TEAM` | Taken from the provisioning profile |
|
||||
| `--bundle-id ID` | `FX_BUNDLE_ID` | `local.factorio.native` |
|
||||
| `--bundle-id ID` | `FX_BUNDLE_ID` | From the provisioning profile (see [Signing](#signing)) |
|
||||
| `--device ID` | `FX_DEVICE` | First paired device |
|
||||
| `--no-build` | | Install/launch the existing bundle |
|
||||
|
||||
@@ -110,7 +115,7 @@ files under the phone → Files → Factorio. A save from the Mac can be copied
|
||||
|
||||
```sh
|
||||
xcrun devicectl device copy to --device <id> --domain-type appDataContainer \
|
||||
--domain-identifier local.factorio.native \
|
||||
--domain-identifier <bundle identifier> \
|
||||
--source ~/Library/Application\ Support/factorio/saves/my-save.zip \
|
||||
--destination Documents/factorio/write/saves/my-save.zip
|
||||
```
|
||||
@@ -119,8 +124,8 @@ xcrun devicectl device copy to --device <id> --domain-type appDataContainer \
|
||||
|
||||
| Symptom | Cause and fix |
|
||||
| --- | --- |
|
||||
| `unexpected input …; only the inspected 2.0.77 ARM64 slice is supported` | The installed game is a different version. Install 2.0.77, or delete `build/factorio.arm64` if it was extracted from another install. |
|
||||
| `no provisioning profile covers …` | See [Signing](#signing). |
|
||||
| `wrong Factorio version` | The installed game is not 2.0.77. Select that version in Steam (game Properties → Betas) or pass `--game` to a 2.0.77 install. |
|
||||
| `no provisioning profile found` | See [Signing](#signing). |
|
||||
| `Unable to launch … because the device was not, or could not be, unlocked` | Unlock the phone and run the launch again. |
|
||||
| App shows "Game data missing" | Run `python3 tools/build_native.py --no-build --push-data`. |
|
||||
| App closes during play | Run with `--launch`, then `python3 tools/symbolize_native.py` to turn the `[fx-crash]` lines in `build/native/console.log` into function names. If there is no crash report, iOS may have stopped it for memory; check Settings → Privacy & Security → Analytics & Improvements → Analytics Data for a `JetsamEvent` report. |
|
||||
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
# Builds Factorio for iPhone from your local Steam copy, installs it on the connected iPhone and
|
||||
# copies the game data. Safe to run again: data that is already on the phone is skipped and saves
|
||||
# are kept. Extra arguments are passed to tools/build_native.py (see docs/building.md).
|
||||
cd "$(dirname "$0")" || exit 1
|
||||
mkdir -p build
|
||||
LOG=build/install.log
|
||||
: > "$LOG"
|
||||
|
||||
fail() {
|
||||
echo
|
||||
echo "Failed: $1"
|
||||
echo "Details are in $LOG"
|
||||
exit 1
|
||||
}
|
||||
|
||||
step() {
|
||||
# step "message" args... : run build_native.py with args, logging its output.
|
||||
message=$1; shift
|
||||
printf '%s... ' "$message"
|
||||
if python3 tools/build_native.py "$@" >> "$LOG" 2>&1; then
|
||||
echo "ok"
|
||||
else
|
||||
echo
|
||||
if grep -q "not, or could not be, unlocked" "$LOG"; then
|
||||
fail "device was not unlocked. Unlock the iPhone and run ./install.sh again."
|
||||
fi
|
||||
# build_native.py ends with a one-line explanation of what went wrong.
|
||||
reason=$(grep -v '^+' "$LOG" | grep -v '^\s*$' | tail -n 3)
|
||||
fail "$reason"
|
||||
fi
|
||||
}
|
||||
|
||||
command -v xcrun > /dev/null 2>&1 || fail "Xcode is not installed (README step 1)."
|
||||
xcrun --sdk iphoneos --show-sdk-path > /dev/null 2>&1 || fail "Xcode's iOS platform is missing (README step 1)."
|
||||
command -v python3 > /dev/null 2>&1 || fail "python3 not found; open Xcode once to finish installing its tools."
|
||||
|
||||
step "Building the app" "$@"
|
||||
step "Installing on the iPhone" --no-build --install "$@"
|
||||
step "Copying game data to the iPhone (first time takes a few minutes)" --no-build --push-data "$@"
|
||||
echo
|
||||
echo "Done. Open Factorio from the iPhone home screen."
|
||||
+48
-22
@@ -12,7 +12,8 @@ Usage:
|
||||
Options (each also readable from the environment variable shown):
|
||||
--game PATH factorio.app/Contents of a local install (FX_GAME; default: Steam location)
|
||||
--team ID Apple developer team ID (FX_TEAM; default: from your provisioning profiles)
|
||||
--bundle-id ID app bundle identifier (FX_BUNDLE_ID; default: local.factorio.native)
|
||||
--bundle-id ID app bundle identifier (FX_BUNDLE_ID; default: the App ID of a provisioning profile
|
||||
containing "factorio", else local.factorio.native with a wildcard profile)
|
||||
--device ID devicectl device identifier or name (FX_DEVICE; default: first paired device)
|
||||
|
||||
The game executable is the unmodified ARM64 slice with only Mach-O header changes (see
|
||||
@@ -24,6 +25,7 @@ import json
|
||||
import os
|
||||
import plistlib
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
@@ -36,7 +38,9 @@ SRC = ROOT / "platform/native"
|
||||
MIN_IOS = "17.0"
|
||||
# Set from command-line options / environment in main().
|
||||
GAME = STEAM_GAME
|
||||
BUNDLE_ID = "local.factorio.native"
|
||||
BUNDLE_ID = None # resolved from the provisioning profile unless given
|
||||
DEFAULT_BUNDLE_ID = "local.factorio.native"
|
||||
SLICE_SHA256 = "2cb4de127b50d54c6c5666acfef2263fae16d11a3361ad39353ecf8a66a4d9c7" # 2.0.77 Steam, arm64
|
||||
TEAM = None
|
||||
|
||||
SLICE = ROOT / "build/factorio.arm64"
|
||||
@@ -113,12 +117,14 @@ def build_icon():
|
||||
|
||||
def prepare_inputs():
|
||||
"""Extract the ARM64 slice from the local install and fetch the pinned Wuffs source."""
|
||||
if not SLICE.exists():
|
||||
binary = GAME / "MacOS/factorio"
|
||||
if not binary.exists():
|
||||
raise SystemExit(f"Factorio executable not found at {binary}; pass --game PATH/factorio.app/Contents")
|
||||
SLICE.parent.mkdir(parents=True, exist_ok=True)
|
||||
run(["lipo", "-thin", "arm64", binary, "-output", SLICE])
|
||||
binary = GAME / "MacOS/factorio"
|
||||
if not binary.exists():
|
||||
raise SystemExit(f"Factorio not found at {GAME}.\nInstall Factorio from Steam on this Mac, or pass --game PATH/factorio.app/Contents.")
|
||||
SLICE.parent.mkdir(parents=True, exist_ok=True)
|
||||
# Re-extract every build so a Steam update is noticed.
|
||||
run(["lipo", "-thin", "arm64", binary, "-output", SLICE])
|
||||
if hashlib.sha256(SLICE.read_bytes()).hexdigest() != SLICE_SHA256:
|
||||
raise SystemExit("wrong Factorio version: this port needs Factorio 2.0.77 for macOS from Steam.")
|
||||
if not WUFFS.exists() or hashlib.sha256(WUFFS.read_bytes()).hexdigest() != WUFFS_SHA256:
|
||||
WUFFS.parent.mkdir(parents=True, exist_ok=True)
|
||||
print("+ fetch", WUFFS_URL, flush=True)
|
||||
@@ -164,24 +170,42 @@ def build():
|
||||
sign()
|
||||
|
||||
|
||||
def find_profile():
|
||||
"""A development profile covering BUNDLE_ID (explicit or wildcard), optionally for TEAM."""
|
||||
def load_profiles():
|
||||
folder = Path.home() / "Library/Developer/Xcode/UserData/Provisioning Profiles"
|
||||
candidates = []
|
||||
profiles = []
|
||||
for path in sorted(folder.glob("*.mobileprovision")):
|
||||
plist = plistlib.loads(subprocess.check_output(["security", "cms", "-D", "-i", str(path)]))
|
||||
team = plist["TeamIdentifier"][0]
|
||||
app_id = plist["Entitlements"]["application-identifier"]
|
||||
if TEAM and team != TEAM:
|
||||
continue
|
||||
if app_id == f"{team}.{BUNDLE_ID}":
|
||||
candidates.insert(0, (path, plist, team)) # explicit App ID wins over wildcard
|
||||
elif app_id == f"{team}.*":
|
||||
candidates.append((path, plist, team))
|
||||
if not candidates:
|
||||
raise SystemExit(f"no provisioning profile covers {BUNDLE_ID}" + (f" for team {TEAM}" if TEAM else "") +
|
||||
". Create one in Xcode (any project, automatic signing, same team) or pass --team.")
|
||||
return candidates[0]
|
||||
if plist.get("ExpirationDate") and plist["ExpirationDate"].timestamp() < time.time():
|
||||
continue
|
||||
bundle = plist["Entitlements"]["application-identifier"].split(".", 1)[1]
|
||||
profiles.append((path, plist, team, bundle))
|
||||
return profiles
|
||||
|
||||
|
||||
def find_profile():
|
||||
"""Choose the signing profile and the bundle identifier it allows.
|
||||
|
||||
Preference: an explicit App ID equal to --bundle-id; otherwise an explicit App ID containing
|
||||
"factorio" (what the README's one-time Xcode project creates); otherwise a wildcard profile.
|
||||
"""
|
||||
global BUNDLE_ID
|
||||
profiles = load_profiles()
|
||||
if BUNDLE_ID:
|
||||
matches = [p for p in profiles if p[3] == BUNDLE_ID] + [p for p in profiles if p[3] == "*"]
|
||||
else:
|
||||
named = sorted((p for p in profiles if "factorio" in p[3].lower() and p[3] != "*"),
|
||||
key=lambda p: p[1].get("CreationDate"), reverse=True)
|
||||
matches = named + [p for p in profiles if p[3] == "*"]
|
||||
if not matches:
|
||||
raise SystemExit("no provisioning profile found for the app.\n"
|
||||
"Do README step 4 once (an Xcode project named \"factorio\" run on your iPhone).")
|
||||
path, plist, team, bundle = matches[0]
|
||||
if not BUNDLE_ID:
|
||||
BUNDLE_ID = bundle if bundle != "*" else DEFAULT_BUNDLE_ID
|
||||
return path, plist, team
|
||||
|
||||
|
||||
def signing_identity(profile):
|
||||
@@ -222,7 +246,7 @@ def device(requested=None):
|
||||
for d in data["result"]["devices"]:
|
||||
if d.get("connectionProperties", {}).get("pairingState") == "paired":
|
||||
return d["identifier"]
|
||||
raise SystemExit("no paired device")
|
||||
raise SystemExit("no iPhone found: plug it in, unlock it, tap Trust, and turn on Developer Mode.")
|
||||
|
||||
|
||||
def main():
|
||||
@@ -234,10 +258,12 @@ def main():
|
||||
parser.add_argument("--no-build", action="store_true")
|
||||
parser.add_argument("--game", default=os.environ.get("FX_GAME", str(STEAM_GAME)))
|
||||
parser.add_argument("--team", default=os.environ.get("FX_TEAM"))
|
||||
parser.add_argument("--bundle-id", default=os.environ.get("FX_BUNDLE_ID", BUNDLE_ID))
|
||||
parser.add_argument("--bundle-id", default=os.environ.get("FX_BUNDLE_ID"))
|
||||
parser.add_argument("--device", default=os.environ.get("FX_DEVICE"))
|
||||
args = parser.parse_args()
|
||||
GAME, BUNDLE_ID, TEAM = Path(args.game), args.bundle_id, args.team
|
||||
find_profile()
|
||||
print(f"+ bundle identifier {BUNDLE_ID}", flush=True)
|
||||
if not args.no_build:
|
||||
build()
|
||||
if args.install or args.push_data or args.launch:
|
||||
|
||||
Reference in new issue
Block a user