Compartilhamento de Dados da Área de Transferência entre Dispositivos no HarmonyOS

A funcionalidade de área de transferência entre dispositivos no HarmonyOS permite aos usuários copiar conteúdo em um dispositivo e colá-lo em outro dispositivo logado com a mesma conta. Essa capacidade quebra as barreiras entre dispositivos, oferecendo aos desenvolvedores uma nova maneira de compartilhar conteúdo.

Nota Importante: Todos os exemplos de código neste artigo são baseados no HarmonyOS Next API 10+ e DevEco Studio 4.0+. Certifique-se de que seu ambiente de desenvolvimento esteja configurado corretamente.

Preparação do Ambiente de Desenvolvimento

Pré-requisitos

  • Sistema de Contas: Todos os dispositivos devem estar logados na mesma conta Huawei.

Configuração de Permissões

A área de transferência entre dispositivos requer a seguinte permissão. Adicione-a ao arquivo module.json5 do seu módulo:


{
 "module": {
   "requestPermissions": [
     {
       "name": "ohos.permission.DISTRIBUTED_DATASYNC"
     }
   ]
 }
}
 

Operações Básicas da Área de Transferência

Área de Transferência de Dispositivo Único

Primeiro, vamos entender as operações básicas da área de transferência, que são a base para a funcionalidade entre dispositivos:


import { pasteboard } from "@kit.ArkData";

// Cria um objeto PasteData
let pasteData = pasteboard.createData("text/plain");

// Define o conteúdo de texto
pasteData.addText("Olá HarmonyOS!");

// Escreve na área de transferência
pasteboard
 .setSystemPasteData(pasteData)
 .then(() => {
   console.info("Dados escritos na área de transferência com sucesso");
 })
 .catch((err: BusinessError) => {
   console.error(`Falha ao escrever dados: ${err.code}, ${err.message}`);
 });
 

Lendo Dados da Área de Transferência


// Lê dados da área de transferência
pasteboard
 .getSystemPasteData()
 .then((data: pasteboard.PasteData) => {
   if (data) {
     // Verifica e obtém o conteúdo de texto
     if (data.hasType(pasteboard.MIMETYPE_TEXT_PLAIN)) {
       let text = data.getPrimaryText();
       console.info(`Texto recuperado: ${text}`);
     }
   }
 })
 .catch((err: BusinessError) => {
   console.error(`Falha ao ler dados: ${err.code}, ${err.message}`);
 });
 

Implementação da Área de Transferência entre Dispositivos

Visão Geral das APIs Principais

A área de transferência entre dispositivos depende principalmente das seguintes APIs:

Nome da API Descrição da Função Cenários de Uso
createData() Cria um objeto de dados da área de transferência Inicialização de dados
addText() Adiciona conteúdo de texto Cópia de dados de texto
addHtml() Adiciona conteúdo HTML Cópia de texto rico
addPixelMap() Adiciona dados de imagem Cópia de imagem
setSystemPasteData() Define a área de transferência do sistema Operação de escrita
getSystemPasteData() Obtém a área de transferência do sistema Operação de leitura

Implementação Completa de Cópia entre Dispositivos


import { pasteboard } from "@kit.ArkData";
import { BusinessError } from "@kit.BasicServicesKit";

class CrossDeviceClipboard {
 /**
  * Copia texto para a área de transferência entre dispositivos.
  * @param text O conteúdo de texto a ser copiado.
  */
 async copyTextToCrossDevice(text: string): Promise<void> {
   try {
     // 1. Cria os dados da área de transferência
     let pasteData = pasteboard.createData("text/plain");

     // 2. Adiciona o conteúdo de texto
     pasteData.addText(text);

     // 3. Define um rótulo de propriedade (opcional, para identificar o aplicativo)
     pasteData.addProperty("sourceApp", "com.example.myapp");

     // 4. Escreve na área de transferência do sistema (sincroniza automaticamente com outros dispositivos)
     await pasteboard.setSystemPasteData(pasteData);

     console.info("Texto copiado para a área de transferência entre dispositivos");
   } catch (err) {
     let error = err as BusinessError;
     console.error(`Cópia falhou: ${error.code}, ${error.message}`);
     throw error;
   }
 }

