Integração do Amap em Aplicativos H5 com UniApp e Desenvolvimento de Funcionalidades Personalizadas

Por que integrar o Amap no lado H5 do UniApp?

Ao desenvolver uma aplicação H5 com a framework UniApp e necessitar de funcionalidades de mapas, você pode se deparar com uma limitação específica. O componente nativo <map> da UniApp, quando renderizado em ambiente H5, utiliza por padrão os mapas do Tencent ou Google. Para desenvolvedores no contexto chinês que preferem ou necessitam das capacidades mais ricas e prceisas do Amap (AutoNavi Maps), como planejamento de rotas detalhado, destaque de áreas administrativas ou o avançado sistema de agrupamento de marcadores (clustering), o uso do componente padrão apresenta restrições significativas.

Em um projeto recente, a demanda era exibir um grande número de estabelecimentos comerciais em uma página de evento, com agrupamento eficiente. O componente padrão demonstrou limitações tanto no estilo quanto na funcionalidade de agrupamento no H5. A solução consiste em ignorar o componente <map> padrão e integrar diretamente a JavaScript API do Amap. Este guia visa conduzi-lo por esse processo, demonstrando como incorporar o Amap em suas páginas H5 do UniApp e explorar funcionalidades avançadas.

O benefício central é: superar as limitações da plataforma padrão e obter capacidades de mapa mais potentes e personalizáveis. A API JS do Amap oferece controle de baixo nível, essencial para a exibição fluida de milhares de marcadores ou para interações complexas. Comecemos pelos preparativos iniciais.

Preparação Inicial: Solicitação de Chave e Configuração de Segurança

Antes de escrever qualquer código, é obrigatório solicitar uma Chave de Desenvolvedor na plataforma aberta do Amap. Sem esta chave, o mapa não carregará. Embora o processo seja direto, alguns detalhes são cruciais para evitar problemas de depuração.

Acesse a plataforma aberta do Amap, registre-se e faça login. No painel de controle, navegue até "Gerenciamento de Aplicativos" > "Minhas Aplicações" e crie uma nova aplicação. Selecione o tipo como "Web (JS API)". Após a criação, você receberá duas informações críticas: a Key e o securityJsCode (chave de segurança). Atualmente, o Amap exige a configuração de segurança para todas as chaves. Ignorar esta etapa resultará em erros de permissão confusos no console do navegador.

A configuração de segurança envolve definir o parâmetro securityJsCode e configurar uma lista de domínios permitidos. Dentro da aplicação recém-criada, clique em "Configurações" ao lado da Key. Certifique-se de que "Web Service" e "Web (JS API)" estejam habilitados. O passo mais importante é, em "Configurações de Segurança", habilitar a "Chave de segurança da Web (JS API)" e gerar um securityJsCode. Anote-o. Adicionalmente, na seção "Plataforma de Serviço", adicione os domínios onde sua aplicação H5 será executada (ex.: localhost, 127.0.0.1 para testes locais, e seu domínio de produção). Sem isso, o mapa não carregará no ambiente correspondente.

Com a Key e o securityJsCode em mãos, a integração no projeto UniApp ocorrerá no código JavaScript. Para manter o projeto ogranizado, recomenda-se ainda preencher a configuração de mapa no manifest.json > Configurações H5 > Mapa, selecionando Amap e inserindo a Key. Isso garante compatibilidade caso outras partes do projeto utilizem o componente de mapa padrão.

Dois Esquemas de Integração Principais

Com os preparativos concluídos, existem duas abordagens principais para incorporar o Amap na sua aplicação H5.

Esquema 1: Utilizando Web-View para Carregar um Arquivo HTML Independente

Esta abordagem é estável e utiliza um arquivo HTML dedicado. A lógica do mapa é escrita em HTML/JS puro, e este arquivo é carregado dentro da aplicação UniApp usando o componente <web-view>.

Passo a Passo:

  1. Crie uma pasta hybrid/html na raiz do seu projeto UniApp (diretório reservado para recursos HTML locais). Dentro dela, crie um arquivo map_display.html.
  2. Dentro de map_display.html, desenvolva a lógica completa do mapa. A inicialização requer a inclusão do Loader da API JS do Amap e a configuração da segurança. Veja um exemplo de estrutura modificada:

