Skip to content

iOS: a URL scheme per game - #482

Closed
oliverames wants to merge 1 commit into
seedds:mainfrom
oliverames:ios-integration-tweaks
Closed

oliverames wants to merge 1 commit into
seedds:mainfrom
oliverames:ios-integration-tweaks

Conversation

@oliverames

@oliverames oliverames commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

What and why

build_ipa.sh registers two URL schemes in the app's Info.plist, nothing else:

  • the shared nxnative
  • this game's own nxnative-<title id>, so a launcher or a Shortcut can detect and open exactly this game

The keys go into the Info.plist xcodegen has just written, so a failure stops the build (die), as MetalCaptureEnabled does.

Scope note: this PR first carried four changes. After review it is the first of the split: the App Intent is #572, the launcher was dropped in favour of main's own, and the ProMotion hint is withdrawn (see the review reply). GCSupportsGameMode is dropped too: Apple deprecated it in iOS 18.6 in favour of LSSupportsGameMode, which project.yml already sets. It is now one commit rebased on current main: the eight URL-scheme lines and their test.

Checked

  • Tests: dm/ios/tests/test_ipa_unsigned.py runs the block against a fresh Info.plist and checks the single CFBundleURLTypes entry with both schemes for two title IDs (lowercased), that the rest of the plist is untouched, and that a plist which already names schemes stops the build instead of gaining a second entry. All 7 tests in that file pass, the packaging and Xcode-workflow tests pass, and test_docs/test_env_switches pass.
  • Games run, with title ID and version: not stated. Opening the schemes has not been separately exercised.
  • Devices and OS: earlier deployment records include these schemes in builds on two iPhones (iOS 27) since Oct 27. This packaging-only change does not claim a new device install.
  • scripts/regress.py check --games: not stated.

Front ends

None: no front end has to act on this.

Docs

  • The finding is in its game note or its docs/reference/<subsystem>.md entry, and python3 dm/tools/docs_symptoms.py was run (the symptom index). Not ticked: the diff touches only build_ipa.sh and its test, with no docs entry.
  • A chain tool changed: dmsh_chain.py --header was run and dm/gfx/nvn/dmsh_chain.h is part of the change. Not applicable: no chain tool changed (the diff is dm/ios/tools/build_ipa.sh and dm/ios/tests/test_ipa_unsigned.py).
  • No game files, keys or data extracted from a game in the change or the attachments (the diff is two source files).

@v0lumehi

