Funciones web
Queremos cerrar la brecha de capacidades entre la Web y los anuncios nativos, de modo que los desarrolladores puedan crear experiencias excelentes en la Web abierta con facilidad. Creemos firmemente que todos los desarrolladores deben tener acceso a las capacidades que necesitan para ofrecer una gran experiencia web y estamos comprometidos con una Web más capaz.
Sin embargo, hay algunas capacidades, como el acceso al sistema de archivos y la detección de inactividad, que están disponibles para los anuncios nativos, pero no para la Web. Estas funciones faltan significan que algunos tipos de aplicaciones no se pueden entregar en la Web o son menos útiles.
Diseñaremos y desarrollaremos estas nuevas capacidades de forma abierta y transparente, mediante los procesos existentes de estándares de plataformas web abiertas, a la vez que recibimos comentarios anticipados de los desarrolladores y otros proveedores de navegadores a medida que iteramos en el diseño, a fin de garantizar un diseño interoperable.
Qué compilarás
En este codelab, probarás varias API web que son nuevas o solo están disponibles detrás de una marca. Por lo tanto, este codelab se enfoca en las API en sí y en los casos de uso que estas desbloquean, en lugar de compilar un producto final específico.
Qué aprenderás
En este codelab, aprenderás los mecanismos básicos de varias API de vanguardia. Ten en cuenta que estas mecánicas todavía no son definitivas, y agradecemos tus comentarios sobre el flujo de desarrolladores.
Requisitos
Como las API que se incluyen en este codelab están a la vanguardia, los requisitos para cada API varían. Asegúrese de leer con atención la información de compatibilidad al comienzo de cada sección.
Cómo abordar el codelab
El codelab no necesariamente debe realizarse de forma secuencial. Cada sección representa una API independiente, así que puedes elegir los que más te interesen.
El objetivo de la API de insignias es dirigir a los usuarios la información sobre lo que ocurre en segundo plano. A los fines de la simplicidad de la demostración en este codelab, usemos la API para acercar a los usuarios a algo que suceda en primer plano. Luego, puede realizar la transferencia mental de lo que sucede en segundo plano.
Instala Airhorner
Para que esta API funcione, necesitas tener una AWP que esté instalada en la pantalla principal. Por lo tanto, el primer paso es instalar una AWP, como el infame famoso airhorner.com. Presiona el botón Instalar en la esquina superior derecha o usa el menú de tres puntos para realizar la instalación de forma manual.

Cuando lo hagas, se mostrará un mensaje de confirmación y haz clic en Instalar.

Ahora tienes un ícono nuevo en el conector del sistema operativo. Haz clic en él para iniciar la AWP. Tendrá su propia ventana de la app y se ejecutará en modo independiente.
|
|
Cómo configurar una insignia
Ahora que tienes una AWP instalada, necesitas algunos datos numéricos (las insignias solo pueden contener números) para que se muestren en una insignia. Algo que vale la pena mencionar en The Air Horner es el suspiro, es decir, la cantidad de veces que se sirvió. En realidad, con la app de Airhorner instalada, toca la Alarma y revisa la insignia. Cuenta uno cada vez que suenas.

¿Cómo funciona? En esencia, el código es el siguiente:
let hornCounter = 0;
const horn = document.querySelector('.horn');
horn.addEventListener('click', () => {
navigator.setExperimentalAppBadge(++hornCounter);
});
Haz sonar la bocina varias veces y revisa el ícono de la AWP: se actualizará una vez. Así de fácil.

Cómo borrar una insignia
El contador aumenta hasta 99 y, luego, vuelve a comenzar. También puedes restablecerlo de forma manual. Abre la pestaña de la consola de DevTools, pega la línea que aparece a continuación y presiona Intro.
navigator.setExperimentalAppBadge(0);
Como alternativa, también puede deshacerse de la insignia si la borra explícitamente, como se muestra en el siguiente fragmento. Ahora, el ícono de tu AWP debería verse nuevamente como al principio, y sin distintivos.
navigator.clearExperimentalAppBadge();

