iOS中Network Extension安全科学Tunnel应用(Swift5)

栏目: Swift · 发布时间: 5年前

内容简介:本文简要介绍iOS中Network Extension在提供安全科学(双s)使用G高级搜索、Y视频等App简单应用,同时使用了第三方库NEKit提供路由规则支持。demo代码已适配swift5,点击demo运行需要有开发者账号,修改bundle id,在自己的开发者账号进行注册。

本文简要介绍iOS中Network Extension在提供安全科学(双s)使用G高级搜索、Y视频等App简单应用,同时使用了第三方库NEKit提供路由规则支持。

demo代码已适配swift5,点击 GitHub链接 查看。

demo运行需要有开发者账号,修改bundle id,在自己的开发者账号进行注册。

在创建应用之前我们需要安装 NEProviderTargetTemplates.pkg ,在xcode10.12之后苹果在xcode中删除了这个文件,为什么?可能和中国区被下架的那些VXN一样的原因吧。好在我们还可以从老版本的xcode中提取这个文件,链接在此点击下载 ,提取码: 18ek ,要低调,安装好后重启xcode。

创建工程

接下来我们开始创建工程,首先和创建普通App一样创建一个Project

iOS中Network Extension安全科学Tunnel应用(Swift5)

创建好后我们在当前Project中创建一个Target

iOS中Network Extension安全科学Tunnel应用(Swift5)

选择Network Extension,Next

iOS中Network Extension安全科学Tunnel应用(Swift5)

语言选择swift,因为NEKit是swift写的,并且对oc支持不是很好,所以这里就用swift来写了。

iOS中Network Extension安全科学Tunnel应用(Swift5)

创建好后,目录下会出现一个新的文件夹

iOS中Network Extension安全科学Tunnel应用(Swift5)

有关代理的代码在PacketTunnelProvider.swift中编写。

在工程创建完毕后,需要在Target的Capabilities中开启Network Extensions和Personal VXN功能,注意项目本身主Target及PacketTunnel都需要开启这两项功能。

iOS中Network Extension安全科学Tunnel应用(Swift5)

好了,到此工程就创建好了。

NEKit集成

由于项目中使用的NEKit这个第三方库只支持Carthage进行集成管理,所以demo使用的集成 工具 也是Carthage,没有用过的可以自行Google,安装使用难度不高,一看即会。

但是 注意 在第三方库编译的时候需要使用NEKit提供的编译方式,直接carthage update项目无法运行。

carthage update --no-use-binaries --platform mac,ios

第三方库编译好后会在Carthage目录下Build/iOS中生成.framework文件,我们需要把这些framework添加到项目中去,下图的两个位置都要需要添加,与Net无关的包在packetTunnel中可以不需要添加。

iOS中Network Extension安全科学Tunnel应用(Swift5)
iOS中Network Extension安全科学Tunnel应用(Swift5)

至此相关环境配置就已经搞定了,下面开始看代码如何建立VXN链接

创建VXN Manager

首先需要创建一个NETunnelProviderManager

fileprivate func createProviderManager() -> NETunnelProviderManager {
    let manager = NETunnelProviderManager()
    let conf = NETunnelProviderProtocol()
    conf.serverAddress = "BearFree"
    manager.protocolConfiguration = conf
    manager.localizedDescription = "BearFree"
    return manager
}
复制代码

将manager保存至系统中

manager.saveToPreferences{
    error in
        if error != nil{print(error);return;}
        //Todo
}
复制代码

执行save方法后会跳转系统VXN菜单,添加我们创建的VPN

iOS中Network Extension安全科学Tunnel应用(Swift5)

此时如果save方法调用多次,会出现VPN 1 VPN 2等多个描述文件 ,因此,苹果也要求,在创建前应读取当前的managers

NETunnelProviderManager.loadAllFromPreferencesWithCompletionHandler{ 
    (managers, error) in
    guard let managers = managers else{return}
    let manager: NETunnelProviderManager
    if managers.count > 0 {
        manager = managers[0]
    }else{
        manager = self.createProviderManager()
    }
    // Todo
    // manager.saveToPreferences.......
}
复制代码

配置Network Extension

打开extension中的模板文件,对应Swift版本与父类修改语法。主要需要以下两个函数控制VPN状态

//启动VPN时调用
func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void)

//停止VPN时调用
func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void)
复制代码

此时我们仅仅需要测试VPN连接是否能正常建立。因此我们只需要在startTunnelWithOptions中调用setTunnelNetworkSettings 方法即可。当completionHandler()执行后VPN连接就会显示在手机上了。

override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
    let ipv4Settings = NEIPv4Settings(addresses: ["192.169.89.1"], subnetMasks: ["255.255.255.0"])
    let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "8.8.8.8")
    networkSettings.mtu = 1500
    networkSettings.iPv4Settings = ipv4Settings
    setTunnelNetworkSettings(networkSettings) {
        error in
        guard error == nil else {
            completionHandler(error)
            return
        }
            completionHandler(nil)
    }
}
复制代码