 /**
  * Cola texto da área de transferência entre dispositivos.
  */
 async pasteTextFromCrossDevice(): Promise<string | null> {
   try {
     // 1. Obtém os dados da área de transferência
     let pasteData = await pasteboard.getSystemPasteData();

     if (!pasteData) {
       console.info("A área de transferência está vazia");
       return null;
     }

     // 2. Verifica o tipo de dados
     if (pasteData.hasType(pasteboard.MIMETYPE_TEXT_PLAIN)) {
       // 3. Obtém o conteúdo de texto
       let text = pasteData.getPrimaryText();
       console.info(`Texto colado: ${text}`);
       return text;
     } else {
       console.info("A área de transferência não contém dados de texto");
       return null;
     }
   } catch (err) {
     let error = err as BusinessError;
     console.error(`Colagem falhou: ${error.code}, ${error.message}`);
     throw error;
   }
 }
}
 

Processamento de Conteúdo de Texto Rico

Além de texto puro, a área de transferência entre dispositivos também suporta conteúdo de texto rico:


class RichTextClipboard {
 /**
  * Copia conteúdo HTML para a área de transferência entre dispositivos.
  */
 async copyHtmlContent(): Promise<void> {
   let htmlContent = `
     <h1>Guia de Desenvolvimento HarmonyOS</h1>
     <p>Este é texto em <strong>negrito</strong> e <em>itálico</em></p>
     <ul>
       <li>Item de lista 1</li>
       <li>Item de lista 2</li>
     </ul>
   `;

   let pasteData = pasteboard.createData("text/html");
   pasteData.addHtml(htmlContent);

   // Adiciona uma versão de texto puro como alternativa
   pasteData.addText(
     "Guia de Desenvolvimento HarmonyOS - Este é texto em negrito e itálico - Item de lista 1 - Item de lista 2"
   );

   await pasteboard.setSystemPasteData(pasteData);
   console.info("Conteúdo HTML copiado para a área de transferência entre dispositivos");
 }

 /**
  * Cola conteúdo HTML.
  */
 async pasteHtmlContent(): Promise<{ html?: string; text?: string }> {
   let pasteData = await pasteboard.getSystemPasteData();

   if (!pasteData) {
     return {};
   }

   let result: { html?: string; text?: string } = {};

   // Prioriza a obtenção do conteúdo HTML
   if (pasteData.hasType(pasteboard.MIMETYPE_TEXT_HTML)) {
     result.html = pasteData.getPrimaryHtml();
   }

   // Alternativa de texto puro
   if (pasteData.hasType(pasteboard.MIMETYPE_TEXT_PLAIN)) {
     result.text = pasteData.getPrimaryText();
   }

   return result;
 }
}
 

Implementação de Recursos Avançados

Tipos de Dados Personalizados

Para estruturas de dados específicas do aplicativo, você pode usar tipos MIME personalizados:


// Define um tipo MIME personalizado
const MIMETYPE_APP_DATA = "application/vnd.example.appdata+json";

class CustomDataClipboard {
 /**
  * Copia dados personalizados para a área de transferência.
  */
 async copyCustomData(userData: object): Promise<void> {
   try {
     let pasteData = pasteboard.createData(MIMETYPE_APP_DATA);

     // Converte o objeto para uma string JSON
     let jsonData = JSON.stringify(userData);
     pasteData.addText(jsonData);

     // Adiciona propriedades para marcar a origem dos dados
     pasteData.addProperty("dataType", "userProfile");
     pasteData.addProperty("timestamp", Date.now().toString());

     await pasteboard.setSystemPasteData(pasteData);
     console.info("Dados personalizados copiados para a área de transferência");
   } catch (err) {
     let error = err as BusinessError;
     console.error(`Cópia de dados personalizados falhou: ${error.code}, ${error.message}`);
   }
 }