Comentarios
¿Qué te pareció esta API? Ayúdanos a responder esta encuesta brevemente:
¿Esta API fue intuitiva para el uso?
¿Pudo ejecutar el ejemplo?
¿Tienes algo más que decir? ¿Faltan funciones? Proporciona comentarios rápidos en esta encuesta. Gracias
La API de Native File System permite que los programadores creen potentes aplicaciones web que interactúan con archivos del dispositivo local del usuario. Después de que un usuario otorga acceso a una aplicación web, esta API permite que las aplicaciones web lean o guarden cambios directamente en archivos y carpetas del dispositivo del usuario.
Cómo leer un archivo
La "Hello, World" de la API de Native File System es leer un archivo local y obtener su contenido. Crea un archivo sin formato .txt y, luego, ingresa texto. A continuación, navegue a cualquier sitio seguro (es decir, un sitio publicado mediante HTTPS), como example.com, y abra la consola de Herramientas para desarrolladores. Pega el siguiente fragmento de código en la consola. Debido a que la API de Native File System requiere un gesto del usuario, adjuntamos un controlador de doble clic en el documento. Más adelante, necesitaremos el controlador de archivo, así que lo haremos una variable global.
document.ondblclick = async () => {
window.handle = await window.chooseFileSystemEntries();
const file = await handle.getFile();
document.body.textContent = await file.text();
};

Cuando haga doble clic en cualquier parte de la página example.com, aparecerá un selector de archivos.

Selecciona el archivo .txt que creaste antes. El contenido del archivo reemplazará el contenido real de body de example.com.

Cómo guardar un archivo
A continuación, queremos realizar algunos cambios. Por lo tanto, para hacer que body sea editable, pega el siguiente fragmento de código. Ahora, puede editar el texto como si el navegador fuera un editor de texto.
document.body.contentEditable = true;

Ahora, queremos volver a escribir estos cambios en el archivo original. Por lo tanto, necesitamos un escritor en el controlador del archivo, que podemos obtener pegando el siguiente fragmento en la consola. Nuevamente, necesitamos un gesto del usuario, por lo que esta vez esperamos un clic en el documento principal.
document.onclick = async () => {
const writer = await handle.createWriter();
await writer.truncate(0);
await writer.write(0, document.body.textContent);
await writer.close();
};

Cuando haga clic en el documento (no con doble clic), aparecerá un mensaje de permiso. Cuando otorgues permiso, el contenido del archivo será el que editaste en el body anteriormente. Para verificar los cambios, abra el archivo en otro editor (o vuelva a iniciar el proceso haciendo doble clic en el documento nuevamente y volviendo a abrirlo).


¡Felicitaciones! Acabas de crear el editor de texto más pequeño del mundo, [citation needed].
Comentarios
¿Qué te pareció esta API? Ayúdanos a responder esta encuesta brevemente:
¿Esta API fue intuitiva para el uso?
¿Pudo ejecutar el ejemplo?
¿Tienes algo más que decir? ¿Faltan funciones? Proporciona comentarios rápidos en esta encuesta. Gracias
La API de detección de formas proporciona acceso a detectores de formas acelerados (p.ej., para los rostros humanos) y funciona en imágenes fijas o feeds de imágenes en vivo. Los sistemas operativos tienen detectores de funciones eficaces y altamente optimizados, como el FaceDetector de Android. La API de Shape Detection abre estas implementaciones nativas y las expone a través de un conjunto de interfaces de JavaScript.
Actualmente, las funciones compatibles son la detección de rostro mediante la interfaz FaceDetector, la detección de código de barras a través de la interfaz BarcodeDetector y la detección de texto (reconocimiento óptico de caracteres) a través de la interfaz TextDetector.
Detección de rostro
Una función fascinante de la API de detección de formas es la detección de rostro. Para probarlo, necesitamos una página con rostros. Esta página con la cara del autor es un buen comienzo. Tendrá un aspecto como el de la siguiente captura de pantalla. En un navegador compatible, se reconocerán el cuadro de límite del rostro y los puntos de referencia faciales.
Si desea ver lo poco que se necesita para hacer esto, debe remezclar o editar el proyecto Glitch, especialmente el archivo script.js.

