1. Introdução e configuração
Recursos da Web
Queremos diminuir a lacuna de recursos entre a Web e o ambiente nativo e facilitar a criação de experiências incríveis na Web aberta para os desenvolvedores. Acreditamos que todos os desenvolvedores devem ter acesso aos recursos necessários para criar uma ótima experiência na Web, e estamos comprometidos com uma Web mais eficiente.
No entanto, há alguns recursos, como acesso ao sistema de arquivos e detecção de inatividade, que estão disponíveis para nativos, mas não na Web. Essas funcionalidades ausentes significam que alguns tipos de apps não podem ser disponibilizados na Web ou são menos úteis.
Vamos projetar e desenvolver esses novos recursos de maneira aberta e transparente, usando os processos padrão da plataforma da Web aberta. Também vamos receber feedback antecipado de desenvolvedores e outros fornecedores de navegadores à medida que iteramos no design para garantir a interoperabilidade.
O que você vai criar
Neste codelab, você vai testar várias APIs da Web que são novas ou estão disponíveis apenas com uma flag. Por isso, este codelab se concentra nas APIs e nos casos de uso que elas desbloqueiam, em vez de criar um produto final específico.
O que você vai aprender
Este codelab vai ensinar a você a mecânica básica de várias APIs de ponta. Essas mecânicas ainda não estão definidas, e agradecemos muito seu feedback sobre o fluxo de desenvolvedores.
O que é necessário
Como as APIs apresentadas neste codelab são realmente de ponta, os requisitos de cada uma variam. Leia com atenção as informações de compatibilidade no início de cada seção.
Como abordar o codelab
O codelab não precisa ser feito em sequência. Cada seção representa uma API independente. Portanto, sinta-se à vontade para fazer cherry-pick do que mais interessa.
2. API Badging
O objetivo da API Badging é chamar a atenção dos usuários para o que acontece em segundo plano. Para simplificar a demonstração neste codelab, vamos usar a API para chamar a atenção dos usuários para algo que está acontecendo em primeiro plano. Depois, você pode fazer a transferência mental para coisas que acontecem em segundo plano.
Instalar o Airhorner
Para que essa API funcione, é necessário ter um PWA instalado na tela inicial. Portanto, a primeira etapa é instalar um PWA, como o famoso airhorner.com. Clique no botão Instalar no canto superior direito ou use o menu de três pontos para instalar manualmente.

Uma mensagem de confirmação vai aparecer. Clique em Instalar.

Agora você tem um novo ícone no dock do seu sistema operacional. Clique nele para iniciar o PWA. Ele terá uma janela própria e será executado no modo independente.
|
|
Definir um ícone
Agora que você tem um PWA instalado, precisa de alguns dados numéricos (os selos só podem conter números) para mostrar em um selo. Uma coisa simples de contar em The Air Horner é, suspiro, o número de vezes que ele foi tocado. Com o app Airhorner instalado, toque a buzina e confira o selo. Ele conta um a mais sempre que você buzina.

Como isso funciona? Essencialmente, o código é este:
let hornCounter = 0;
const horn = document.querySelector('.horn');
horn.addEventListener('click', () => {
navigator.setExperimentalAppBadge(++hornCounter);
});
Toque a buzina algumas vezes e verifique o ícone do PWA: ele será atualizado a cada. única. vez. que a buzina tocar. É simples assim.

Como limpar um selo
O contador vai até 99 e depois começa de novo. Também é possível fazer isso manualmente. Abra a guia "Console" das DevTools, cole a linha abaixo e pressione "Enter".
navigator.setExperimentalAppBadge(0);
Como alternativa, você também pode se livrar do ícone limpando-o explicitamente, conforme mostrado no snippet a seguir. O ícone do PWA vai ficar como no início, claro e sem um selo.
navigator.clearExperimentalAppBadge();

Feedback
O que você achou desta API? Responda a esta pesquisa para nos ajudar:
Essa API foi intuitiva de usar?
Você conseguiu executar o exemplo?
Quer dizer mais alguma coisa? Faltaram recursos? Envie seu feedback rápido nesta pesquisa. Agradecemos pela atenção!
3. API Native File System
A API Native File System permite que os desenvolvedores criem apps da Web avançados que interagem com arquivos no dispositivo local do usuário. Depois que um usuário concede acesso a um web app, essa API permite que os web apps leiam ou salvem mudanças diretamente em arquivos e pastas no dispositivo do usuário.
Ler um arquivo
O "Hello, world" da API Native File System é ler um arquivo local e receber o conteúdo dele. Crie um arquivo .txt simples e digite algum texto. Em seguida, acesse qualquer site seguro (ou seja, um site disponibilizado por HTTPS), como example.com, e abra o console do DevTools. Cole o snippet de código abaixo no console. Como a API Native File System exige um gesto do usuário, anexamos um manipulador de clique duplo ao documento. Vamos precisar do identificador de arquivo mais tarde, então vamos transformá-lo em uma variável global.
document.ondblclick = async () => {
window.handle = await window.chooseFileSystemEntries();
const file = await handle.getFile();
document.body.textContent = await file.text();
};

