index.uts 6.4 KB
Newer Older
杜庆泉's avatar
杜庆泉 已提交
1
import { GetLocation, GetLocationOptions, GetLocationSuccess } from "../interface.uts"
DCloud-yyl's avatar
DCloud-yyl 已提交
2
import { GetLocationFailImpl, getErrcode } from '../unierror';
3 4 5 6 7 8 9 10 11 12 13 14
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) {
DCloud-yyl's avatar
DCloud-yyl 已提交
15
	
16 17 18
	/**
	 * 准备权限
	 */
DCloud-yyl's avatar
DCloud-yyl 已提交
19 20
	let permissionNeed = ["android.permission.ACCESS_FINE_LOCATION"]
	UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, permissionNeed, function (allRight:boolean,_:string[]) {
21 22 23 24
		if (allRight) {
			// 交给目前的location 引擎,真实执行
			getLocationImpl(options)
		}
DCloud-yyl's avatar
DCloud-yyl 已提交
25 26 27
		
	}, function (_:boolean,_:string[]) {
		let err = new GetLocationFailImpl(getErrcode(1505004));
28 29 30 31 32 33 34 35 36 37 38 39
		options.fail?.(err)
		options.complete?.(err)
	})

}

/****************************************内部功能实现****************************************************/

/**
 * 封装系统监听回调
 */
class CustomSystemLocationListener extends LocationListener {
DCloud-yyl's avatar
DCloud-yyl 已提交
40 41 42 43 44 45 46
	
	hostRequest:LocationRequest
	constructor(request:LocationRequest){
		super()
		this.hostRequest = request
	}
	
47
	override onLocationChanged(location : Location) : void {
DCloud-yyl's avatar
DCloud-yyl 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
		
		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
72 73 74
	}
}

DCloud-yyl's avatar
DCloud-yyl 已提交
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
/**
 * 延迟请求
 */
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);
	}
	
	
	
}
142 143 144 145 146

/**
 * 真实的执行位置定位
 */
function getLocationImpl(options : GetLocationOptions) {
DCloud-yyl's avatar
DCloud-yyl 已提交
147
	
148 149 150 151 152 153 154 155 156
	/**
	 * add since 2023-09-14 增加默认值兼容逻辑
	 */
	if(options.type == null){
		options.type = 'wgs84'
	}
	if(options.highAccuracyExpireTime == null){
		options.highAccuracyExpireTime = 3000
	}
DCloud-yyl's avatar
DCloud-yyl 已提交
157 158
	
	
159 160
	if(options.type != 'wgs84'){
		// 系统定位只支持wgs84,如果不是则报错
DCloud-yyl's avatar
DCloud-yyl 已提交
161
		let err = new GetLocationFailImpl(getErrcode(1505022));
162 163 164 165
		options.fail?.(err)
		options.complete?.(err)
		return
	}
DCloud-yyl's avatar
DCloud-yyl 已提交
166
	
167 168
	if(options.geocode != null && options.geocode == true){
		// 系统定位不支持逆地理编码
DCloud-yyl's avatar
DCloud-yyl 已提交
169
		let err = new GetLocationFailImpl(getErrcode(1505023));
170 171 172 173
		options.fail?.(err)
		options.complete?.(err)
		return
	}
DCloud-yyl's avatar
DCloud-yyl 已提交
174
	
175

DCloud-yyl's avatar
DCloud-yyl 已提交
176
	
177 178
	let locationManager = UTSAndroid.getAppContext()!.getSystemService(Context.LOCATION_SERVICE) as LocationManager;
	let criteria = new Criteria()
DCloud-yyl's avatar
DCloud-yyl 已提交
179
	
180 181 182 183 184 185 186 187 188 189
	// 用户明确开启了高度
	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)
	}
DCloud-yyl's avatar
DCloud-yyl 已提交
190
	
191 192
	criteria.setPowerRequirement(Criteria.POWER_LOW)
	criteria.setSpeedRequired(true)
DCloud-yyl's avatar
DCloud-yyl 已提交
193
	
194 195 196 197 198 199 200
	/**
	 * 如果存在gps,那么优先gps,这样才有高度信息
	 */
	let providerName:string|null = "gps"
	if(!locationManager.getProviders(criteria, true).contains("gps")){
		providerName = locationManager.getBestProvider(criteria, true)
	}
DCloud-yyl's avatar
DCloud-yyl 已提交
201
	
202 203
	if (providerName == null) {
		// 没有找到合法的系统定位能力提供者,错误的逻辑 todo
DCloud-yyl's avatar
DCloud-yyl 已提交
204
		let err = new GetLocationFailImpl(getErrcode(1505024));
205 206 207 208
		options.fail?.(err)
		options.complete?.(err)
		return;
	}
DCloud-yyl's avatar
DCloud-yyl 已提交
209
	
210 211 212 213 214 215 216

	// 默认超时6000ms
	let timeoutMill:number = 6000;
	/**
	 * 只有设置超出3000ms 才会认为有效
	 * https://uniapp.dcloud.net.cn/api/location/location.html#getlocation
	 */
DCloud-yyl's avatar
DCloud-yyl 已提交
217
	if(options.highAccuracyExpireTime != null && options.highAccuracyExpireTime! >= 3000 && options.isHighAccuracy == true){
218 219
		timeoutMill = options.highAccuracyExpireTime!
	}
DCloud-yyl's avatar
DCloud-yyl 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
	
	// 兜底的逻辑是上次定位的信息
	/**
	 * todo 是否要考虑缓存过期时间elapsedRealtimeAgeMillis
	 */
	let lastLocation = locationManager.getLastKnownLocation(providerName)
	let locationRequest:LocationRequest = new LocationRequest(options,locationManager)
	if (lastLocation != null) {
		
		// 存在预期的缓存,直接返回,即使返回缓存,也要继续走位置更新
		locationRequest.returnLastLocation(lastLocation)
	}
	/**
	 * 没有预期中的缓存,则等待位置更新
	 */
	locationRequest.returnProviderUpdate(providerName,timeoutMill)
	
237
}