ID único persistente para las pestañas de Chrome que dura entre sesiones del navegador

Estoy tratando de determinar alguna forma de establecer una identificación única para las pestañas de Chrome que cumpla con las siguientes condiciones:

  • Identifica de forma única cada pestaña
  • Permanece igual para una pestaña dada entre reinicios del navegador (pestañas restauradas por sesión)
  • Permanece igual si se cierra una pestaña y luego se vuelve a abrir con Deshacer pestaña cerrada (Ctrl+Shift+T)
  • Permanece distinto si una pestaña está duplicada

He realizado una investigación bastante agresiva para encontrar una solución completa, pero nada parece funcionar. Estos son los métodos que he probado, en orden creciente de eficacia:

  • Utilice el tab.id proporcionado por Chrome: no persiste entre sesiones del navegador o cerrar/deshacer-cerrar
  • Poner un GUID en cookies: no es único por pestaña, solo por dominio/URL
  • Ponga un GUID en localStorage: persiste entre las sesiones del navegador y cerrar/deshacer-cerrar, pero no es único por pestaña, solo por dominio
  • Ponga un GUID en sessionStorage: único por pestaña, persiste al cerrar/deshacer-cerrar, único para pestañas duplicadas, pero se elimina entre sesiones del navegador
  • Use atributos de documentos de páginas web identificables como una clave única: este es el mejor enfoque que he encontrado hasta ahora. Se puede construir una clave a través de un script de contenido a partir de los siguientes valores: [location.href, document.referrer, history.length].

Con respecto a este último enfoque, la clave construida es única en todas las pestañas que comparten una URL, una referencia y una longitud de historial comunes. Esos valores seguirán siendo los mismos para una pestaña determinada entre reinicios del navegador/restauraciones de sesión y cierre/deshacer-cierre. Si bien esta clave es "bastante" única, hay casos en los que es ambigua: por ejemplo, se abrieron 3 pestañas nuevas para http://www.google.com todos tendrían la misma clave en común (y este tipo de cosas sucede con bastante frecuencia en la práctica).

El método "poner GUID en sessionStorage" también se puede usar para eliminar la ambigüedad entre varias pestañas con la misma clave construida para los casos de cerrar/deshacer-cerrar y pestañas duplicadas durante la sesión actual del navegador. Pero esto no resuelve el problema de la ambigüedad entre los reinicios del navegador.

Esta última ambigüedad se puede mitigar parcialmente durante la restauración de la sesión al observar qué pestañas Chrome abre juntas en qué ventanas y extrapolar para una clave ambigua dada qué pestaña pertenece a qué ventana en función de la presencia de pestañas "hermanas" esperadas (registradas durante el navegador anterior). sesión). Como puede imaginar, la implementación de esta solución es bastante complicada y poco fiable. Y solo puede eliminar la ambigüedad entre pestañas con la misma clave que Chrome restaura en diferentes ventanas. Eso deja las pestañas con la misma clave que se restauran en la misma ventana como irreconciliablemente ambiguas.

¿Hay una mejor manera? Un GUID único garantizado, generado por el navegador, por pestaña que persiste entre los reinicios del navegador (restauraciones de sesión) y cerrar/deshacer-cerrar sería ideal, pero hasta ahora no he encontrado nada como esto.

preguntado el 12 de junio de 12 a las 22:06

3 Respuestas

La pregunta aquí hace la mayor parte del trabajo de descubrimiento, y la respuesta aceptada básicamente lo completa, pero todavía hay una gran brecha de implementación para las personas que buscan implementar algo que requiere ID de pestañas persistentes. He intentado destilar esto en una implementación real.

Para recapitular: las pestañas se pueden identificar (casi) de manera única y consistente según lo requiera la pregunta manteniendo un registro de pestañas que almacena la siguiente combinación de variables en el almacenamiento persistente local:

  • Tab.id
  • Tab.index
  • Una 'huella digital' del documento abierto en la pestaña - [location.href, document.referrer, history.length]

Estas variables se pueden rastrear y almacenar en el registro mediante escuchas en una combinación de los siguientes eventos:

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

Todavía hay formas de engañar a este método, pero en la práctica probablemente sean bastante raras, en su mayoría casos extremos.

Como parece que no soy el único que ha necesitado resolver este problema, construí mi implementación como una biblioteca con la intención de que pudiera usarse en cualquier extensión de Chrome. Tiene licencia del MIT y disponible en GitHub para bifurcaciones y solicitudes de extracción (de hecho, cualquier comentario sería bienvenido, definitivamente hay posibles mejoras).

Respondido el 25 de enero de 13 a las 09:01

Si entiendo correctamente su problema, su quinto método debería funcionar, pero junto con estos dos criterios:

  • chrome.tabs.windowId (El ID de la ventana en la que se encuentra la pestaña)
  • chrome.tabs.index (El índice de base cero de la pestaña dentro de su ventana)

Todos estos valores deben almacenarse dentro de su extensión. Además de eso, también tendrá que conectar su extensión a chrome.tabs.onUpdated() y actualizado en consecuencia, cuando las pestañas se arrastran, se mueven a través de las ventanas del propietario, etc.

Respondido el 15 de junio de 12 a las 07:06

Grandes ideas. Desafortunadamente, windowId cambia entre sesiones del navegador, pero si puedo deducir cambios de windowId entre sesiones recordando y comparando qué pestañas hay en cada ventana antes y después de reiniciar el navegador, debería poder usar .index como usted sugiere para eliminar la ambigüedad de dos pestañas idénticas. en una ventana dada. Muchas gracias. - joelpt

Agregaré que debería poder correlacionar un identificador de ventana recordado "antes de reiniciar" con un identificador de ventana abierto "después de reiniciar", si puedo identificar alguno soltero pestaña que tiene una URL única + URL de referencia + clave de longitud de historial. Dado que dicha pestaña es la única con esa clave en particular, sé a qué ventana pertenece; Por lo tanto, sé que cualquier pestaña recordada con el mismo ID de ventana "antiguo" también pertenece a la misma ventana "nueva". - joelpt

@joelpt sí, windowId no es confiable, pero si te conectas chrome.window.onCreated and chrome.window.onRemoved detectores de eventos puede emular fácilmente un índice (ID de pedido) en todas las ventanas. - Silviu Marian

¿Se enumeran las ventanas en el mismo orden entre los reinicios del navegador? - Gen Golovchinsky

@GeneGolovchinsky prueba y mira. normalmente debería - Silviu Marian

Ponga esto como un script de fondo persistente en manifest.json:

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

Aquí está background.js. Esperemos que el código se explique por sí mismo.

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();

Uso matriz para guardar datos, porque de esta manera puedo conservar el orden de las pestañas, lo cual es poco probable si los datos se guardaran en el objeto. Al cargar datos después de reiniciar el navegador, incluso si la URL no es única, puedo confiar en que estará bajo algún índice "lo suficientemente cercano". Lo haría de manera más compleja, por ejemplo, verifique de forma inversa si no se encontró la pestaña, pero esto funciona bien hasta ahora.

Respondido 11 Feb 17, 13:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.