package com.shoyoo.react.anavi.location import android.annotation.SuppressLint import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.content.pm.PackageManager import android.graphics.Color import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.graphics.drawable.Icon import android.os.Build import com.amap.api.location.AMapLocation import com.amap.api.location.AMapLocationClient import com.amap.api.location.AMapLocationClientOption import com.amap.api.location.AMapLocationClientOption.AMapLocationMode import com.amap.api.location.AMapLocationClientOption.AMapLocationProtocol import com.amap.api.location.AMapLocationListener import com.facebook.react.bridge.* import com.facebook.react.modules.core.DeviceEventManagerModule class AMapLocationModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext), AMapLocationListener, LifecycleEventListener { private val locationClient: AMapLocationClient = AMapLocationClient(reactContext) init { reactContext.addLifecycleEventListener(this) locationClient.setLocationListener(this) } override fun getName(): String { return "AMapLocation" } @ReactMethod fun start(options: ReadableMap) { val locationOptions = defaultOptions.clone() if (options.hasKey("httpTimeout")) { locationOptions.httpTimeOut = options.getInt("httpTimeout").toLong() } if (options.hasKey("interval")) { locationOptions.interval = options.getInt("interval").toLong() } if (options.hasKey("cacheEnabled")) { locationOptions.isLocationCacheEnable = options.getBoolean("cacheEnabled") } if (options.hasKey("mode")) { locationOptions.locationMode = AMapLocationMode.valueOf(options.getString("mode")!!) } if (options.hasKey("protocol")) { AMapLocationClientOption.setLocationProtocol(AMapLocationProtocol.valueOf(options.getString("protocol")!!)) } if (options.hasKey("mockEnabled")) { locationOptions.isMockEnable = options.getBoolean("mockEnabled") } if (options.hasKey("needAddress")) { locationOptions.isNeedAddress = options.getBoolean("needAddress") } if (options.hasKey("sensorEnable")) { locationOptions.isSensorEnable = options.getBoolean("sensorEnable") } if (options.hasKey("wifiScan")) { locationOptions.isWifiScan = options.getBoolean("wifiScan") } locationClient.setLocationOption(locationOptions) locationClient.startLocation() } @ReactMethod fun stop() { locationClient.stopLocation() } @ReactMethod fun enabledBackground(enabled: Boolean) { if(enabled) { locationClient.enableBackgroundLocation(10087, defaultNotification()) } else { locationClient.disableBackgroundLocation(true) } } @SuppressLint("NewApi") private fun defaultNotification(): Notification? { var builder: Notification.Builder? = null var notification: Notification? = null if (Build.VERSION.SDK_INT >= 26) { //Android O上对Notification进行了修改,如果设置的targetSDKVersion>=26建议使用此种方式创建通知栏 val channelId: String = reactContext.packageName val notificationChannel = NotificationChannel(channelId, "AMapBackgroundLocation", NotificationManager.IMPORTANCE_DEFAULT) notificationChannel.enableLights(false) //是否在桌面icon右上角展示小圆点 notificationChannel.lightColor = Color.BLUE //小圆点颜色 notificationChannel.setShowBadge(true) //是否在久按桌面图标时显示此渠道的通知 notificationManager.createNotificationChannel(notificationChannel) builder = Notification.Builder(reactContext.applicationContext, channelId) } else { builder = Notification.Builder(reactContext.applicationContext) } builder.setSmallIcon(Icon.createWithBitmap((applicationIcon as BitmapDrawable).bitmap)) .setContentTitle(applicationName) .setContentText("正在后台运行") .setWhen(System.currentTimeMillis()) notification = if (Build.VERSION.SDK_INT >= 16) { builder.build() } else { return builder.notification } return notification } private val applicationIcon: Drawable get() { return packageManager.getApplicationIcon(reactContext.applicationInfo) } private val applicationName: CharSequence get() { return packageManager.getApplicationLabel(reactContext.applicationInfo) } private val packageManager: PackageManager get() = reactContext.packageManager private val defaultOptions: AMapLocationClientOption get() { return AMapLocationClientOption().apply { //可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式 locationMode = AMapLocationMode.Hight_Accuracy //可选,设置是否gps优先,只在高精度模式下有效。默认关闭 isGpsFirst = false //可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效 httpTimeOut = 30000 //可选,设置定位间隔。默认为2秒 interval = 2000 //可选,设置是否返回逆地理地址信息。默认是true isNeedAddress = true //可选,设置是否单次定位。默认是false isOnceLocation = false //可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用 isOnceLocationLatest = false //可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP AMapLocationClientOption.setLocationProtocol(AMapLocationProtocol.HTTP) //可选,设置是否使用传感器。默认是false isSensorEnable = false //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差 isWifiScan = true //可选,设置是否使用缓存定位,默认为true isLocationCacheEnable = true } } private val notificationManager: NotificationManager get() = reactContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager override fun onLocationChanged(location: AMapLocation?) { val emitter: DeviceEventManagerModule.RCTDeviceEventEmitter = reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) val result: WritableMap = Arguments.createMap() val data: WritableMap = Arguments.createMap() if(location != null) { result.putInt("code", location.errorCode) result.putString("info", location.errorInfo) result.putString("details", location.locationDetail) if(location.errorCode == 0) { data.putInt("type", location.locationType) data.putDouble("latitude", location.latitude) data.putDouble("longitude", location.longitude) data.putDouble("accuracy", location.accuracy.toDouble()) data.putString("provider", location.provider) data.putDouble("speed", location.speed.toDouble()) data.putDouble("bearing", location.bearing.toDouble()) data.putInt("satellites", location.satellites) data.putString("country", location.country) data.putString("city", location.city) data.putString("cityCode", location.cityCode) data.putString("district", location.district) data.putString("address", location.address) data.putString("poiName", location.poiName) val quality = Arguments.createMap().apply { putString("adviseMessage", location.locationQualityReport.adviseMessage) putInt("gpsSatellites", location.locationQualityReport.gpsSatellites) putInt("gpsStatus", location.locationQualityReport.gpsStatus) putInt("netUseTime", location.locationQualityReport.netUseTime.toInt()) putString("networkType", location.locationQualityReport.networkType) putBoolean("isInstalledHighDangerMockApp", location.locationQualityReport.isInstalledHighDangerMockApp) } data.putMap("quality", quality) } } else { result.putInt("code", -1000) } data.putMap("error", result) emitter.emit("amap_location", data) } override fun onHostResume() { } override fun onHostPause() { } override fun onHostDestroy() { } }