 /**
  * Cola e analisa dados personalizados.
  */
 async pasteCustomData(): Promise<object | null> {
   try {
     let pasteData = await pasteboard.getSystemPasteData();

     if (!pasteData || !pasteData.hasType(MIMETYPE_APP_DATA)) {
       return null;
     }

     let jsonString = pasteData.getPrimaryText();
     let userData = JSON.parse(jsonString);

     // Valida a origem dos dados (opcional)
     let dataType = pasteData.getProperty("dataType");
     if (dataType === "userProfile") {
       console.info("Dados personalizados válidos recebidos");
       return userData;
     }

     return null;
   } catch (err) {
     let error = err as BusinessError;
     console.error(
       `Colagem de dados personalizados falhou: ${error.code}, ${error.message}`
     );
     return null;
   }
 }
}
 

Monitoramento de Mudanças na Área de Transferência

Monitore as mudanças no conteúdo da área de transferência em tempo real:


class ClipboardMonitor {
 private listener: pasteboard.SystemPasteboardChangedListener | null = null;

 /**
  * Inicia o monitoramento de mudanças na área de transferência.
  */
 startMonitoring(): void {
   this.listener = (pasteData: pasteboard.PasteData) => {
     console.info("Conteúdo da área de transferência alterado");

     if (pasteData) {
       // Verifica o tipo do novo conteúdo
       if (pasteData.hasType(pasteboard.MIMETYPE_TEXT_PLAIN)) {
         let text = pasteData.getPrimaryText();
         console.info(`Novo conteúdo de texto: ${text}`);
       }

       if (pasteData.hasType(pasteboard.MIMETYPE_TEXT_HTML)) {
         console.info("Novo conteúdo HTML disponível");
       }

       // Verifica o dispositivo de origem dos dados
       let sourceDevice = pasteData.getProperty("sourceDevice");
       if (sourceDevice) {
         console.info(`Dados do dispositivo: ${sourceDevice}`);
       }
     }
   };

   // Registra o listener
   pasteboard.on("systemPasteboardChanged", this.listener);
   console.info("Monitoramento da área de transferência iniciado");
 }

 /**
  * Para o monitoramento.
  */
 stopMonitoring(): void {
   if (this.listener) {
     pasteboard.off("systemPasteboardChanged", this.listener);
     this.listener = null;
     console.info("Monitoramento da área de transferência parado");
   }
 }
}
 

Estudo de Caso Prático: Compartilhamento de Notas entre Dispositivos

Vamos construir um aplicativo completo de compartilhamento de notas entre dispositivos:


import { pasteboard } from "@kit.ArkData";
import { BusinessError } from "@kit.BasicServicesKit";
import { UIAbility, AbilityConstant, Want } from "@kit.AbilityKit";

class CrossDeviceNoteApp {
 private readonly MIMETYPE_NOTE = "application/vnd.notepad.note+json";

 /**
  * Copia uma nota para outros dispositivos.
  */
 async copyNoteToDevices(note: Note): Promise<void> {
   try {
     let pasteData = pasteboard.createData(this.MIMETYPE_NOTE);

     // Constrói os dados da nota
     let noteData = {
       title: note.title,
       content: note.content,
       createdAt: note.createdAt,
       category: note.category,
     };

     pasteData.addText(JSON.stringify(noteData));

     // Adiciona metadados
     pasteData.addProperty("dataType", "crossDeviceNote");
     pasteData.addProperty("version", "1.0");
     pasteData.addProperty("sourceApp", "NotePadApp");

     await pasteboard.setSystemPasteData(pasteData);

     console.info(`Nota "${note.title}" copiada para a área de transferência entre dispositivos`);
   } catch (err) {
     let error = err as BusinessError;
     console.error(`Cópia da nota falhou: ${error.code}, ${error.message}`);
     throw new Error("Falha ao copiar nota para outros dispositivos");
   }
 }