开启VXN

对刚刚创建的manager调用startVPNTunnel方法即可

try manager.connection.startVPNTunnel(options: [:])
复制代码

如果在创建VXN saveToPreferences后立刻执行startVPNTunnel,此时可能会出现Domin="null",说明系统并未准备好,所以启动代码放至loadAndCreatePrividerManager方法的返回block中

func connect(){
    self.loadAndCreatePrividerManager { (manager) in
        guard let manager = manager else{return}
        do{
            try manager.connection.startVPNTunnel(options: [:])
        }catch let err{
            print(err)
        }
    }
}
复制代码

具体的实现逻辑可以查看demo中vpnManager.swift文件。

连接成功后manager.connection.status会发生改变,所以我们需要监听status值,从而得知目前的vpn连接状态,用于更新UI显示。

func addVPNStatusObserver() {
    guard !observerAdded else{
        return
    }
    loadProviderManager { [unowned self] (manager) -> Void in
        if let manager = manager {
            self.observerAdded = true
            NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: manager.connection, queue: OperationQueue.main, using: { [unowned self] (notification) -> Void in
                self.updateVPNStatus(manager)
                })
            }
        }
}
复制代码

VXN配置(IP、端口等)

manager通过protocolConfiguration的属性向Network Extension传递配置信息,在vpnManager中实现如下配置方法,并在启动vpn前调用即可

fileprivate func setRulerConfig(_ manager:NETunnelProviderManager){
    var conf = [String:AnyObject]()
    conf["ss_address"] = ip_address as AnyObject?
    conf["ss_port"] = port as AnyObject?
    conf["ss_method"] = algorithm as AnyObject? // 大写 没有横杠 看Extension中的枚举类设定 否则引发fatal error
    conf["ss_password"] = password as AnyObject?
    conf["ymal_conf"] = getRuleConf() as AnyObject?
    let orignConf = manager.protocolConfiguration as! NETunnelProviderProtocol
    orignConf.providerConfiguration = conf
    manager.protocolConfiguration = orignConf
    print(ip_address,port,algorithm,password)
}
复制代码

在Extension中

public var protocolConfiguration: NEVPNProtocol { get }    
复制代码

存入了上面写入的配置信息,我们可以直接读取。

关于网络状态的改变

4G与wifi切换,这里确实有点坑,在里面绕了很久,一开始调试发现vxn是通的,但是过段时间就不能用了,删了重装也不行,无意中改了一个extension中的ip又好用了,换了网络环境又不能用了,百思不得其解,debug了半天也没找到问题,下面先说下怎么如何监听网络环境变化:

NEProvider 中存在属性 public var defaultPath: NWPath? { get } 表明当前系统的网络请求路径。我们可以通过KVO监听 defaultPath 的改变。当 defaultPath 与之前状态发生改变,且 defaultPath.status == .Satisfied 时,我们可以认定系统网络进行了切换。此时我们需要重启VPN及重启代理服务器。

重连VPN方法非常简单,只需要再次调用StartVPN函数即可。

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "defaultPath" {
        if self.defaultPath?.status == .satisfied && self.defaultPath != lastPath{
            if(lastPath == nil){
                lastPath = self.defaultPath
            }else{
                NSLog("received network change notifcation")
                DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
                // 延迟1s确保系统就绪
                    guard let strongSelf = self else { return }
                    strongSelf.startTunnel(options: nil){ _ in }
                }
            }
        }else{
            lastPath = defaultPath
        }
    }
}
复制代码

那如何在这个Network Extension中debug呢?我们用正常的debug方式,尝试在当前文件中加入断点,发现毫无反应,所以Tunnel的调试有着单独的调试方式,首先我们需要将主程序在设备上运行,然后通过Xcode->Debug->Attach To Process (有个列表加载过程,需要稍等一下)选择你的Tunnel名进行debug, debug过程中如果不手动关闭tunnel的调试模式,会出现vxn链接后秒断的情况,需要注意一下。 下面再来说我是如何解决上面所说的切换网络时出现的问题,在系统设置中找到我们的App,将 网络访问权限调整为WLAN与蜂窝移动网 ,至此再切换网络就没有之前的问题了,为了App在刚启动时就可以获取网络权限,我加了一个无用的网络请求,你也可以用自己的方式来获取权限。

iOS中Network Extension安全科学Tunnel应用(Swift5)

demoUI

UI层我直接使用了Eureka这个第三方框架,它是XLForm的swift版本,也是通过carthage集成,想了解的也可以看下demo。


以上所述就是小编给大家介绍的《iOS中Network Extension安全科学Tunnel应用(Swift5)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Alone Together

Alone Together

Sherry Turkle / Basic Books / 2011-1-11 / USD 28.95

Consider Facebookit’s human contact, only easier to engage with and easier to avoid. Developing technology promises closeness. Sometimes it delivers, but much of our modern life leaves us less connect......一起来看看 《Alone Together》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具