Flutter终端模拟插件terminal_library的使用
Flutter终端模拟插件terminal_library
的使用
演示
文档
- 文档
- YouTube
- Telegram支持群组
- 联系开发者(检查社交媒体或README文件中的GitHub个人资料)
功能
- ✅ 📱️ 跨平台 支持(设备、边缘服务器无函数)
- ✅ 📜️ 标准化 样式代码
- ✅ ⌨️ CLI(终端帮助你使用此库或创建项目)
- ✅ 🔥️ API(如果你开发机器人/用户机器人,可以使用此库而无需交互CLI,只需添加库并使用🚀️)
- ❌ 🧩️ 可定制扩展(如果你想添加扩展,可以加快开发速度)
- ❌ ✨️ 漂亮信息(对新手友好)
有趣的小知识
此库在所有平台(CLI、服务器、Web、GUI)上运行,忽略flutter标志,仅限pub.dev
安装库
- Dart
dart pub add terminal_library
- Flutter
flutter pub add terminal_library
使用此项目/示例项目的应用
- 通用工作室开发者应用
- 通用机器人应用/通用自动化应用
- 通用应用程序
快速开始
以下是一个快速入门脚本的最小示例,旨在为你提供灵感,或者使你更容易使用此库,因为它非常简单。
// ignore_for_file: empty_catches, non_constant_identifier_names
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:general_lib/general_lib.dart';
import 'package:general_lib_flutter/extension/build_context.dart';
import 'package:general_lib_flutter/widget/widget.dart';
import 'package:terminal_library/pty_library/pty_library.dart';
import 'package:terminal_library/xterm_library/xterm.dart';
void main(List<String> args) {
WidgetsFlutterBinding.ensureInitialized();
runApp(const App());
}
class App extends StatelessWidget {
static GeneralLibFlutterApp generalLibFlutterApp = GeneralLibFlutterApp();
const App({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return GeneralLibFlutterAppMain(
generalLibFlutterApp: generalLibFlutterApp,
builder: (themeMode, lightTheme, darkTheme, widget) {
Widget child = MaterialApp(
theme: lightTheme,
darkTheme: darkTheme,
themeMode: themeMode,
debugShowCheckedModeBanner: false,
home: const MyApp(),
);
return child;
},
);
}
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
TerminalLibraryFlutterController terminalLibraryFlutterController = TerminalLibraryFlutterController();
final TerminalLibraryFlutter terminalLibraryFlutter = TerminalLibraryFlutter(
maxLines: 1000,
);
late final PtyLibrary ptyLibrary;
[@override](/user/override)
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await refresh();
});
}
[@override](/user/override)
void dispose() {
ptyLibrary.kill();
terminalLibraryFlutterController.dispose();
super.dispose();
}
bool is_loading = false;
Future<void> refresh() async {
if (is_loading) {
return;
}
setState(() {
is_loading = true;
});
await Future(() async {
await Future.delayed(Duration(milliseconds: 500));
ptyLibrary = PtyLibrary.start(
shell,
columns: terminalLibraryFlutter.viewWidth,
rows: terminalLibraryFlutter.viewHeight,
);
ptyLibrary.output.listen((event) {
if (event.isNotEmpty) {
try {
terminalLibraryFlutter.write(utf8.decode(event, allowMalformed: true));
} catch (e) {}
}
});
terminalLibraryFlutter.onOutput = (String value) {
if (value.isNotEmpty) {
try {
ptyLibrary.write(utf8.encode(value));
} catch (e) {}
}
};
terminalLibraryFlutter.onResize = (w, h, pw, ph) {
ptyLibrary.resize(h, w);
};
terminalLibraryFlutter.buffer.clear();
terminalLibraryFlutter.buffer.setCursor(0, 0);
terminalLibraryFlutter.textInput("clear");
terminalLibraryFlutter.keyInput(TerminalLibraryFlutterKey.enter);
setState(() {});
});
setState(() {
is_loading = false;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
if (is_loading) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(
color: context.theme.indicatorColor,
),
),
);
}
return Scaffold(
appBar: AppBar(
title: const Text("终端库:"),
),
body: TerminalLibraryFlutterViewWidget(
terminalLibraryFlutter,
controller: terminalLibraryFlutterController,
autofocus: true,
backgroundOpacity: 0,
simulateScroll: true,
padding: const EdgeInsets.all(5),
alwaysShowCursor: true,
deleteDetection: Dart.isMobile,
),
);
}
static String get shell {
if (Platform.isMacOS || Platform.isLinux) {
return Platform.environment['SHELL'] ?? 'bash';
}
if (Platform.isWindows) {
return 'cmd.exe';
}
return 'sh';
}
}
示例代码
// 忽略文件: empty_catches, non_constant_identifier_names
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:general_lib/general_lib.dart';
import 'package:general_lib_flutter/extension/build_context.dart';
import 'package:general_lib_flutter/widget/widget.dart';
import 'package:terminal_library/pty_library/pty_library.dart';
import 'package:terminal_library/xterm_library/xterm.dart';
void main(List<String> args) {
WidgetsFlutterBinding.ensureInitialized();
runApp(const App());
}
class App extends StatelessWidget {
static GeneralLibFlutterApp generalLibFlutterApp = GeneralLibFlutterApp();
const App({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return GeneralLibFlutterAppMain(
generalLibFlutterApp: generalLibFlutterApp,
builder: (themeMode, lightTheme, darkTheme, widget) {
Widget child = MaterialApp(
theme: lightTheme,
darkTheme: darkTheme,
themeMode: themeMode,
debugShowCheckedModeBanner: false,
home: const MyApp(),
);
return child;
},
);
}
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
TerminalLibraryFlutterController terminalLibraryFlutterController = TerminalLibraryFlutterController();
final TerminalLibraryFlutter terminalLibraryFlutter = TerminalLibraryFlutter(
maxLines: 1000,
);
late final TerminalPtyLibrary ptyLibrary;
[@override](/user/override)
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await refresh();
});
}
[@override](/user/override)
void dispose() {
ptyLibrary.kill();
terminalLibraryFlutterController.dispose();
super.dispose();
}
bool is_loading = false;
Future<void> refresh() async {
if (is_loading) {
return;
}
setState(() {
is_loading = true;
});
await Future(() async {
await Future.delayed(Duration(milliseconds: 500));
ptyLibrary = TerminalPtyLibrary(
executable: TerminalPtyLibraryBase.defaultShell,
columns: terminalLibraryFlutter.viewWidth,
rows: terminalLibraryFlutter.viewHeight,
);
ptyLibrary.on(
eventName: ptyLibrary.event_output,
onCallback: onCallback,
);
terminalLibraryFlutter.onOutput = (String value) {
if (value.isNotEmpty) {
try {
ptyLibrary.write(utf8.encode(value));
} catch (e) {}
}
};
terminalLibraryFlutter.onResize = (w, h, pw, ph) {
ptyLibrary.resize(h, w);
};
terminalLibraryFlutter.buffer.clear();
terminalLibraryFlutter.buffer.setCursor(0, 0);
terminalLibraryFlutter.textInput("clear");
terminalLibraryFlutter.keyInput(TerminalLibraryFlutterKey.enter);
terminalLibraryFlutter.write("Hello World");
setState(() {});
});
setState(() {
is_loading = false;
});
}
FutureOr<dynamic> onCallback(dynamic update, TerminalPtyLibraryBase te) {
if (update is Uint8List) {
try {
terminalLibraryFlutter.write(utf8.decode(update, allowMalformed: true));
} catch (e) {}
} else if (update is String) {
terminalLibraryFlutter.write(update);
}
}
[@override](/user/override)
Widget build(BuildContext context) {
if (is_loading) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(
color: context.theme.indicatorColor,
),
),
);
}
return Scaffold(
appBar: AppBar(
title: const Text("终端库:"),
),
body: TerminalLibraryFlutterViewWidget(
terminalLibraryFlutter,
controller: terminalLibraryFlutterController,
autofocus: true,
backgroundOpacity: 0,
simulateScroll: true,
padding: const EdgeInsets.all(5),
alwaysShowCursor: true,
deleteDetection: Dart.isMobile,
),
);
}
}
更多关于Flutter终端模拟插件terminal_library的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter终端模拟插件terminal_library的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter中使用terminal_library
(假设这是一个提供终端模拟功能的插件)的基本示例代码。请注意,由于terminal_library
可能不是一个真实存在的Flutter插件(Flutter社区中的插件通常会有更具体的命名,如terminal_view
或flutter_term
等),以下代码将基于一个假设的API进行说明。如果terminal_library
确实存在,你可能需要根据其官方文档进行调整。
首先,确保在pubspec.yaml
文件中添加了对该插件的依赖:
dependencies:
flutter:
sdk: flutter
terminal_library: ^x.y.z # 替换为实际版本号
然后,运行flutter pub get
来安装依赖。
接下来,在你的Flutter应用中,你可以按照以下方式使用terminal_library
:
import 'package:flutter/material.dart';
import 'package:terminal_library/terminal_library.dart'; // 假设这是插件的导入路径
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: TerminalScreen(),
);
}
}
class TerminalScreen extends StatefulWidget {
@override
_TerminalScreenState createState() => _TerminalScreenState();
}
class _TerminalScreenState extends State<TerminalScreen> {
TerminalController _terminalController;
@override
void initState() {
super.initState();
_terminalController = TerminalController(
onCommandReceived: (command) {
// 处理接收到的命令
print('Received command: $command');
// 这里可以添加自定义的逻辑,比如执行命令、显示输出等
_terminalController.writeLine('Command executed successfully.');
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Terminal Emulator'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: TerminalView(
controller: _terminalController,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 打开一个键盘输入框,用于向终端发送命令
showCupertinoModalPopup<void>(
context: context,
builder: (BuildContext context) {
return BottomSheet(
onClosing: () => Navigator.pop(context),
builder: (BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
decoration: InputDecoration(
hintText: 'Enter command...',
),
onEditingComplete: () {
_terminalController.sendCommand(
_textFieldController.text,
);
Navigator.pop(context);
},
controller: _createTextFieldController(),
),
],
),
);
},
);
},
),
},
tooltip: 'Send Command',
child: Icon(Icons.send),
),
);
}
TextFieldController _createTextFieldController() {
final TextFieldController textFieldController = TextFieldController();
// 注意:这里我们需要在某处保存这个controller的引用,以便在onEditingComplete中使用
// 但由于Flutter的State管理,我们不能直接在这里保存它作为实例变量
// 因此,这里我们假设有一个机制(比如闭包、全局变量等)来确保我们可以访问到这个controller
// 在这个示例中,为了简化,我们省略了这个机制,实际使用时需要自行实现
// 例如,你可以使用State的某个变量来保存这个controller的引用,并在onEditingComplete中访问它
return textFieldController;
}
// 注意:上面的_createTextFieldController方法存在一个问题,即TextFieldController的引用管理
// 在实际应用中,你应该在State类中维护一个TextFieldController的实例变量,并在initState中初始化它
// 然后直接在TextField的controller属性中使用这个实例变量
// 下面的代码展示了如何正确管理TextFieldController的引用
TextFieldController _textFieldController;
@override
void initState() {
super.initState();
_textFieldController = TextFieldController();
_terminalController = TerminalController(
onCommandReceived: (command) {
print('Received command: $command');
_terminalController.writeLine('Command executed successfully.');
},
);
}
@override
void dispose() {
_textFieldController.dispose(); // 不要忘记在dispose中释放资源
super.dispose();
}
}
// 假设的TerminalController类,用于管理终端的行为
class TerminalController {
final ValueChanged<String> onCommandReceived;
List<String> _history = [];
TerminalController({required this.onCommandReceived});
void sendCommand(String command) {
_history.add(command);
onCommandReceived(command);
}
void writeLine(String line) {
// 这里可以添加逻辑来在UI中显示新行
// 例如,通过调用某个状态更新函数来更新UI
print('Terminal Output: $line'); // 假设的输出方式
}
}
// 假设的TerminalView组件,用于显示终端内容
class TerminalView extends StatelessWidget {
final TerminalController controller;
TerminalView({required this.controller});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: controller._history.map((line) => Text(line)).toList(),
);
}
}
请注意,上面的代码是一个高度简化和假设的示例,用于说明如何在Flutter应用中集成一个终端模拟插件。在实际应用中,你可能需要处理更多的细节,比如输入验证、命令执行结果的实时显示、错误处理等。此外,TerminalController
和TerminalView
类的实现也会根据插件的实际API有所不同。因此,建议查阅terminal_library
(或你实际使用的插件)的官方文档,以获取准确的API信息和用法示例。