Release 3.8.2.13: iOS Packet Tunnel client and Clash URL subscriptions.
Add SwiftUI + Network Extension (LibXray/hev), parse Clash Meta YAML from subscription URLs into vless/trojan/hy2 share links, keep the selected server on connect, and ship Navis-3.8.2.13.ipa with versioned changelog. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import Foundation
|
||||
|
||||
enum Proto: String, Codable, Sendable {
|
||||
case vless
|
||||
case vmess
|
||||
case trojan
|
||||
case hy2
|
||||
case naive
|
||||
case awg
|
||||
case unknown
|
||||
|
||||
var label: String { rawValue }
|
||||
|
||||
static func detect(_ uri: String) -> Proto {
|
||||
let lower = uri.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
||||
if lower.hasPrefix("vless://") { return .vless }
|
||||
if lower.hasPrefix("vmess://") { return .vmess }
|
||||
if lower.hasPrefix("trojan://") { return .trojan }
|
||||
if lower.hasPrefix("hysteria2://") || lower.hasPrefix("hy2://") { return .hy2 }
|
||||
if lower.hasPrefix("naive+") || lower.hasPrefix("naive://") { return .naive }
|
||||
// Desktop DetectProtocol: bare http(s)/quic with userinfo → naive
|
||||
if lower.hasPrefix("https://") || lower.hasPrefix("http://") || lower.hasPrefix("quic://") {
|
||||
return .naive
|
||||
}
|
||||
if lower.hasPrefix("awg://") || lower.hasPrefix("amneziawg://") || lower.hasPrefix("wireguard://") {
|
||||
return .awg
|
||||
}
|
||||
if lower.localizedCaseInsensitiveContains("[Interface]") && lower.contains("Jc") {
|
||||
return .awg
|
||||
}
|
||||
return .unknown
|
||||
}
|
||||
|
||||
/// Protocols with a working in-process core in the current iOS appex.
|
||||
var supportedOnIOS: Bool {
|
||||
switch self {
|
||||
case .vless, .vmess, .trojan:
|
||||
return true
|
||||
case .hy2:
|
||||
// YAML builder ready; runtime needs unified NavisCore (LibXray Go runtime conflict).
|
||||
return false
|
||||
case .naive, .awg, .unknown:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var iosUnsupportedReason: String? {
|
||||
switch self {
|
||||
case .hy2:
|
||||
return "Hysteria2: пока используйте VLESS/VMess/Trojan (единый NavisCore для Hy2 — следующий шаг)"
|
||||
case .naive:
|
||||
return "NaiveProxy на iOS недоступен (Chromium-ядро)"
|
||||
case .awg:
|
||||
return "AmneziaWG на iOS — следующим этапом"
|
||||
case .unknown:
|
||||
return "Неизвестный протокол"
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Profile: Identifiable, Codable, Equatable, Sendable {
|
||||
var id: String
|
||||
var name: String
|
||||
var uri: String
|
||||
var host: String
|
||||
|
||||
var protocolKind: Proto { Proto.detect(uri) }
|
||||
|
||||
init(id: String, name: String, uri: String, host: String = "") {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.uri = uri
|
||||
self.host = host.isEmpty ? LinkParser.hostOf(uri) : host
|
||||
}
|
||||
}
|
||||
|
||||
struct PingResult: Identifiable, Sendable {
|
||||
var id: String
|
||||
var ms: Int64 = -1
|
||||
var ok: Bool = false
|
||||
var error: String?
|
||||
}
|
||||
|
||||
struct TunnelConfig: Codable, Sendable {
|
||||
var name: String
|
||||
var uri: String
|
||||
var startedAt: Double
|
||||
}
|
||||
Reference in New Issue
Block a user