You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ionic6安卓模拟器Google Maps多标记不显示问题排查修复

问题根因
  • 经纬度类型不兼容:接口返回的经纬度多为字符串格式,桌面浏览器的Google Maps JS SDK会自动做隐式类型转换,但安卓WebView环境下SDK类型校验更严格,字符串经纬度无法被google.maps.LatLng正确解析,直接导致标记渲染失败。
  • 地图实例重复初始化:每次调用addMarkersToMap都会重新创建Map实例,安卓WebView的DOM渲染性能弱于桌面浏览器,旧实例未销毁、新实例就挂载的操作会导致图层状态错乱,标记无法正常挂载到图层上。
  • 条件判断逻辑错误:接口返回校验写为response != null || response != undefined,该逻辑恒为真——哪怕response是null/undefined,判断条件也会成立,此时如果传入结构异常的driverList(比如undefined、非数组),会直接触发JS报错中断渲染,安卓端WebView的报错默认不会明显提示,很容易被忽略。
  • 变更检测触发不合理:this.cdr.detectChanges()写在forEach循环内部,每添加一个标记就触发一次全量变更检测,会导致安卓WebView频繁重绘DOM,标记还没完成挂载就被重绘流程打断。
  • Marker配置传入无效属性:初始化Marker时额外传入了SDK不识别的latitude、longitude字段,部分WebView版本下会触发SDK内部校验报错,中断标记渲染。
  • 图层覆盖问题:渲染路线时没有清空旧的路线图层,当路线图层z-index高于标记层时,会直接遮盖已渲染的标记。
修复方案

修复逻辑遵循几个原则:地图实例全局只初始化一次、所有入参做类型校验、渲染前清空旧图层、减少不必要的变更检测触发。

  1. 把地图初始化逻辑移到页面视图加载完成的生命周期(Angular下为ngAfterViewInit),全局只初始化一次,同时提前初始化路线渲染器、创建数组存储已生成的标记实例方便后续清理。
  2. 所有传入地图SDK的经纬度强制转为Number类型,过滤无效经纬度点,避免类型不兼容报错。
  3. 修正接口返回的判断逻辑,同时校验driverList为有效数组后再执行标记渲染。
  4. 移除Marker配置中SDK不识别的自定义属性,所有标记添加完成后只触发一次变更检测。
  5. 每次渲染新标记、新路线前先清空旧的标记和路线图层,避免图层堆叠覆盖。

修复后的核心代码如下:

// 页面视图加载完成后执行,仅初始化一次地图
ngAfterViewInit() {
  const centerPosition = { lat: 23.8042, lng: 90.3667 };
  this.map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10,
    center: centerPosition,
  });
  // 初始化路线渲染器
  this.directionsRenderer = new google.maps.DirectionsRenderer();
  // 存储已创建的标记实例,用于后续清理
  this.existMarkers = [];
}

getCurrentPosition() {
  navigator.geolocation.getCurrentPosition((pos) => {
    this.updateLocation.latitude = String(pos.coords.latitude);
    this.updateLocation.longitude = String(pos.coords.longitude);
    this.updateLocation.phoneNumber = this.phoneNoValue.value;
    this.updateLocation.userType = UserType.Customer;
    this.updateLocationService.updateLocation(this.updateLocation).subscribe(async (response) => {
      // 修正判断逻辑,同时校验司机列表为有效数组
      if (response && Array.isArray(response.driverList)) {
        this.driverList = response.driverList;
        this.addMarkersToMap(this.driverList);
        const toast = await this.toastController.create({
          message: 'Location Updated',
          duration: 2000,
          position: 'bottom',
          color: 'tertiary',
        });
        await toast.present();
      }
    });
  });
}

addMarkersToMap(driverList) {
  // 先清空所有已存在的旧标记
  this.existMarkers.forEach(marker => marker.setMap(null));
  this.existMarkers = [];

  driverList.forEach(element => {
    // 强制将经纬度转为数值类型,兼容安卓WebView
    const lat = Number(element.latitude);
    const lng = Number(element.longitude);
    // 过滤无效经纬度,避免渲染报错
    if (isNaN(lat) || isNaN(lng)) return;

    const myLatLng = new google.maps.LatLng(lat, lng);
    const marker = new google.maps.Marker({
      position: myLatLng,
      map: this.map
      // 移除SDK不识别的自定义latitude、longitude字段
    });
    this.existMarkers.push(marker);
  });
  // 所有标记渲染完成后,仅触发一次变更检测
  this.cdr.detectChanges();
}

async calculateAndDisplayRoute() {
  this.directionsService.route(
    {
      origin: { query: this.sourceLocation },
      destination: { query: this.destinationLocation.input },
      travelMode: google.maps.TravelMode.DRIVING,
    },
    (response, status) => {
      console.log('google', response);
      this.googleMapResponse = response;
      if (status == "OK") {
        // 先解绑旧路线图层,再渲染新路线,避免图层堆叠
        this.directionsRenderer.setMap(null);
        this.directionsRenderer.setMap(this.map); 
        this.directionsRenderer.setDirections(response);

        this.driver.userLatitude = String(response.routes[0].legs[0].start_location.lat());
        this.driver.userLongitude = String(response.routes[0].legs[0].start_location.lng());
        this.driver.phoneNumber = this.phoneNoValue.value;
        this.driver.destinationLatitude = String(response.routes[0].legs[0].end_location.lat());
        this.driver.destinationLongitude = String(response.routes[0].legs[0].end_location.lng());
        this.driver.pickupLocation = response.routes[0].legs[0].start_address;

        this.rideRequestService.getDriverList(this.driver).subscribe(async (res) => {
          if (res && Array.isArray(res.driverList)) {
            this.driverLocaiton.phoneNumber = res.phoneNumber;
            this.driverLocaiton.driverList = res.driverList;
            this.driverLocaiton.rideFareModelList = res.rideFareModelList;
            // 拿到最新司机列表后同步渲染标记
            this.addMarkersToMap(res.driverList);

            const toast = await this.toastController.create({
              message: 'Location Updated',
              duration: 2000,
              position: 'bottom',
              color: 'tertiary',
            });
            await toast.present();
            this.isExpand = false;
          }
          await Storage.set({key: 'google',  value: `${JSON.stringify(response)}`});
        });
      } else {
        window.alert("Direction req failed due to" + status);
      }
    }
  )
  this.isExpand = false;
}
调试提示
  • 确保安卓模拟器已安装Google Play服务,否则WebView内的Maps SDK会出现功能异常。
  • 调试安卓端WebView时,可在桌面Chrome打开chrome://inspect/#devices连接模拟器,直接查看WebView控制台的报错信息,排查效率更高。
  • 安卓配置文件config.xml中需要给WebView开启DOM存储权限,同时放行Google Maps相关域名的访问请求,避免资源被拦截。

内容的提问来源于stack exchange,提问作者Ataur Rahman Shaon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 11:39:39