Em seguida, clique duas vezes em qualquer lugar da página example.com para abrir um seletor de arquivos.

Selecione o arquivo .txt que você criou antes. O conteúdo do arquivo vai substituir o conteúdo real de body em example.com.

Como salvar um arquivo
Em seguida, vamos fazer algumas mudanças. Portanto, vamos tornar o body editável colando o snippet de código abaixo. Agora, você pode editar o texto como se o navegador fosse um editor de texto.
document.body.contentEditable = true;

Agora, vamos gravar essas mudanças no arquivo original. Portanto, precisamos de um gravador no identificador de arquivo, que pode ser obtido colando o snippet abaixo no console. Mais uma vez, precisamos de um gesto do usuário. Desta vez, aguardamos um clique no documento principal.
document.onclick = async () => {
const writer = await handle.createWriter();
await writer.truncate(0);
await writer.write(0, document.body.textContent);
await writer.close();
};

Quando você clicar (não clicar duas vezes) no documento, uma solicitação de permissão vai aparecer. Quando você concede permissão, o conteúdo do arquivo é o que você editou no body antes. Verifique as mudanças abrindo o arquivo em outro editor ou reinicie o processo clicando duas vezes no documento e reabrindo o arquivo.


Parabéns! Você acabou de criar o menor editor de texto do mundo [citation needed].
Feedback
O que você achou desta API? Responda a esta pesquisa para nos ajudar:
Essa API foi intuitiva de usar?
Você conseguiu executar o exemplo?
Quer dizer mais alguma coisa? Faltaram recursos? Envie seu feedback rápido nesta pesquisa. Agradecemos pela atenção!
4. API Shape Detection
A API Shape Detection oferece acesso a detectores de formas acelerados (por exemplo, para rostos humanos) e funciona em imagens estáticas e/ou feeds de imagens ao vivo. Os sistemas operacionais têm detectores de recursos eficientes e altamente otimizados, como o FaceDetector do Android. A API Shape Detection abre essas implementações nativas e as expõe por um conjunto de interfaces JavaScript.
No momento, os recursos compatíveis são detecção facial pela interface FaceDetector, detecção de código de barras pela interface BarcodeDetector e detecção de texto (reconhecimento óptico de caracteres) pela interface TextDetector.
Detecção facial
Um recurso fascinante da API Shape Detection é a detecção facial. Para testar, precisamos de uma página com rostos. Esta página com o rosto do autor é um bom começo. Ele vai ficar parecido com a captura de tela abaixo. Em um navegador compatível, a caixa delimitadora do rosto e os pontos de referência faciais serão reconhecidos.
Para ver como foi necessário pouco código para isso, remixe ou edite o projeto do Glitch, principalmente o arquivo script.js.

Se você quiser usar um recurso totalmente dinâmico e não apenas trabalhar com o rosto do autor, acesse esta página de resultados da Pesquisa Google cheia de rostos em uma guia privada ou no modo visitante. Agora, nessa página, abra as Ferramentas para desenvolvedores do Chrome clicando com o botão direito do mouse em qualquer lugar e depois em Inspecionar. Em seguida, na guia "Console", cole o snippet abaixo. O código vai destacar os rostos detectados com uma caixa vermelha 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);
}
});
Você vai notar que há algumas mensagens DOMException e que nem todas as imagens estão sendo processadas. Isso ocorre porque as imagens acima da dobra são inlines como URIs de dados e, portanto, podem ser acessadas. Já as imagens abaixo da dobra vêm de um domínio diferente que não está configurado para oferecer suporte ao CORS. Para fins de demonstração, não precisamos nos preocupar com isso.
Detecção de pontos de referência do rosto
Além de rostos, o macOS também oferece suporte à detecção de pontos de referência faciais. Para testar a detecção de pontos de referência faciais, cole o snippet a seguir no console. Lembrete: o alinhamento dos pontos de referência não é perfeito devido a crbug.com/914348, mas você pode ver para onde isso está indo e o quanto esse recurso pode ser útil.
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);
}
});
Detecção de código de barras
O segundo recurso da API Shape Detection é a detecção de códigos de barras. Assim como antes, precisamos de uma página com códigos de barras, como esta. Ao abrir em um navegador, você verá os vários QR codes decifrados. Remixe ou edite o projeto Glitch, principalmente o arquivo script.js, para saber como isso é feito.

