Repository navigation
Conversation
Contributor
|
thank you for your contribution we will take. it. into consideration sooon |
Preserve the macOS managed VPN lifecycle while adopting upstream logging and dependency changes. Avoid restarting a tunnel already restored by macOS on app startup.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat(macos): run VPN in a packet tunnel system extension
Related to #187 and #1788.
Scope and behavior
This PR moves native macOS VPN mode into an OS-managed packet tunnel system extension. The Flutter app runs as the logged-in user, while macOS manages the tunnel lifecycle.
Quitting the app leaves the VPN running. Reopening the app restores its connection state and control client. Disconnect disables on-demand reconnection before stopping the tunnel, and changing profiles or connection modes stops the previous engine first. Proxy and system-proxy modes continue to use the foreground core.
Changes
lipoversions by verifying each requested architecture separately.Ordinary Debug builds default to proxy support with Network Extension disabled. Local VPN development requires a paid Apple Developer team and signing/provisioning for both targets; setup instructions are below.
The private SIP-disabled testing kit and ad hoc VPN signing exception are outside this PR. Android, iOS, Windows, and Linux retain their existing platform backends; shared Dart changes add macOS lifecycle integration and propagate configuration errors.
Maintainer setup required before distributing macOS builds
The notarization workflow is implemented, but release maintainers must supply the signing identities, provisioning profiles, and notarization credentials. The Developer ID distribution path has not been validated using the local ad hoc test build.
1. Configure Apple signing and capabilities
Configure these explicit App IDs under the same Apple Developer team:
app.hiddify.comapp.hiddify.com.HiddifyPacketTunnelEnable Network Extension for both App IDs and generate or regenerate their macOS Developer ID provisioning profiles. Both profiles must authorize the Developer ID Application certificate that will be imported into CI. The distribution entitlement is
packet-tunnel-provider-systemextension.Runner also requires
com.apple.developer.system-extension.install. Both targets use this application group:For a team prefix of
YOURTEAMID., the resolved group isYOURTEAMID.app.hiddify.com.vpn. The provider’sNEMachServiceNameis that same group followed by.HiddifyPacketTunnel.Keep the application group identical in both targets and ensure its prefix matches the signing team. This macOS team-prefixed group does not require registration in the Developer portal; it is distinct from a
group.-prefixed provisioned group. See Apple’s app group guidance and Network Extensions entitlement guidance.Sign Runner and the embedded provider with Developer ID Application; sign the installer package with Developer ID Installer. Preserve hardened runtime, secure timestamps, and distribution entitlements without
get-task-allow. Hardened runtime and Release/Profile base-entitlement settings are already configured in this branch. See Apple’s notarization requirements.2. Prepare and supply the CI secrets
Add the following secrets in the repository that runs the workflow, under Settings → Secrets and variables → Actions → Repository secrets. Organization secrets are also suitable if that repository has access to them.
APPLE_CERTIFICATE_P12APPLE_CERTIFICATE_P12_PASSWORDAPPLE_MOBILE_PROVISIONING_PROFILES_TARGZ_BASE64APPLE_MACOS_SIGNING_XCCONFIGAPPLE_MACOS_INSTALLER_SIGN_IDENTITYDeveloper ID Installer: Organization (TEAMID).APPLE_NOTARIZATION_APPLE_IDAPPLE_NOTARIZATION_TEAM_IDAPPLE_NOTARIZATION_PASSWORDIn Keychain Access, export both Developer ID signing identities, including their private keys, together as a password-protected
.p12file. On macOS, this command copies its base64 representation to the clipboard forAPPLE_CERTIFICATE_P12:Create the provisioning archive with the two files at its root. Replace the directory and filenames below with the downloaded profiles:
Paste that clipboard value into
APPLE_MOBILE_PROVISIONING_PROFILES_TARGZ_BASE64. CI extracts the archive directly into its provisioning-profile directory.Example
APPLE_MACOS_SIGNING_XCCONFIG:Replace every placeholder. The two provisioning settings select the installed profiles by their internal Name or UUID, not their downloaded filenames. Each profile must match its target’s bundle identifier, team, capabilities, and imported Developer ID Application certificate.
PR builds use
CODE_SIGNING_ALLOWED = NOand skip notarization. Every macOS workflow run producing uploaded artifacts requires this setup, including draft builds from pushes.3. Validate the distribution path
Runner and the embedded provider must already be correctly signed before packaging.
macos/scripts/notarize-release.shsigns the installer package and notarizes/staples the distribution artifacts; it does not sign or repair the application bundle.After packaging, the script:
notarytool.Acceptedresult for each submission.An invalid submission stops that macOS artifact pipeline.
Before releasing, maintainers should validate the signed, notarized installation on a Mac with SIP enabled: installation in
/Applications, system extension and VPN configuration approval, connection, quit/reopen, disconnect, and reconnect. Local ad hoc testing does not verify this distribution path.Local VPN development
For local VPN development, copy the existing signing example from the repository root:
Replace
YOURTEAMIDin the copied file with your paid Apple Developer team ID and configure Apple Development signing/provisioning for both Runner and HiddifyPacketTunnel.The example enables the extension in Debug builds, selects Apple Development signing, and uses the host’s VPN development entitlements. Ordinary Debug builds keep the extension disabled until these overrides are supplied.
Apple Development signing is for local VPN development. Developer ID signing and notarization are required for distributed Release/Profile builds.
Local testing
Test machine: Apple M4 MacBook Air, arm64, macOS 27.2 (26B5091g), with SIP disabled. Build tools: Xcode 27.0 (27A266a), Flutter 3.38.5, Dart 3.10.4, and Go 1.25.6 for the tunnel core.
Demo
I used a separate private source snapshot with distinct local bundle IDs and an ad hoc Debug signing patch. The normal repository retains its Apple-team signing requirement for VPN builds. On that local test build, I manually tested VPN connection, quitting and reopening the app, and reconnecting.
Compilation and stability validation:
CODE_SIGNING_ALLOWED = NOpassed. Botharm64andx86_64slices were verified in the app, embedded provider, Flutter/Dart frameworks, and desktop core.Runtime testing was on arm64. Intel runtime behavior and Developer ID signing/notarization with SIP enabled remain for maintainer validation.