Chrome浏览器会话之间的持久唯一ID

时间:2012-06-12 21:38:20

标签: javascript google-chrome google-chrome-extension guid

我正在尝试确定某些方法来为Chrome标签创建符合以下条件的唯一ID:

  • 唯一标识每个标签
  • 在浏览器重新启动(会话恢复选项卡)之间为给定选项卡保持相同
  • 如果选项卡已关闭,然后使用“撤消已关闭”选项卡(Ctrl + Shift + T)重新打开,则保持相同
  • 如果选项卡重复,则保持不同

我已经做了一些相当激进的研究来找到一个全面的解决方案,但似乎没有什么可以做到的。以下是我尝试的方法,以提高效力的顺序:

  • 使用Chrome提供的标签。<:strong>在浏览器会话之间不存在或关闭/撤消关闭
  • 在Cookie中添加GUID:每个标签不是唯一的,只有每个域/网址
  • 在localStorage中放置一个GUID:在浏览器会话和关闭/撤消关闭之间保持不变,但每个标签不是唯一的,只有每个域
  • 在每个标签的sessionStorage中放置一个GUID:唯一,在关闭/撤消关闭时保持不变,对于重复的标签是唯一的,但在浏览器会话之间被清除
  • 使用可识别的网页文档属性作为唯一键:这是我迄今为止发现的最佳方法。可以通过以下值的内容脚本构建密钥:[location.href, document.referrer, history.length]

关于最后一种方法,构建的密钥在共享公共URL,引用者和历史记录长度的所有选项卡中是唯一的。对于浏览器重新启动/会话恢复和关闭/撤消关闭之间的给定选项卡,这些值将保持不变。虽然这个键“非常”独特,但有些情况下它是不明确的:例如,向http://www.google.com打开的3个新选项卡都将具有相同的共同键(这种事情在实践中经常发生)

“在sessionStorage中放置GUID”方法还可以用于在当前浏览器会话期间使用相同的构造密钥来区分关闭/撤消关闭和重复选项卡案例的多个选项卡之间的歧义。但这并不能解决浏览器重启之间的模糊问题。

在会话恢复期间,通过观察Chrome在哪些窗口中打开哪些标签,以及根据预期的“同级”标签的存在(在记录期间记录)为一个标签属于哪个窗口的给定模糊键进行外推,可以在会话恢复期间部分缓解这种最后的歧义。以前的浏览器会话)。正如您可能想象的那样,实施此解决方案非常复杂且相当狡猾。并且它只能消除Chrome恢复到不同窗口的相同键控选项卡之间的歧义。这会留下同样关键的标签,这些标签可以恢复到同一个窗口,并且不可调整地模糊不清。

有更好的方法吗?浏览器重新启动(会话恢复)和关闭/撤消关闭之间保持唯一的浏览器生成的每个标签GUID是理想的,但到目前为止我还没有找到这样的。

3 个答案:

答案 0 :(得分:3)

这里的问题完成了大部分的发现工作,并且接受的答案基本上完成了它,但是对于那些希望实现需要持久标签ID的人来说仍然存在很大的实现差距。我试图将其提炼成实际的实现。

回顾一下:通过维护一个选项卡寄存器,可以(几乎)唯一且一致地标识选项卡,这些选项卡在本地持久存储中存储以下变量组合:

  • Tab.id
  • Tab.index
  • 在标签中打开文档的“指纹” - [location.href, document.referrer, history.length]

可以使用以下事件组合的侦听器跟踪这些变量并将其存储在注册表中:

  • onUpdated
  • onCreated
  • onMoved
  • onDetached
  • onAttached
  • onRemoved
  • onReplaced

仍有办法愚弄这种方法,但在实践中它们可能非常罕见 - 主要是边缘情况。

