我使用Network Extension框架来配置和管理VPN连接。当我运行我的代码时,它将记录错误消息:"保存配置faild [(null)]"在我完成安装配置文件之前。我编写了如下代码:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.vpnManager = [NEVPNManager sharedManager];
[_vpnManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"Load config failed [%@]", error.localizedDescription);
return ;
}
// config IPSec protocol
NEVPNProtocolIKEv2 *p = _vpnManager.protocol;
if (p) {
}else{
p = [[NEVPNProtocolIKEv2 alloc]init];
}
p.username = @"qlvpn";
p.serverAddress = @"my serverAddress";
// get password persistent reference from keychain
p.passwordReference = [self searchKeychainCopyMatching:@"kd2014@"];
// If password doesn't exist in keychain, should create it beforehand.
if (!p.passwordReference) {
[self createKeychainValue:@"kd2014@" forIdentifier:@"kd2014@"];
p.passwordReference = [self searchKeychainCopyMatching:@"kd2014@"];
}
p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
p.sharedSecretReference = [self searchKeychainCopyMatching:@"PSK"];
if (!p.sharedSecretReference) {
[self createKeychainValue:@"qlvpn_kd2014@" forIdentifier:@"PSK"];
p.sharedSecretReference = [self searchKeychainCopyMatching:@"PSK"];
}
p.localIdentifier = @"qlvpn.client";
p.remoteIdentifier = @"qlvpn.server";
p.useExtendedAuthentication = YES;
p.disconnectOnSleep = NO;
_vpnManager.protocol = p;
_vpnManager.localizedDescription = @"IKEv2 Demo";
[_vpnManager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
NSLog(@"Save config faild[%@]",error.localizedDescription);
}];
}];
}
keyChain方法如下:
static NSString * const serviceName = @"qlvpn.vpn_config";
- (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
[searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount];
[searchDictionary setObject:serviceName forKey:(__bridge id)kSecAttrService];
return searchDictionary;
}
- (NSData *)searchKeychainCopyMatching:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
// Add search attributes
[searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
// Add search return types
// Must be persistent ref !!!!
[searchDictionary setObject:@YES forKey:(__bridge id)kSecReturnPersistentRef];
CFTypeRef result = NULL;
SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &result);
return (__bridge_transfer NSData *)result;
}
- (BOOL)createKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier {
NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)dictionary);
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:passwordData forKey:(__bridge id)kSecValueData];
status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL);
if (status == errSecSuccess) {
return YES;
}
return NO;
}
所以,我真的不知道为什么我不能保存配置..
答案 0 :(得分:0)
loadAllFromPreferencesWithCompletionHandler
loadFromPreferencesWithCompletionHandler
然后才
saveToPreferencesWithCompletionHandler