Flutter ADB调试插件flutter_adb的使用
Flutter ADB调试插件flutter_adb的使用
Native dart 实现的 ADB 网络协议
flutter_adb
是一个基于 Cameron Gutman 的 Java 版本实现的 Dart 包,用于连接到网络上的 Android 设备。它支持自-ADB(即连接到同一设备上运行 Flutter 应用的 ADB 实例)。
使用说明
- 创建 ADB 加密对象
- 根据连接设备的安全设置,您可能需要通过 RSA 密钥对进行身份验证。
- 该包包含了一个帮助类来生成密钥对并进行设备身份验证,但您也可以提供自己的密钥对。
- 包使用 pointycastle 进行 RSA 加密,因此您可以使用自己生成的密钥对。
final AsymmetricKeyPair<RSAPublicKey, RSAPrivateKey> keyPair = AdbCrypto.generateRSAKeyPair();
final crypto = AdbCrypto(keyPair: keyPair);
// 或者不传递密钥对以自动生成
final crypto = AdbCrypto();
- 第一次连接设备时,您需要从设备本身授权连接。之后,密钥对将存储在设备上,并且可以在保存和重用密钥对的情况下无需进一步交互连接。
-
创建 ADB 连接
- 创建 ADB 连接对象。
final adb = AdbConnection( '172.0.0.1', 5555, crypto, ); bool connected = await connection.connect(); // 您还可以监听连接状态更改 connection.onConnectionChanged.listen((connected) { print('Connected: $connected'); });
-
打开 shell 等操作
- 从这里开始,您可以打开 shell 等操作。
final AdbStream shell = await connection.open('shell:'); // 或者使用方便的方法 final AdbStream shell = await connection.openShell();
-
读取和写入流
- 读取和写入流。
// 监听传入数据 shell.onPayload.listen((payload) { print('Received: $payload'); }); // 向流写入数据 bool success = await shell.write('ls\n'); // 关闭流 shell.sendClose();
-
使用方便的方法打开 shell 发送单个命令并获取输出
final String result = Adb.sendSingleCommand( 'monkey -p com.google.android.googlequicksearchbox 1;sleep 3;input keyevent KEYCODE_HOME', ip: '127.0.0.1', port: 5555, crypto: crypto, ); print(result);
- 这种方法会自动打开连接、打开 shell、发送命令、关闭 shell 和连接,然后给出输出。可以使用
;
运算符连接多个命令。
- 这种方法会自动打开连接、打开 shell、发送命令、关闭 shell 和连接,然后给出输出。可以使用
示例代码
查看示例应用以了解简单的 ADB 终端实现(使用 riverpod)。
import 'package:flutter/material.dart';
import 'package:flutter_adb/adb_connection.dart';
import 'package:flutter_adb/adb_crypto.dart';
import 'package:flutter_adb/adb_stream.dart';
import 'package:flutter_adb/flutter_adb.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final StateProvider<AdbConnection> adbConnectionProvider = StateProvider((ref) {
final crypto = AdbCrypto();
final connection = AdbConnection('127.0.0.1', 5555, crypto, verbose: true);
return connection;
});
final FutureProvider<AdbStream> adbStreamProvider = FutureProvider((ref) async {
final connection = ref.watch(adbConnectionProvider);
await connection.connect();
return await connection.openShell();
});
void main() {
final ProviderContainer container = ProviderContainer();
WidgetsFlutterBinding.ensureInitialized();
runApp(UncontrolledProviderScope(container: container, child: const MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Adb Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends ConsumerStatefulWidget {
const MyHomePage({super.key});
[@override](/user/override)
ConsumerState<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends ConsumerState<MyHomePage> {
final _formKey = GlobalKey<FormState>();
final TextEditingController _ipController = TextEditingController();
final TextEditingController _portController = TextEditingController();
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: StreamBuilder(
stream: ref.read(adbConnectionProvider).onConnectionChanged,
initialData: false,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data ?? false) {
return Text(
'ADB Flutter Example, Connected to: ${ref.watch(adbConnectionProvider).ip}:${ref.watch(adbConnectionProvider).port}',
style: const TextStyle(fontSize: 32),
);
} else {
return const Text(
'ADB Flutter Example, Not connected',
style: TextStyle(fontSize: 32),
);
}
} else {
return const CircularProgressIndicator();
}
},
),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Form(
key: _formKey,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Spacer(),
IntrinsicWidth(
child: TextFormField(
controller: _ipController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
hintText: ref.watch(adbConnectionProvider).ip,
),
// 验证有效的 IPv4 地址
validator: (value {
if (value == null || value.isEmpty) {
return 'Invalid IP';
}
if (!RegExp(r'^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$').hasMatch(value)) {
return 'Invalid IP';
}
return null;
},
),
),
const SizedBox(width: 10),
IntrinsicWidth(
child: TextFormField(
controller: _portController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
hintText: ref.watch(adbConnectionProvider).port.toString(),
),
// 验证有效的端口
validator: (value {
if (value == null || value.isEmpty) {
return 'Invalid Port';
}
if (int.tryParse(value) == null || int.tryParse(value)! < 0 || int.tryParse(value)! > 65535 {
return 'Invalid Port';
}
return null;
},
),
),
TextButton(
onPressed: () async {
if (_formKey.currentState!.validate()) {
await ref.read(adbConnectionProvider).disconnect();
ref.read(adbConnectionProvider.notifier).state = AdbConnection(
_ipController.text,
int.parse(_portController.text),
AdbCrypto(),
);
}
},
child: const Text('Connect'),
),
],
),
),
Expanded(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 700),
child: ref.watch(adbStreamProvider).maybeWhen(
data: (adbStream) {
return AdbTerminal(stream: adbStream);
},
loading: () => const CircularProgressIndicator(),
error: (error, stack) {
return Text('Error: $error');
},
orElse: () => const SizedBox(),
),
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final result = await Adb.sendSingleCommand(
'monkey -p com.google.android.googlequicksearchbox 1;sleep 3;input keyevent KEYCODE_HOME',
ip: '127.0.0.1',
port: 5555,
crypto: crypto,
);
debugPrint('Result: $result');
},
tooltip: 'Send single command',
child: const Icon(Icons.send),
));
}
}
更多关于Flutter ADB调试插件flutter_adb的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter ADB调试插件flutter_adb的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用flutter_adb
插件进行ADB调试的代码案例。flutter_adb
插件允许你在Flutter应用中直接与Android设备的ADB(Android Debug Bridge)进行交互。
首先,你需要在你的Flutter项目中添加flutter_adb
依赖。在pubspec.yaml
文件中添加以下依赖:
dependencies:
flutter:
sdk: flutter
flutter_adb: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来获取依赖。
接下来,你可以在你的Flutter应用中使用flutter_adb
插件。以下是一个简单的示例,展示如何使用该插件获取已连接的设备列表并执行一些基本的ADB命令。
import 'package:flutter/material.dart';
import 'package:flutter_adb/flutter_adb.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<String> devices = [];
@override
void initState() {
super.initState();
_getDevices();
}
Future<void> _getDevices() async {
try {
List<AdbDevice> adbDevices = await FlutterAdb.getDevices();
setState(() {
devices = adbDevices.map((device) => device.id).toList();
});
} catch (e) {
print("Error getting devices: $e");
}
}
Future<void> _runAdbCommand(String deviceId, String command) async {
try {
String result = await FlutterAdb.runCommand(deviceId, command);
print("Command result: $result");
} catch (e) {
print("Error running command: $e");
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter ADB Demo'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text('Connected Devices:'),
Wrap(
spacing: 8.0,
runSpacing: 8.0,
children: devices.map((deviceId) => Chip(
label: Text(deviceId),
onDeleted: () {
// Here you can add a button to run a command on the selected device
// For example:
// _runAdbCommand(deviceId, 'shell input keyevent 26'); // Home button
},
)).toList(),
),
SizedBox(height: 20.0),
ElevatedButton(
onPressed: () async {
if (devices.isNotEmpty) {
String deviceId = devices.first; // For demonstration, using the first device
await _runAdbCommand(deviceId, 'shell input keyevent 26'); // Simulate pressing the home button
} else {
print("No devices connected.");
}
},
child: Text('Press Home on First Device'),
),
],
),
),
),
);
}
}
在这个示例中:
- 我们在
initState
方法中调用_getDevices
函数来获取已连接的Android设备列表,并将它们显示在屏幕上。 FlutterAdb.getDevices()
方法返回一个包含所有已连接设备的列表。_runAdbCommand
函数用于在指定的设备上运行ADB命令。在这个例子中,我们模拟按下Home按钮(shell input keyevent 26
)。- 我们使用
ElevatedButton
来触发在第一个连接的设备上运行ADB命令的操作。
请注意,这只是一个基本的示例。你可以根据需要扩展这个示例,以包括更多的ADB命令和设备交互功能。确保在实际应用中处理错误和异常情况,并提供适当的用户反馈。