You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Windows应用:用户无活动20秒后关闭第三方程序并返回播放器

解决方案

1. 记录并控制Chrome进程

Flutter本身无法直接访问外部进程,但可以通过以下两种方式获取Chrome的进程ID(PID)并操作它:

  • 启动时记录PID:如果是通过Flutter主动启动Chrome,用dart:io的Process.start可以直接拿到PID,后续用这个PID终止进程:
    import 'dart:io';
    
    int? chromePid;
    
    Future<void> launchChrome() async {
      final process = await Process.start('chrome.exe', ['https://your-target-url.com']);
      chromePid = process.pid;
    }
    
  • 枚举进程获取PID:如果是通过url_launcher等方式打开Chrome,需要用Windows API枚举系统进程,根据进程名(chrome.exe)或窗口标题匹配目标进程。可以借助win32包调用Windows原生API:
    import 'package:win32/win32.dart';
    
    int? findChromePid() {
      final snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
      if (snapshot == INVALID_HANDLE_VALUE) return null;
    
      final processEntry = PROCESSENTRY32.allocate();
      processEntry.dwSize = sizeOf<PROCESSENTRY32>();
    
      if (!Process32First(snapshot, processEntry.addressOf)) {
        CloseHandle(snapshot);
        return null;
      }
    
      do {
        final processName = processEntry.szExeFile.toDartString();
        if (processName.toLowerCase() == 'chrome.exe') {
          final pid = processEntry.th32ProcessID;
          CloseHandle(snapshot);
          processEntry.free();
          return pid;
        }
      } while (Process32Next(snapshot, processEntry.addressOf));
    
      CloseHandle(snapshot);
      processEntry.free();
      return null;
    }
    

拿到PID后,调用Windows API的TerminateProcess关闭Chrome:

void terminateChrome(int pid) {
  final processHandle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
  if (processHandle != NULL) {
    TerminateProcess(processHandle, 0);
    CloseHandle(processHandle);
  }
}

2. 监听系统级用户无活动状态

Flutter没有内置全局用户活动监听,需要调用Windows API的GetLastInputInfo获取系统无活动时长:

import 'package:win32/win32.dart';

int getInactiveSeconds() {
  final lastInputInfo = LASTINPUTINFO.allocate();
  lastInputInfo.cbSize = sizeOf<LASTINPUTINFO>();
  
  GetLastInputInfo(lastInputInfo.addressOf);
  final inactiveMillis = GetTickCount() - lastInputInfo.dwTime;
  
  lastInputInfo.free();
  return (inactiveMillis / 1000).floor();
}

然后启动一个定时任务,每隔1秒检查一次无活动时长,达到20秒时执行关闭和切换操作:

import 'dart:async';

Timer? inactivityTimer;

void startInactivityMonitor() {
  inactivityTimer?.cancel();
  inactivityTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
    if (getInactiveSeconds() >= 20) {
      if (chromePid != null) {
        terminateChrome(chromePid!);
      }
      bringMediaPlayerToFront();
      timer.cancel();
    }
  });
}

3. 切换回后台的媒体播放器

同样通过Windows API找到媒体播放器的窗口句柄,调用SetForegroundWindow将其带到前台:

void bringMediaPlayerToFront() {
  // 替换为你的媒体播放器窗口标题或类名
  final mediaPlayerHwnd = FindWindow(NULL, TEXT('My Media Player'));
  if (mediaPlayerHwnd != NULL) {
    // 确保窗口不是最小化状态
    ShowWindow(mediaPlayerHwnd, SW_RESTORE);
    SetForegroundWindow(mediaPlayerHwnd);
  }
}

注意事项

  • 依赖win32包:需要在pubspec.yaml中添加win32: ^5.0.0(或最新版本)
  • 权限问题:OpenProcess需要足够的权限,确保你的应用以合适的权限运行
  • Chrome多进程:Chrome会启动多个子进程,若需要完全关闭所有Chrome实例,需要枚举所有chrome.exe进程并逐一终止

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 07:58:13