Electron: ¿Cómo abro una URL desde <a>el navegador del sistema operativo predeterminado?</a>

Creado en 1 abr. 2015  ·  26Comentarios  ·  Fuente: electron/electron

Comentario más útil

Encontré este fragmento de código en SO:

    var shell = require('electron').shell;
    //open links externally by default
    $(document).on('click', 'a[href^="http"]', function(event) {
        event.preventDefault();
        shell.openExternal(this.href);
    });

Lo coloqué en mi archivo de índice principal, parece estar funcionando hasta donde puedo decir, incluso para enlaces generados dinámicamente. Soy demasiado novato en electron para saber si hay algún inconveniente que deba tener en cuenta. ¿Pensamientos?

Todos 26 comentarios

En mi configuración, probé shell.openExternal('http://example.com') y shell.openItem('http://example.com') y ambos abrieron el sitio web en segundo plano.

Terminé usando child_process.execSync('start http://example.com') en Win32 y child_process.execSync('open http://example.com') en Darwin, por lo que el navegador realmente aparece y se enfoca.

En Linux, puede usar xdg-open:
child_process.execSync('xdg-open http://example.com')

De hecho, he decidido usar node-open . Debería intentarlo si no quiere meterse con el escape y demás.

Chicos, pero sus soluciones son geniales, pero me pregunto cómo interceptar el intento de abrir una URL como " http://someurl.com " y luego abrir con shell.openExternal . El trabajador de servicio permite capturar solo solicitudes de archivos en el mismo dominio. ¿Existe la posibilidad de hacer esto? / cc @maxogden @AlicanC

La misma pregunta aquí que @havenchyk , ¿hay alguna manera de decirle a electron que abra enlaces externos de forma predeterminada?

Si su aplicación solo usa una ventana, y puede garantizar que todos los enlaces externos de su aplicación se abren en una nueva ventana (a través de, por ejemplo, target="_blank" ), puede hacer algo como:

webContents.on('new-window', function(event, url){
  event.preventDefault();
  open(url);
});

Donde webContents es el contenido web de su BrowserWindow principal y open es una función que abre la URL en su navegador (yo uso node-open como lo recomienda AlicanC).

Sería bueno que se disparara un evento cuando se hace clic en _cualquier_ enlace, para que la aplicación pueda decidir si debe abrirse en el navegador, pero no he encontrado tal evento si existe.

Encontré este fragmento de código en SO:

    var shell = require('electron').shell;
    //open links externally by default
    $(document).on('click', 'a[href^="http"]', function(event) {
        event.preventDefault();
        shell.openExternal(this.href);
    });

Lo coloqué en mi archivo de índice principal, parece estar funcionando hasta donde puedo decir, incluso para enlaces generados dinámicamente. Soy demasiado novato en electron para saber si hay algún inconveniente que deba tener en cuenta. ¿Pensamientos?

Estoy usando este código:

var handleRedirect = (e, url) => {
  if(url != webContents.getURL()) {
    e.preventDefault()
    require('electron').shell.openExternal(url)
  }
}

webContents.on('will-navigate', handleRedirect)
webContents.on('new-window', handleRedirect)

Primero declare un proceso de generación

`app.controller ('GuideCtrl', ['$ alcance', ($ alcance) => {
const spawn = require ('child_process'). spawn;

  $scope.openBrowser=(url)=>{
     let exec = spawn('explore', [url], {});
     exec.stdout.on('data', (data)=> {
        console.log('stdout: ' + data)
     });
  }

}]) `

y antes de llamar al método

<a ng-click="openBrowser('https://google.com')">Goto google</a>

¿Tiene shell.openExternal algún problema de seguridad? Por ejemplo, si los enlaces salen de la red, los datos netos sin procesar se pasan a shell.openExternal o cualquiera de las otras funciones anteriores. ¿ shell.openExternal asegura de que no suceda nada malo? ¿Necesito filtrar por esquemas?

Basado en el código de @rubencodes , utilicé:

const shell = require('electron').shell; $('.open-in-browser').click((event) => { event.preventDefault(); shell.openExternal(event.target.href); });

Luego, solo tiene que colocar la clase 'abrir en el navegador' para cada elemento que desea abrir en el navegador.

Aquí hay uno que no requiere JQuery, en caso de que alguien más lo esté buscando. Automáticamente abrirá cualquier enlace que comience con 'http' en el navegador externo.

Pon esto en tu proceso de renderizado:

// Open all links in external browser
let shell = require('electron').shell
document.addEventListener('click', function (event) {
  if (event.target.tagName === 'A' && event.target.href.startsWith('http')) {
    event.preventDefault()
    shell.openExternal(event.target.href)
  }
})

Si desea que TODAS las etiquetas <a> abran en el navegador predeterminado, intente esto en su main.ts:

const shell = require('electron').shell;

mainWin.webContents.on('will-navigate', (event, url) => {
  event.preventDefault()
  shell.openExternal(url)
});

