Skip to content

build(macos): add app bundle packaging script - #376

Closed
afrijaldz wants to merge 2 commits into
Oppzippy:masterfrom
afrijaldz:feat/macos-packaging
Closed

afrijaldz wants to merge 2 commits into
Oppzippy:masterfrom
afrijaldz:feat/macos-packaging

Conversation

@afrijaldz

Copy link
Copy Markdown

Depends on #374 (macOS connection backend). This branch is stacked on top of it, so the diff shows both commits until #374 is merged; only cea5da72 (build(macos): add app bundle packaging script) is new here. I'll rebase once #374 lands.

Summary

Adds packaging for a macOS app bundle, mirroring the Windows installer setup:

  • packaging/macos/build.sh — wraps build-output/openscq30-gui into build-output/OpenSCQ30.app: generates an .icns from the existing icon with sips/iconutil, fills in Info.plist with the workspace version, and applies an ad-hoc code signature so Gatekeeper allows running a locally built app.
  • packaging/macos/Info.plist — template (@VERSION@ placeholder), includes NSBluetoothAlwaysUsageDescription.
  • just build-gui-app recipe ([macos]), analogous to build-gui-installer on Windows. The gui must be built first (just build-gui).
  • An "App bundle" section in docs/build-macos.md.

Not included: signing with a Developer ID / notarization and a CI job to publish the bundle in releases. Both need secrets/decisions on your side, so I left them out; happy to add a CI job if you'd like one.

Testing

just build-gui && just build-gui-app on macOS 15 (Apple Silicon) produces a working OpenSCQ30.app that launches from Finder/Spotlight and connects to a Soundcore R50i. plutil -lint passes on the generated Info.plist.

Adds an RFCOMM backend for macOS so the CLI and GUI work there. A small
Objective-C shim (compiled via the cc crate in build.rs) wraps
IOBluetooth: listing connected paired devices, resolving SDP service
UUIDs to RFCOMM channel ids, and opening/reading/writing channels.

Notes on IOBluetooth behaviour that shaped the design:

- On current macOS versions, IOBluetooth is backed by CoreBluetooth and
  delivers every RFCOMM delegate event on the main thread's run loop,
  regardless of which thread opened the channel. openRFCOMMChannelSync
  fails when called from a thread without a run loop, so the shim uses
  openRFCOMMChannelAsync and waits for rfcommChannelOpenComplete:status:.
- The CLI therefore runs its tokio runtime on a secondary thread while
  the main thread spins a run loop (run_with_main_run_loop). The GUI
  already has one via winit.
- IOBluetooth flattens single element SDP sequences, so ServiceClassIDList
  may be a bare UUID rather than an array.
- The system sqlite on macOS is too old for the migrations, so rusqlite
  is built with the bundled feature like on Windows and Android.

Tested with a Soundcore R50i (A3949): listing settings, reading battery
and firmware info, and changing the equalizer preset.
Adds packaging/macos/build.sh and a `just build-gui-app` recipe that
wrap the gui binary in build-output/OpenSCQ30.app, mirroring the Windows
installer setup. The bundle gets an icns generated from the existing
icon, an Info.plist with the workspace version and a Bluetooth usage
description, and an ad-hoc code signature so Gatekeeper allows running
it locally.
@SeanathanVT

Copy link
Copy Markdown

Also duplicates some functionality from #372.

@afrijaldz

Copy link
Copy Markdown
Author

Same as #374 — this stacks on it and #372 already includes packaging/macos. Happy to close this in favour of #372.

@afrijaldz afrijaldz mentioned this pull request Sep 17, 2026
SeanathanVT added a commit to SeanathanVT/OpenSCQ30 that referenced this pull request Sep 17, 2026
…igning

The .app bundle had no LSMinimumSystemVersion/CFBundleSupportedPlatforms
and was never signed, which Launch Services was misidentifying as an
iOS app instead of a native macOS one. Adds both plist keys and an
ad-hoc codesign step in build.sh after bundle assembly. Ad-hoc signing
fixes the local build/Kind issue but isn't notarization: downloaded
zips still need right-click -> Open, docs updated to reflect that.

afrijaldz's competing macOS PR (Oppzippy#376) independently landed the same fix.

Co-Authored-By: Afrijal Dzuhri <[email protected]>
Co-Authored-By: Claude Sonnet 5 <[email protected]>
@Oppzippy

Copy link
Copy Markdown
Owner

Closing in favor of #372

@Oppzippy Oppzippy closed this Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants