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:
- Compartilhamento Contínuo de Conteúdo: Permite o compartilhamento instantâneo de texto, texto rico e dados personalizados entre diferentes dispositivos.
- Suporte a Múltiplos Tipos de Dados: Atende a várias necessidades de aplicativos, desde texto simples até dados estruturados personalizados complexos.
- 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.
- 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.