startVPNTunnelWithOptions未返回错误的定制VPN隧道问题求助
首先得明确一个关键细节:startVPNTunnelWithOptions:andReturnError:这个方法的同步返回错误仅处理启动隧道的即时系统级错误(比如配置完全无效、缺少VPN权限、系统不支持等),而像凭据错误这类连接过程中的业务逻辑错误,并不会通过这个方法的返回值传递——这类错误需要通过VPN状态通知和NEVPNConnection的error属性来捕获。
结合你的代码,我发现几个核心问题:
1. startTunnelWithOptions中的回调逻辑完全搞反了
看你Provider里的代码:
if(success == 0) { NSLog(@"packettunnel: newerror: %d", 0); completion(error); // error是nil } else { NSLog(@"packettunnel: newerror: %@", newError); completion(newError); }
这里的逻辑明显和预期相反:如果success == 0代表连接失败(比如凭据错误),你却传递了nil错误告诉系统"连接成功";而成功时反而传递了错误。这会导致系统认为隧道启动正常,上层自然收不到错误通知。
修复方案:
先确认vpnAdapter的success返回值定义(通常0代表成功,非0代表失败,但你这里的日志和逻辑矛盾),然后修正回调逻辑:
// 假设success=0代表连接成功,非0代表失败(凭据错误等) if(success == 0) { NSLog(@"packettunnel: connection initiated successfully"); completion(nil); // 告诉系统启动成功 } else { NSLog(@"packettunnel: connection failed with invalid credentials"); completion(newError); // 传递业务错误给系统 }
2. 上层未监听连接过程中的状态变化和错误
你的openTunnel方法里只检查了startVPNTunnelWithOptions的同步返回错误,但这类错误不会包含业务逻辑错误。当Provider通过completion(newError)传递错误时,系统会将这个错误关联到NEVPNConnection的error属性,并触发NEVPNStatusDidChangeNotification通知。
修复方案:
完善你的receiveNotification:方法,监听状态变化并获取错误:
- (void)receiveNotification:(NSNotification *)notification { NEVPNConnection *connection = (NEVPNConnection *)notification.object; switch (connection.status) { case NEVPNStatusDisconnected: case NEVPNStatusInvalid: { NSError *connectionError = connection.error; if (connectionError) { NSLog(@"viewcontroller: VPN failed with error: %@", connectionError); // 在这里处理凭据错误等业务逻辑 } break; } case NEVPNStatusConnected: NSLog(@"viewcontroller: VPN connected successfully"); break; default: break; } }
3. 额外注意点
- 确保你在Provider中传递的
newError是正确的错误域和错误码,系统才能正确关联到NEVPNConnection。 - 如果你的VPN配置使用了App Group,Provider和上层App之间也可以通过UserDefaults或者自定义消息传递错误信息,但优先使用系统提供的
NEVPNConnection.error机制。
总结一下:你之前的问题核心是Provider里的错误回调逻辑搞反了,导致系统没有收到错误通知;同时上层没有监听状态变化来捕获连接过程中的业务错误。修正这两点后,错误凭据的场景下就能正确捕获到错误了。
内容的提问来源于stack exchange,提问作者ikel

