近对VPN的开发来了兴致,花些时间研究研究。由于在VPN方面苹果并没有给出官方文档,我觉得有必要把自己研究出来的东西分享出来,方便大家的学习和交流。 VPN的开发主要依赖于苹果在iOS 8推出的NetworkExtension框架。 准备工作 1.由于VPN无法在模拟器上进行调试,因此,需要一台系统是iOS 8以上的真机。 2.Xcode版本必须是6.0及以上。 3.由于测试无法在模拟器上进行,因此你需要在苹果开发者中心注册开发者账户。 配置 如果你还没有provisioning profiles,那么你需要在苹果开发者中心创建一个。 首先,你需要登录开发者账户,然后点击“Certificate, IDs & Profiles”: 选择“Identifiers”->“App IDs”,选择你的app所对应的id,并将“Personal VPN”改为选中状态。 然后,下载provisioning profile取代原先旧的provisioning profile。 代码 回到xcode中并创建一个“single view application project”。然后,在屏幕的中央位置放置一个UIButton并连接到对应的控制器中。 我将要做的是在控制器的viewDidLoad:方法中当按钮被点击时应用程序可以连接到VPN服务器上。在这之前,你需要了解它是如何工作的。如果你对NetworkExtension框架足够了解,那么去开发会更容易。 NetworkExtension.framework 这个框架允许每个符合条件的app能够访问系统的偏好设置,但是限制在应用自己的沙盒中。这是说你不能访问别的应用的沙盒。 首先,被保存的偏好信息会被操作系统加载以确保应用程序能够去访问。一旦它们被加载了,那么你能够去进行修改。偏好信息发生改动后,它们需要得到保存,未被保存的偏好信息将不会被应用。如果你不再需要你的app的偏好信息,你也可以移除。因此,要创建VPN配置我们需要做以下几件事: · 加载APP的偏好信息 · 修改偏好信息 · 保存偏好信息 注:即使你还没有设置任何的配置你也需要去加载应用程序的偏好信息。 NetworkExtension包含三个主要的类: · NEVPNManager · NEVPNProtocol · NEVPNConnection NEVPNManager是这个框架中重要的类。它主要负责加载、保存、移除偏好信息。实际上,所有的VPN任务都不得不通过这个类来实现。 创建VPN连接 通过NEVPNManager的单例方法获取该类的实例: NEVPNManager *manager = [NEVPNManager sharedManager]; 当NEVPNManager的实例变量被初始化后,系统的偏好信息通过loadFromPreferencesWithCompletionHandler:方法加载: [manager loadFromPreferencesWithCompletionHandler:^(NSError *error) { // Put your codes here... }]; 在上面这个方法中包含一个block,这个block会在加载进程完成时触发。block包含一个NSError类型的参数,如果加载成功,那么这个参数将会为空,否则,它将会是非空的。 当加载进程完成后,该去设置VPN连接了。iOS 8支持两种协议:IPSec和IKEv2.这是苹果第一次在它们自己的操作系统中支持IKEv2协议。这个协议被几乎所有的主流操作系统所支持,包括安卓、Windows phone、Linux等。除了这两个协议外,苹果也支持你自己创建的协议。这个特性对于那些自己实现协议的人来说非常重要。以下我将以IPSec协议为例来进行设置: NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init]; p.username = @"[Your username]"; p.passwordReference = [VPN user password from keychain]; p.serverAddress = @"[Your server address]"; p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret; p.sharedSecretReference = [VPN server shared secret from keychain]; p.localIdentifier = @"[VPN local identifier]"; p.remoteIdentifier = @"[VPN remote identifier]"; p.useExtendedAuthentication = YES; p.disconnectOnSleep = NO; 上面代码的第一行我创建了一个NEVPNProtocolIPSec实例。这个类继承自NEVPNProtocol类。NEVPNProtocol是一个虚基类来让你去创建自己的协议。然后,在第二行第三行设置用户名和密码。注意,密码是和钥匙串关联的,因此,你需要先在钥匙串中储存你的密码然后获取它。第四行是我们的服务器地址。服务器地址可以是IP地址,主机名或者是URL。再下面一行是验证方法。iOS 8支持三种验证方法: · NEVPNIKEAuthenticationMethodNone:不需要与服务器进行验证 · NEVPNIKEAuthenticationMethodCertificate:使用证书和私钥作为验证凭证 · NEVPNIKEAuthenticationMethodSharedSecret:使用共享的秘钥作为验证凭证 再往下一行是共享秘钥的引用。由于它引用自钥匙串,因此要从钥匙串获取共享的秘钥。如果你你准备使用证书而不是共享秘钥的方式,那没必要设置sharedSecretReference属性,但是你需要设置identityData属性。Identity data是PKCS12数据类型的VPN验证实体。这个属性的值必须是PKCS12的NSData类型的: p.identityData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"clientCert" ofType:@"p12"]]; 下面两行是本地和远程的标识符属性。这两个字符串用来标识本地和远程的验证的IPSec的终止。再往下的属性叫做useExtendedAuthetication。这是一个布尔值用来指示是否使用额外的验证方法。这个验证方式是作为IKE验证方法的所额外添加的,它用来验证IKE会话的终止。后一个属性是disconnectOnSleep,这个布尔值用来指示当设备进入睡眠状态时,VPN连接是否断开。