You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

  1. Zip your entire platform-tools folder (name it platform-tools.zip)
  2. Place the ZIP in your assets folder
  3. 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 substring values to extract device names—output can vary between devices.
  • For Option 1, you can run the batch script instead of flutter build windows to automate the copy process.

内容的提问来源于stack exchange,提问作者TantrumV

火山引擎 最新活动