Files
factorio-ios/docs/building.md
T
SashaGoncharov19 51d085e865 Native iPhone port of Factorio 2.0.77
Run the original macOS ARM64 game code on iOS:
- tools/retarget.py: header-only Mach-O retargeting to an iOS dylib
- platform/native: UIKit host and macOS API shims (AppKit for SDL's
  Cocoa backend, CoreGraphics displays, CoreAudio device, Metal device
  properties, Wuffs PNG decoding, Steam and peripheral stubs)
- touch, overlay, iOS keyboard and hardware keyboard input
- tools/build_native.py: build, sign, install, data copy, launch
- docs: build guide, controls, architecture

Also includes the earlier static-translation research (ARM64 -> WASM ->
native) under docs/research, runtime/, tests/ and tools/.

No game files are included; the build reads them from a local install.
2026-10-23 15:27:58 +04:00

6.7 KiB

Building, installing and running

All commands run from the repository root on the Mac. Nothing needs to be installed with pip; the scripts use only the Python standard library and Xcode's command-line tools.

1. Prepare the Mac

  1. Install Xcode from the App Store, open it once, and install the iOS platform when it asks (Xcode → Settings → Components).
  2. Sign into your Apple developer account: Xcode → Settings → Accounts.
  3. Install Factorio for macOS through Steam and let it finish downloading. The build expects version 2.0.77; it checks the SHA-256 of the executable's ARM64 slice (2cb4de127b50d54c6c5666acfef2263fae16d11a3361ad39353ecf8a66a4d9c7) and stops if it differs. Turning off automatic Steam updates for the game keeps the build working until the port is updated for a newer version.

The default game location is ~/Library/Application Support/Steam/steamapps/common/Factorio/factorio.app/Contents. Pass --game /path/to/factorio.app/Contents (or set FX_GAME) if yours is elsewhere.

2. Prepare the iPhone

  1. Connect the iPhone by cable, unlock it and tap Trust for this Mac.

  2. Enable Developer Mode: Settings → Privacy & Security → Developer Mode, then restart.

  3. Check that the Mac sees it:

    xcrun devicectl list devices
    

    The phone should be listed as available (paired).

Signing

The app is signed with your Apple Development certificate and a development provisioning profile. The build script picks them automatically:

  • 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).

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.

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.

3. Build and install

python3 tools/build_native.py --install --push-data

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 third_party/wuffs/ and checked against its pinned SHA-256.
  2. Retarget. tools/retarget.py writes build/native/Factorio.dylib, changing only Mach-O header bytes, and records the changes in build/native/retarget.json.
  3. Shims and host. The shim libraries and the small host executable are compiled for iOS with clang; the app icon is generated from the game's own icon.
  4. Bundle and sign. build/native/Factorio.app is assembled, signed, and installed with devicectl.
  5. Data. --push-data copies the game's data/ folder (~1.5 GB) into the app's Documents/factorio/data on the phone. This is only needed the first time, after deleting the app, or after a game update.

The bundle never contains game data. Game settings, saves and logs are written to Documents/factorio/ inside the app's container and survive reinstalls.

4. Run

Tap the Factorio icon on the home screen, or launch it from the Mac with the console attached:

python3 tools/build_native.py --no-build --launch

The phone must be unlocked for a launch from the Mac. Console output (the shim's [fx] lines and Factorio's own log) is shown and saved to build/native/console.log. The first start after installing takes the longest; the main menu normally appears after about 16 seconds.

Options

Option Environment Default
--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
--device ID FX_DEVICE First paired device
--no-build Install/launch the existing bundle

python3 tools/build_native.py --help prints the same list.

Rendering resolution

By default the game renders at the panel's native resolution. To render fewer pixels (for battery or frame rate), put a divisor in Documents/factorio/render-divisor.txt on the phone, for example 1.5, using Finder's file sharing for the app or devicectl device copy to. Valid values are 1 to 4. Restart the app afterwards.

Copying saves

Saves are in Documents/factorio/write/saves/. With the phone connected, Finder shows the app's files under the phone → Files → Factorio. A save from the Mac can be copied in the same way:

xcrun devicectl device copy to --device <id> --domain-type appDataContainer \
  --domain-identifier local.factorio.native \
  --source ~/Library/Application\ Support/factorio/saves/my-save.zip \
  --destination Documents/factorio/write/saves/my-save.zip

Troubleshooting

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.
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.
Image looks blurry Check that render-divisor.txt is absent or contains 1. Text size is set separately with Factorio's UI scale.

Diagnostics

  • python3 tools/native_audit.py build/factorio.arm64 lists, per library, the game's imports that the iOS SDK does not provide. Every missing symbol must be implemented by a shim.
  • python3 tools/symbolize_native.py [console.log] symbolizes crash reports using the factorio.dSYM that ships with the macOS game.
  • tests/native/png_parity.m checks the PNG decoder against macOS ImageIO for every PNG in the game data; the build command is in native-port.md.