<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Visualização do Mapa Amap</title>
    <style>
        .map-area {
            width: 100%;
            height: 100vh;
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
    <div class="map-area" id="mapContainer"></div>

    <script>
        // 1. Configuração de Segurança Necessária
        window._AMapSecurityConfig = {
            securityJsCode: 'SEU_SECURITY_JSCODE_AQUI'
        };

        // 2. Carregamento Assíncrono da API
        function initMapModule() {
            const scriptTag = document.createElement('script');
            scriptTag.src = 'https://webapi.amap.com/loader.js';
            scriptTag.onload = setupMap;
            document.head.appendChild(scriptTag);
        }

        function setupMap() {
            AMapLoader.load({
                key: 'SUA_AMAP_KEY_AQUI',
                version: '2.0',
                plugins: ['AMap.Scale', 'AMap.ToolBar']
            }).then(function(AMapCore) {
                // 3. Instanciando o Mapa
                const mapInstance = new AMapCore.Map('mapContainer', {
                    zoom: 14,
                    viewMode: '2D',
                    center: [116.407395, 39.904211] // Coordenadas de Pequim
                });

                // 4. Adicionando Marcadores (Exemplo Modificado)
                const markerPoints = [
                    { lng: 116.39, lat: 39.91, label: 'Ponto A' },
                    { lng: 116.41, lat: 39.92, label: 'Ponto B' }
                ];

                markerPoints.forEach(function(point) {
                    const marker = new AMapCore.Marker({
                        position: new AMapCore.LngLat(point.lng, point.lat),
                        title: point.label,
                        offset: new AMapCore.Pixel(-10, -10)
                    });
                    mapInstance.add(marker);
                });

                // 5. (Opcional) Lógica para Reagir a Mensagens do UniApp
                window.addEventListener('message', function(event) {
                    // Processar dados recebidos do componente web-view
                });

            }).catch(function(err) {
                console.error('Erro ao carregar a API do Amap:', err);
            });
        }

        // Iniciar o processo
        initMapModule();
    </script>
</body>
</html>

  1. No seu arquivo Vue do UniApp, utilize o componente <web-view> para carregar este arquivo HTML local.
<template>
  <view class="map-page-container">
    <web-view :src="mapResourceUrl" @message="handleWebViewMessage"></web-view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      mapResourceUrl: '/hybrid/html/map_display.html'
    }
  },
  methods: {
    handleWebViewMessage(event) {
      // Processar mensagens recebidas do HTML interno
      const messageData = event.detail.data;
      console.log('Dados recebidos do mapa:', messageData);
    }
  }
}
</script>

Vantagens: Isolamento completo, comportamento previsível, ideal para mapas complexos que requerem controle total. Desvantagens: Comunicação com o restante da aplicação UniApp requer a troca de mensagens via postMessage.

Esquema 2: Integrando Diretamente em uma Página Vue do UniApp

Esta abordagem carrega a API do Amap diretamente dentro do ciclo de vida de um componente Vue, mantendo tudo em um único contexto.

<template>
  <view class="page-wrapper">
    <div class="map-wrapper" ref="mapElementRef"></div>
    <button @click="addRandomMarker">Adicionar Marcador Aleatório</button>
  </view>
</template>

<script>
let amapCore = null; // Variável de escopo para o módulo AMap
let currentMapInstance = null;

export default {
  data() {
    return {
      markersList: []
    }
  },
  mounted() {
    this.loadAmapScript();
  },
  beforeDestroy() {
    // Limpar instância do mapa ao desmontar o componente
    if (currentMapInstance) {
      currentMapInstance.destroy();
      currentMapInstance = null;
    }
  },
  methods: {
    loadAmapScript() {
      if (window.AMap) {
        this.initializeMapWithAMap(window.AMap);
        return;
      }
      // Configurar segurança antes de carregar o loader
      window._AMapSecurityConfig = {
        securityJsCode: 'SEU_SECURITY_JSCODE_AQUI'
      };
      const script = document.createElement('script');
      script.src = 'https://webapi.amap.com/loader.js';
      script.onload = () => {
        this.fetchAndInitMap();
      };
      document.head.appendChild(script);
    },

    fetchAndInitMap() {
      AMapLoader.load({
        key: 'SUA_AMAP_KEY_AQUI',
        version: '2.0',
        plugins: []
      }).then(AMapModule => {
        amapCore = AMapModule;
        this.initializeMapWithAMap(AMapModule);
      }).catch(err => {
        uni.showToast({ title: 'Falha ao carregar mapa', icon: 'none' });
      });
    },

    initializeMapWithAMap(AMap) {
      this.$nextTick(() => {
        if (this.$refs.mapElementRef) {
          currentMapInstance = new AMap.Map(this.$refs.mapElementRef, {
            zoom: 12,
            resizeEnable: true,
            center: [121.472644, 31.231706] // Coordenadas de Xangai
          });
          // Adicionar escala e barra de ferramentas após a inicialização
          currentMapInstance.addControl(new AMap.Scale());
        }
      });
    },

    addRandomMarker() {
      if (!currentMapInstance || !amapCore) return;
      // Gerar coordenada aleatória próxima ao centro
      const baseLng = 121.472644;
      const baseLat = 31.231706;
      const randomOffset = () => (Math.random() - 0.5) * 0.02;
      const position = new amapCore.LngLat(baseLng + randomOffset(), baseLat + randomOffset());

      const newMarker = new amapCore.Marker({
        position: position,
        content: '<div style="background:#007bff;color:white;padding:2px 5px;border-radius:3px;font-size:12px;">Novo</div>'
      });
      currentMapInstance.add(newMarker);
      this.markersList.push(newMarker);
      currentMapInstance.setFitView(); // Ajustar visualização para incluir todos os marcadores
    }
  }
}
</script>

<style scoped>
.page-wrapper { height: 100vh; display: flex; flex-direction: column; }
.map-wrapper { flex: 1; } /* O container do mapa deve ter dimensão definida */
button { padding: 10px; margin: 10px; background: #4CAF50; color: white; border: none; }
</style>

Vantagens: Integração mais direta com a lógica do aplicativo Vue, compartilhamento fácil de dados via propriedades e eventos. Desvantagens: Requer atenção ao ciclo de vida do componente para evitar erros de acesso a DOM não renderizado ou mapas não destruídos.

A escolha entre os esquemas depende da complexidade do mapa e do nível de integração desejado com a lógica principal do aplicativo UniApp. Ambos os métodos fornecem acesso completo à poderosa API do Amap.

Tags: uniapp H5 AMap JavaScript API Web-View

Publicado em 7-16 00:57