Si quieres ser más dinámico y no solo trabajar con el rostro del autor, ve a la página de resultados de la Búsqueda de Google, llena de rostros en una pestaña privada o en modo de invitado. Ahora, en esa página, abra las Herramientas para desarrolladores de Chrome. Para ello, haga clic con el botón derecho en cualquier parte y, luego, en Inspeccionar. Luego, en la pestaña Consola, pegue el siguiente fragmento. El código destacará los rostros detectados con un cuadro semitransparente.
document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
try {
const faces = await new FaceDetector().detect(img);
faces.forEach(face => {
const div = document.createElement('div');
const box = face.boundingBox;
const computedStyle = getComputedStyle(img);
const [top, right, bottom, left] = [
computedStyle.marginTop,
computedStyle.marginRight,
computedStyle.marginBottom,
computedStyle.marginLeft
].map(m => parseInt(m, 10));
const scaleX = img.width / img.naturalWidth;
const scaleY = img.height / img.naturalHeight;
div.style.backgroundColor = 'rgba(255, 0, 0, 0.5)';
div.style.position = 'absolute';
div.style.top = `${scaleY * box.top + top}px`;
div.style.left = `${scaleX * box.left + left}px`;
div.style.width = `${scaleX * box.width}px`;
div.style.height = `${scaleY * box.height}px`;
img.before(div);
});
} catch(e) {
console.error(e);
}
});
Notarás que hay algunos mensajes DOMException y no todas las imágenes se están procesando. Esto se debe a que las imágenes de la mitad superior de la página están intercaladas como URI de datos y, por lo tanto, se puede acceder a ellas, mientras que las imágenes de la mitad inferior de la página provienen de un dominio diferente que no está configurado para admitir CORS. A los fines de la demostración, no tenemos que preocuparnos por esto.
Detección de puntos de referencia faciales
Además de solo rostros, macOS admite la detección de puntos de referencia faciales. Para probar la detección de puntos de referencia faciales, pega el siguiente fragmento en Console. Recordatorio: La selección de los puntos de referencia no es perfecta en función de crbug.com/914348, pero puedes ver hacia dónde se dirige y qué tan poderosa puede ser esta función.
document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
try {
const faces = await new FaceDetector().detect(img);
faces.forEach(face => {
const div = document.createElement('div');
const box = face.boundingBox;
const computedStyle = getComputedStyle(img);
const [top, right, bottom, left] = [
computedStyle.marginTop,
computedStyle.marginRight,
computedStyle.marginBottom,
computedStyle.marginLeft
].map(m => parseInt(m, 10));
const scaleX = img.width / img.naturalWidth;
const scaleY = img.height / img.naturalHeight;
div.style.backgroundColor = 'rgba(255, 0, 0, 0.5)';
div.style.position = 'absolute';
div.style.top = `${scaleY * box.top + top}px`;
div.style.left = `${scaleX * box.left + left}px`;
div.style.width = `${scaleX * box.width}px`;
div.style.height = `${scaleY * box.height}px`;
img.before(div);
const landmarkSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
landmarkSVG.style.position = 'absolute';
landmarkSVG.classList.add('landmarks');
landmarkSVG.setAttribute('viewBox', `0 0 ${img.width} ${img.height}`);
landmarkSVG.style.width = `${img.width}px`;
landmarkSVG.style.height = `${img.height}px`;
face.landmarks.map((landmark) => {
landmarkSVG.innerHTML += `<polygon class="landmark-${landmark.type}" points="${
landmark.locations.map((point) => {
return `${scaleX * point.x},${scaleY * point.y} `;
}).join(' ')
}" /></svg>`;
});
div.before(landmarkSVG);
});
} catch(e) {
console.error(e);
}
});
Detección de código de barras
La segunda característica de la API de detección de formas es la detección de códigos de barras. Al igual que antes, necesitamos una página con códigos de barras, como esta. Cuando lo abras en un navegador, verás los diversos códigos QR descifrados. Remezcla o edita el proyecto de Glitch, especialmente el archivo script.js para ver cómo se hace.

