10

次の条件を満たすChromeタブの一意のIDを確立する方法を確認しようとしています:

  • 各タブを一意に識別
  • 特定のタブについて、ブラウザーの再起動後も同じ状態を維持します (セッション復元されたタブ)
  • タブを閉じてから、[閉じたタブを元に戻す] (Ctrl+Shift+T) で再度開いた場合も同じままです。
  • タブが重複しても区別されたまま

包括的な解決策を見つけるためにかなり積極的な調査を行いましたが、うまくいくものは何もないようです。私が試した方法を、有効性の高い順に示します。

  • Chrome が提供する tab.id を使用:ブラウザ セッション間または閉じる/元に戻す間は保持されません
  • GUID を Cookie に入れる:タブごとに一意ではなく、ドメイン/URL ごとにのみ一意です
  • GUID を localStorage に配置:ブラウザー セッションと閉じる/元に戻す間で保持されますが、タブごとに一意ではなく、ドメインごとにのみ一意です
  • GUID を sessionStorage に入れます:タブごとに一意であり、閉じる/元に戻しても保持され、複製されたタブでは一意ですが、ブラウザ セッション間で消去されます
  • 識別可能な Web ページのドキュメント属性を一意のキーとして使用します。これは、私がこれまでに見つけた最良のアプローチです。キーは、次の値からコンテンツ スクリプトを介して構築できます[location.href, document.referrer, history.length]

この最後のアプローチに関して、構築されたキーは、共通の URL、リファラー、および履歴の長さを共有するすべてのタブで一意です。これらの値は、ブラウザーの再起動/セッションの復元と閉じる/元に戻す間で、特定のタブに対して同じままです。このキーは「非常に」ユニークですが、あいまいな場合があります。たとえば、http://www.google.comに対して開かれた 3 つの新しいタブはすべて共通の同じキーを持っています (この種のことはかなり起こります) 。多くの場合、実際に)。

さらに、「GUID を sessionStorage に入れる」メソッドを使用して、現在のブラウザー セッション中に閉じる/元に戻す、および重複したタブの場合に、同じ構築キーを持つ複数のタブ間のあいまいさを解消することができます。しかし、これはブラウザーの再起動間のあいまいさの問題を解決しません。

この最後のあいまいさは、セッションの復元中に、Chrome がどのウィンドウでどのタブを一緒に開くかを観察し、予想される「兄弟」タブの存在に基づいて、どのタブがどのウィンドウに属しているかを特定のあいまいなキーを推定することによって部分的に軽減できます (以前のブラウザーで記録されたセッション)。ご想像のとおり、このソリューションの実装は非常に複雑でやや危険です。また、Chrome が別のウィンドウに復元する同じキーのタブ間でのみあいまいさを解消できます。これにより、同じウィンドウに復元される同じキーのタブが、相容れないほどあいまいになります。

より良い方法はありますか?ブラウザーの再起動 (セッションの復元) と閉じる/元に戻す間で保持される、ブラウザーによって生成された、保証された一意のタブごとの GUID が理想的ですが、これまでのところ、このようなものは見つかりませんでした。

4

3 に答える 3

4

ここでの質問は発見作業のほとんどを行い、受け入れられた回答は基本的にそれを完了しますが、永続的なタブ ID を必要とする何かを実装しようとしている人々にとっては、まだ大きな実装ギャップがあります。これを実際の実装に抽出しようとしました。

要約すると、次の変数の組み合わせをローカルの永続ストレージに格納するタブのレジスタを維持することにより、質問で必要とされるように、タブを (ほぼ) 一意かつ一貫して識別することができます。

  • Tab.id
  • Tab.index
  • タブで開いている文書の「指紋」 -[location.href, document.referrer, history.length]

これらの変数は、次のイベントの組み合わせでリスナーを使用して追跡し、レジストリに保存できます。

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

この方法をだます方法はまだありますが、実際にはおそらくかなりまれで、ほとんどがエッジ ケースです。

この問題を解決する必要があるのは私だけではないように思われるので、どの Chrome 拡張機能でも使用できるように、実装をライブラリとして作成しました。これは MIT でライセンスされており、フォークやプル リクエストのために GitHub で利用できます (実際、どんなフィードバックも歓迎します - 間違いなく改善の可能性があります)。

于 2013-01-25T09:23:45.727 に答える
1

私があなたの問題を正しく理解していれば、あなたの5番目の方法でうまくいくはずですが、次の2つの基準があります。

  • chrome.tabs.windowId(タブが含まれているウィンドウのID)
  • chrome.tabs.index(ウィンドウ内のタブのゼロベースのインデックス)

これらの値はすべて、拡張機能内に保存する必要があります。chrome.tabs.onUpdated()さらに、タブがドラッグされたり、所有者のウィンドウ間を移動したりする場合などに、拡張機能を接続してそれに応じて更新する必要があります。

于 2012-06-15T06:25:54.297 に答える
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 が一意でなくても、「十分に近い」インデックスの下にあると信頼できます。たとえば、タブが見つからない場合のリバースチェックなど、もっと複雑にしますが、これは今のところ問題なく機能します。

于 2017-02-10T17:53:50.917 に答える