 /**
  * Importa uma nota da área de transferência.
  */
 async importNoteFromClipboard(): Promise<Note | null> {
   try {
     let pasteData = await pasteboard.getSystemPasteData();

     if (!pasteData || !pasteData.hasType(this.MIMETYPE_NOTE)) {
       return null;
     }

     // Valida o formato dos dados
     let dataType = pasteData.getProperty("dataType");
     if (dataType !== "crossDeviceNote") {
       return null;
     }

     let jsonString = pasteData.getPrimaryText();
     let noteData = JSON.parse(jsonString);

     // Cria o objeto Note
     let note: Note = {
       title: noteData.title || "Nota Importada",
       content: noteData.content || "",
       createdAt: noteData.createdAt || Date.now(),
       category: noteData.category || "Geral",
       sourceDevice: pasteData.getProperty("sourceDevice") || "Desconhecido",
     };

     console.info(`Nota importada do dispositivo: ${note.sourceDevice}`);
     return note;
   } catch (err) {
     let error = err as BusinessError;
     console.error(`Importação da nota falhou: ${error.code}, ${error.message}`);
     return null;
   }
 }

 /**
  * Limpa a área de transferência entre dispositivos.
  */
 async clearCrossDeviceClipboard(): Promise<void> {
   try {
     await pasteboard.clearSystemPasteData();
     console.info("Área de transferência entre dispositivos limpa");
   } catch (err) {
     let error = err as BusinessError;
     console.error(`Limpeza da área de transferência falhou: ${error.code}, ${error.message}`);
   }
 }
}

// Definição do tipo de dados da Nota
interface Note {
 title: string;
 content: string;
 createdAt: number;
 category: string;
 sourceDevice?: string;
}
 

Otimização de Desempenho e Melhores Práticas

Limitação de Tamanho dos Dados

A área de transferência entre dispositivos tem um limite de tamanho de dados que requer gerenciamento cuidadoso:


class ClipboardOptimizer {
 private readonly MAX_TEXT_SIZE = 1024 * 1024; // 1MB

 /**
  * Otimiza a cópia de dados de texto grandes.
  */
 async copyLargeTextOptimized(text: string): Promise<void> {
   if (text.length > this.MAX_TEXT_SIZE) {
     console.warn("Texto excede o limite de tamanho, truncando...");
     text = text.substring(0, this.MAX_TEXT_SIZE);
   }

   let pasteData = pasteboard.createData("text/plain");
   pasteData.addText(text);

   await pasteboard.setSystemPasteData(pasteData);
 }

 /**
  * Processa conteúdo grande em blocos.
  */
 async copyLargeContentInChunks(
   largeContent: string,
   chunkSize: number = 50000
 ): Promise<void> {
   let chunks: string[] = [];

   for (let i = 0; i < largeContent.length; i += chunkSize) {
     chunks.push(largeContent.substring(i, i + chunkSize));
   }

   // Copia apenas o primeiro bloco, outros blocos transferidos por outros meios
   if (chunks.length > 0) {
     let pasteData = pasteboard.createData("text/plain");
     pasteData.addText(chunks[0]);
     pasteData.addProperty("totalChunks", chunks.length.toString());
     pasteData.addProperty("contentId", this.generateContentId());

     await pasteboard.setSystemPasteData(pasteData);
   }
 }

