first commit

This commit is contained in:
douboer
2026-03-21 18:57:10 +08:00
commit c49aa1a5e9
570 changed files with 107167 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "RemoteConnSSHPlugin",
platforms: [.iOS(.v15)],
products: [
.library(name: "RemoteConnSSHPlugin", targets: ["RemoteConnSSHPlugin"])
],
dependencies: [
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0")
],
targets: [
.target(
name: "RemoteConnSSHPlugin",
dependencies: [
.product(name: "Capacitor", package: "capacitor-swift-pm")
],
path: "Sources/RemoteConnSSHPlugin"
),
.testTarget(
name: "RemoteConnSSHPluginTests",
dependencies: ["RemoteConnSSHPlugin"],
path: "Tests/RemoteConnSSHPluginTests"
)
]
)

View File

@@ -0,0 +1,24 @@
# RemoteConnSSHPlugin
iOS 原生插件Capacitor骨架提供以下 JS 能力:
- `connect({ host, port, username, credential, cols, rows })`
- `send({ data })`
- `resize({ cols, rows })`
- `disconnect({ reason })`
监听事件:
- `connected`
- `stdout`
- `stderr`
- `latency`
- `disconnect`
- `error`
## 接入建议
1. 在 iOS App 中通过 SwiftPM 引入本插件包。
2. 替换 `RemoteConnSSHPlugin.swift` 中的占位逻辑为真实 SSH 实现libssh2 / SwiftNIO SSH
3. 对齐 Web 端 `IosNativeTransport` 事件协议,确保状态机一致。
4. 完整覆盖真机回归:连接、命令发送、断线重连、后台切换。

View File

@@ -0,0 +1,96 @@
import Foundation
import Capacitor
/**
iOS SSH
- 便 Web Capacitor
- SSH libssh2 / SwiftNIO SSH /
*/
@objc(RemoteConnSSHPlugin)
public class RemoteConnSSHPlugin: CAPPlugin, CAPBridgedPlugin {
public let identifier = "RemoteConnSSHPlugin"
public let jsName = "RemoteConnSSH"
public let pluginMethods: [CAPPluginMethod] = [
CAPPluginMethod(name: "connect", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "send", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "resize", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "disconnect", returnType: CAPPluginReturnPromise)
]
private let sessionQueue = DispatchQueue(label: "remoteconn.ssh.session")
private var connected = false
@objc public func connect(_ call: CAPPluginCall) {
let host = call.getString("host") ?? ""
let port = call.getInt("port") ?? 22
let username = call.getString("username") ?? ""
let credential = call.getObject("credential") ?? [:]
guard !host.isEmpty, !username.isEmpty else {
call.reject("host/username 不能为空", "INVALID_ARGUMENT")
return
}
sessionQueue.async {
// SSH /pty/shell/channel
// 线
self.connected = true
self.notifyListeners("connected", data: [
"host": host,
"port": port,
"username": username,
"fingerprint": credential["knownHostFingerprint"] as? String ?? ""
])
self.notifyListeners("stdout", data: ["data": "[iOS] SSH channel initialized\n"])
call.resolve(["ok": true])
}
}
@objc public func send(_ call: CAPPluginCall) {
guard connected else {
call.reject("会话未连接", "NOT_CONNECTED")
return
}
let data = call.getString("data") ?? ""
sessionQueue.async {
// data SSH channel
self.notifyListeners("stdout", data: ["data": data])
call.resolve(["ok": true])
}
}
@objc public func resize(_ call: CAPPluginCall) {
guard connected else {
call.reject("会话未连接", "NOT_CONNECTED")
return
}
let cols = call.getInt("cols") ?? 80
let rows = call.getInt("rows") ?? 24
sessionQueue.async {
// pty resize
self.notifyListeners("latency", data: ["latency": 0])
call.resolve([
"ok": true,
"cols": cols,
"rows": rows
])
}
}
@objc public func disconnect(_ call: CAPPluginCall) {
let reason = call.getString("reason") ?? "manual"
sessionQueue.async {
self.connected = false
self.notifyListeners("disconnect", data: ["reason": reason])
call.resolve(["ok": true])
}
}
}

View File

@@ -0,0 +1,8 @@
import XCTest
@testable import RemoteConnSSHPlugin
final class RemoteConnSSHPluginTests: XCTestCase {
func testPlaceholder() {
XCTAssertTrue(true)
}
}