欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

在这里插入图片描述

前言

在桌面端(macOS/Windows/Linux)开发中,我们经常需要调用系统命令,比如 git clonenpm install,或者执行一段 Python 脚本。而在移动端(Android/iOS/OpenHarmony),虽然由于沙箱限制能调用的命令有限,但在某些特定场景(如获取设备属性、Ping 网络、文件操作)下,执行 Shell 命令依然非常有用。

process_run 是一个强大的 Dart 库,它不仅封装了 Process.run,还提供了自动查找可执行文件路径、跨平台参数转义等高级功能。本文将介绍如何在 OpenHarmony 上利用它执行允许的系统命令。

一、核心功能

  • 跨平台兼容:自动处理 Windows 和 Unix 系(OpenHarmony 属于此类)的命令差异。
  • 简化 API:比原生的 Process.run 更易用。
  • Shell 工具:内置 Shell 类,支持链式调用和环境变量注入。

调用 shell.run 接口

调用系统 Process 接口

在子进程中执行

回传标准输出(stdout)/错误(stderr)

处理并返回执行结果

Flutter 应用

process_run 核心库

HarmonyOS/Unix 系统内核

底层 Shell 命令

二、集成与基础用法

2.1 添加依赖

dependencies:
  process_run: ^1.3.0

2.2 执行简单命令 (Ping)

import 'package:process_run/shell.dart';

Future<void> pingGoogle() async {
  var shell = Shell();
  
  // 在 OpenHarmony 上,ping 通常位于 /system/bin/ping 或 /bin/ping
  // 注意:部分系统可能限制普通应用执行 ping
  try {
    await shell.run('ping -c 3 www.baidu.com');
  } catch (e) {
    print('Ping 失败: $e');
  }
}

在这里插入图片描述

三、进阶场景与示例

3.1 示例一:获取系统属性 (getprop)

OpenHarmony 基于 Linux 内核,依然保留了大量 Unix 工具。例如 getprop 可以获取系统属性(如果权限允许)。

import 'package:process_run/shell.dart';

Future<String> getSystemProperty(String key) async {
  var result = await Shell().run('getprop $key');
  // result 是一个 List<ProcessResult>,因为 run 可能一次执行多条
  return result.first.stdout.toString().trim();
}

// 调用
// var version = await getSystemProperty('ro.build.version.release');

在这里插入图片描述

3.2 示例二:文件系统操作 (ls, mkdir)

虽然 Dart 有 Directory 类,但有时用 Shell 更快,比如递归删除。
注意:只能操作应用沙箱内的文件。

import 'package:process_run/shell.dart';
import 'package:path_provider/path_provider.dart';

Future<void> listAppFiles() async {
  final dir = await getApplicationDocumentsDirectory();
  var shell = Shell(workingDirectory: dir.path);
  
  // 执行 ls -R (递归列出)
  await shell.run('ls -R');
}

在这里插入图片描述

3.3 示例三:执行自定义脚本

如果你的 App 携带了可执行脚本(需放置在 native lib 目录并赋予 x 权限),可以通过完整路径调用。

// 假设脚本路径
var scriptPath = '${appDir.path}/libs/libmyscript.so'; // 假装是 so,其实是 script
// await Shell().run('chmod +x $scriptPath');
// await Shell().run(scriptPath);

在这里插入图片描述

四、OpenHarmony 平台适配

4.1 权限限制

OpenHarmony 对应用权限管理非常严格。普通应用无法执行绝大多数系统管理命令(如 reboot, ifconfig 等)。即便是 ping,在某些版本上也可能被 SELinux 拦截。

4.2 路径问题

系统命令通常在 /system/bin/bin 下,process_run 会自动在 PATH 环境变量中查找。如果找不到,尝试指定绝对路径。

五、完整实战示例:系统信息查看器

本示例尝试执行多个系统命令,展示当前环境的基本信息。

5.1 示例代码

import 'package:flutter/material.dart';
import 'package:process_run/shell.dart';

void main() {
  runApp(const MaterialApp(home: CommandRunnerPage()));
}

class CommandRunnerPage extends StatefulWidget {
  const CommandRunnerPage({super.key});

  
  State<CommandRunnerPage> createState() => _CommandRunnerPageState();
}

class _CommandRunnerPageState extends State<CommandRunnerPage> {
  final TextEditingController _controller = TextEditingController(text: 'uname -a');
  String _output = '准备就绪';
  bool _running = false;

  Future<void> _runCommand() async {
    if (_controller.text.isEmpty) return;
    
    setState(() {
      _running = true;
      _output = '正在执行: ${_controller.text}...\n';
    });

    try {
      var shell = Shell(
        verbose: false, // 不要在控制台输出太多
        commandVerbose: true,
      );
      
      // 注意:run 返回的是 List<ProcessResult>
      var results = await shell.run(_controller.text);
      
      var outBuffer = StringBuffer();
      for (var result in results) {
        if (result.stdout.toString().isNotEmpty) {
          outBuffer.writeln('[STDOUT]\n${result.stdout}');
        }
        if (result.stderr.toString().isNotEmpty) {
          outBuffer.writeln('[STDERR]\n${result.stderr}');
        }
        outBuffer.writeln('(Exit Code: ${result.exitCode})');
      }
      
      setState(() => _output = outBuffer.toString());
    } catch (e) {
      setState(() => _output = '执行错误: $e');
    } finally {
      setState(() => _running = false);
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('系统命令执行器')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _controller,
              decoration: const InputDecoration(
                labelText: '输入命令 (如 ls, uname -a, date)',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: _running ? null : _runCommand,
              child: _running 
                  ? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator())
                  : const Text('执行'),
            ),
            const SizedBox(height: 20),
            Expanded(
              child: Container(
                width: double.infinity,
                padding: const EdgeInsets.all(8),
                decoration: BoxDecoration(
                  color: Colors.black87,
                  borderRadius: BorderRadius.circular(4),
                ),
                child: SingleChildScrollView(
                  child: Text(
                    _output,
                    style: const TextStyle(color: Colors.greenAccent, fontFamily: 'monospace'),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

在这里插入图片描述

六、总结

process_run 在 Flutter for OpenHarmony 中主要用于调试、测试以及调用有限的底层工具。

最佳实践

  1. 不要依赖特定的命令:不同设备厂商裁剪的系统工具可能不同(如有的没 curl)。
  2. 异步处理:命令执行是阻塞的,务必使用 await 并处理超时。
  3. 安全风险:严禁直接执行用户输入的命令,极易导致注入攻击(rm -rf /)。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