Integrar com o DUST Go
O DUST Go é um navegador móvel incorporado: carrega a sua aplicação Web numa WebView e disponibiliza à página o hardware de digitalização DUST do dispositivo através de uma pequena interface JavaScript, @dustid/dust-go-connect. Pode criar e alojar uma aplicação Web comum; o DUST Go fornece a câmara, os acessórios óticos e o processo de captura — sem necessidade de uma cadeia de ferramentas nativa.
Esta página orienta-o até obter uma digitalização resolvida. Tudo o que vai além disso — início de sessão, geolocalização, compatibilidade e hardware para computador — encontra-se em Para além da primeira digitalização, abaixo.
Antes de começar
- Função
- Uma credencial de Conta de Serviço mantida pelo seu backend
- Dispositivo
- Um iPhone com o DUST Go e um acessório Loupe compatível para captura DUST
Como tudo se interliga
Seção intitulada “Como tudo se interliga”- Um utilizador abre a sua aplicação Web no DUST Go (através de uma ligação de aplicação).
- A sua página importa
@dustid/dust-go-connect; a biblioteca deteta a interface do DUST Go e disponibiliza umconnector. - A sua página chama
scanAsync(). O DUST Go abre o digitalizador nativo sobre a sua página. - Após a captura, o DUST Go envia um evento de digitalização de volta à sua página: o conteúdo transporta os dados e os metadados da captura.
- A sua página envia a captura para o seu backend, que chama a APID (
/api/v1/tags/identify,/bindou/verify) para a resolver.
Uma digitalização DUST fornece à sua página uma captura em bruto (um JPEG codificado em base64), juntamente com os metadados da captura — não um Identificador resolvido. A identificação, a verificação e a vinculação ocorrem todas no servidor.
Instalar
Seção intitulada “Instalar”npm install @dustid/dust-go-connectO pacote não tem dependências, utiliza a licença MIT e inclui tipos TypeScript.
Detetar o DUST Go
Seção intitulada “Detetar o DUST Go”A exportação connector é undefined quando a sua página não está a ser executada no DUST Go, pelo que a mesma versão da sua aplicação pode servir navegadores comuns e o DUST Go:
import { connector } from "@dustid/dust-go-connect";
export const insideDustGo = Boolean(connector);Há dois aspetos a ter em conta:
- Momento da importação. A deteção ocorre no momento da importação do módulo, no navegador. Se utilizar renderização no servidor, condicione qualquer utilização do conector à hidratação.
- Deteção no servidor. As versões recentes do DUST Go também identificam o User-Agent da WebView com
DustGo/<version> (<app id>), pelo que o seu servidor pode detetar a aplicação antes de qualquer JavaScript ser executado. Considere isto uma indicação, não um limite de segurança — qualquer pessoa pode falsificar um User-Agent.
Capturar uma digitalização
Seção intitulada “Capturar uma digitalização”O caminho mais simples é a API de promessas — apresentar o digitalizador e aguardar uma captura:
import { scanAsync } from "@dustid/dust-go-connect";
const payload = await scanAsync();// payload: { type: 'DUST' | 'QR' | 'BARCODE' | 'DATA_MATRIX' | 'NFC',// data: string, metadata?: ScanMetadata }scanAsync() devolve uma Promise<ScanPayload>. É rejeitada se o utilizador fechar o digitalizador sem efetuar uma captura e é rejeitada imediatamente quando chamada fora do DUST Go (sem um conector presente) — por isso, verifique primeiro o connector se o mesmo caminho de código for executado em navegadores comuns.
O que contém o conteúdo
Seção intitulada “O que contém o conteúdo”payload.type | payload.data | Notas |
|---|---|---|
DUST | JPEG codificado em base64 da captura DUST | Grande; resolva-o no servidor através da APID |
QR, BARCODE, DATA_MATRIX | O conteúdo descodificado do símbolo | |
NFC | O ID hexadecimal lido do chip NFC |
payload.metadata (do tipo ScanMetadata) descreve a captura: identificadores do dispositivo (deviceId, modelName, osName, osVersion, appVersion), seleção da lente/câmara e, opcionalmente, campos óticos (zoom, focagem, exposição, ISO), geolocalização (latitude/longitude/accuracy) e detalhes da origem da captura para acessórios de digitalização externos (captureSource, usbVendorId, usbProductId, dragonBackend). Encaminhe-o sem alterações ao vincular — a APID armazena-o com o Identificador.
Onde ficam as credenciais
Seção intitulada “Onde ficam as credenciais”Leia esta secção antes do passo de resolução: ela determina a estrutura de toda a sua integração.
Assim, o passo de resolução envolve dois ficheiros em dois locais:
| Ficheiro | Onde é executado | Contém a credencial DUST? |
|---|---|---|
| A sua página de digitalização | Navegador no DUST Go | Não |
O seu processador /api/dust-scan | O seu servidor | Sim |
Resolver a digitalização através da APID
Seção intitulada “Resolver a digitalização através da APID”A captura DUST só é útil depois de a APID encontrar uma correspondência. A página descodifica a captura em base64 para binário e envia-a para o seu próprio endpoint:
// No DUST credential in this file.async function identifyDustScan(base64Jpeg: string) { // The scan arrives base64-encoded; APID expects binary multipart data. const bytes = Uint8Array.from(atob(base64Jpeg), (c) => c.charCodeAt(0)); const form = new FormData(); form.set("operation", "identify"); form.set("tagType", "DUST"); form.set("data", new Blob([bytes], { type: "image/jpeg" }));
const response = await fetch("/api/dust-scan", { method: "POST", body: form, credentials: "same-origin", }); return { status: response.status, body: await response.json() };}O seu backend adiciona a credencial e o contexto e define o próprio âmbito da pesquisa:
export async function handleIdentify(form: FormData, session: Session) { // `searchTeamIds` is a JSON array of Team UUIDs. Set it on the server — a // browser-supplied scope is a request, never an authorization. form.set("searchTeamIds", JSON.stringify(session.allowedTeamIds));
const response = await fetch("https://apid.dustid.io/api/v1/tags/identify", { method: "POST", headers: { Authorization: `Bearer ${await getDustToken()}`, "Dust-Ctx-Org-Id": session.organizationId, }, body: form, });
// Pass the status and body through unchanged: the page needs to tell // "nothing matched" (404 IDENTIFIER_NOT_FOUND) from "try again" // (503 SCAN_SEARCH_INCOMPLETE). return new Response(await response.text(), { status: response.status, headers: { "Content-Type": "application/json" }, });}O campo é searchTeamIds. Os conteúdos de identificação rejeitam propriedades que não declarem, pelo que a grafia antiga searchGroupIds faz com que todo o pedido falhe com 400 INVALID_REQUEST, em vez de ser ignorada. O único nome antigo group que se mantém é o cabeçalho Dust-Ctx-Grp-Id, ainda aceite como alias de Dust-Ctx-Team-Id.
A mesma estrutura multipart serve para as outras duas operações:
/api/v1/tags/bind— adicionethreadId.options.enrollmentSessionIdé opcional: forneça um UUID gerado pelo cliente e reutilizado ao longo de uma execução quando várias capturas pertencerem ao mesmo grupo (por exemplo, uma estação de inscrição a processar um lote); omita-o para uma vinculação pontual./api/v1/tags/verify— adicionethreadIdetags, uma matriz de objetos ([{ "tagId": "…", "tagType": "DUST" }], codificada em JSON no multipart), não strings de ID.tagsé obrigatório.
Consulte Identificadores para ver os contratos completos dos pedidos e respostas e o Digitalizador React para obter um componente pronto a copiar que implementa as três operações através de um processador de backend como o apresentado acima.
Testar a integração
Seção intitulada “Testar a integração”- Instale o DUST Go através da App Store ou do Google Play (consulte Dispositivos compatíveis para conhecer os requisitos de hardware — a captura DUST necessita de um acessório ótico compatível).
- Disponibilize a sua aplicação por HTTPS num URL acessível pelo dispositivo (um endereço de LAN é adequado para desenvolvimento).
- No DUST Go, adicione o seu URL como uma ligação de aplicação personalizada e abra-o.
- Verifique se o conector é detetado e, em seguida, efetue uma digitalização.
- Confirme que a captura chega ao seu backend e que a chamada DUST efetuada pelo backend devolve um resultado que pode apresentar — incluindo o caso «sem correspondência».
Está disponível no repositório do pacote uma página mínima de diagnóstico que testa toda a interface (deteção, scanAsync e registo de eventos).
Para além da primeira digitalização
Seção intitulada “Para além da primeira digitalização”Tudo o que se segue é opcional. Regresse a esta secção depois de conseguir resolver uma única digitalização de ponta a ponta.
Fluxos de trabalho com várias digitalizações
Seção intitulada “Fluxos de trabalho com várias digitalizações”Para fluxos em que são efetuadas várias digitalizações antes do envio, utilize a API de listeners — o digitalizador permanece aberto entre capturas:
import { connector } from "@dustid/dust-go-connect";
connector?.add("my-listener", (event) => { switch (event.type) { case "scan": handleScan(event.payload); break; case "hide": // scanner closed case "show": // scanner opened break; default: // Ignore unknown event types — the protocol may grow. break; }});
connector?.showScanner();// later: connector?.hideScanner(); connector?.remove("my-listener");addScanListener faz o mesmo sem a gestão de listeners — recebe todas as digitalizações e devolve a sua própria função de cancelamento da subscrição:
import { addScanListener } from "@dustid/dust-go-connect";
const stop = addScanListener((payload) => handleScan(payload));// later: stop();Uma sessão do digitalizador pode fornecer uma série de capturas, pelo que deve enviá-las uma de cada vez. Um conteúdo DUST é um JPEG grande em base64; carregar vários em simultâneo satura a ligação e não fornece ao operador qualquer indicação útil do progresso. Coloque os conteúdos numa fila e aguarde a conclusão de cada envio antes de iniciar o seguinte.
O que o digitalizador pode fazer
Seção intitulada “O que o digitalizador pode fazer”As aplicações anfitriãs diferem — um telemóvel pode ajustar o zoom e a exposição, um acessório de microscópio USB disponibiliza um conjunto diferente de controlos e uma versão mais antiga pode não disponibilizar nenhum. Consulte as capacidades em vez de as inferir a partir do User-Agent:
const capabilities = connector?.getCapabilities?.();Considere uma declaração ausente ou vazia como apenas capturas individuais, sem qualquer parâmetro ajustável. Nunca interprete o silêncio como uma capacidade.
Geolocalização
Seção intitulada “Geolocalização”As chamadas comuns a navigator.geolocation funcionam no DUST Go — a aplicação encaminha-as de forma transparente através do pedido de permissão do sistema operativo nativo. Não é necessário código do conector.
Fluxos de início de sessão no DUST Go
Seção intitulada “Fluxos de início de sessão no DUST Go”Se a sua aplicação utilizar OAuth/OIDC, tenha em atenção que o DUST Go transfere as navegações para fornecedores de identidade externos para o navegador do sistema e que a chamada de retorno regressa à sua página através de um esquema de URL personalizado.
Ao construir um redirect_uri OAuth na página, envolva-o sempre da seguinte forma:
import { connector } from "@dustid/dust-go-connect";
const origin = window.location.origin;const redirectUri = ( connector?.rewriteRedirect(new URL(`${origin}/auth/callback`)) ?? new URL(`${origin}/auth/callback`)).href;Fora do DUST Go (e em aplicações anfitriãs onde não seja necessária qualquer reescrita), isto não produz qualquer alteração. No DUST Go, substitui o protocolo do URL pelo esquema personalizado da aplicação, produzindo um URI como com.dustidentity.dustgo://your-host/auth/callback (o esquema exato provém da versão do DUST Go; dustgo é a alternativa), que o seu fornecedor de identidade tem de ter registado como URI de redirecionamento permitido.
Controlo de versões e compatibilidade
Seção intitulada “Controlo de versões e compatibilidade”A interface utiliza um protocolo numerado. A página anuncia os eventos que compreende através de um processo hello automático no momento da importação e a aplicação anfitriã envia apenas os eventos anunciados pela página — deste modo, uma aplicação anfitriã mais antiga e uma página mais recente continuam a funcionar em conjunto através de uma redução das funcionalidades, em vez de falharem.
Leia o número a partir do pacote que instalou, não a partir desta página: o SDK exporta-o.
import { CONNECT_PROTOCOL_VERSION } from "@dustid/dust-go-connect";| Protocolo | Adições |
|---|---|
| 1 | O contrato antigo implícito: scan / hide / show, sem processo de negociação. |
| 2 | O processo de negociação hello e o evento calibrationResult. |
| 3 | A declaração capabilities da aplicação anfitriã para a página, o comando runCapture da página para a aplicação anfitriã e o evento captureStatus que lhe responde. |
| 4 | CaptureRequirements.app (uma política de versão da aplicação imposta pela aplicação anfitriã) e CaptureCapabilities.enforcedRequirements, para que uma página consiga distinguir uma aplicação anfitriã que verifica um requisito de outra que o ignoraria. |
| 5 | ScanPayload.exif — os dados EXIF fotográficos da captura, com a respetiva proveniência. Totalmente aditivo. |
| 6 | O comando capturePhoto da página para a aplicação anfitriã e o evento photo que lhe responde: uma fotografia comum (por exemplo, um anexo de um Registo), deliberadamente distinta de uma digitalização. |
O SDK na árvore de código-fonte desta documentação é o @dustid/dust-go-connect 0.2.0, que utiliza o protocolo 6. Não se afirma aqui o que o registo npm público disponibiliza atualmente — verifique CONNECT_PROTOCOL_VERSION e o campo version do pacote que instalou e contacte a DUST Identity se necessitar de uma versão específica.
Regras que permanecem válidas independentemente do número da versão:
- A deteção de capacidades em tempo de execução é a fonte de autoridade. Um número de protocolo indica o que o SDK da página consegue expressar; nada diz sobre a aplicação anfitriã do outro lado ou sobre o hardware ligado. Consulte as capacidades com
getCapabilities()e considere uma declaração ausente como «apenas capturas individuais, sem qualquer parâmetro ajustável». - Utilize
event.typenas instruçõesswitche ignore o que não reconhecer. São adicionados novos tipos de eventos; uma página que gera uma exceção perante um tipo desconhecido deixa de funcionar após uma atualização da aplicação anfitriã com a qual nunca teria de se preocupar. - Um controlo manual na interface de uma aplicação anfitriã não é uma capacidade do protocolo e um comando de hardware bem-sucedido não prova que o valor tenha sido aplicado no momento da captura.
- Os eventos
calibrationResulteackCalibrationResults()são mecanismos internos dos fluxos de trabalho de calibração da DUST — as integrações de terceiros podem ignorá-los.
Controlos do Dragon para computador
Seção intitulada “Controlos do Dragon para computador”Esta secção refere-se a um Dragon ligado a um computador de secretária, controlado a partir de um navegador comum através da aplicação complementar. Não se refere ao percurso Android: no DUST Go para Android, a própria aplicação controla o Dragon ligado e as respetivas capturas chegam através do fluxo runCapture comum descrito acima — createDragonClient() não intervém e não é instalada nenhuma aplicação complementar no telemóvel. Consulte Dispositivos compatíveis.
O seu site pode controlar a pré-visualização do Dragon e os respetivos controlos de focagem. A aplicação complementar instalada processa os comandos USB em segundo plano. Na primeira utilização, os utilizadores aprovam o seu site no DUST Camera Controls e concedem ao navegador acesso à câmara e ao dispositivo local quando solicitado. A aprovação é memorizada para esse site e navegador. O site tem de utilizar HTTPS. O Camera Controls pode permanecer na barra de menus com a janela fechada; não é necessária qualquer janela de contexto de ligação. Não é necessário nenhum site alojado pela DUST.
Instale o DUST Camera Controls em Aplicações e abra-o uma vez. A aplicação indica se o Dragon está ligado e permanece disponível na barra de menus. O arranque no início de sessão está ativado por predefinição; pode desativá-lo na aplicação.
Os instaladores de cada plataforma encontram-se na página Transferências. As distribuições com atualizações ativadas procuram atualizações automaticamente e disponibilizam a opção Procurar atualizações… na barra de menus. Cabe-lhe escolher quando instalar uma atualização; guarde o seu trabalho e conclua a digitalização antes de reiniciar a aplicação. As versões de avaliação sem uma fonte de atualizações necessitam de um instalador de substituição fornecido pela DUST.
No DICE, abra Digitalizar, selecione DUST, ative Controlos de focagem do Dragon sob o digitalizador e escolha Ligar na primeira utilização. Após a aprovação, a área de visualização disponibiliza focagem automática, definições de focagem e a opção Digitalizar através da operação selecionada. Quando regressa a Digitalizar com o modo ativado, o DICE volta a estabelecer automaticamente a ligação se o Camera Controls estiver em execução e o navegador ainda tiver acesso à câmara. Se as permissões do navegador necessitarem de intervenção, escolha Ligar ou Iniciar câmara para concluir a ligação.
import { createDragonClient } from "@dustid/dust-go-connect";
const dragon = createDragonClient();const video = document.querySelector("video")!;
// First use: request native approval and browser permissions from a user action.connectButton.onclick = async () => { try { await dragon.connect(); await dragon.openVideo(video); const controls = await dragon.getControls(); const focus = controls.find((control) => control.name === "focus"); // Use focus.min / focus.max for your manual slider when focus is available. } catch (error) { showConnectionError(error); }};
// On a later visit, reuse approval without creating a native approval prompt.// If this rejects, present Connect Dragon; do not repeatedly request approval.// await dragon.connect({ interactive: false });// Reopen video only after browser camera permission has already been granted.
manualSlider.onchange = async () => { await dragon.setControl("focus", Number(manualSlider.value));};
autofocusButton.onclick = async () => { try { const result = await dragon.autofocus(video, { radius: Number(autofocusRangeSlider.value), onProgress: ({ position, sampled }) => showProgress(position, sampled), }); manualSlider.value = String(result.position); // "low-contrast" means autofocus retained the starting focus. showFocusResult(result.outcome); } catch (error) { showFocusError(error); }};cancelButton.onclick = () => dragon.cancelAutofocus();
captureButton.onclick = async () => { const payload = await dragon.capture(video); // Send the raw DUST JPEG to your server, which calls the Identifier API. await sendToYourServer(payload);};
const unsubscribe = dragon.onState(({ connected, controls }) => { updateDeviceUI(connected, controls);});// On page/component teardown: unsubscribe(); dragon.dispose();Apenas uma sessão de um site pode controlar o Dragon de cada vez. O utilizador pode revogar o acesso através de Gerir acesso de sites… no Camera Controls. Fechar a janela nativa mantém a ligação disponível; encerrar a aplicação interrompe-a. Uma sessão aprovada recebe atualizações do estado do dispositivo quando o Dragon se desliga ou volta a ligar. Reabra o vídeo após uma nova ligação. Ligar o hardware não concede silenciosamente aos sites acesso ao mesmo.
A focagem automática pesquisa em torno do último comando de focagem, dentro dos limites do intervalo calibrado do dispositivo. O respetivo controlo deslizante de intervalo representa a distância de cada lado dessa posição inicial. Mantenha a página visível e a amostra imóvel, com o detalhe pretendido no centro da imagem. Uma amostra sem características distintivas ou com pouca iluminação pode não fornecer contraste suficiente para selecionar a focagem. Verifique a imagem resultante antes da captura.
Os valores de focagem são comandos, não posições medidas da lente. Estes métodos de controlo manual não garantem as definições no momento do disparo nem permitem capturas prescritas ou combinadas. O digitalizador móvel e o respetivo contrato scanAsync() existente continuam disponíveis de forma independente.
Conteúdo relacionado
Seção intitulada “Conteúdo relacionado”- Identificadores — a API através da qual esta integração resolve as capturas.
- Erros e resultados da digitalização — as tabelas de resultados que a sua interface de digitalização deve considerar.
- Dispositivos compatíveis — o hardware necessário para a captura DUST.
- Digitalizador React — o mesmo fluxo sem o DUST Go, utilizando a câmara do dispositivo.
- Desenvolver com agentes de IA — uma competência de agente que abrange esta integração, destinada a agentes de programação.