由于与 ionic://localhost 的不安全连接(在 cordova-ios 上),对地理定位的访问被阻止

Access to geolocation was blocked over insecure connection to ionic://localhost (on cordova-ios)

我正在尝试使用我创建的 "location.service" 获取移动设备的位置和方向(罗盘航向)。它曾经在 android 和 ios 上工作,现在在 ios 上工作,我得到了位置,但设备方向错误。

[blocked] Access to geolocation was blocked over insecure connection to ionic://localhost.

Geolocation PositionError {code: 1, message: "Origin does not have permission to use Geolocation service"

我已经在 *.plist 文件上尝试了所有这些:

我正在使用:

当我在 iPhone (ios 13.4.1) 上 cordova build ios, 运行 它来自 Xcode 并检查 Safari 的开发控制台:

location.service:

import {Injectable} from '@angular/core';
import {BehaviorSubject, combineLatest, fromEvent, Observable, of, timer} from 'rxjs';
import {HttpClient} from '@angular/common/http';
import {map, switchMap} from 'rxjs/operators';
import { Globals } from '../globals';

export interface DefiLocation {
  accuracy: number;
  altitude: number;
  altitudeAccuracy: number;
  heading: number;
  latitude: number;
  longitude: number;
  speed: number;
  compass: number;
}

@Injectable({
  providedIn: 'root'
})
export class LocationService {
  errorMessage$: string;
  currentLocation$: BehaviorSubject<{
    accuracy?: number,
    altitude: number,
    altitudeAccuracy: number,
    heading: number,
    latitude: number,
    longitude: number,
    speed: number
  }> = new BehaviorSubject({
    accuracy: 0,
    altitude: 0,
    altitudeAccuracy: 0,
    heading: 0,
    latitude: 32.5,
    longitude: 35,
    speed: 0,
  });

  currentCompass$: BehaviorSubject<number> = new BehaviorSubject(0);
  currentCompass: number = 0;
  currentPosition: {
    accuracy: 0,
    altitude: 0,
    altitudeAccuracy: 0,
    heading: 0,
    latitude: 32.5,
    longitude: 35,
    speed: 0,
  };
  locationTimer;
  sendLocationError: boolean = true;

  constructor(public globals: Globals) {
    this.isCurrentPosition$.next(true);
    this.trackMe();
  }

  private trackMe() {
    if (this.globals.iphone) {
        window.addEventListener('deviceorientation', (event) => {
          this.currentCompass$.next(Math.round(event['webkitCompassHeading']));
        });
      // }
    } else {
      window.addEventListener('deviceorientationabsolute', (event) => {
        this.currentCompass$.next(360 - Math.round(event['alpha']));
      }, true);
    }


    if (navigator.geolocation) {
      this.locationTimer = timer(0, 100).subscribe(tick => {
        navigator.geolocation.getCurrentPosition((position) => {
          this.currentLocation$.next(position.coords);
          this.isCurrentPosition$.next(true);
          this.sendLocationError = true;
        }, (err) => {
          this.isCurrentPosition$.next(false);
          this.sendError(err.message);
          console.log(err);
          this.errorMessage$ = err.message;
          console.log(this.errorMessage$);
        }, {
          enableHighAccuracy: true
        });
      });

    } else {
      alert('Geolocation is not supported by this browser.');
      this.sendError('navigator.geolocation = null ("Geolocation is not supported by this browser.")');
    }
  }

  getCurrentLocation$(): Observable<DefiLocation> {
    return combineLatest(this.currentCompass$.asObservable(), this.currentLocation$.asObservable())
      .pipe(
        map(([compass, location]) => {
            return {
              longitude: location.longitude,
              latitude: location.latitude,
              accuracy: location.accuracy,
              altitude: location.altitude,
              altitudeAccuracy: location.altitudeAccuracy,
              heading: location.heading,
              speed: location.speed,
              compass
            };
          }
        ));
  }

  sendError(error) {
    if (this.sendLocationError) {
      this.sendLocationError = false;
      window['cordova'].plugins.firebase.analytics.logEvent('user_location_failed', {param1: error});
      setTimeout(function() { this.sendLocationError = true; }, 5000);
    }
  }
}

原来错误消息与设备的位置无关(当我修复位置时错误仍然存​​在)。方向有点问题,但我有一个答案:

  1. 位置 - 当我请求 .plist 文件中的所有正确权限时,我收到了正确的位置。 Here is a nice explanation about the permissions. BTW, i'm using cordova-plugin-geolocation.
  2. 方位(罗盘)-根据“Safari 13 Release Notes”:

Added a permission API on iOS for DeviceMotionEvent and DeviceOrientationEvent.

一个。权限 API - Up-until 现在,Chrome 和 Safari 只显示关于“在没有用户手势的情况下询问设备方向”的警告,但是在 ios 13+ 上苹果又采取了一步并且完全阻止了它。 The full w3c discussion在下面的 last 代码示例中请求权限的正确方法示例。

b。 old/new 替代方案 (cordova-plugin-device-orientation) - 因为这种行为在应用程序中确实不自然,所以我尝试了一个使用本机资源的旧的已弃用插件,它起作用了,幸运的是,现在该插件实际上未被弃用!


我的带有回退的完整代码

  1. 尝试在设备就绪时向浏览器请求位置和方向许可(适应 android 和 ios)。
  2. 如果没有,请尝试 orientation-plugin(本机资源)。
  3. 如果不是,则在 ios13+ 网络协议状态下请求用户手势许可。

此 运行 在设备上就绪:

private trackMe() {

    // compass listener (also ios13+ fallback at "compassPremissioniOS13" funtion)
    if (typeof DeviceOrientationEvent['requestPermission'] !== 'function') {
      const deviceOrientationLestener = (event) => {
        if (this.globals.iphone) {
          this.currentCompass$.next(event['webkitCompassHeading']);
        } else {
          if (event.absolute) {
            this.currentCompass$.next(360 - event.alpha);
          } else {
            window.removeEventListener('deviceorientation', deviceOrientationLestener);
            window.addEventListener('deviceorientationabsolute', (eventB) => {
              this.currentCompass$.next(360 - eventB['alpha']);
            }, true);
          }
        }
      };
      window.addEventListener('deviceorientation', deviceOrientationLestener);
    }  else {
      document.addEventListener('deviceready', () => {
        navigator['compass'].watchHeading((head) => {
          this.currentCompass$.next(head.trueHeading);
        }, (error) => console.log(error), {frequency: 10});
      }, false);
    }

    // GET LOCATION - energy saving and preformance inhancing for mobile, dumm and cyclic for desktop.
    if (this.globals.cordova) {
      document.addEventListener('deviceready', () => {
        if (navigator.geolocation) {
          navigator.geolocation.watchPosition((position) => {
            this.currentLocation$.next(position.coords);
            this.isCurrentPosition$.next(true);
            this.sendLocationError = true;
          }, (err) => {
            this.isCurrentPosition$.next(false);
            this.sendError(err.message);
            this.errorMessage$ = err.message;
          }, {
            enableHighAccuracy: true
          });
        } else {
          alert('Geolocation is not supported by this browser.');
          this.sendError('navigator.geolocation = null ("Geolocation is not supported by this browser.")');
        }
      }, false);
    } else {
      if (navigator.geolocation) { // fallback for desktop testing
        this.locationTimer = timer(0, 100).subscribe(tick => {
          navigator.geolocation.getCurrentPosition((position) => {
            this.currentLocation$.next(position.coords);
            this.isCurrentPosition$.next(true);
            this.sendLocationError = true;
          }, (err) => {
            this.isCurrentPosition$.next(false);
            this.sendError(err.message);
            this.errorMessage$ = err.message;
          }, {
            enableHighAccuracy: true
          });
        });
      } else {
        alert('Geolocation is not supported by this browser.');
        this.sendError('navigator.geolocation = null ("Geolocation is not supported by this browser.")');
      }
    }
  }

用户按下导航按钮时 运行 秒:

compassPremissioniOS13$() {
    return new Promise((resolve, reject) => {
      if (navigator.geolocation) {
        if (typeof DeviceOrientationEvent['requestPermission'] === 'function') {
          DeviceOrientationEvent['requestPermission']()
            .then(permissionState => {
              if (permissionState === 'granted') {
                window.addEventListener('deviceorientation', (event) => {
                  this.currentCompass$.next(event['webkitCompassHeading']);
                });
                resolve('User accepted');
              } else {
                reject('User declined');
              }
            })
            .catch(console.error);
        }
      } else {
        alert('deviceorientation is not supported by this browser.');
        this.sendError('deviceorientation = null ("deviceorientation is not supported by this browser.")');
      }
    });
  }