Si quieres algo más dinámico, podemos usar la Búsqueda de imágenes de Google de nuevo. Esta vez, en tu navegador, navega a esta página de resultados de la Búsqueda de Google en una pestaña privada o en modo de invitado. Ahora, pegue el siguiente fragmento en la pestaña de la consola de las Herramientas para desarrolladores de Chrome. Después de un breve momento, los códigos de barras reconocidos se anotarán con el valor sin procesar y el tipo de código de barras.
document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
try {
const barcodes = await new BarcodeDetector().detect(img);
barcodes.forEach(barcode => {
const div = document.createElement('div');
const box = barcode.boundingBox;
const computedStyle = getComputedStyle(img);
const [top, right, bottom, left] = [
computedStyle.marginTop,
computedStyle.marginRight,
computedStyle.marginBottom,
computedStyle.marginLeft
].map(m => parseInt(m, 10));
const scaleX = img.width / img.naturalWidth;
const scaleY = img.height / img.naturalHeight;
div.style.backgroundColor = 'rgba(255, 255, 255, 0.75)';
div.style.position = 'absolute';
div.style.top = `${scaleY * box.top + top}px`;
div.style.left = `${scaleX * box.left - left}px`;
div.style.width = `${scaleX * box.width}px`;
div.style.height = `${scaleY * box.height}px`;
div.style.color = 'black';
div.style.fontSize = '14px';
div.textContent = `${barcode.rawValue}`;
img.before(div);
});
} catch(e) {
console.error(e);
}
});
Detección de texto
La última función de la API de detección de formas es la detección de texto. A esta altura, ya sabes cómo funciona: Necesitamos una página con imágenes que contengan texto, como esta con los resultados del escaneo de Google Libros. En los navegadores compatibles, verás el texto reconocido y un cuadro de límite alrededor de los pasajes de texto. Remezcla o edita el proyecto de Glitch, especialmente el archivo script.js para ver cómo se hace.

Para probarlo de forma dinámica, ve a esta página de resultados de búsqueda en una pestaña privada o en modo de invitado. Ahora, pegue el siguiente fragmento en la pestaña de la consola de las Herramientas para desarrolladores de Chrome. Con un poco de espera, se reconocerá parte del texto.
document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
try {
const texts = await new TextDetector().detect(img);
texts.forEach(text => {
const div = document.createElement('div');
const box = text.boundingBox;
const computedStyle = getComputedStyle(img);
const [top, right, bottom, left] = [
computedStyle.marginTop,
computedStyle.marginRight,
computedStyle.marginBottom,
computedStyle.marginLeft
].map(m => parseInt(m, 10));
const scaleX = img.width / img.naturalWidth;
const scaleY = img.height / img.naturalHeight;
div.style.backgroundColor = 'rgba(255, 255, 255, 0.75)';
div.style.position = 'absolute';
div.style.top = `${scaleY * box.top + top}px`;
div.style.left = `${scaleX * box.left - left}px`;
div.style.width = `${scaleX * box.width}px`;
div.style.height = `${scaleY * box.height}px`;
div.style.color = 'black';
div.style.fontSize = '14px';
div.innerHTML = text.rawValue;
img.before(div);
});
} catch(e) {
console.error(e);
}
});
Comentarios
¿Qué te pareció esta API? Ayúdanos a responder esta encuesta brevemente:
¿Esta API fue intuitiva para el uso?
¿Pudo ejecutar el ejemplo?
¿Tienes algo más que decir? ¿Faltan funciones? Proporciona comentarios rápidos en esta encuesta. Gracias
La API de Web Share Target permite que las aplicaciones web instaladas se registren con el sistema operativo subyacente como destino para compartir y puedan recibir contenido compartido de la API de Web Share o eventos del sistema, como el botón para compartir a nivel del sistema operativo.
Instala una AWP para compartir
Como primer paso, necesitas una AWP que luego puedas compartir. Esta vez, Airhorner (por suerte) no hará el trabajo, pero la app de demostración de Web Share Target podrá ayudarte. Instala la app en la pantalla principal del dispositivo.

Comparte algo con la AWP
A continuación, necesitas algo para compartir, como una foto de Google Fotos. Usa el botón Compartir y selecciona la AWP del libro de recortes como destino para compartir.

Cuando presionas el ícono de la app, llegas directamente a la AWP del libro de recortes y la foto se encuentra allí.

