zoukankan      html  css  js  c++  java
  • Chrome 消息传递机制

    Chrome插件开发入门(二)——消息传递机制

    Blog | Qiushi Chen 2014-03-31 9538 阅读

    由于插件的js运行环境有区别,所以消息传递机制是一个重要内容。阅读了很多博文,大家已经说得很清楚了,直接转一篇@姬小光 的博文,总结的挺好。后面附一个自己写过的demo,基本就对消息传递能够熟悉了。

    在开发 Chrome 扩展时经常需要在页面之间进行通讯,比如 background 与 content script 之间,background 与 popup 之间等等,本文结合官方文档中的例子介绍了 chrome 扩展开发中消息传递的基本实现。

    一般情况下,我们会让 background 来控制一切,将扩展的主要逻辑都放在 background 中比较便于管理。其它页面可以通过消息传递的机制与 background 进行通讯。

    理论上 content script 与 popup 之间也可以传递消息,但不建议这么做。

    对于 background 和 popup 之间,其实可以直接相互调用对方的方法,也不需要消息传递。那么消息传递其实主要就是 content script 和 background 之间进行的了。

    在 Chrome 扩展内部的消息传递分为两种,一种是单次的消息请求,另外一种是长连接。下面详细举例说明。

    简单的单次请求(Simple one-time requests)

    如果只是想简单的给扩展的其它页面发送一次消息,那么可以使用 runtime.sendMessage 或者 tabs.sendMessage 方法,它允许你发送单次的JSON序列化后的数据,可以从 content script 发送给扩展页面,反之亦然。也可以选择性地传入一个处理响应的回调函数。

    从 content script 发送请求代码如下:

    contentscript.js
    ================
    chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
        console.log(response.farewell);
    });

    从扩展页面发送给 content script 也很类似,只是需要指定发送给那个 tab,下面的例子即为向选中的 tab 发送消息:

    background.html
    ===============
    chrome.tabs.getSelected(null, function(tab) {
        chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
            console.log(response.farewell);
        });
    });

    注:官方例子中的 getSelected 方法已经被废弃了,可以使用 chrome.tabs.query({active:true}, function(tab) {}) 来替代。

    在消息接收完毕时,需要设置一个  runtime.onMessage 事件监听器来处理消息,这部分在 content script 和扩展页面种都是一样的:

    chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
            console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
            if (request.greeting == "hello")
                sendResponse({farewell: "goodbye"});
    });

    注意:如果有多个页面同时监听 onMessage 事件,那么只有第一个调用 sendResponse() 的页面可以成功返回响应信息,其它的都会被忽略。

    小技巧:当事件监听器返回时函数就不可用了,不过如果让函数 return: true 的话,可以让该函数异步响应,直到调用 sendResponse 后才结束,具体说明请见文档

    长连接(Long-lived connections)

    有时候我们需要在 content script 和扩展页面之间保持一个长期的通讯信道,那么你可以分别使用 runtime.connect 和 tabs.connect 来建立长连接信道。可以选择性地给信道命名,方便你区分不同类型的连接。

    每个连接建立完成后都会返回一个 runtime.Port 对象,用来在连接之间发送和接收消息。

    下面的例子展示了如何从 content script 建立连接,并发送和接收消息:

    contentscript.js
    ================
    var port = chrome.runtime.connect({name: "knockknock"});
    port.postMessage({joke: "Knock knock"});
    port.onMessage.addListener(function(msg) {
        if (msg.question == "Who's there?")
            port.postMessage({answer: "Madame"});
        else if (msg.question == "Madame who?")
            port.postMessage({answer: "Madame... Bovary"});
    });

    从扩展页面建立连接也很类似,只是要指定要连接到哪个tab。最简单地可以把上面的连接的代码改成 tabs.connect 即可。

    为了能够处理连接请求,需要设置一个  runtime.onConnect 事件监听器,在 content script 和扩展页面中中都是一样的。当扩展的某一部分调用了 “connect() ”,该事件即被触发,然后就可以使用 runtime.Port 对象来发送和接收消息了。响应连接的代码大致如下所示:

    chrome.runtime.onConnect.addListener(function(port) {
        console.assert(port.name == "knockknock");
        port.onMessage.addListener(function(msg) {
            if (msg.joke == "Knock knock")
                port.postMessage({question: "Who's there?"});
            else if (msg.answer == "Madame")
                port.postMessage({question: "Madame who?"});
            else if (msg.answer == "Madame... Bovary")
                port.postMessage({question: "I don't get it."});
        });
    });

    或许有时你还想知道连接何时关闭,那么你可以监听 runtime.Port.onDisconnect 事件,当通讯的任意一端调用  runtime.Port.disconnect,或者包含该端口的页面已被卸载。onDisconnect 事件可以保证在每个端口上只触发一次。

    另外,消息传递还包括不同扩展之间的消息传递,还有 Chrome 与本地程序之间的消息传递,这里就不介绍了,感兴趣的同学可以直接查看官方文档

    —————————————–分割线——————————————-

    demo:

    几个最基本的文件

    在这里,先假设大家对chrome插件开发的最基本知识已有所掌握。例如什么是manifest.json,什么是background.html等。

    manifest.json

    {
          "name": "A browser action with a popup that changes the page color.",
          "version": "1.0",
          "permissions":["tabs","<all_urls>"],
          "browser_action": {
            "default_icon": "icon.png"
          },
          "background": {
            "page": "background.html"
          },
          "content_scripts": [
            {
              "matches": ["<all_urls>"],
              "js" : ["jquery-1.7.1.js","injectscript.js"]
            }
          ],
          "manifest_version": 2
        }

    background.html

    <!DOCTYPE html>
        <html>
            <head>
                <title>bg</title>
                <script type="text/javascript" src="http://blog.chenqiushi.com/2014/03/31/chrome%e6%8f%92%e4%bb%b6%e5%bc%80%e5%8f%91%e5%85%a5%e9%97%a8%ef%bc%88%e4%ba%8c%ef%bc%89-%e6%b6%88%e6%81%af%e4%bc%a0%e9%80%92%e6%9c%ba%e5%88%b6/bg.js"><script>
            </head>
            <body>
                hello
            <body>
        </html>

    这里引用了一个后台处理程序,bg.js,后面会讲到。

    扩展程序发送请求数据到内容脚本,内容脚本给出回应

    扩展程序后台脚本bg.js

    (function(){
            chrome.browserAction.onClicked.addListener(function(tab) {
                // 扩展向内容脚本发送消息
                chrome.tabs.sendMessage(tab.id,{
                    greeting: "hello to content script!"
                }, function(response) {
                    console.log(response.farewell);
                });
            });
        })();

    内容脚本injectscript.js

    (function(){
            console.log("injected");
    
            var resOK = {
                farewell: "content script send response back..."
            };
    
            var resError = {
                farewell: "content script hasError!"
            };
    
            chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
                console.log("Request comes from extention " + sender.tab.url);
    
                if (request.greeting === "hello to content script!"){
                    sendResponse(resOK);
                }else{
                    sendResponse(resError);
                }
            });
        })();

    扩展程序向内容脚本发送一条消息hello to content script!,内容脚本接收到这条消息后去判断是不是那句话,如果是,就返回resOK对象,如果不是,就返回resError对象。

    这时,扩展程序收到内容脚本的一条回应,至此,此番通话就结束了。

    看一下结果截图

    扩展程序到内容脚本

    内容脚本发送请求数据到扩展程序,扩展程序给出回应

    扩展程序后台脚本bg.js

    (function(){
    
            var resOK = {
                farewell: "extension send response back..."
            };
    
            var resError = {
                farewell: "extension hasError!"
            };
    
            chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
                console.log("Request comes from content script " + sender.tab.url);
    
                if (request.greeting === "hello to extention!"){
                    sendResponse(resOK);
                }else{
                    sendResponse(resError);
                }
            });
    
        })();

    内容脚本injectscript.js

    (function(){
            console.log("injected");
    
            chrome.extension.sendMessage({greeting: "hello to extention!"}, function(response) {
                console.log(response.farewell);
            });
        })();

    内容脚本向扩展程序发送一条消息hello to extention!,扩展程序接收到这条消息后去判断是不是那句话,如果是,就返回resOK对象,如果不是,就返回resError对象。

    这时,内容脚本收到扩展程序的一条回应,至此,此番通话就结束了。

    特别应该注意的是:扩展程序向内容脚本发送请求数据时用的是chrome.tabs.sendMessage,反过来,用的是chrome.extension.sendMessage

    看一下结果截图

    内容脚本到扩展程序

    如果以后还有一些chrome插件的学习总结,还会写在这里。

    demo地址:
    点击下载demo

    The post Chrome插件开发入门(二)——消息传递机制 appeared first on Blog | Qiushi Chen.

  • 相关阅读:
    Atitit (Sketch Filter)素描滤镜的实现  图像处理  attilax总结v2
    JS设置cookie、读取cookie、删除cookie
    Atitit 图像处理30大经典算法attilax总结
    Atitit数据库层次架构表与知识点 attilax 总结
    Atitit 游戏的通常流程 attilax 总结 基于cocos2d api
    Atitti css transition Animation differ区别
    Atitit 图像清晰度 模糊度 检测 识别 评价算法 源码实现attilax总结
    Atitit 全屏模式的cs桌面客户端软件gui h5解决方案 Kiosk模式
    Atitit 混合叠加俩张图片的处理 图像处理解决方案 javafx blend
    Atitit  rgb yuv  hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别
  • 原文地址:https://www.cnblogs.com/developer-ios/p/5925680.html
Copyright © 2011-2022 走看看