chrome打开本地链接

同事之前给我提了一个需求,想实现在网页里点击链接地址后直接打开指定的地址(路径是内网共享的目录,file://share.xx.com\x\x)。


浏览器因为有安全的限制,是无法访问 web 页面时,可以打开本地PC的目录。当你点击带有本地文件链接的超链接(file://),控制台上会报错:Not allowed to load local resource:


最开始在网上搜索了一下,有二个插件看上去似乎可以满足需求。

(1)Enable local file links

(2)Local Explore – File Manager on web browser


image

插件启用后,类似下面这种效果(跟他们想要的效果还是有区别)。

image


Local Explore,自定义了协议,然后呼起本地 exe,再打开资源管理器,是期望的效果。但是它最大的问题是:如果路径有中文,就乱码,无法正常使用。


它的原理倒是比较简单,修改超链接为 LocalExplore:file://xxxx,如果注册表添加了对该协议的监听,当浏览器访问该协议时,会触发指定的 exe 并传入相关的参数。


我要解决乱码问题,先处理浏览器扩展插件,再就是替换 exe 的实现就可以了。

image


(1)替换插件,解决因插件 escape 导致的乱码问题(注:不太能理解作者为啥要用 JSON.parse 处理一下)

对比了二个插件的实现,我准备在 Local Explore 插件的基础上进行精简。只留下必要的代码,然后通过开发者模式,加载进 chrome 的扩展程序里。

image

background.js 里的代码被我删光了,content.js 只进行一个操作,遍历文档所有超链接,然后修改其 href 属性。

$(document).ready(function() {
    var optOpenFolders = "true";
    var protocolStr = "LocalExplorer:";

    // var clickEventHandler = function(evt) {
    //     evt.preventDefault();

    //     chrome.extension.sendMessage({
    //         cmd: "click",
    //         data: this.href
    //     });
    // };

    $("a").each(function(i, e) {
        if (e.href !== undefined && e.href !== null && e.href !== "") {
            if (!e.href.match(/^file:\/\//)) {
                return;
            }

            if (e.href.match(/^file:\/\//)) {
                if (window.debug) console.log(e.href);

                e.href = protocolStr + e.href;
                if (e.target) e.target = "_self";
            }
            // $(e).off("click", clickEventHandler);
            // $(e).on("click", clickEventHandler);
        }
    });
});


manifest.json 也做了一点修改

{
    "update_url": "https://clients2.google.com/service/update2/crx",
    "version": "2021.7.6",
    "short_name": "Meteoric Local Explorer",
    "name": "Meteoric Local Explorer - File Manager on web browser",
    "description": "__MSG_extDescription__",
    "default_locale": "zh_CN",
    "icons": {
        "128": "icon/icon128.png",
        "32": "icon/icon32.png",
        "16": "icon/icon16.png"
    },
    "browser_action": {
        "default_icon": "icon/icon32.png",
        "default_title": "Meteoric Local Explorer"
    },
    "content_scripts": [{
        "matches": ["<all_urls>"],
        "js": ["jquery.js", "content.js"],
        "all_frames": false,
        "run_at": "document_start"
    }],
    "background": {
        "scripts": ["background.js"]
    },
    "options_page": "", // options.html
    "permissions": [
        "http://*/*",
        "https://*/*",
        "tabs"
    ],
    "manifest_version": 2
}


(2)替换 exe,支持打开中文链接

这里我直接用 C# 简单写了一个 exe,实现了基本的功能。为了精简 Release 版本生成的内容,我对几处设置作了简单的调整

(1)项目属性里面的,生成 –> 高级 –> 高级生成设置,输出 –> 调试信息,选择无,避免生成 pdb 文件;

(2)App.config 的文件属性,修改‘生成操作’为‘嵌入的资源’,避免生成  *.exe.config 文件;


这样生成的 Release 目录就是比较干净的了,只有一个叫 LocalExplorer.exe 的文件。替换掉安装在 C 盘里面的 exe(默认路径在:"C:\Program Files (x86)\LocalExplorer\LocalExplorer.exe" )

using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace FriendTimesLocalExplorer { class Program { static void Main(string[] args) { /* for (int i = 0, len = args.Length; i < len; i++) { // Get first param } */ if (args.Length < 1) { MessageBox.Show("File Path is Empty", "System Tips", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } string filePath = args[0]; // escape filePath = Uri.UnescapeDataString(filePath).Replace("/", "\\"); // delete protocol filePath = filePath.Replace("localexplorer:", ""); filePath = filePath.Replace("file:", "");

// get right file path filePath = filePath.Substring(filePath.IndexOf('\\')); //Console.WriteLine(filePath); if (Directory.Exists(filePath) || File.Exists(filePath)) { Process p = new Process(); p.StartInfo.FileName = "explorer.exe"; p.StartInfo.CreateNoWindow = true; p.StartInfo.UseShellExecute = false; // hidden p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; p.EnableRaisingEvents = true; p.StartInfo.RedirectStandardError = true; if (File.Exists(filePath)) { p.StartInfo.Arguments = @"/select," + filePath; } else { p.StartInfo.Arguments = filePath; } try { p.Start(); // explorer.exe 异常结束时,会导致启动不断重启 p.WaitForExit(); if (p != null) { p.Close(); p.Dispose(); p = null; } } catch (Exception e) { MessageBox.Show(e.ToString(), "System error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else { MessageBox.Show("Not Found Path : \n" + filePath, "System error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } }


浏览器插件 和 exe 都进行替换后,就能实现点击链接调用本地exe,再通过 exe 打开指定的目录了。迅雷、QQ或其它客户端软件,基本上也是使用类似的原理,实现点击网页链接呼起本地的客户端应用程序(应用程序想干嘛就自己实现)


注意点击时,会弹出一个提示。

image

posted @ 2021-07-06 20:54  meteoric_cry  阅读(1234)  评论(1编辑  收藏  举报