由于看起来我不是唯一需要解决此问题的人,因此我将我的实现构建为库,目的是可以在任何Chrome扩展程序中使用它。这是MIT许可和available on GitHub分叉请求(事实上,任何反馈都是受欢迎的 - 肯定有可能改进)。

答案 1 :(得分:1)

如果我正确理解你的问题,那么你的第五种方法应该可以解决这个问题,但是还有以下两个标准:

  • chrome.tabs.windowId(标签所包含的窗口的ID)
  • chrome.tabs.index(窗口中标签的从零开始的索引)

所有这些值都需要存储在您的扩展程序中。除此之外,您还必须将您的扩展程序连接到chrome.tabs.onUpdated(),并相应地更新,当拖动标签,在所有者窗口之间移动等时。

答案 2 :(得分:1)

将它作为manifest.json中的持久后台脚本:

"background": {
        "scripts": [ "background.js" ],
        "persistent": true
},

这是background.js。 希望代码是自我解释的。

var tabs_hashes = {};
var tabs_hashes_save_queued = false;

function Start(){
    chrome.tabs.query({windowType: "normal"}, function(querytabs){
        querytabs.forEach(function(tab){
            tabs_hashes[tab.id] = GetHash(tab.url);
        });

        if (localStorage.getItem("tabs_hashes") !== null){

            var ref_load = JSON.parse(localStorage["tabs_hashes"]);
            var ref_tabId = {};


            querytabs.forEach(function(tab){
                for (var t = 0; t < ref_load.length; t++){
                    if (ref_load[t][1] === tabs_hashes[tab.id]){
                        ref_tabId[ref_load[t][0]] = tab.id;
                        ref_load.splice(t, 1);
                        break;
                    }
                }
            });

            // do what you have to do to convert previous tabId to the new one
            // just use ref_tabId[your_previous_tabId] to get the current corresponding new tabId
            console.log(ref_tabId);

        }
    });
}


function SaveHashes(){
    if (!tabs_hashes_save_queued && Object.keys(tabs_hashes).length > 0){
        tabs_hashes_save_queued = true;
        chrome.tabs.query({windowType: "normal"}, function(querytabs){
            var data = [];
            querytabs.forEach(function(tab){
                if (tabs_hashes[tab.id]){
                    data.push([tab.id, tabs_hashes[tab.id]]);
                } else {
                    data.push([tab.id, GetHash(tab.url)]);
                }
            });
            localStorage["tabs_hashes"] = JSON.stringify(data);
            setTimeout(function(){ tabs_hashes_save_queued = false; }, 1000);
        });
    }
}

function GetHash(s){
    var hash = 0;
    if (s.length === 0){
        return 0;
    }
    for (var i = 0; i < s.length; i++){
        hash = (hash << 5)-hash;
        hash = hash+s.charCodeAt(i);
        hash |= 0;
    }
    return Math.abs(hash);
}


chrome.tabs.onCreated.addListener(function(tab){
    SaveHashes();
});
chrome.tabs.onAttached.addListener(function(tabId){
    SaveHashes();
});
chrome.tabs.onRemoved.addListener(function(tabId){
    delete tabs_hashes[tabId];
    SaveHashes();
});
chrome.tabs.onDetached.addListener(function(tabId){
    SaveHashes();
});
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo){
    if (changeInfo.pinned != undefined || changeInfo.url != undefined){
        delete tabs_hashes[tabId];
        SaveHashes();
    }
});
chrome.tabs.onMoved.addListener(function(tabId){
    SaveHashes();
});
chrome.tabs.onReplaced.addListener(function(addedTabId, removedTabId){
    delete tabs_hashes[removedTabId];
    SaveHashes();
});


Start();

我使用数组来保存数据,因为这样我可以保留标签顺序,如果数据保存在对象中,这是不太可能的。在浏览器重启后加载数据时,即使url不是唯一的,我也相信它会在一些“足够接近”的索引下。我会做的更复杂,例如反向检查是否找不到制表符,但到目前为止这个工作正常。