Se você quiser algo mais dinâmico, use a Pesquisa de imagens do Google. Desta vez, no navegador, acesse esta página de resultados da Pesquisa Google em uma guia privada ou no modo visitante. Agora cole o snippet abaixo na guia "Console" do Chrome DevTools. Depois de alguns segundos, os códigos de barras reconhecidos serão anotados com o valor bruto e o 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);
}
});
Detecção de texto
O último recurso da API Shape Detection é a detecção de texto. Você já sabe o que fazer: precisamos de uma página com imagens que contenham texto, como esta com resultados de digitalização do Google Livros. Em navegadores compatíveis, você vai ver o texto reconhecido e uma caixa delimitadora desenhada ao redor das passagens de texto. Remixe ou edite o projeto Glitch, principalmente o arquivo script.js, para saber como isso é feito.

Para testar isso de forma dinâmica, acesse esta página de resultados da pesquisa em uma guia privada ou no modo visitante. Agora cole o snippet abaixo na guia "Console" do Chrome DevTools. Depois de um tempo, parte do texto será reconhecida.
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);
}
});
Feedback
O que você achou desta API? Responda a esta pesquisa para nos ajudar:
Essa API foi intuitiva de usar?
Você conseguiu executar o exemplo?
Quer dizer mais alguma coisa? Faltaram recursos? Envie seu feedback rápido nesta pesquisa. Agradecemos pela atenção!
5. API Web Share Target
A API Web Share Target permite que apps da Web instalados se registrem no sistema operacional subjacente como um destino de compartilhamento para receber conteúdo compartilhado da API Web Share ou de eventos do sistema, como o botão de compartilhamento no nível do sistema operacional.
Instalar um PWA para compartilhar com
Primeiro, você precisa de um PWA para compartilhar. Desta vez, o Airhorner (felizmente) não vai funcionar, mas o app de demonstração do Web Share Target vai ajudar você. Instale o app na tela inicial do dispositivo.

Compartilhar algo com o PWA
Em seguida, você precisa de algo para compartilhar, como uma foto do Google Fotos. Use o botão "Compartilhar" e selecione o PWA do Scrapbook como destino de compartilhamento.

Ao tocar no ícone do app, você vai direto para o PWA do Scrapbook, e a foto estará lá.

Como isso funciona? Para saber mais, confira o manifesto do app da Web do PWA do Scrapbook. A configuração para fazer a API Web Share Target funcionar está localizada na propriedade "share_target" do manifesto, que no campo "action" aponta para um URL decorado com parâmetros, conforme listado em "params".
O lado do compartilhamento preenche esse modelo de URL de acordo (facilitado por uma ação de compartilhamento ou controlado programaticamente pelo desenvolvedor usando a API Web Share), para que o lado do recebimento possa extrair os parâmetros e fazer algo com eles, como mostrá-los.
{
"action": "/_share-target",
"enctype": "multipart/form-data",
"method": "POST",
"params": {
"files": [{
"name": "media",
"accept": ["audio/*", "image/*", "video/*"]
}]
}
}
Feedback
O que você achou desta API? Responda a esta pesquisa para nos ajudar:
Essa API foi intuitiva de usar?
Você conseguiu executar o exemplo?
Quer dizer mais alguma coisa? Faltaram recursos? Envie seu feedback rápido nesta pesquisa. Agradecemos pela atenção!
6. API Wake Lock
Para evitar o descarregamento da bateria, a maioria dos dispositivos entra em estado de suspensão rapidamente quando fica ociosa. Embora isso não seja um problema na maioria das vezes, alguns apps precisam manter a tela ou o dispositivo ativado para concluir o trabalho. A API Wake Lock oferece uma maneira de impedir que o dispositivo escureça e bloqueie a tela ou entre em suspensão. Esse recurso permite novas experiências que, até agora, exigiam um app nativo.
Configurar um protetor de tela
Para testar a API wake lock, primeiro verifique se o dispositivo entraria entrará em suspensão. Portanto, no painel de preferências do seu sistema operacional, ative um protetor de tela de sua escolha e verifique se ele é iniciado após 1 minuto. Para verificar se ele funciona, deixe o dispositivo sozinho por exatamente esse tempo (sim, eu sei, é doloroso). As capturas de tela abaixo mostram o macOS, mas você pode testar isso no seu dispositivo Android ou em qualquer plataforma de computador compatível.

