import { GetLocation, GetLocationOptions, GetLocationSuccess } from "../interface.uts" import { GetLocationFailImpl, getErrcode } from '../unierror'; import Context from 'android.content.Context'; import LocationManager from 'android.location.LocationManager'; import Criteria from 'android.location.Criteria'; import Location from 'android.location.Location'; import LocationListener from 'android.location.LocationListener'; /** * 对外的函数接口 */ export const getLocation : GetLocation = function (options : GetLocationOptions) { /** * 准备权限 */ let permissionNeed = ["android.permission.ACCESS_FINE_LOCATION"] UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, permissionNeed, function (allRight:boolean,_:string[]) { if (allRight) { // 交给目前的location 引擎,真实执行 getLocationImpl(options) } }, function (_:boolean,_:string[]) { let err = new GetLocationFailImpl(getErrcode(1505004)); options.fail?.(err) options.complete?.(err) }) } /****************************************内部功能实现****************************************************/ /** * 封装系统监听回调 */ class CustomSystemLocationListener extends LocationListener { hostRequest:LocationRequest constructor(request:LocationRequest){ super() this.hostRequest = request } override onLocationChanged(location : Location) : void { this.hostRequest.hostLocationManager.removeUpdates(this) if(this.hostRequest.hasSuccessDone == true){ /** * 已经成功返回了,则不需要继续 */ return } let ret : GetLocationSuccess = { latitude: location.getLatitude(), longitude: location.getLongitude(), speed: location.getSpeed(), accuracy: location.getAccuracy(), altitude: location.getAltitude(), verticalAccuracy: 0, horizontalAccuracy: location.getAccuracy(), address: null } // 标记已经通过系统位置返回位置 this.hostRequest.hostOption.success?.(ret) this.hostRequest.hostOption.complete?.(ret) this.hostRequest.hasSuccessDone = true } } /** * 延迟请求 */ class LocationRequest{ /** * 标记本次请求是否已经提前结束 */ hasSuccessDone:boolean = false hostOption:GetLocationOptions hostLocationManager:LocationManager constructor(options:GetLocationOptions,locationManager:LocationManager){ this.hostOption = options this.hostLocationManager = locationManager } /** * 存在预期的缓存,直接返回 */ returnLastLocation(lastLocation:Location){ let ret : GetLocationSuccess = { latitude: lastLocation.getLatitude(), longitude: lastLocation.getLongitude(), speed: lastLocation.getSpeed(), accuracy: lastLocation.getAccuracy(), altitude: lastLocation.getAltitude(), verticalAccuracy: 0, horizontalAccuracy: lastLocation.getAccuracy(), address: null } this.hostOption.success?.(ret) this.hostOption.complete?.(ret) this.hasSuccessDone = true } /** * 不存在预期的缓存,需要等待provider的位置更新 */ returnProviderUpdate(providerName:string,timeoutMill:number){ let systemListener = new CustomSystemLocationListener(this) /** * TODO * 1 0.0/2000 是否合理 * 2 providerName */ this.hostLocationManager.requestLocationUpdates(providerName, 2000, 0.0.toFloat(), systemListener) /** * 此状态下,需要同时开启一个超时检测 */ setTimeout(function () { this.hostLocationManager.removeUpdates(systemListener) if (!this.hasSuccessDone) { // 超过6s/或者设定的超时时间,尚未成功返回,则需要返回错误 let err = new GetLocationFailImpl(getErrcode(-4)); this.hostOption.fail?.(err) this.hostOption.complete?.(err) }else{ // 已经成功返回了, 则不需要处理 } }, timeoutMill); } } /** * 真实的执行位置定位 */ function getLocationImpl(options : GetLocationOptions) { /** * add since 2023-09-14 增加默认值兼容逻辑 */ if(options.type == null){ options.type = 'wgs84' } if(options.highAccuracyExpireTime == null){ options.highAccuracyExpireTime = 3000 } if(options.type != 'wgs84'){ // 系统定位只支持wgs84,如果不是则报错 let err = new GetLocationFailImpl(getErrcode(1505022)); options.fail?.(err) options.complete?.(err) return } if(options.geocode != null && options.geocode == true){ // 系统定位不支持逆地理编码 let err = new GetLocationFailImpl(getErrcode(1505023)); options.fail?.(err) options.complete?.(err) return } let locationManager = UTSAndroid.getAppContext()!.getSystemService(Context.LOCATION_SERVICE) as LocationManager; let criteria = new Criteria() // 用户明确开启了高度 if (options.altitude != null && options.altitude == true) { criteria.setAltitudeRequired(true) } // 设置精度 if (options.isHighAccuracy != null && options.isHighAccuracy == true) { criteria.setAccuracy(Criteria.ACCURACY_FINE) } else{ criteria.setAccuracy(Criteria.ACCURACY_COARSE) } criteria.setPowerRequirement(Criteria.POWER_LOW) criteria.setSpeedRequired(true) /** * 如果存在gps,那么优先gps,这样才有高度信息 */ let providerName:string|null = "gps" if(!locationManager.getProviders(criteria, true).contains("gps")){ providerName = locationManager.getBestProvider(criteria, true) } if (providerName == null) { // 没有找到合法的系统定位能力提供者,错误的逻辑 todo let err = new GetLocationFailImpl(getErrcode(1505024)); options.fail?.(err) options.complete?.(err) return; } // 默认超时6000ms let timeoutMill:number = 6000; /** * 只有设置超出3000ms 才会认为有效 * https://uniapp.dcloud.net.cn/api/location/location.html#getlocation */ if(options.highAccuracyExpireTime != null && options.highAccuracyExpireTime! >= 3000 && options.isHighAccuracy == true){ timeoutMill = options.highAccuracyExpireTime! } // 兜底的逻辑是上次定位的信息 /** * todo 是否要考虑缓存过期时间elapsedRealtimeAgeMillis */ let lastLocation = locationManager.getLastKnownLocation(providerName) let locationRequest:LocationRequest = new LocationRequest(options,locationManager) if (lastLocation != null) { // 存在预期的缓存,直接返回,即使返回缓存,也要继续走位置更新 locationRequest.returnLastLocation(lastLocation) } /** * 没有预期中的缓存,则等待位置更新 */ locationRequest.returnProviderUpdate(providerName,timeoutMill) }