Desenvolver aplicações web responsivas que funcionem adequadamente em diferentes plataformas móveis requer técnicas específicas de detecção do sistema operacional do dispositivo. Este artigo apresenta abordagens práticas para identificar Android, iOS e HarmonyOS, coletar dados do dispositivo e direcionar usuários para as lojas de aplicativos corretas.
Identificando a Plataforma do Dispositivo Através do User-Agent
A propriedade navigator.userAgent fornece informações detalhadas sobre o navegador e sistema opreacional do usuário. Analisando essa string, é possível determinar se o dispositivo é Apple, Android ou Huawei/Honor (HarmonyOS).
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Identificador de Plataforma Móvel</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.info-card {
background: white;
border-radius: 16px;
padding: 24px;
max-width: 400px;
width: 90%;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
.info-card h2 { color: #333; margin-bottom: 16px; }
.detail-row { padding: 8px 0; border-bottom: 1px solid #eee; }
.label { font-weight: 600; color: #555; }
.value { color: #2196F3; word-break: break-all; }
.hint-msg {
display: none;
background: #FFF3CD;
border-radius: 8px;
padding: 12px;
margin-top: 12px;
text-align: center;
}
</style>
</head>
<body>
<div class="info-card">
<h2>Detecção de Plataforma</h2>
<div id="platform-result"></div>
<div class="hint-msg" id="hint-msg">
Toque nos três pontos (⋮) no canto superior e selecione "Abrir no navegador"
</div>
</div>
<script>
const PlatformDetector = {
_ua: navigator.userAgent,
isIOS() {
return /iPhone|iPad|iPod/i.test(this._ua);
},
isAndroid() {
return /Android/i.test(this._ua);
},
isHuawei() {
return /HUAWEI|HONOR|HarmonyOS/i.test(this._ua);
},
isXiaomi() {
return /Xiaomi|Redmi|POCO|MIUI/i.test(this._ua);
},
isSamsung() {
return /Samsung|SM-/i.test(this._ua);
},
isWeChat() {
return /MicroMessenger/i.test(this._ua);
},
getPlatform() {
if (this.isIOS()) return 'iOS';
if (this.isHuawei()) return 'HarmonyOS';
if (this.isXiaomi()) return 'Xiaomi (Android)';
if (this.isSamsung()) return 'Samsung (Android)';
if (this.isAndroid()) return 'Android';
return 'Desconhecido';
}
};
function exibirResultado() {
const plataforma = PlatformDetector.getPlatform();
const container = document.getElementById('platform-result');
const detalhes = [
['Plataforma', plataforma],
['User Agent', navigator.userAgent],
['Linguagem', navigator.language],
['Conectado', navigator.onLine ? 'Sim' : 'Não'],
['Cookies', navigator.cookieEnabled ? 'Habilitados' : 'Desabilitados']
];
container.innerHTML = detalhes.map(([rotulo, valor]) =>
`<div class="detail-row">
<span class="label">${rotulo}:</span>
<span class="value">${valor}</span>
</div>`
).join('');
if (PlatformDetector.isWeChat()) {
document.getElementById('hint-msg').style.display = 'block';
}
}
exibirResultado();
</script>
</body>
</html>
Redirecionamento Inteligente para Lojas de Aplicativos
Uma funcionalidade comum é redirecionar usuários para a loja de aplicativos correspondente ao seu dispositivo. O código abaixo implementa uma solução completa que detecta a marca do dispositivo e redireciona para a loja apropriada, incluindo tratamento para navegadores embutidos em aplicativos como WeChat e QQ.
<script>
const AppStoreRedirector = {
APP_ID: 'com.example.meuapp',
LOJAS: {
apple: 'https://apps.apple.com/br/app/id123456789',
huawei: 'appmarket://details?id=com.example.meuapp',
xiaomi: 'mimarket://details?id=com.example.meuapp',
oppo: 'oppomarket://details?packagename=com.example.meuapp',
vivo: 'vivomarket://details?id=com.example.meuapp',
samsung: 'samsungapps://ProductDetail/com.example.meuapp',
androidGenerico: 'https://exemplo.com/downloads/meuapp.apk'
},
navegaEmbutido() {
const ua = navigator.userAgent.toLowerCase();
if (/micromessenger/i.test(ua)) return 'wechat';
if (/qq\//i.test(ua)) return 'qq';
if (/alipay/i.test(ua)) return 'alipay';
return null;
},
identificarFabricante() {
const ua = navigator.userAgent;
if (/iPhone|iPad|iPod/i.test(ua)) return 'apple';
if (/HUAWEI|HONOR|HarmonyOS/i.test(ua)) return 'huawei';
if (/OPPO|PACM00/i.test(ua)) return 'oppo';
if (/vivo/i.test(ua)) return 'vivo';
if (/Xiaomi|Redmi|POCO|MIUI|Mi\s/i.test(ua)) return 'xiaomi';
if (/Samsung|SM-/i.test(ua)) return 'samsung';
return 'desconhecido';
},
executarRedirecionamento() {
const navegador = this.navegaEmbutido();
if (navegador) {
this.mostrarAvisoNavegador(navegador);
return;
}
const fabricante = this.identificarFabricante();
const urlDestino = this.LOJAS[fabricante] || this.LOJAS.androidGenerico;
window.location.href = urlDestino;
},
mostrarAvisoNavegador(tipo) {
const nomes = { wechat: 'WeChat', qq: 'QQ', alipay: 'Alipay' };
const nome = nomes[tipo] || 'este aplicativo';
alert(`Você está navegando pelo ${nome}. Para continuar, abra esta página no navegador padrão do seu dispositivo.`);
}
};
AppStoreRedirector.executarRedirecionamento();
</script>
Verificando a Instalação de um Aplicativo via Deep Link
É possível verificar se um aplicativo está instalado tentando abrir um esquema de URL (URI scheme) específico. Se o aplicativo estiver presente, ele será aberto; caso contrário, após um tempo limite, o usuário é redirecionado para a loja.
<script>
const AppAvailabilityChecker = {
TEMPO_ESPERA: 2500,
_temporizador: null,
verificarESolicitar(esquemaApp, urlDownload) {
const ua = navigator.userAgent;
const ehIOS = /iPhone|iPad|iPod/i.test(ua);
const ehAndroid = /Android/i.test(ua);
const ehWechat = /MicroMessenger/i.test(ua);
if (ehWechat) {
alert('Por favor, abra esta página no navegador do seu dispositivo.');
return;
}
if (!ehIOS && !ehAndroid) {
alert('Esta funcionalidade é exclusiva para dispositivos móveis.');
return;
}
this._tentarAbrirApp(esquemaApp, urlDownload);
},
_tentarAbrirApp(esquema, fallbackUrl) {
const inicio = Date.now();
// Listener para detectar perda de foco (app abriu)
const aoPerderFoco = () => {
if (Date.now() - inicio < this.TEMPO_ESPERA + 500) {
clearTimeout(this._temporizador);
document.removeEventListener('visibilitychange', aoVisibilidadeMudou);
}
};
const aoVisibilidadeMudou = () => {
if (document.hidden) aoPerderFoco();
};
document.addEventListener('visibilitychange', aoVisibilidadeMudou);
// Tentar abrir o aplicativo
window.location.href = esquema;
// Fallback: redirecionar para download se o app não abrir
this._temporizador = setTimeout(() => {
document.removeEventListener('visibilitychange', aoVisibilidadeMudou);
// Verificar se a página ainda está visível
const oculto = document.hidden ||
document.webkitHidden ||
document.msHidden;
if (!oculto) {
window.location.href = fallbackUrl;
}
}, this.TEMPO_ESPERA);
}
};
// Exemplo de uso para o aplicativo de SMS
// AppAvailabilityChecker.verificarESolicitar(
// 'sms:',
// 'https://loja.exemplo.com/meuapp'
// );
</script>
Consultando Propriedades do Navigator
O objeto navigator disponibiliza diversas propriedades úteis para diagnóstico. Veja como listar as principais informações:
<div id="diagnostico"></div>
<script>
function listarPropriedadesNavigator() {
const container = document.getElementById('diagnostico');
const propriedades = {
'appCodeName': navigator.appCodeName,
'appName': navigator.appName,
'appVersion': navigator.appVersion,
'userAgent': navigator.userAgent,
'platform': navigator.platform,
'language': navigator.language,
'cookieEnabled': navigator.cookieEnabled,
'onLine': navigator.onLine,
'hardwareConcurrency': navigator.hardwareConcurrency,
'maxTouchPoints': navigator.maxTouchPoints,
'vendor': navigator.vendor
};
let html = '<table border="1" cellpadding="8" cellspacing="0">';
html += '<tr><th>Propriedade</th><th>Valor</th></tr>';
for (const [chave, valor] of Object.entries(propriedades)) {
html += `<tr>
<td><strong>${chave}</strong></td>
<td>${valor}</td>
</tr>`;
}
html += '</table>';
container.innerHTML = html;
}
listarPropriedadesNavigator();
</script>
Considerações sobre Compatibilidade
A detecção baseada em userAgent apresenta limitações importantes:
- Navegadores podem enviar strings de user agent modificadas ou incorretas.
- A propriedade
userAgentestá marcada como obsoleta pela especificação HTML, embora ainda amplamente suportada. - Para detecção mais confiável, combine a análise do user agent com a propriedade
navigator.userAgentDatadisponível em navegadores Chromium. - Alguns navegadores embutidos em aplicativos bloqueiam redirecionamentos para lojas — sempre ofereça uma instrução para o usuário abrir no navegador externo.
- Testes em dispositivos reais são essenciais, pois simuladores nem sempre reproduzem fielmente os comportamantos de navegação nativos.