¿Cómo funciona? Para averiguarlo, explora el manifiesto de las apps web de la AWP del libro de recortes. La configuración para que funcione la API de Web Share Target se encuentra en la propiedad "share_target" del manifiesto, que en su campo "action" apunta a una URL que se decora con parámetros como se muestra en "params".
El lado de uso compartido completa esta plantilla de URL según corresponda (ya sea mediante una acción de uso compartido o controlada de manera programática por el desarrollador usando la API de Web Share), para que el lado de recepción pueda extraer los parámetros y hacer algo con ellos, como mostrarlos.
{
"action": "/_share-target",
"enctype": "multipart/form-data",
"method": "POST",
"params": {
"files": [{
"name": "media",
"accept": ["audio/*", "image/*", "video/*"]
}]
}
}
Comentarios
¿Qué te pareció esta API? Ayúdanos a responder esta encuesta brevemente:
¿Esta API fue intuitiva para el uso?
¿Pudo ejecutar el ejemplo?
¿Tienes algo más que decir? ¿Faltan funciones? Proporciona comentarios rápidos en esta encuesta. Gracias
Para evitar que se agote la batería, la mayoría de los dispositivos se suspenden rápidamente cuando están inactivos. Si bien esto es suficiente la mayoría de las veces, algunas aplicaciones deben mantener activa la pantalla o el dispositivo para completar su trabajo. La API de bloqueo de activación proporciona una manera de evitar que el dispositivo atenúe y bloquee la pantalla, o bien que se suspenda. Esta función habilita nuevas experiencias que, hasta ahora, requerían una aplicación nativa.
Configura un protector de pantalla
Para probar la API de Wake Lock, primero debes asegurarte de que tu dispositivo se suspenda. Por lo tanto, en el panel de preferencias de tu sistema operativo, activa el protector de pantalla que elijas y asegúrate de que se inicie al cabo de 1 minuto. Para asegurarte de que funcione, deja el dispositivo solo durante exactamente ese momento (sí, es muy doloroso). Las capturas de pantalla que aparecen a continuación muestran macOS, pero puedes probar esto en tu dispositivo Android o en cualquier plataforma de escritorio compatible.

Configura un bloqueo de activación de pantalla
Ahora que sabes que el protector de pantalla está funcionando, usarás un bloqueo de activación de tipo "screen" para evitar que el protector de pantalla haga su trabajo. Ve a la app de demostración de Bloqueo de activación y haz clic en la casilla de verificación para activar screen Wake Lock.

A partir de ese momento, se activará un bloqueo de activación. Si eres lo suficientemente paciente como para dejar tu dispositivo intacto durante un minuto, ahora verás que el protector de pantalla no se inició.
¿Cómo funciona? Para averiguarlo, ve al proyecto Glitch de la app de demostración de Wake Lock y consulta script.js. La esencia del código se encuentra en el siguiente fragmento. Abre una nueva pestaña (o utiliza cualquier pestaña que tengas abierta) y pega el siguiente código en una consola de herramientas para desarrolladores de Chrome. Al hacer clic en la ventana, deberías ver un bloqueo de activación que se activa exactamente durante 10 segundos (consulta los registros de la consola) y el protector de pantalla no debería iniciarse.
if ('wakeLock' in navigator && 'request' in navigator.wakeLock) {
let wakeLock = null;
const requestWakeLock = async () => {
try {
wakeLock = await navigator.wakeLock.request('screen');
wakeLock.addEventListener('release', () => {
console.log('Wake Lock was released');
});
console.log('Wake Lock is active');
} catch (e) {
console.error(`${e.name}, ${e.message}`);
}
};
requestWakeLock();
window.setTimeout(() => {
wakeLock.release();
}, 10 * 1000);
}

