import { GetLocation, GetLocationOptions, GetLocationSuccess } from "../interface.uts" import UTSAndroid from 'io.dcloud.uts.UTSAndroid'; 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 : string[] = utsArrayOf("android.permission.ACCESS_FINE_LOCATION"); UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, permissionNeed, function (allRight:boolean,_grantedList:string[]) { if (allRight) { // 交给目前的location 引擎,真实执行 getLocationImpl(options) } }, function (_doNotAskAgain:boolean,_grantedList:string[]) { console.log("用户拒绝了部分权限:") let err = new UniError("uni-getLocation-system",-10,"permission missed."); options.fail?.(err) options.complete?.(err) }) } /****************************************内部功能实现****************************************************/ /** * 全局信息处理 */ class Global { /** * 默认实现 */ static lastLocation : Location | null = null; } /** * 封装系统监听回调 */ class CustomSystemLocationListener extends LocationListener { override onLocationChanged(location : Location) : void { Global.lastLocation = location } } /** * 真实的执行位置定位 */ 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 UniError("uni-getLocation-system",-1,"system location support wgs84 only."); options.fail?.(err) options.complete?.(err) return } if(options.geocode != null && options.geocode == true){ // 系统定位不支持逆地理编码 let err = new UniError("uni-getLocation-system",-2,"system location not support geocode."); 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 UniError("uni-getLocation-system",-3,"Provider is not find,Please ensure that the device location function is turned on"); options.fail?.(err) options.complete?.(err) return; } // 兜底的逻辑是上次定位的信息 Global.lastLocation = locationManager.getLastKnownLocation(providerName) let systemListener = new CustomSystemLocationListener() locationManager.requestLocationUpdates(providerName, 2000, 0.0.toFloat(), systemListener) // 默认超时6000ms let timeoutMill:number = 6000; /** * 只有设置超出3000ms 才会认为有效 * https://uniapp.dcloud.net.cn/api/location/location.html#getlocation */ if(options.highAccuracyExpireTime != null && options.highAccuracyExpireTime! >= 3000){ timeoutMill = options.highAccuracyExpireTime! } let taskId = 0 let startTimeMill = (new Date()).getTime() // 不管返回结果如何,延迟2s 返回数据 taskId = setInterval(function () { if (Global.lastLocation == null) { // 没有得到想要的位置,统计错误计数+1 let currentTimeMill = (new Date()).getTime() let diffTimeNum = currentTimeMill - startTimeMill if (diffTimeNum > timeoutMill) { locationManager.removeUpdates(systemListener) // 超过6s了,返回错误 clearInterval(taskId) let err = new UniError("uni-getLocation-system",-4,"location fail: timeout"); options.fail?.(err) options.complete?.(err) } } else { locationManager.removeUpdates(systemListener) clearInterval(taskId) let ret : GetLocationSuccess = { latitude: Global.lastLocation!.getLatitude(), longitude: Global.lastLocation!.getLongitude(), speed: Global.lastLocation!.getSpeed(), accuracy: Global.lastLocation!.getAccuracy(), altitude: Global.lastLocation!.getAltitude(), verticalAccuracy: 0, horizontalAccuracy: Global.lastLocation!.getAccuracy(), address: null } options.success?.(ret) Global.lastLocation = null } }, 2000); }