Skip to content

Commit c4c59dc

Browse files
committed
feat(mobile): iOS is single-hop only (hide multi-hop until it's reworked)
Single-hop (Fast) now connects on iOS after dropping the second Go runtime. Multi-hop stays disabled on iOS (it needs the wgnest core, a second Go runtime in the tunnel extension). Force routeStyle to 'single' on iOS and hide the Fast/Multi-hop toggle so users don't hit a dead multi-hop path. Android unchanged (both hops).
1 parent 119d57b commit c4c59dc

2 files changed

Lines changed: 28 additions & 14 deletions

File tree

clients/mobile/src/screens/ConnectScreen.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -167,17 +167,22 @@ export function ConnectScreen({
167167
) : null}
168168
</View>
169169

170-
{/* Fast / Multi-hop toggle — multi-hop is OFF by default (docs/11 §UX). */}
171-
<ModeToggle
172-
multihop={vpn.multihop}
173-
disabled={connected || busy}
174-
onFast={() => void vpn.setRouteStyle('single')}
175-
onMultihop={() =>
176-
void vpn.setRouteStyle(
177-
vpn.routeStyle === 'single' ? 'multihop-same-country' : vpn.routeStyle,
178-
)
179-
}
180-
/>
170+
{/* Fast / Multi-hop toggle — multi-hop is OFF by default (docs/11 §UX).
171+
Hidden on iOS: multi-hop is single-hop-only there for now (the wgnest
172+
core would be a second Go runtime in the tunnel extension — see
173+
MULTIHOP_SUPPORTED in useVpn). */}
174+
{Platform.OS !== 'ios' ? (
175+
<ModeToggle
176+
multihop={vpn.multihop}
177+
disabled={connected || busy}
178+
onFast={() => void vpn.setRouteStyle('single')}
179+
onMultihop={() =>
180+
void vpn.setRouteStyle(
181+
vpn.routeStyle === 'single' ? 'multihop-same-country' : vpn.routeStyle,
182+
)
183+
}
184+
/>
185+
) : null}
181186

182187
{vpn.multihop ? (
183188
<MultihopControls

clients/mobile/src/state/useVpn.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@ import {
2222
status as fetchStatus,
2323
} from '@cumulusvpn/core';
2424
import type { EnrollResponse, GatewayInfo, Keypair, RouteStyle, Tier } from '@cumulusvpn/core';
25+
import { Platform } from 'react-native';
2526
import {
2627
CumulusTunnel,
2728
onTunnelStatus,
2829
type TunnelState,
2930
type TunnelStatus,
3031
} from '../native/CumulusTunnel';
32+
33+
// Multi-hop runs the gomobile wgnest core, which on iOS would be a SECOND Go
34+
// runtime alongside WireGuardKit's libwg-go in the one Packet Tunnel extension
35+
// process — two Go runtimes crash it. So multi-hop is disabled on iOS until it
36+
// is reworked onto a single runtime; iOS is single-hop only.
37+
const MULTIHOP_SUPPORTED = Platform.OS !== 'ios';
3138
import {
3239
discoverFleet,
3340
groupByCountry,
@@ -359,7 +366,7 @@ export function useVpn(): VpnModel & VpnActions {
359366
}
360367
setKeypair(restored);
361368
setSelectedCode(await loadSelectedCountry());
362-
setRouteStyleState(await loadRouteStyle());
369+
setRouteStyleState(MULTIHOP_SUPPORTED ? await loadRouteStyle() : 'single');
363370
setEntryCode(await loadEntryCountry());
364371
setExitCode(await loadExitCountry());
365372
setKillSwitchState(await loadKillSwitch());
@@ -721,8 +728,10 @@ export function useVpn(): VpnModel & VpnActions {
721728
}, []);
722729

723730
const setRouteStyle = useCallback(async (style: RouteStyle): Promise<void> => {
724-
setRouteStyleState(style);
725-
await saveRouteStyle(style);
731+
// iOS is single-hop only (see MULTIHOP_SUPPORTED) — never enter a multihop style.
732+
const next = MULTIHOP_SUPPORTED ? style : 'single';
733+
setRouteStyleState(next);
734+
await saveRouteStyle(next);
726735
}, []);
727736

728737
const selectEntryCountry = useCallback(async (code: string | null): Promise<void> => {

0 commit comments

Comments
 (0)