v0lumehi commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Thanks for this, and nice to see the on-device run (60 fps, 0 dropped). Speaking as a fellow contributor (what lands is @seedds's call), a few suggestions that would make it easier to review:

  1. Split it into four PRs. CONTRIBUTING.md asks for one concern per PR, and these four are independent. That way each can land on its own. The URL scheme per game and GCSupportsGameMode are small and generally useful, so they'd be a good first one. The compact-width launcher layout for the Duo's outer display and the App Intents shortcut can follow separately.
  2. ProMotion: the iOS front end already drives a display link that drops to 30 Hz when the game asks for 30 fps (dm/games/README.md, the present_interval key). Could you check how the new CADisplayLink interacts with that one? Measurements with and without it at a 30 and a 60 fps target would help: frame times and power, if you have them. Also, hle_fpslock.c writes a few engines' own frame limits into game memory; present pacing itself is in hle_nvn.c / nvn_fstep.h.
  3. The regress run used DM_ALLOW_OTHER_METAL=1. For the chain comparison, Xcode 27.1 (the toolchain in dmsh_chain.lock) gives a result others can reproduce. Since these changes don't touch the shader chain or the host, a short note saying so may be enough instead.
  4. Rebase onto current main: it conflicts at the moment, and CI hasn't run yet.

@oliverames
oliverames force-pushed the ios-integration-tweaks branch from 9cd756f to ea37ff7 Compare October 28, 2026 14:42
@oliverames oliverames changed the title iOS shell: foldable-aware launcher, ProMotion rate hint, per-game schemes + Game Mode, App Intents iOS shell: ProMotion rate hint, per-game schemes + Game Mode, App Intents Oct 28, 2026
@oliverames
oliverames force-pushed the ios-integration-tweaks branch from ea37ff7 to 231a17f Compare October 28, 2026 18:59
@oliverames oliverames changed the title iOS shell: ProMotion rate hint, per-game schemes + Game Mode, App Intents iOS: per-game URL scheme and the Game Mode opt-in Oct 28, 2026
@oliverames

Copy link
Copy Markdown
Contributor Author

Thanks @v0lumehi, all four points taken:

  1. Split. This PR is now just the per-game URL scheme + GCSupportsGameMode (your suggested first one). The App Intent is iOS: an App Intent that opens the game (Siri, Shortcuts, the Action Button) #572. The compact launcher layout is dropped: main's own launcher (the saved-choices store and iOS sub-settings) supersedes it.
  2. ProMotion: withdrawn. You were right to ask. The host's CAMetalDisplayLink in nvn_mtl.m already sets the panel range itself (link_range, including 30/30/30 when present_interval settles on 30 fps). The hint added a second CADisplayLink preferring 60, and since the panel runs at the highest rate any link requests, it could hold 60 Hz exactly when the host asks for 30: no benefit at 60, a likely power cost at 30. So it's gone rather than measured.
  3. Toolchain. Neither remaining PR touches the shader chain, the host or game code (Info.plist keys here; one Swift file in iOS: an App Intent that opens the game (Siri, Shortcuts, the Action Button) #572), so the chain comparison doesn't apply.
  4. Rebased onto current main (beea17c).

@oliverames
oliverames force-pushed the ios-integration-tweaks branch from 231a17f to 0bde5ea Compare October 28, 2026 19:19
@oliverames oliverames changed the title iOS: per-game URL scheme and the Game Mode opt-in iOS: a URL scheme per game Oct 28, 2026
@oliverames

Copy link
Copy Markdown
Contributor Author

One correction to my reply above: GCSupportsGameMode is out as well. Apple deprecated it in iOS 18.6 in favour of LSSupportsGameMode, and project.yml already sets that one, so the key added nothing. This PR is now only the per-game URL scheme. I also switched the PlistBuddy calls from || true to || die, matching MetalCaptureEnabled.

@oliverames
oliverames force-pushed the ios-integration-tweaks branch from 13fa6ee to d957288 Compare October 29, 2026 18:44
@oliverames

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (9474a63) as the single commit @v0lumehi suggested keeping: the merge commit and the branch that brought upstream in are gone, so the diff is the eight URL-scheme lines plus one new test. test_ipa_unsigned.py now runs that block on a fresh Info.plist (one CFBundleURLTypes entry, both schemes, lowercased title ID, nothing else touched) and checks that a plist which already names schemes stops the build instead of gaining a second entry. 7 tests pass in that file.

@oliverames

Copy link
Copy Markdown
Contributor Author

Hi @seedds, this note is about all of my open PRs rather than just this one. I have 14 open, and all of them merge cleanly into main today.

I know the queue is long, with 183 PRs open, so I'm not asking for a date. Would it help if I picked an order? #482, #572, #575, #576 and #634 are each under 70 lines, so they'd be the quickest to read. I can also close any that don't fit.

If you've already taken parts of my work in another form, tell me and I'll close those PRs.

@oliverames

Copy link
Copy Markdown
Contributor Author

Hi @seedds, thank you for landing #653 and #787 and for crediting me on both. I'm glad the Vorbis and pso_gpu work could go in, and I appreciate the care you took with the review notes.

A short update on the open PRs, since main has moved:

No reply needed. If you've taken any of these in another form, tell me and I'll close the PR.

@github-actions github-actions Bot added packing Building an IPA or a Mac app: the NSP script, extraction, the shader split, the packers ios The iPhone and iPad app (dm/ios) labels Nov 3, 2026
@oliverames

Copy link
Copy Markdown
Contributor Author

Hi @seedds, a status update on my open PRs against current main (7249ee9).

Ten PRs had conflicts with main again, so I rebased them and pushed the new heads to my fork branches: #642 (d3a8e2eb), #645 (9cf0b25), #634 (ac05703), #651 (0429ace), #565 (60a0b127), #590 (ff9bfc37), #656 (1ef9a0f4), #1140 (c3a677d), #1158 (26246d02) and #1160 (8f239ba2). The tests that can run on this Mac pass. I have not run them on a device or built the iOS apps.

#1102 is on hold for a decision. main already has part of it (b6dbb85). The PR's stricter NRR header checks fail main's test_nro_collect fixture, which has no size field and sets only byte 5. Two options: update that fixture to match the header rules, or keep only the CRA line from the PR. Tell me which you prefer.

main's lint-c has been red since f083873 because of dm/gfx/tests/t_int_float_view.m, which has unchecked Metal results. I filed the nil-check fix as #1338. It passes the local clang-tidy ratchet with the baseline unchanged, but it has not run in CI yet.

#651: the pso_gpu docs row does not generate on main, because the docs generator reads only the header( section of game.py. I have not changed the generator.

None of my open PRs looks already landed on main, so I am not closing any. Tell me if you want any closed.

@oliverames
oliverames force-pushed the ios-integration-tweaks branch 3 times, most recently from 6a91bf2 to 74e2c95 Compare November 10, 2026 03:13
build_ipa.sh registers two URL schemes in the app's Info.plist: the shared
nxnative and this game's own nxnative-<title id>, so a launcher or a Shortcut can
detect and open exactly this game. The keys are added to the Info.plist xcodegen
just wrote, so a failure stops the build (die) like MetalCaptureEnabled's.

test_ipa_unsigned.py runs the block on a fresh Info.plist and checks the single
entry and the lowercased title ID, and that a plist which already names schemes
stops the build instead of gaining a second entry.
@oliverames
oliverames force-pushed the ios-integration-tweaks branch from 74e2c95 to ed63c38 Compare November 10, 2026 14:04
@oliverames

Copy link
Copy Markdown
Contributor Author

Closing this. A per-game URL scheme is something a front end can add itself, and I'd rather keep the open list to changes the host needs. Thanks for looking!

@oliverames oliverames closed this Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ios The iPhone and iPad app (dm/ios) packing Building an IPA or a Mac app: the NSP script, extraction, the shader split, the packers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants