Flutter Windows应用打包时集成platform-tools以无需修改路径执行adb命令的实现方法咨询
Hey there! Let's tackle this problem step by step. You want to bundle the platform-tools folder with your Flutter Windows app so it works out of the box on a fresh Windows machine—here are two reliable ways to do it:
Option 1: Copy platform-tools directly to the EXE directory (Simple & Straightforward)
This method ensures the platform-tools folder sits right next to your app's EXE after building, so your code can easily access it without path changes.
Step 1: Fix your pubspec.yaml asset configuration
Make sure you're including the entire platform-tools folder (use a trailing slash to capture all its contents):
flutter: uses-material-design: true assets: - assets/platform-tools/ # Trailing slash = include all files in the folder - assets/platform-tools/app-release-v3.1.01.apk
Step 2: Automate copying platform-tools after build
Create a batch script (name it build_windows.bat) in your Flutter project's root directory. This script will run the Flutter build command, then copy the platform-tools folder to the EXE's release directory:
@echo off flutter build windows xcopy /E /I /Y "assets\platform-tools" "build\windows\runner\Release\platform-tools"
/E: Copies all subdirectories (including empty ones)/I: Treats the destination as a folder if it doesn't exist/Y: Overwrites files without prompting
Step 3: Update your Dart code to use the EXE's directory
Modify your code to dynamically get the EXE's location, then build the path to platform-tools:
import 'dart:io'; import 'package:path/path.dart' as path; import 'package:fluent_ui/fluent_ui.dart'; import 'installation_and_permissions.dart' as installer; var stdoutCommand = "", stderrCommand = "", deviceName = ""; // Get the directory where the EXE is running from String getExeDirectory() { final exePath = Platform.resolvedExecutable; return path.dirname(exePath); } Future<void> main() async { final exeDir = getExeDirectory(); final platformToolsDir = path.join(exeDir, 'platform-tools'); final adbPath = path.join(platformToolsDir, 'adb.exe'); // Windows needs .exe suffix await Process.run( adbPath, ['devices'], workingDirectory: platformToolsDir, runInShell: false, // No need for shell since we're using the full path ).then((ProcessResult res) { stdoutCommand = res.stdout.toString(); stderrCommand = res.stderr.toString(); // Use a safer way to extract device name (avoid fixed substrings) if (stdoutCommand.contains('\tdevice')) { deviceName = stdoutCommand.split('\n')[1].split('\t')[0]; } print(stdoutCommand); print(stderrCommand); }); runApp(const MyApp()); }
Option 2: Embed platform-tools in the EXE, extract at runtime (Cleaner)
If you don't want users to see the platform-tools folder, you can bundle it as a ZIP asset and extract it to a hidden cache directory when the app first runs.
Step 1: Prepare the ZIP asset
- Zip your entire
platform-toolsfolder (name itplatform-tools.zip) - Place the ZIP in your
assetsfolder - Update
pubspec.yaml:
flutter: uses-material-design: true assets: - assets/platform-tools.zip - assets/app-release-v3.1.01.apk
Step 2: Add required dependencies
Add these to your pubspec.yaml to handle ZIP extraction and directory access:
dependencies: flutter: sdk: flutter fluent_ui: ^4.7.0 archive: ^3.3.7 # For ZIP extraction path_provider: ^2.1.1 # For accessing app cache directories
Step 3: Update Dart code to extract and use the ZIP
import 'dart:io'; import 'dart:typed_data'; import 'package:path/path.dart' as path; import 'package:flutter/services.dart'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:archive/archive.dart'; import 'package:path_provider/path_provider.dart'; import 'installation_and_permissions.dart' as installer; var stdoutCommand = "", stderrCommand = "", deviceName = ""; // Extract ZIP file to target directory Future<void> extractZip(Uint8List zipData, String targetDir) async { final archive = ZipDecoder().decodeBytes(zipData); for (final file in archive) { final filePath = path.join(targetDir, file.name); if (file.isFile) { final fileBytes = file.content as List<int>; await File(filePath).writeAsBytes(fileBytes); // Ensure adb.exe has execution permissions (Windows-specific) if (path.basename(filePath) == 'adb.exe') { await Process.run('icacls', [filePath, '/grant', 'Everyone:F']); } } else { await Directory(filePath).create(recursive: true); } } } // Get a hidden cache directory for platform-tools Future<String> getPlatformToolsCacheDir() async { final appSupportDir = await getApplicationSupportDirectory(); return path.join(appSupportDir.path, 'platform-tools'); } Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); // Required for asset access final cacheDir = await getPlatformToolsCacheDir(); final adbPath = path.join(cacheDir, 'adb.exe'); // Extract ZIP only if adb.exe doesn't exist if (!await File(adbPath).exists()) { final zipData = await rootBundle.load('assets/platform-tools.zip'); await extractZip(zipData.buffer.asUint8List(), cacheDir); } // Run adb command await Process.run( adbPath, ['devices'], workingDirectory: cacheDir, runInShell: false, ).then((ProcessResult res) { stdoutCommand = res.stdout.toString(); stderrCommand = res.stderr.toString(); if (stdoutCommand.contains('\tdevice')) { deviceName = stdoutCommand.split('\n')[1].split('\t')[0]; } print(stdoutCommand); print(stderrCommand); }); runApp(const MyApp()); }
Important Notes
- Always test your built app on a fresh Windows machine to ensure paths work correctly.
- Avoid using fixed
substringvalues to extract device names—output can vary between devices. - For Option 1, you can run the batch script instead of
flutter build windowsto automate the copy process.
内容的提问来源于stack exchange,提问作者TantrumV




