Flutter windows 使用指定浏览器打开指定网址

1,030 阅读2分钟

Flutter windows 使用指定浏览器打开指定网址。

以 打开Chrome为例 :我们需要三步走

1、找到注册表的应用程序安装路径。

参考文献:zhidao.baidu.com/question/73…

第一次尝试使用的注册表地址是

Software\Microsoft\Windows\CurrentVersion\Uninstall\Google Chrome

发现部分电脑装了chrome 但是在这个路径下面没有找到 chrome的安装路径

最终使用的是

Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache

研究表明,此路径下的大部分电脑都是可以找到相应的应用程序安装路径。

2、使用win32第三方库、从注册表获取Chrome安装路径。

win32这个库、就是给Flutter调用windows API 使用的。 自行 pub.dev 查看。

添加依赖之后、可以创建一个dart文件, 专门用于获取注册表信息。 例如我的...

import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:win32/win32.dart';

// 注册表应用程序安装路径
const regChromeKey =
    r'Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache';

const MAX_ITEMLENGTH = 1024;

class RegistryKeyValuePair {
  final String key;
  final String value;

  const RegistryKeyValuePair(this.key, this.value);
}

int getRegistryKeyHandle(int hive, String key) {
  final phKey = calloc<HANDLE>();
  final lpKeyPath = key.toNativeUtf16();

  try {
    if (RegOpenKeyEx(hive, lpKeyPath, 0, KEY_READ, phKey) != ERROR_SUCCESS) {
      throw Exception("Can't open registry key");
    }

    return phKey.value;
  } finally {
    free(phKey);
    free(lpKeyPath);
  }
}

RegistryKeyValuePair? enumerateKey(int hKey, int index) {
  final lpValueName = wsalloc(MAX_PATH);
  final lpcchValueName = calloc<DWORD>()..value = MAX_PATH;
  final lpType = calloc<DWORD>();
  final lpData = calloc<BYTE>(MAX_ITEMLENGTH);
  final lpcbData = calloc<DWORD>()..value = MAX_ITEMLENGTH;

  try {
    final status = RegEnumValue(hKey, index, lpValueName, lpcchValueName,
        nullptr, lpType, lpData, lpcbData);

    switch (status) {
      case ERROR_SUCCESS:
        if (lpType.value != REG_SZ) throw Exception('Non-string content.');
        return RegistryKeyValuePair(
            lpValueName.toDartString(), lpData.cast<Utf16>().toDartString());

      case ERROR_MORE_DATA:
        throw Exception('An item required more than $MAX_ITEMLENGTH bytes.');

      case ERROR_NO_MORE_ITEMS:
        return null;

      default:
        throw Exception('unknown error');
    }
  } finally {
    free(lpValueName);
    free(lpcchValueName);
    free(lpType);
    free(lpData);
    free(lpcbData);
  }
}

调用

  // 获取 chrome 安装路径
  static String getChromePath() {
    String chromePath = "";
    var hKey;
    var dwIndex = 1;
    RegistryKeyValuePair? item;

    try {
      hKey = getRegistryKeyHandle(HKEY_CURRENT_USER, regChromeKey);
      item = enumerateKey(hKey, dwIndex);
    } catch (e) {
      return "";
    }

    while (item != null) {
      if (item.key.isNotEmpty && item.key.contains("chrome.exe")) {
        chromePath = item.key;
        break;
      }
      dwIndex++;
      try {
        item = enumerateKey(hKey, dwIndex);
      } catch (e) {
        return "";
      }
    }
    return chromePath;
  }

结束、调用方法即可获取 chrome 安装路径

3、使用C++调用 cmd 打开chrome 并打开指定网址

Flutter 吗。大家都知道的写windows,很多API还是要考C++来完成。

拿到chrome 安装路径之后, 就是帮路径传给 C++ 然后执行cmd

前提:大家可以提前试一下哈。 在你们的 cmd 中输入如下命令 是可以打开指定浏览器并访问指定网址的。

start chromePath www.baidu.com

chromePath 是你的chrome安装路径哈,不要整句复制过去了。


言归正传。 调用 C++ 打开指定网址。

C++和Flutter交互代码都在 flutter_windows.cpp 中。这个就不多介绍了。 具体代码如下

if (methodName.compare("openUrl") == 0) {
    const flutter::EncodableValue* args = call.arguments();
    const flutter::EncodableList arg_list = std::get<flutter::EncodableList>(*args);
    std::string path = std::get<std::string>(arg_list[0]);
    std::string path2 = "start " + path;
    system(path2.c_str());
    result->Success();
}

Flutter 代码如下

我这里采用的方案是,优先使用chrome打开网址,如果打不开。会使用 url_launcher 打开默认浏览器并访问网址。 (url_launcher 也是一个flutter第三方库哈,需要的话可以pub.dev看看)

import 'package:url_launcher/url_launcher.dart';
import 'package:win32/win32.dart';
import 'package:wxwork_helper/main.dart';
import 'package:wxwork_helper/wuneng/CommonUtils/JCRegistry.dart';

class JCLaunch {
  // 1、获取chrome安装路径
  // 2、调用C++执行 cmd  start path baidu.com
  static openUrl(String urlString) {
    String chromePath = getChromePath();

    if (chromePath.isNotEmpty) {
      print("user have install chrome : " + chromePath);
      List pathList = chromePath.split("chrome.exe");
      if (pathList.isNotEmpty) {
        chromePath = pathList[0].toString() + "chrome.exe";
        mainMethodChannel
            .invokeMethod("openUrl", [chromePath + " " + urlString]);
      }
    } else {
      print("user have not install chrome");
      launch(urlString);
    }
  }
}