Definir um wake lock da tela
Agora que você sabe que o protetor de tela está funcionando, use um wake lock do tipo "screen" para impedir que ele faça o trabalho. Acesse o app de demonstração Wake Lock e clique em Ativar
Marque a caixa de seleção screen Wake Lock.

A partir desse momento, um wake lock fica ativo. Se você tiver paciência para deixar o dispositivo sem tocar por um minuto, vai perceber que o protetor de tela não foi iniciado.
Como isso funciona? Para descobrir, acesse o projeto do Glitch do app de demonstração Wake Lock e confira o script.js. O resumo do código está no snippet abaixo. Abra uma nova guia (ou use qualquer guia aberta) e cole o código abaixo em um console das Ferramentas para Desenvolvedores do Chrome. Ao clicar na janela, você vai ver um wake lock ativo por exatamente 10 segundos (consulte os logs do console), e o protetor de tela não vai iniciar.
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);
}

Feedback
O que você achou desta API? Responda a esta pesquisa para nos ajudar:
Essa API foi intuitiva de usar?
Você conseguiu executar o exemplo?
Quer dizer mais alguma coisa? Faltaram recursos? Envie seu feedback rápido nesta pesquisa. Agradecemos pela atenção!
7. API Contact Picker
Uma API que nos deixa muito animados é a API Seletor de contatos. Ele permite que um web app acesse os contatos do gerenciador de contatos nativo do dispositivo. Assim, o web app tem acesso aos nomes, endereços de e-mail e números de telefone dos seus contatos. Você pode especificar se quer apenas um ou vários contatos e se quer todos os campos ou apenas um subconjunto de nomes, endereços de e-mail e números de telefone.
Considerações sobre privacidade
Quando o seletor abrir, escolha os contatos que você quer compartilhar. Não há uma opção "Selecionar tudo", o que é proposital: queremos que o compartilhamento seja uma decisão consciente. Da mesma forma, o acesso não é contínuo, mas uma decisão única.
Acessar contatos
Acessar os contatos é uma tarefa simples. Antes de abrir o seletor, você pode especificar quais campos quer (as opções são name, email e telephone) e se quer acessar vários contatos ou apenas um. Você pode testar essa API em um dispositivo Android abrindo o aplicativo de demonstração. A seção relevante do código-fonte é essencialmente o snippet abaixo:
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);
});

8. API Async Clipboard
Como copiar e colar texto
Até agora, não havia como copiar e colar imagens de forma programática na área de transferência do sistema. Recentemente, adicionamos suporte a imagens à API Async Clipboard.
Agora você pode copiar e colar imagens. A novidade é que agora você também pode gravar imagens na área de transferência. A API assíncrona da área de transferência já oferece suporte à cópia e colagem de texto há algum tempo. Você pode copiar texto para a área de transferência chamando navigator.clipboard.writeText() e, depois, colar esse texto chamando navigator.clipboard.readText().
Copiar e colar imagens
Agora também é possível gravar imagens na área de transferência. Para isso, você precisa dos dados da imagem como um blob, que é transmitido ao construtor de itens da área de transferência. Por fim, copie o item da área de transferência chamando 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);
}
Colar a imagem de volta da área de transferência parece complicado, mas consiste apenas em recuperar o blob do item da área de transferência. Como pode haver vários, você precisa fazer um loop até encontrar o que quer. Por motivos de segurança, no momento, isso está limitado a imagens PNG, mas mais formatos podem ser aceitos no 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);
}
}
Você pode conferir essa API em ação em um app de demonstração. Os snippets relevantes do código-fonte estão incorporados acima. É possível copiar imagens para a área de transferência sem permissão, mas você precisa conceder acesso para colar conteúdo dela.

Depois de conceder acesso, você pode ler a imagem da área de transferência e colá-la no aplicativo:

9. Parabéns!
Parabéns, você chegou ao fim do codelab. Vale lembrar que a maioria das APIs ainda está em fluxo e sendo trabalhada ativamente. Por isso, a equipe agradece seu feedback, já que apenas a interação com pessoas como você nos ajudará a criar essas APIs.
Recomendamos que você acesse com frequência a página de destino de recursos. Vamos manter esse documento atualizado, e ele tem links para todos os artigos detalhados das APIs com que trabalhamos. Continue assim!
Tom e toda a equipe de recursos 🐡