Esto supone que tienes una aplicación de una sola página como yo. Si no es así, deberá realizar una desinfección adicional.

Solo quiero reiterar que usar esto con contenido de usuario sin una lista blanca es probablemente un enorme agujero de seguridad. No sé qué hacen todos los esquemas y cuáles son sus entradas, pero solo como un ejemplo simple, un enlace como este

 <a href="imessage:hello">click me</a>

Solicitará al usuario en Chrome y Safari en macOS, pero con el código anterior, Electron simplemente abrirá la aplicación.

Casi parece que el propio Electron debería ser más seguro aquí en lugar de dejar que cada programador individual averigüe cómo hacerlo seguro por su cuenta.

Como mínimo, probablemente quieras algo como

function isSafeishURL(url) {
  return url.startsWith('http:') || url.startsWith('https:');
}

mainWin.webContents.on('will-navigate', (event, url) => {
  event.preventDefault();
  if (isSafeishURL(url)) {
    shell.openExternal(url);
  }
});

@greggman Vea el tipo de permiso externo abierto en https://electronjs.org/docs/api/session#sessetpermissionrequesthandlerhandler

Puedes bloquear esos 👍

Hola, estoy usando vue.js y resuelvo este problema inspirado en la discusión anterior, en caso de que alguien como yo que usa vue también tenga el mismo problema, pego mi código aquí.

<template>
<div class="board-item" v-for="element in list" :key="element.id">
<span><a class='board-item-a' :href='element.url' target='_blank'>{{element.title}}</a></span>
</div>
</template>

<script>
mounted () {
this.$el.querySelectorAll('.board-item-a').forEach(a => {
a.addEventListener('click', (e) => {
e.preventDefault()
require('electron').shell.openExternal(e.target.href)
})
})
},
</script>

Basado en el comentario de @alangrainger - versión ts:

const {app, shell, BrowserWindow} = require('electron');

...
mainWindow.webContents.on('new-window', function(event, url){
   event.preventDefault();
   shell.openExternal(url);
});

¿Qué pasa con las URL de datos?

Versión Angular 7 (con recargas en vivo):

        const openExternalLinksInOSBrowser = (event, url) => {
            if (url.match(/.*localhost.*/gi) === null && (url.startsWith('http:') || url.startsWith('https:'))) {
                event.preventDefault();
                shell.openExternal(url);
            }
        };
        win.webContents.on('new-window', openExternalLinksInOSBrowser);
        win.webContents.on('will-navigate', openExternalLinksInOSBrowser);

La parte url.match(/.*localhost.*/gi) === null es necesaria porque, de lo contrario, cuando cambie algo en su aplicación angular, se abrirá una nueva ventana / pestaña en el navegador de su sistema operativo en lugar de volver a cargarla en la aplicación electrónica.

Todos los métodos funcionan bien, pero solo en una aplicación que no sea root electron, ¿qué puedo usar para abrir una URL externa en el navegador del sistema operativo predeterminado en un proceso de root elevado?

Solo quería publicar una respuesta para otros usuarios de Vue.js.

<template>
  <div>
    <a href="https://google.com" target="_blank" @click.prevent="openExternalBrowser">Google.com Status</a>
  </div>
</template>

<script>
const { remote } = require('electron');

export default {
  name: 'HelloWorld',
  methods: {
    openExternalBrowser(e) {
      remote.shell.openExternal(e.target.href);
    },
  },
};
</script>

Solo quería publicar una respuesta para otros usuarios de Vue.js.

<template>
  <div>
    <a href="https://google.com" target="_blank" @click.prevent="openExternalBrowser">Google.com Status</a>
  </div>
</template>

<script>
const { remote } = require('electron');

export default {
  name: 'HelloWorld',
  methods: {
    openExternalBrowser(e) {
      remote.shell.openExternal(e.target.href);
    },
  },
};
</script>

Gracias.

En main.js :

app.on('web-contents-created', (e, contents) => {
    contents.on('new-window', (e, url) => {
      e.preventDefault();
      require('open')(url);
    });
    contents.on('will-navigate', (e, url) => {
      if (url !== contents.getURL()) e.preventDefault(), require('open')(url);
    });
});

Necesita instalar el paquete abierto :

npm i open --save

Solo quería publicar una respuesta para otros usuarios de Vue.js.

@ travis5491811 Esto abre otra ventana de Electron con la página de la derecha. ¿Es este el comportamiento esperado?

No, cuando se implementa correctamente, mi publicación debe responder al ticket del hilo "¿Cómo abro una URL desde el navegador del sistema operativo predeterminado? ", Pero para los usuarios de vue .

Solo quería publicar una respuesta para otros usuarios de Vue.js.

@ travis5491811 Esto abre otra ventana de Electron con la página de la derecha. ¿Es este el comportamiento esperado?

¿Fue útil esta página
0 / 5 - 0 calificaciones