 private generateContentId(): string {
   return `content_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
 }
}
 

Considerações e Perguntas Frequentes

Dicas de Segurança Improtantes

Aviso de Segurança: - A área de transferência pode conter informações confidenciais; garanta que seu aplicativo tenha uma política de privacidade clara.

  • Não leia o conteúdo da área de transferência automaticamente; isso deve ser acionado pelo usuário.
  • Limpe regularmente os dados da área de transferência que não são mais necessários.

Compatibilidade de Versão

Versão HarmonyOS Suporte à Área de Transferência entre Dispositivos Observações
API 10+ Suporte total Exemplos neste artigo são baseados nesta versão
API 9 Suporte parcial Faltam alguns recursos avançados
API 8 e anteriores Não suportado Requer atualização da versão de destino

Tratamento de Erros Comuns


class ClipboardErrorHandler {
 static handleCommonErrors(error: BusinessError): string {
   const ERROR_CODES = {
     201: "Permissão negada - Verifique a permissão DISTRIBUTED_DATASYNC",
     202: "Erro de parâmetro - Verifique os parâmetros de entrada",
     203: "Tempo limite da operação - Problema de conectividade de rede",
     204: "Serviço indisponível - Serviço entre dispositivos não está em execução",
   };

   let errorCode = error.code.toString();
   return (
     ERROR_CODES[errorCode] || `Erro desconhecido: ${error.code}, ${error.message}`
   );
 }

 // Exemplo de uso
 static async safeClipboardOperation(
   operation: () => Promise<void>
 ): Promise<boolean> {
   try {
     await operation();
     return true;
   } catch (err) {
     let error = err as BusinessError;
     let errorMessage = this.handleCommonErrors(error);
     console.error(`Falha na operação da área de transferência: ${errorMessage}`);
     return false;
   }
 }
}
 

Dicas de Depuração


class ClipboardDebugger {
 /**
  * Depura o conteúdo da área de transferência.
  * @param verbose Se deve exibir informações detalhadas.
  */
 static async debugClipboard(verbose: boolean = false): Promise<void> {
   try {
     console.info('=== Informações de Depuração da Área de Transferência ===');

     // Obtém os dados da área de transferência
     let pasteData = await pasteboard.getSystemPasteData();

     if (!pasteData) {
       console.info('A área de transferência está atualmente vazia');
       return;
     }

     // Verifica os tipos de dados
     console.info('Tipos de dados disponíveis:');

     const MIME_TYPES = [
       {type: pasteboard.MIMETYPE_TEXT_PLAIN, label: 'Texto Puro'},
       {type: pasteboard.MIMETYPE_TEXT_HTML, label: 'HTML'},
       {type: pasteboard.MIMETYPE_IMAGE_PIXELMAP, label: 'Imagem'}
     ];

     for (const {type, label} of MIME_TYPES) {
       if (pasteData.hasType(type)) {
         console.info(`- ${label}`);

         // Exibe prévia do conteúdo
         if (verbose) {
           if (type === pasteboard.MIMETYPE_TEXT_PLAIN) {
             let text = pasteData.getPrimaryText();
             // Limita o comprimento da saída
             let preview = text.length > 100 ? text.substring(0, 100) + '...' : text;
             console.info(`  Prévia do conteúdo: ${preview}`);
           } else if (type === pasteboard.MIMETYPE_TEXT_HTML) {
             let html = pasteData.getPrimaryHtml();
             let preview = html.length > 100 ? html.substring(0, 100) + '...' : html;
             console.info(`  Prévia do HTML: ${preview}`);
           }
         }
       }
     }

     // Exibe informações de propriedades
     if (verbose) {
       console.info('\nPropriedades da área de transferência:');

       // Obtém todas as chaves de propriedade
       const properties = ['sourceApp', 'dataType', 'timestamp', 'sourceDevice', 'version'];

       for (const prop of properties) {
         let value = pasteData.getProperty(prop);
         if (value) {
           console.info(`- ${prop}: ${value}`);
         }
       }
     }

     console.info('=== Depuração Concluída ===');

   } catch (err) {
     let error = err as BusinessError;
     console.error(`Depuração falhou: ${error.code}, ${error.message}`);
   }
 }

 /**
  * Monitora mudanças na área de transferência e registra logs.
  */
 static enableMonitoringLog(): () => void {
   console.info('Habilitando logs de monitoramento da área de transferência');

   const listener = (pasteData: pasteboard.PasteData) => {
     console.log('EVENTO ÁREA DE TRANSFERÊNCIA:', new Date().toISOString());

     if (pasteData) {
       // Verifica o tipo principal do conteúdo
       if (pasteData.hasType(pasteboard.MIMETYPE_TEXT_PLAIN)) {
         let text = pasteData.getPrimaryText();
         console.log('  Novo conteúdo de texto (comprimento):', text?.length || 0);
       }

       // Verifica se os dados são de outro dispositivo
       let sourceDevice = pasteData.getProperty('sourceDevice');
       if (sourceDevice) {
         console.log('  Dados entre dispositivos de:', sourceDevice);
       }
     }
   };

   pasteboard.on('systemPasteboardChanged', listener);
   console.info('Monitor da área de transferência anexado');

   // Retorna uma função de limpeza
   return () => {
     pasteboard.off('systemPasteboardChanged', listener);
     console.info('Monitor da área de transferência desanexado');
   };
 }
}
 

Resumo e Perspectivas

Resumo das Capacidades Principais

A área de transferência entre dispositivos é um recurso poderoso no ecossistema HarmonyOS, oferecendo aos desenvolvedores as seguintes capacidades essenciais:

  1. Compartilhamento Contínuo de Conteúdo: Permite o compartilhamento instantâneo de texto, texto rico e dados personalizados entre diferentes dispositivos.
  2. Suporte a Múltiplos Tipos de Dados: Atende a várias necessidades de aplicativos, desde texto simples até dados estruturados personalizados complexos.
  3. Sincronização de Dados em Tempo Real: Utiliza tecnologia de sincronização de dados distribuídos para garantir a transferência de conteúdo rápida e confiável.
  4. Mecanismo de Escuta de Eventos: Responde às mudanças de conteúdo da área de transferência em tempo real através de um padrão de listener.

Recomendações de Desenvolvimento

Ao implementar a funcionalidade de área de transferência entre dispositivos, é recomendável seguir estas melhores práticas:

  • Declaração de Permissões: Certifique-se de declarar corretamente a permissão DISTRIBUTED_DATASYNC.
  • Tratamento de Erros: Implemente um traatmento de erros abrangente, especialmente para possíveis problemas de rede ou sincronização em operações entre dispositivos.
  • Segurança de Dados: Ao lidar com informações confidenciais, considere estratégias de criptografia e limpeza oportuna.
  • Experiência do Usuário: Forneça feedback claro ao usuário, indicando que o conteúdo foi copiado com sucesso para outros dispositivos.
  • Otimização de Desempenho: Utilize processamento em blocos para arquivos grandes para evitar exceder os limites de tamanho da área de transferência.

Direções Futuras de Desenvolvimento

Com o desenvolvimento contínuo do ecossistema HarmonyOS, a funcionalidade de área de transferência entre dispositivos provavelmente será aprimorada nas seguintes áreas:

  • Suporte a Mais Tipos de Mídia: No futuro, pode haver suporte para mais tipos de conteúdo de mídia, como videoclipes, arquivos de áudio, etc.
  • Reconhecimento Inteligente de Conteúdo: Identificação automática do tipo de conteúdo copiado e oferta de sugestões de processamento.
  • Seleção de Dispositivos: Permite que os usuários selecionem dispositivos de destino específicos para compartilhamento de conteúdo.
  • Gerenciamento de Histórico: Fornece um histórico da área de transferência para facilitar aos usuários a revisão e reutilização de conteúdo.

Ao utilizar a funcionalidade de área de transferência entre dispositivos de forma eficaz, os desenvolvedores podem criar experiências de aplicativos multidispositivo mais imersivas e coesas, permitindo que os usuários alternem perfeitamente os fluxos de trabalho entre diferentes dispositivos, aumentando significativamente a eficiência e a conveniência.

Recomendação Final: Na aplicação prática, sempre respeite a privacidade do usuário, evite o uso indevido da funcionalidade da área de transferência e forneça opções claras de controle ao usuário.

Tags: HarmonyOS Área de Transferência Compartilhamento entre Dispositivos desenvolvimento de aplicativos APIs Distribuídas

Publicado em 6-7 02:45 por Thomas