nxnative
Play your own Nintendo Switch games natively on iPhone and iPad. Bring your game (its NSP files) and your prod.keys; one script turns them into an IPA that you sideload.
It is not an emulator: the game's own code runs directly on the Apple chip, with Switch graphics rebuilt on Metal. Nothing from any game is in this repository, and the project is not affiliated with Nintendo or any game publisher.
Acknowledgements
This project is built on other people's work:
- d2r-mobile (MIT) developed this native-execution approach, for Diablo II: Resurrected. nxnative (first called smbw-mobile) started as a copy of its generic parts: the NSO rewriter, the host that stands in for Horizon, the NVN-on-Metal layer and the iOS app shell. Fixes go both ways.
- Ryujinx (MIT): its shader translator (
Ryujinx.Graphics.Shader,Ryujinx.CommonandSpv.Generator1.3.2, unmodified indm/third_party/ryujinx) turns the games' Maxwell shaders into SPIR-V. Its emulation of the kernel and system services is also a reference when the host's behaviour is in doubt. - Atmosphère: its kernel, mesosphère, is the reference for Horizon's synchronization semantics (address arbiter, condition variables).
- yuzu: Maxwell instruction encodings for the shader reference tool, and a cross-check for kernel behaviour.
- LibHac: reads NSPs and layers updates over the base game in
dm/tools/nx_extract. hactool did the first extractions. - SPIRV-Cross: SPIR-V to Metal Shading Language.
- deko3d (zlib): its texture layout size algorithm is ported in
dm/gfx/nvn/nvn_tex.c. - libvpx (VP9 movies), stb_vorbis (movie sound), libdeflate, bcdec and NVIDIA FLIP ship in
dm/third_partywith their licenses (list). - Capstone, lz4, fontTools and XcodeGen are used by the build.
Games
All of these are tested on an iPhone and playable:
| Game | NSPs to put in the folder | IPA | Notes |
|---|---|---|---|
| Super Mario Bros. Wonder | base game + update 1.2.1 | ~4 GB | |
| Fire Emblem Engage | base game + update 2.0.0 (+ Expansion Pass DLC) | ~15 GB | Upgraded to 60 fps (30 fps on Switch) |
| Metroid Dread | base game + update 2.1.0 | ~5 GB | |
| 13 Sentinels: Aegis Rim | base game + update 1.10 | ~5 GB | |
| Super Mario 3D World + Bowser's Fury | base game + update 1.2.2 | ~3 GB | |
| The Legend of Zelda: Breath of the Wild | base game + update 1.9.0 (+ DLC) | ~16 GB | Upgraded to 60 fps (30 fps on Switch) |
New, runs on the Mac, not yet tested on an iPhone: The Legend of Zelda: Link's Awakening (base game + update 1.1.0, ~6 GB).
Needs iOS / iPadOS 26 or later. Other games aren't supported yet: for them the script writes a survey instead of an IPA.
Pack an IPA
1. Get nxnative and its tools (once, on a Mac with Xcode and Homebrew):
git clone https://github.com/seedds/nxnative.git && cd nxnative
brew install xcodegen zstd spirv-cross
brew install --cask dotnet-sdk
python3 -m pip install lz4 capstone fonttools
2. Put one game's NSPs in a folder, base game and update (and any DLC):
~/Games/MarioWonder/
Super Mario Bros. Wonder [010015100B514000][v0].nsp
Super Mario Bros. Wonder [010015100B514800][v327680].nsp
3. Run the script:
python3 scripts/build_ipa_from_nsp.py ~/Games/MarioWonder -k ~/keys/prod.keys
The IPA appears in the same folder (here ~/Games/MarioWonder/SMBWMobile.ipa). The first build takes 30–60 minutes, later ones about 10. You need free disk space of about twice the NSPs' size plus 10 GB. Options such as -o (output path) and --app-name are listed by -h.
4. Install the IPA with your sideloading tool (AltStore, Sideloadly, LiveContainer, …). The app gets the game's name and icon.
Play
Touch controls. Tap 2D / 3D at the top to switch layouts; the app remembers your choice. 3D World and Breath of the Wild start in 3D, the other games in 2D.
ZL L3* [−] 2D/3D [+] R3* ZR
L R
X
( L stick ) Y A
✚ D-pad* ( R stick )* B
* 3D layout only
A connected game controller hides the touch controls and keeps every button.
- Game language is English by default. For Chinese, add the line
DM_LANG=zh-HanstoDocuments/env.txt. - Saves and logs are in the Files app, under the app's name:
save/andlog.txt. When something goes wrong, sendlog.txt(the previous run islog.prev.txt). - Short stutters the first time a new scene appears are normal: the app compiles graphics for it once and remembers them for the next launch.
- Reinstalling: some sideloading tools give a reinstalled app a new data folder. Copy
save/andpso_user.tsvover from the old one to keep your progress. - Settings without rebuilding: put lines like
DM_OPMODE=0(handheld mode: lower resolution, higher frame rate) inDocuments/env.txt.
Known issues
- No amiibo and no online features.
- Fire Emblem Engage: after switching away from the app and back, some sounds may stay silent until you restart it.
- Super Mario 3D World: a few small magenta squares can appear near the birds in World 1-1.
For developers
How it works, the script's options, running games on the Mac, adding a game, and per-game notes: docs/development.md. In-depth bring-up and debugging notes: docs/agents.
License
MIT (see LICENSE). Third-party code keeps its own license; see dm/third_party.
中文说明
在 iPhone 和 iPad 上原生运行你自己的 Nintendo Switch 游戏。准备好游戏(NSP 文件)和你的 prod.keys,一个脚本就能把它们打包成 IPA,再侧载安装。
这不是模拟器:游戏自己的代码直接跑在苹果芯片上,Switch 的图形在 Metal 上重建。本仓库不含任何游戏内容,项目与任天堂及各游戏发行商无关。
致谢
本项目建立在他人的工作之上:
- d2r-mobile(MIT)为《暗黑破坏神 II:狱火重生》开发了这套原生运行方法。nxnative(最初叫 smbw-mobile)从它的通用部分起步:NSO 改写器、代替 Horizon 的宿主、Metal 上的 NVN 层和 iOS 应用外壳。修正双向共享。
- Ryujinx(MIT):它的着色器翻译器(
Ryujinx.Graphics.Shader、Ryujinx.Common和Spv.Generator1.3.2,原样放在dm/third_party/ryujinx)把游戏的 Maxwell 着色器转成 SPIR-V。宿主行为拿不准时,它对内核和系统服务的模拟也是参考。 - Atmosphère:它的内核 mesosphère 是 Horizon 同步语义(地址仲裁器、条件变量)的参考。
- yuzu:着色器参考工具用到的 Maxwell 指令编码,以及内核行为的交叉核对。
- LibHac:在
dm/tools/nx_extract里读取 NSP、把更新叠到本体上。最早的解包用的是 hactool。 - SPIRV-Cross:SPIR-V 转 Metal 着色语言。
- deko3d(zlib):
dm/gfx/nvn/nvn_tex.c移植了它的贴图布局尺寸算法。 - libvpx(VP9 影片)、stb_vorbis(影片声音)、libdeflate、bcdec 和 NVIDIA FLIP 连同许可证放在
dm/third_party(清单)。 - 构建时用到 Capstone、lz4、fontTools 和 XcodeGen。
游戏
以下游戏都已在 iPhone 上测试,可以正常游玩:
| 游戏 | 文件夹里放的 NSP | IPA 大小 | 备注 |
|---|---|---|---|
| 超级马力欧兄弟 惊奇 | 本体 + 1.2.1 更新 | 约 4 GB | |
| 火焰纹章 Engage | 本体 + 2.0.0 更新(+ 扩展通行证 DLC) | 约 15 GB | 升级到 60 fps(Switch 上 30 fps) |
| 密特罗德 生存恐惧 | 本体 + 2.1.0 更新 | 约 5 GB | |
| 十三机兵防卫圈 | 本体 + 1.10 更新 | 约 5 GB | |
| 超级马力欧 3D 世界 + 狂怒世界 | 本体 + 1.2.2 更新 | 约 3 GB | |
| 塞尔达传说 旷野之息 | 本体 + 1.9.0 更新(+ DLC) | 约 16 GB | 升级到 60 fps(Switch 上 30 fps) |
新加入、已在 Mac 上运行、还没在 iPhone 上测试:塞尔达传说 织梦岛(本体 + 1.1.0 更新,约 6 GB)。
需要 iOS / iPadOS 26 或更高版本。其他游戏暂不支持:脚本会为它们写一份分析报告,而不是出 IPA。
打包 IPA
1. 获取 nxnative 和所需工具(只需一次,在装有 Xcode 和 Homebrew 的 Mac 上):
git clone https://github.com/seedds/nxnative.git && cd nxnative
brew install xcodegen zstd spirv-cross
brew install --cask dotnet-sdk
python3 -m pip install lz4 capstone fonttools
2. 把一个游戏的 NSP 放进一个文件夹,本体和更新(有 DLC 也放进去):
~/Games/MarioWonder/
Super Mario Bros. Wonder [010015100B514000][v0].nsp
Super Mario Bros. Wonder [010015100B514800][v327680].nsp
3. 运行脚本:
python3 scripts/build_ipa_from_nsp.py ~/Games/MarioWonder -k ~/keys/prod.keys
IPA 会出现在同一个文件夹里(这里是 ~/Games/MarioWonder/SMBWMobile.ipa)。第一次打包要 30–60 分钟,之后约 10 分钟。需要的空闲磁盘空间约为 NSP 大小的两倍再加 10 GB。-o(输出路径)、--app-name 等选项用 -h 查看。
4. 安装:用你的侧载工具(AltStore、Sideloadly、LiveContainer 等)安装 IPA。App 会带上游戏的名字和图标。
游玩
触屏按键。 点顶部的 2D / 3D 切换布局,App 会记住你的选择。3D 世界和旷野之息默认 3D 布局,其他游戏默认 2D。
ZL L3* [−] 2D/3D [+] R3* ZR
L R
X
( 左摇杆 ) Y A
✚ 十字键* ( 右摇杆 )* B
* 只在 3D 布局里
连上游戏手柄后,触屏按键会隐藏,手柄上的所有按键都能用。
- 游戏语言默认英文。想用中文,在
Documents/env.txt里加一行DM_LANG=zh-Hans。 - 存档和日志在「文件」App 里,App 名字对应的文件夹下:
save/和log.txt。出问题时请发log.txt(上一次运行的是log.prev.txt)。 - 第一次进新场景时短暂卡顿是正常的:App 会为它编译一次图形,下次启动就记住了。
- 重装: 有些侧载工具重装后会给 App 一个新的数据文件夹。把旧文件夹里的
save/和pso_user.tsv拷过去,进度就不会丢。 - 不重新打包也能改设置: 在
Documents/env.txt里写一行一个设置,例如DM_OPMODE=0(掌机模式:分辨率更低、帧率更高)。
已知问题
- 没有 amiibo,也没有联网功能。
- 火焰纹章 Engage:切到别的 App 再回来后,部分声音可能一直没有,要重开游戏。
- 超级马力欧 3D 世界:1-1 里可能出现几个小的品红色方块。
开发者
工作原理、脚本的全部选项、在 Mac 上运行游戏、添加新游戏、各游戏的技术笔记:docs/development.md。更深入的移植和调试笔记:docs/agents。
许可证
MIT(见 LICENSE)。第三方代码保留各自的许可证,见 dm/third_party。