Comentarios
¿Qué te pareció esta API? Ayúdanos a responder esta encuesta brevemente:
¿Esta API fue intuitiva para el uso?
¿Pudo ejecutar el ejemplo?
¿Tienes algo más que decir? ¿Faltan funciones? Proporciona comentarios rápidos en esta encuesta. Gracias
Una API que nos entusiasma mucho es la API de selector de contactos. Permite que una aplicación web acceda a los contactos desde el administrador de contactos nativo del dispositivo, de modo que la aplicación web tiene acceso a los nombres, los correos electrónicos y los números de teléfono de tus contactos. Puedes especificar si quieres tener uno o varios contactos, y todos los campos o un subconjunto de nombres, direcciones de correo electrónico y números de teléfono.
Consideraciones de privacidad
Una vez que se abre el selector, puedes seleccionar los contactos que deseas compartir. Ten en cuenta que no existe la opción "Seleccionar todo" (que es intencional): Queremos que el uso compartido sea una decisión consciente. Asimismo, el acceso no es continuo, sino que se toma una decisión por única vez.
Cómo acceder a los contactos
Acceder a los contactos es una tarea sencilla. Antes de que se abra el selector, puedes especificar los campos que desees (las opciones son name, email y telephone) y si deseas acceder a varios o solo un contacto. Para probar esta API en un dispositivo Android, abre la aplicación de demostración. La sección relevante del código fuente es básicamente el siguiente fragmento:
getContactsButton.addEventListener('click', async () => {
const contacts = await navigator.contacts.select(
['name', 'email'],
{multiple: true});
if (!contacts.length) {
// No contacts were selected, or picker couldn't be opened.
return;
}
console.log(contacts);
});

Cómo copiar y pegar texto
Hasta ahora, no había forma de copiar y pegar imágenes de manera programática en el portapapeles del sistema. Hace poco, agregamos la compatibilidad con imágenes a la API de Async Clipboard.
para que ahora pueda copiar y pegar imágenes. La novedad es que también puedes escribir imágenes en el portapapeles. La API asíncrona del portapapeles permitió copiar y pegar texto por un tiempo. Puedes copiar texto al portapapeles llamando a navigator.clipboard.writeText() y luego pegar ese texto llamando a navigator.clipboard.readText().
Cómo copiar y pegar imágenes
Ahora también puedes escribir imágenes en el portapapeles. Para que esto funcione, necesitas los datos de la imagen como un BLOB que, luego, pasarás al constructor del elemento del portapapeles. Por último, puedes copiar este elemento del portapapeles llamando a navigator.clipboard.write().
// Copy: Writing image to the clipboard
try {
const imgURL = 'https://developers.google.com/web/updates/images/generic/file.png';
const data = await fetch(imgURL);
const blob = await data.blob();
await navigator.clipboard.write([
new ClipboardItem(Object.defineProperty({}, blob.type, {
value: blob,
enumerable: true
}))
]);
console.log('Image copied.');
} catch(e) {
console.error(e, e.message);
}
Volver a pegar la imagen desde el portapapeles parece bastante complicado, pero, en realidad, solo consiste en recuperar el BLOB del elemento del portapapeles. Como puede haber varios, debes repetir los pasos hasta que encuentres el que te interesa. Por motivos de seguridad, en este momento se limita a imágenes PNG, pero posiblemente se admitan más formatos de imágenes en el futuro.
async function getClipboardContents() {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
try {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
console.log(URL.createObjectURL(blob));
}
} catch (e) {
console.error(e, e.message);
}
}
} catch (e) {
console.error(e, e.message);
}
}
Puede ver esta API en acción en una aplicación de demostración, ya que los fragmentos relevantes de su código fuente están incorporados arriba. Se pueden copiar imágenes al portapapeles sin permiso, pero debes otorgar acceso para pegarlas desde el portapapeles.

Después de otorgar acceso, puedes leer la imagen del portapapeles y pegarla en la aplicación:

¡Felicitaciones! Llegaste al final del codelab. Nuevamente, este es un recordatorio para recordarle que la mayoría de las API aún están en cambio y en las que están trabajando activamente. Por lo tanto, el equipo realmente valora tus comentarios, ya que solo la interacción con personas como tú nos ayudará a corregir estas API.
También le recomendamos que consulte con frecuencia nuestra página de destino de funciones. Lo mantendremos actualizado y tendrá orientación a todos los artículos detallados sobre las API en las que trabajamos. Sigue disfrutando.
Tom y todo el equipo de Funciones 🐡
