美文网首页oc
NetworkExtension5-App和Extension通

NetworkExtension5-App和Extension通

作者: 梦即是幻 | 来源:发表于2020-08-31 14:15 被阅读0次

    环境

    • Xcode 11.6
    • iOS 13
    • MacOS 10.15

    导航

    1-总览

    2-Client开发

    3-Tunnel开发

    4-Server开发

    5-App和Extension通信

    完整代码在此,熟悉的小伙伴可以直接试试。

    共享数据方案

    通过之前文章可以看到,发送和接收的数据都是在Tunnel进程的,而我们需要在主App进程展示发送和接收的数据,怎么拿到呢?

    通过一番Google,推荐使用AppGroup,有下面两种方式:

    1. 通过NSUserDefaults

    2. 通过一个扩展与App都可以访问的共享容器,来存放文件,数据

    其实就是一种。。

    也可以使用类似MMWormhole等框架,使用起来很方便。

    这里我们使用NSUserDefaults方式,也非常简单;但还需要一种垮进程的通知机制,最后选定Darwin Notification

    封装了一下,放到YYVPNLib中,功能如下:

    #import <Foundation/Foundation.h>
    
    typedef void(^YYDarwinNotificationManagerHandler)(void);
    
    /// 如果是Darwin notification center, 无法传递参数
    @interface YYDarwinNotificationManager : NSObject
    
    + (_Nonnull instancetype)sharedInstance;
    
    - (void)registerNotificationForName:(NSString *_Nonnull)name callback:(YYDarwinNotificationManagerHandler _Nullable)callback;
    - (void)postNotificationForName:(NSString *_Nonnull)name;
    
    @end
    

    这里有个坑,最开始想用这个通知直接搞定参数传递的,但是发现怎么也不行,最后看到Api有对应说明,对于object,userInfo,deliverImmediately这些参数:

    If center is a Darwin notification center, this value is ignored.
    

    实现代码

    确定了方案,可以开始撸了,先添加一些扩展:

    public extension UserDefaults {
        var readPackets: String? {
            get {
                string(forKey: #function)
            }
            set {
                set(newValue, forKey: #function)
            }
        }
        
        var receivePackets: String? {
            get {
                string(forKey: #function)
            }
            set {
                set(newValue, forKey: #function)
            }
        }
    }
    
    public extension YYVPNManager {
        static let didChangeStatusNotification = "YYVPNManager.didChangeStatusNotification"
        static let didReadPacketsNotification = "YYVPNManager.didReadPacketsNotification"
        static let didReceivePacketsNotification = "YYVPNManager.didReceivePacketsNotification"
    }
    

    扩展中的实现

    PacketTunnelProvider中添加一个属性:

    private lazy var dataStorage = UserDefaults(suiteName: YYVPNManager.groupID)!
    

    然后在读取到流量和收到服务器响应的地方设置数据,发送通知:

    func remotePacketsToLocal() {
            udpSession.setReadHandler({ [weak self] packets, _ in
                if let packets = packets {
                    packets.forEach {
                        self?.dataStorage.receivePackets = ($0 as NSData).description
                        YYDarwinNotificationManager.sharedInstance().postNotification(forName: YYVPNManager.didReceivePacketsNotification)
                        self?.packetFlow.writePackets([$0], withProtocols: [AF_INET as NSNumber])
                    }
                }
            }, maxDatagrams: .max)
        }
        
    func localPacketsToServer() {
        os_log(.default, log: .default, "LocalPacketsToServer")
        packetFlow.readPackets { [weak self] packets, _ in
            os_log(.default, log: .default, "readPackets")
            packets.forEach {
                self?.dataStorage.readPackets = ($0 as NSData).description
                YYDarwinNotificationManager.sharedInstance().postNotification(forName: YYVPNManager.didReadPacketsNotification)
                self?.udpSession.writeDatagram($0) { error in
                    if let error = error {
                        os_log(.default, log: .default, "udpSession.writeDatagram error: %{public}@", "\(error)")
                    }
                }
            }
    
            self?.localPacketsToServer()
        }
    }
    

    主App中的实现

    包含2个List,监听didReadPacketsNotification和didReceivePacketsNotification,添加数据并展示。

    界面如下:

    image

    直接上代码:

    import SwiftUI
    import YYVPNLib
    
    struct PacketView: View {
        @State var sendPackets: [YYListView.Model] = []
        @State var receviedPackets: [YYListView.Model] = []
        private let dataStorage = UserDefaults(suiteName: YYVPNManager.groupID)!
    
        var body: some View {
            VStack {
                Group {
                    HStack {
                        Text("发送的包")
                        Button(action: cleanSendPackets) {
                            Text("clean")
                        }
                    }.fixedSize()
                    YYListView(items: $sendPackets)
                }
                Group {
                    HStack {
                        Text("接收的包")
                        Button(action: cleanReceviedPackets) {
                            Text("clean")
                        }
                    }.fixedSize()
                    YYListView(items: $receviedPackets)
                }
            }.onAppear(perform: starListening)
        }
    
        private func cleanSendPackets() {
            sendPackets.removeAll()
        }
    
        private func cleanReceviedPackets() {
            receviedPackets.removeAll()
        }
    
        private func starListening() {
            YYDarwinNotificationManager.sharedInstance().registerNotification(forName: YYVPNManager.didReadPacketsNotification) {
                if let data = self.dataStorage.readPackets {
                    DispatchQueue.main.async {
                        self.sendPackets.append(.init(text: data))
                    }
                }
            }
    
            YYDarwinNotificationManager.sharedInstance().registerNotification(forName: YYVPNManager.didReceivePacketsNotification) {
                if let data = self.dataStorage.receivePackets {
                    DispatchQueue.main.async {
                        self.receviedPackets.append(.init(text: data))
                    }
                }
            }
        }
    }
    

    最近再添加一个入口,可以在ConfigView里面添加一个判断,如果VPN连上了,就展示跳转入口:

    Form {
        ...
        if viewModel.status == .on {
        Section {
            NavigationLink(destination: PacketView()) {
                Text("Show packets View")
            }
        }
        }
        ...
    }
    

    搞定~ ~

    相关文章

      网友评论

        本文标题:NetworkExtension5-App和Extension通

        本文链接:https://www.haomeiwen.com/subject/juvusktx.html