Flutter SSH连接插件ssh2的使用
Flutter SSH连接插件ssh2的使用
ssh2
是一个用于Flutter的SSH和SFTP客户端插件,它封装了iOS库NMSSH和Android库JSch。本文将介绍如何在Flutter项目中使用这个插件。
安装
在你的 pubspec.yaml
文件中添加 ssh2
作为依赖:
dependencies:
ssh2: ^x.x.x # 替换为最新版本号
然后运行 flutter pub get
来安装依赖。
已知问题
- 较旧的Gradle版本由于与新的JSch依赖不兼容而不被支持。此版本已通过Gradle版本7.0.2测试。
使用示例
使用密码认证创建客户端
import 'package:ssh2/ssh2.dart';
var client = new SSHClient(
host: "my.sshtest",
port: 22,
username: "sha",
passwordOrKey: "Password01.",
);
使用公钥认证创建客户端
var client = new SSHClient(
host: "my.sshtest",
port: 22,
username: "sha",
passwordOrKey: {
"privateKey": """-----BEGIN RSA PRIVATE KEY-----
......
-----END RSA PRIVATE KEY-----""",
"passphrase": "passphrase-for-key",
},
);
注意:如果使用OpenSSH格式的密钥,需要将其转换为PEM格式。
连接客户端
await client.connect();
关闭客户端
await client.disconnect();
执行SSH命令
var result = await client.execute("ps");
获取远程主机的指纹
var result = await client.getHostFingerprint();
获取远程主机的Banner
var result = await client.getBanner();
Shell操作
启动Shell
var result = await client.startShell(
ptyType: "xterm", // 默认值为vanilla
callback: (dynamic res) {
print(res); // 从shell读取数据
}
);
写入Shell
await client.writeToShell("ls\n");
关闭Shell
await client.closeShell();
SFTP操作
连接SFTP
await client.connectSFTP();
列出目录
var array = await client.sftpLs("/home"); // 默认为当前目录
创建目录
await client.sftpMkdir("testdir");
重命名文件或目录
await client.sftpRename(
oldPath: "testfile",
newPath: "newtestfile",
);
删除目录
await client.sftpRmdir("testdir");
删除文件
await client.sftpRm("testfile");
下载文件
var filePath = await client.sftpDownload(
path: "testfile",
toPath: tempPath,
callback: (progress) {
print(progress); // 读取下载进度
},
);
// 取消下载
await client.sftpCancelDownload();
上传文件
await client.sftpUpload(
path: filePath,
toPath: ".",
callback: (progress) {
print(progress); // 读取上传进度
},
);
// 取消上传
await client.sftpCancelUpload();
关闭SFTP
await client.disconnectSFTP();
示例应用
以下是一个完整的Flutter应用示例,展示如何使用 ssh2
插件进行SSH和SFTP操作:
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:ssh2/ssh2.dart';
import 'package:path_provider/path_provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _result = '';
List _array = [];
final String hostname = 'your.hostname.com';
final String username = 'your_username';
final String password = 'your_password';
final String privateKey = """-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...
-----END RSA PRIVATE KEY-----""";
final String passphrase = "your_passphrase";
final ButtonStyle buttonStyle =
TextButton.styleFrom(backgroundColor: Colors.blue);
void resetValues() {
setState(() {
_result = 'Loading';
_array = [];
});
}
Future<void> onClickCmd() async {
String result = '';
resetValues();
var client = new SSHClient(
host: hostname,
port: 22,
username: username,
passwordOrKey: password,
);
try {
result = await client.connect() ?? 'Null result';
if (result == "session_connected") result = await client.execute("ps") ?? 'Null result';
await client.disconnect();
} on PlatformException catch (e) {
String errorMessage = 'Error: ${e.code}\nError Message: ${e.message}';
result = errorMessage;
print(errorMessage);
}
setState(() {
_result = result;
});
}
Future<void> onClickShell() async {
String result = '';
resetValues();
var client = new SSHClient(
host: hostname,
port: 22,
username: username,
passwordOrKey: {
"privateKey": privateKey,
"passphrase": passphrase,
},
);
try {
result = await client.connect() ?? 'Null result';
if (result == "session_connected") {
result = await client.startShell(
ptyType: "xterm",
callback: (dynamic res) {
setState(() {
result += res;
});
}) ?? 'Null result';
if (result == "shell_started") {
print(await client.writeToShell("echo hello > world\n"));
print(await client.writeToShell("cat world\n"));
}
await client.disconnect();
}
} on PlatformException catch (e) {
String errorMessage = 'Error: ${e.code}\nError Message: ${e.message}';
result += errorMessage;
print(errorMessage);
}
setState(() {
_result = result;
});
}
Future<void> onClickSFTP() async {
String result = '';
List array = [];
resetValues();
var client = new SSHClient(
host: hostname,
port: 22,
username: username,
passwordOrKey: password,
);
try {
result = await client.connect() ?? 'Null result';
if (result == "session_connected") {
result = await client.connectSFTP() ?? 'Null result';
if (result == "sftp_connected") {
array = await client.sftpLs() ?? [];
print(await client.sftpMkdir("testsftp"));
print(await client.sftpRename(
oldPath: "testsftp",
newPath: "testsftprename",
));
print(await client.sftpRmdir("testsftprename"));
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
final String fileName = 'ssh2_test_upload.txt';
final File file = File('$tempPath/$fileName');
await file.writeAsString('Testing file upload');
print(await client.sftpUpload(
path: file.path,
toPath: ".",
callback: (progress) async {
print(progress);
},
) ?? 'Upload failed');
print(await client.sftpDownload(
path: fileName,
toPath: tempPath,
callback: (progress) async {
print(progress);
},
) ?? 'Download failed');
print(await client.sftpRm(fileName));
await file.delete();
await client.disconnect();
}
}
} on PlatformException catch (e) {
String errorMessage = 'Error: ${e.code}\nError Message: ${e.message}';
result += errorMessage;
print(errorMessage);
}
setState(() {
_result = result;
_array = array;
});
}
@override
Widget build(BuildContext context) {
Widget renderButtons() {
return ButtonTheme(
padding: EdgeInsets.all(5.0),
child: ButtonBar(
children: <Widget>[
TextButton(
style: buttonStyle,
child: Text(
'Test command',
style: TextStyle(color: Colors.white),
),
onPressed: onClickCmd,
),
TextButton(
style: buttonStyle,
child: Text(
'Test shell',
style: TextStyle(color: Colors.white),
),
onPressed: onClickShell,
),
TextButton(
style: buttonStyle,
child: Text(
'Test SFTP',
style: TextStyle(color: Colors.white),
),
onPressed: onClickSFTP,
),
],
),
);
}
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('ssh2 plugin example app'),
),
body: ListView(
shrinkWrap: true,
padding: EdgeInsets.all(15.0),
children: <Widget>[
Text(
"Please edit the connection settings in the source code before clicking the test buttons"),
renderButtons(),
Text(_result),
_array.length > 0
? Column(
children: _array.map((f) {
return Text(
"${f["filename"]} ${f["isDirectory"]} ${f["modificationDate"]} ${f["lastAccess"]} ${f["fileSize"]} ${f["ownerUserID"]} ${f["ownerGroupID"]} ${f["permissions"]} ${f["flags"]}");
}).toList(),
)
: Container(),
],
),
),
);
}
}
请根据实际需求修改连接信息(如 hostname
, username
, password
和 privateKey
),并确保您的环境配置正确。希望这个示例能帮助您更好地理解和使用 ssh2
插件。
更多关于Flutter SSH连接插件ssh2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter SSH连接插件ssh2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter应用中使用ssh2
插件进行SSH连接的示例代码。请注意,ssh2
本身并不是一个直接为Flutter设计的包,但在Flutter中可以通过Dart的VM(虚拟机)执行一些后台任务,或者使用平台通道(Platform Channels)在原生代码(如Android的Java/Kotlin或iOS的Swift/Objective-C)中执行SSH操作。不过,为了演示目的,我们可以假设存在一个适用于Dart的SSH库(比如dart-ssh2
,尽管这不是一个真实存在的库,但我们可以基于假设编写代码)。
由于Flutter本身不支持直接运行SSH命令,我们通常会使用平台通道调用原生代码执行这些任务。但这里,为了简化,我将展示一个假设的Dart代码,该代码如果有一个合适的SSH库,应该如何使用。
假设的Dart SSH库使用示例
首先,假设我们有一个名为dart_ssh2
的虚拟Dart包,它提供了SSH连接功能。
添加依赖(假设存在)
在你的pubspec.yaml
文件中添加依赖(注意,这是假设的,实际上并不存在这样的包):
dependencies:
flutter:
sdk: flutter
dart_ssh2: ^0.1.0 # 假设的版本号
使用示例
然后,在你的Flutter项目中,你可以这样使用:
import 'package:flutter/material.dart';
import 'package:dart_ssh2/dart_ssh2.dart'; // 假设的包导入
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('SSH Connection Example'),
),
body: Center(
child: SSHConnectionExample(),
),
),
);
}
}
class SSHConnectionExample extends StatefulWidget {
@override
_SSHConnectionExampleState createState() => _SSHConnectionExampleState();
}
class _SSHConnectionExampleState extends State<SSHConnectionExample> {
String result = '';
void _connectSSH() async {
// 配置SSH连接参数
var config = SSHConfig(
host: 'example.com',
port: 22,
username: 'your_username',
password: 'your_password',
);
// 尝试连接
try {
var ssh = await SSHClient.connect(config);
// 执行命令
var commandResult = await ssh.execute('ls -la');
// 更新UI
setState(() {
result = commandResult.stdout;
});
// 关闭连接
await ssh.disconnect();
} catch (e) {
// 错误处理
setState(() {
result = 'Error: ${e.message}';
});
}
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('SSH Command Result:'),
Text(result, style: TextStyle(fontSize: 16)),
SizedBox(height: 20),
ElevatedButton(
onPressed: _connectSSH,
child: Text('Connect and Execute Command'),
),
],
);
}
}
// 假设的SSH配置类
class SSHConfig {
String host;
int port;
String username;
String password;
SSHConfig({
required this.host,
required this.port,
required this.username,
required this.password,
});
}
// 假设的SSH客户端类
class SSHClient {
String? host;
int? port;
String? username;
String? password;
SSHClient._();
static Future<SSHClient> connect(SSHConfig config) async {
// 这里应该是建立SSH连接的代码
// 但由于这是一个假设的示例,我们直接返回一个模拟的SSHClient实例
return SSHClient._()
..host = config.host
..port = config.port
..username = config.username
..password = config.password;
}
Future<SSHCommandResult> execute(String command) async {
// 这里应该是执行SSH命令的代码
// 但由于这是一个假设的示例,我们直接返回一个模拟的结果
return SSHCommandResult(stdout: 'This is a simulated command output.');
}
Future<void> disconnect() async {
// 这里应该是断开SSH连接的代码
// 但由于这是一个假设的示例,我们什么也不做
}
}
// 假设的SSH命令结果类
class SSHCommandResult {
String stdout;
String stderr;
SSHCommandResult({
required this.stdout,
required this.stderr,
});
}
注意
- 实际实现:在实际项目中,你需要使用如
platform_channels
与原生代码(如Java/Kotlin或Swift/Objective-C)进行交互,以执行SSH命令。 - 安全性:不要在客户端应用中硬编码敏感信息(如密码)。考虑使用更安全的认证方法,如SSH密钥或OAuth。
- 依赖:确保你的项目依赖是真实存在的,并且已经正确配置。
由于Flutter的生态系统不断变化,建议查阅最新的文档和社区资源,以找到最适合你需求的解决方案。