- 一个使用NEKit的iOS App Demo
carthage update --no-use-binaries --platform ios
相关帖子:https://briteming.blogspot.com/2019/09/c4msis.html
------
Leiter
一个基于 NEKit 的网络 Proxy App。
Usage
执行:
> carthage update --no-use-binaries --platform ios
> pod install --repo-update
> open Leiter.xcworkspace
此项目如果要在App上使用,需要99美元的开发者账号
支持的协议:
- Http(s)
- Shadowsock
- Socks5
Contributing
from https://github.com/Tuluobo/Leiter
------
一个iOS端的VPN客户端.
使用说明
操作流程
1,git clone git@github.com:TheAlwaysHaveYou/LightningVPN.git
2,pod update
3,carthage update --no-use-binaries --platform ios 对于NEKit只能使用carthage导入,不能直接carthage update,因为当前swift版本相对于拉下来的framework版本有可能不同,导致拉不下来。 使用carthage update --no-use-binaries --platform ios命令导入,不从远程库里面拉framework,而是将工程拉下来,根据当前Xcode版本的内容进行打包成framework。
4,修改 Bundle Idenfifier
5,将Network Extensions 和Personal VPN 这两个权限打开
6,然后代码里面配置SS服务器的IP,端口,密码,等等。
7,就可以跑起来了。
from https://github.com/TheAlwaysHaveYou/LightningVPN
------
carthage update --no-use-binaries --platform ios
2018-4-23
App Store
- 国区开发者即使选择非国区上架也是违反国家法律的,准确的说
Shadowsocks
的用户就是大陆用户,所以涉及到的其账户都是不合国内法律的; - Shadowsocks 属于 Open source,作为非开发维护人员不应该使用这个名称,所以名字更改为 '1/4DSSA',但是由于 '1' 还是没有办法上架。
LICENSE
CFBundleShortVersionString
问题
解决打包上传时遇到的 defaults write "$PWD/Carthage/Build/iOS/NEKit.framework/Info.plist" CFBundleShortVersionString 0.2.0
defaults write "$PWD/Carthage/Build/iOS/NEKit.framework.dSYM/Contents/Info.plist" CFBundleShortVersionString 0.2.0
---
iOS NetworkExtension ShadowSocket for iOS developer (swift 5) 支持系统小组件开关SS.
Demo代码已适配swift5,点击GitHub链接查看。Demo运行需要有开发者账号,修改bundle id,在自己的开发者账号进行注册。
创建工程
NEKit集成
carthage update --no-use-binaries --platform mac,ios
创建VXN Manager
fileprivate func createProviderManager() -> NETunnelProviderManager {
let manager = NETunnelProviderManager()
let conf = NETunnelProviderProtocol()
conf.serverAddress = "BearFree"
manager.protocolConfiguration = conf
manager.localizedDescription = "BearFree"
return manager
}
manager.saveToPreferences{
error in
if error != nil{print(error);return;}
//Todo
}
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
//启动VPN时调用
func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void)
//停止VPN时调用
func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void)
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
try manager.connection.startVPNTunnel(options: [:])
func connect(){
self.loadAndCreatePrividerManager { (manager) in
guard let manager = manager else{return}
do{
try manager.connection.startVPNTunnel(options: [:])
}catch let err{
print(err)
}
}
}
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、端口等)
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)
}
public var protocolConfiguration: NEVPNProtocol { get }
关于网络状态的改变
public var defaultPath: NWPath? { get }
表明当前系统的网络请求路径。我们可以通过KVO监听defaultPath
的改变。当defaultPath
与之前状态发生改变,且defaultPath.status == .Satisfied
时,我们可以认定系统网络进行了切换。此时我们需要重启VPN及重启代理服务器。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
}
}
}