# officer-net Expo config plugin Wires the OS-level capabilities the VPN needs into the app at prebuild. Enabled from `app.json`: ```js plugins: [ ["officer-net", { appGroup: "group.pastilhas.officer.offscale", neBundleId: "dev.officer.offscale.net", enableNetworkExtension: true, }], ] ``` Props (all optional; defaults shown): | prop | default | what it controls | |--------------------------|------------------------------------|---------------------------------------------------------| | `appGroup` | `group.pastilhas.officer.mobile` | iOS App Group shared by the app and the NE | | `neBundleId` | `dev.officer.mobile.net` | the Network Extension target's bundle id | | `specialUseSubtype` | VPN mesh tunnel justification | Android `FOREGROUND_SERVICE_SPECIAL_USE` purpose | | `enableNetworkExtension` | `false` | add the iOS entitlement and synthesise the NE target | `enableNetworkExtension` is **off by default** because the entitlement fails device code-signing until the Apple provisioning below exists. With it off the app signs, installs and renders; the engine is inert. The repo's own `app.json` turns it on. ## What the plugin does - **iOS** — adds `com.apple.developer.networking.networkextension` (`packet-tunnel-provider`) to the main app, and writes `OfficerNetExtensionBundleId` into `Info.plist`. That key is **load-bearing**, not a breadcrumb: the Swift module reads it to fill `providerBundleIdentifier`, which is how iOS knows which extension to launch. A hardcoded value there means the start command is accepted, nothing matches, and the tunnel silently never starts. - **iOS, under `enableNetworkExtension`** — synthesises the Network Extension Xcode target (`withNetworkExtensionTarget.js`): a new target compiling this package's `ios/PacketTunnelProvider.swift`, its `Info.plist` (`NSExtensionPointIdentifier = com.apple.networkextension.packet-tunnel`), its own entitlements, `NetworkExtension.framework`, the vendored `TailCore.xcframework`, and the app's *Embed App Extensions* phase. Doing this by hand after every `expo prebuild --clean` is what this replaces. - **Android** — adds `FOREGROUND_SERVICE` and `FOREGROUND_SERVICE_SPECIAL_USE`, and registers `OfficerVpnService` with `BIND_VPN_SERVICE`, `foregroundServiceType="specialUse"` and the `android.net.VpnService` intent-filter. ## Apple provisioning prerequisites (one-time, in the Apple Developer portal) - A separate **App ID for the extension** (`neBundleId`) with the **Network Extensions** capability. - The **Network Extensions** capability on the main app ID. - Provisioning profiles for both, with those capabilities. `xcodebuild -allowProvisioningUpdates` cannot create these while Xcode has no account signed in: it falls back to the wildcard team profile and fails with *"Provisioning profile 'iOS Team Provisioning Profile: \*' doesn't include the Network Extensions capability"*. Sign in under **Xcode → Settings → Accounts** first. Android needs none of this.