capacitor-baidu-location 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,246 @@
1
+ package com.hybrid.baidu.location
2
+
3
+ import android.content.Context
4
+ import android.util.Log
5
+ import androidx.annotation.NonNull
6
+ import com.baidu.location.BDAbstractLocationListener
7
+ import com.baidu.location.BDLocation
8
+ import com.baidu.location.LocationClient
9
+ import com.baidu.location.LocationClientOption
10
+ import com.getcapacitor.Logger
11
+ import java.util.concurrent.CountDownLatch
12
+ import java.util.concurrent.TimeUnit
13
+
14
+ /**
15
+ * 百度地图定位插件Android端实现类
16
+ */
17
+ class CPBaiduLocation(private val context: Context, private val config: CPBaiduLocationConfig) {
18
+
19
+ private val TAG = "CPBaiduLocation"
20
+
21
+ /**
22
+ * 上下文对象
23
+ */
24
+ private val mContext: Context = context.applicationContext
25
+
26
+ /**
27
+ * 百度定位客户端
28
+ */
29
+ private var mLocationClient: LocationClient? = null
30
+
31
+ /**
32
+ * 定位结果
33
+ */
34
+ private var mLocation: BDLocation? = null
35
+
36
+ /**
37
+ * 用于等待定位结果的同步锁
38
+ */
39
+ private var latch: CountDownLatch? = null
40
+
41
+ /**
42
+ * 坐标类型
43
+ */
44
+ private var coordinateType = "bd09ll" // 默认百度经纬度坐标
45
+
46
+ // MARK: - 状态管理
47
+ /**
48
+ * API Key
49
+ */
50
+ private var ak: String? = null
51
+
52
+ /**
53
+ * AK验证状态
54
+ */
55
+ private var isAKValidated = false
56
+
57
+ /**
58
+ * AK验证回调接口
59
+ */
60
+ interface AKValidationCallback {
61
+ fun onValidationResult(success: Boolean, errorCode: Int, errorMessage: String)
62
+ }
63
+
64
+ init {
65
+ Log.i(TAG, "getLocationClient: " + getLocationClient())
66
+ }
67
+
68
+
69
+
70
+ /**
71
+ * 设置百度地图API Key
72
+ * @param ak API Key
73
+ * @param callback 验证结果回调
74
+ */
75
+ fun setAK(ak: String?, callback: AKValidationCallback) {
76
+ val realAk = ak ?: config.getAndroidAK()
77
+ if (realAk.isNullOrEmpty()) {
78
+ callback.onValidationResult(false, -2, "AK cannot be empty")
79
+ return
80
+ }
81
+ // 如果AK已验证成功或与当前AK相同,直接返回成功
82
+ if (isAKValidated && realAk == this.ak) {
83
+ callback.onValidationResult(true, 0, "AK已设置")
84
+ return
85
+ }
86
+ // 存储API Key
87
+ this.ak = realAk
88
+ // 自动设置同意隐私协议
89
+ LocationClient.setAgreePrivacy(true)
90
+ // 设置AK
91
+ LocationClient.setKey(realAk)
92
+ isAKValidated = true
93
+ callback.onValidationResult(true, 0, "AK已设置")
94
+ }
95
+
96
+ /**
97
+ * 设置坐标类型
98
+ * @param type 坐标类型(TypeScript枚举字符串值)
99
+ */
100
+ fun setCoordinateType(type: String) {
101
+ // 转换为小写处理
102
+ val lowerType = type.lowercase()
103
+ if (lowerType == coordinateType) return
104
+ coordinateType = when (lowerType) {
105
+ "gcj02", "wgs84", "bd09ll" -> lowerType
106
+ "bd09mc" -> "bd09" // 使用默认值
107
+ else -> "bd09ll"
108
+ }
109
+ getLocationClient()?.locOption?.let { it.coorType = coordinateType }
110
+ }
111
+
112
+ /**
113
+ * 获取当前坐标类型
114
+ * @return 坐标类型(TypeScript枚举字符串值)
115
+ */
116
+ fun getCoordinateType(): String {
117
+ // 将小写字符串转换为TypeScript枚举格式
118
+ return when (coordinateType) {
119
+ "bd09" -> "BD09MC"
120
+ else -> coordinateType.uppercase()
121
+ }
122
+ }
123
+
124
+ /**
125
+ * 获取定位客户端(懒加载)
126
+ * @return 定位客户端
127
+ */
128
+ fun getLocationClient(): LocationClient? {
129
+ if (mLocationClient == null) {
130
+ // 初始化定位客户端
131
+ try {
132
+ mLocationClient = LocationClient(mContext)
133
+ mLocationClient?.let { it.locOption = getLocationClientOption() }
134
+ } catch (e: Exception) {
135
+ Logger.error(TAG, "Error initializing LocationClient", e)
136
+ return null
137
+ }
138
+ }
139
+ return mLocationClient
140
+ }
141
+
142
+ /**
143
+ * 获取当前位置信息
144
+ * @param needAddress 是否需要地址信息
145
+ * @param needLocationDescribe 是否需要位置描述
146
+ * @return 定位结果,包含经纬度、精度、地址信息等
147
+ */
148
+ fun getCurrentPosition(needAddress: Boolean, needLocationDescribe: Boolean): BDLocation? {
149
+ // 重置定位结果
150
+ mLocation = null
151
+ // 创建用于等待定位结果的同步锁
152
+ latch = CountDownLatch(1)
153
+
154
+ try {
155
+ // 检查AK是否已验证
156
+ if (!isAKValidated) {
157
+ Log.e(TAG, "AK not validated")
158
+ return null
159
+ }
160
+
161
+ // 获取定位客户端(懒加载)
162
+ val locationClient = getLocationClient() ?: run {
163
+ Log.e(TAG, "Failed to get location client")
164
+ return null
165
+ }
166
+
167
+ // 创建定位监听器实例
168
+ val myListener = MyLocationListener()
169
+ // 注册定位监听器
170
+ locationClient.registerLocationListener(myListener)
171
+
172
+ // 配置定位选项
173
+ val options = locationClient.locOption
174
+ options.setIsNeedAddress(needAddress) // 设置是否需要地址信息
175
+ options.setIsNeedLocationDescribe(needLocationDescribe) // 设置是否需要位置描述
176
+ locationClient.locOption = options
177
+
178
+ // 开始定位
179
+ locationClient.start()
180
+
181
+ // 等待定位结果,最多10秒
182
+ try {
183
+ latch?.await(10, TimeUnit.SECONDS)
184
+ } catch (e: InterruptedException) {
185
+ Logger.error(TAG, "Interrupted while waiting for location", e)
186
+ // 确保定位客户端被正确关闭
187
+ if (locationClient.isStarted) {
188
+ locationClient.stop()
189
+ locationClient.unRegisterLocationListener(myListener)
190
+ }
191
+ return null
192
+ }
193
+
194
+ // 定位完成后停止定位客户端,释放资源
195
+ if (locationClient.isStarted) {
196
+ locationClient.stop()
197
+ locationClient.unRegisterLocationListener(myListener)
198
+ }
199
+ } catch (e: Exception) {
200
+ Logger.error(TAG, "Error getting location", e)
201
+ // 确保定位客户端被正确关闭,释放资源
202
+ if (mLocationClient?.isStarted == true) {
203
+ mLocationClient?.stop()
204
+ }
205
+ }
206
+
207
+ return mLocation
208
+ }
209
+
210
+ @NonNull
211
+ private fun getLocationClientOption(): LocationClientOption {
212
+ val option = LocationClientOption()
213
+ option.locationMode = LocationClientOption.LocationMode.Hight_Accuracy // 高精度定位模式
214
+ // 直接使用字符串坐标类型设置
215
+ option.coorType = coordinateType
216
+ option.scanSpan = 0 // 单次定位
217
+ option.isOpenGnss = true // 启用GPS
218
+ option.isLocationNotify = true // 当位置变化时通知
219
+ option.setIgnoreKillProcess(false) // 定位服务不被杀死
220
+ option.SetIgnoreCacheException(false) // 不忽略缓存异常
221
+ option.wifiCacheTimeOut = 5 * 60 * 1000 // WiFi缓存超时时间
222
+ option.enableSimulateGps = false // 不启用模拟GPS
223
+ option.isNeedNewVersionRgc = true // 使用新版本的逆地理编码
224
+ return option
225
+ }
226
+
227
+ /**
228
+ * 百度定位监听器
229
+ */
230
+ private inner class MyLocationListener : BDAbstractLocationListener() {
231
+
232
+ /**
233
+ * 接收定位结果
234
+ * @param location 定位结果
235
+ */
236
+ override fun onReceiveLocation(location: BDLocation?) {
237
+ if (location != null) {
238
+ mLocation = location
239
+ Log.i(TAG, "坐标类型 = " + location.coorType)
240
+ Log.i(TAG, "经纬度(lng, lat) = " + location.longitude.toString() + "," + location.latitude)
241
+ }
242
+ // 通知等待线程定位完成
243
+ latch?.countDown()
244
+ }
245
+ }
246
+ }
@@ -0,0 +1,22 @@
1
+ package com.hybrid.baidu.location
2
+
3
+ /**
4
+ * 百度地图定位插件配置类
5
+ * 集中管理所有配置项,提供类型安全的访问方式
6
+ */
7
+ class CPBaiduLocationConfig {
8
+ /**
9
+ * Android平台百度地图API Key
10
+ */
11
+ private var androidAK: String? = null
12
+
13
+ // Getter and Setter methods
14
+ fun getAndroidAK(): String? {
15
+ return androidAK
16
+ }
17
+
18
+ fun setAndroidAK(androidAK: String?) {
19
+ this.androidAK = androidAK
20
+ }
21
+
22
+ }
@@ -0,0 +1,225 @@
1
+ package com.hybrid.baidu.location
2
+
3
+ import com.baidu.location.BDLocation
4
+ import com.getcapacitor.JSObject
5
+ import com.getcapacitor.Plugin
6
+ import com.getcapacitor.PluginCall
7
+ import com.getcapacitor.PluginMethod
8
+ import com.getcapacitor.annotation.CapacitorPlugin
9
+ import com.getcapacitor.annotation.Permission
10
+ import com.getcapacitor.annotation.PermissionCallback
11
+
12
+ /**
13
+ * 百度地图定位插件Android端入口类
14
+ */
15
+ @CapacitorPlugin(
16
+ name = "CPBaiduLocation",
17
+ permissions = [
18
+ Permission(
19
+ alias = "location",
20
+ strings = [android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION]
21
+ )
22
+ ]
23
+ )
24
+ class CPBaiduLocationPlugin : Plugin() {
25
+
26
+ /**
27
+ * 插件实现实例
28
+ */
29
+ private lateinit var implementation: CPBaiduLocation
30
+
31
+ /**
32
+ * 初始化插件
33
+ */
34
+ override fun load() {
35
+ super.load()
36
+
37
+ // 使用配置对象初始化实现实例
38
+ implementation = CPBaiduLocation(context, getCPBaiduLocationConfig())
39
+ }
40
+
41
+ /**
42
+ * 从Capacitor配置创建插件配置对象
43
+ */
44
+ private fun getCPBaiduLocationConfig(): CPBaiduLocationConfig {
45
+ val config = CPBaiduLocationConfig()
46
+ val pluginConfig = getConfig()
47
+
48
+ // 从Capacitor配置读取参数
49
+ pluginConfig.getString("androidAK", null)?.let {
50
+ config.setAndroidAK(it)
51
+ }
52
+ return config
53
+ }
54
+
55
+
56
+
57
+ /**
58
+ * 获取当前位置信息
59
+ * @param call 插件调用对象
60
+ */
61
+ @PluginMethod
62
+ fun getCurrentPosition(call: PluginCall) {
63
+ // 获取调用参数
64
+ val needAddress = call.getBoolean("needAddress", false) ?: false
65
+ val needLocationDescribe = call.getBoolean("needLocationDescribe", false) ?: false
66
+
67
+ // 调用实现类获取定位结果
68
+ val location = implementation.getCurrentPosition(needAddress, needLocationDescribe)
69
+
70
+ // 构建返回结果
71
+ val ret = JSObject()
72
+
73
+ if (location != null) {
74
+ // 添加经纬度和精度
75
+ ret.put("latitude", location.latitude)
76
+ ret.put("longitude", location.longitude)
77
+ ret.put("accuracy", location.radius)
78
+
79
+ // 地址信息(如果需要且可用)
80
+ if (needAddress && location.addrStr != null) {
81
+ ret.put("address", location.addrStr)
82
+ ret.put("country", location.country)
83
+ ret.put("province", location.province)
84
+ ret.put("city", location.city)
85
+ ret.put("district", location.district)
86
+ ret.put("street", location.street)
87
+ ret.put("adcode", location.adCode)
88
+ ret.put("town", location.town)
89
+ }
90
+
91
+ // 位置描述(如果需要且可用)
92
+ if (needLocationDescribe && location.locationDescribe != null) {
93
+ ret.put("locationDescribe", location.locationDescribe)
94
+ }
95
+
96
+ // 错误信息(如果定位类型不是GPS、网络或离线定位)
97
+ if (
98
+ location.locType != BDLocation.TypeGpsLocation &&
99
+ location.locType != BDLocation.TypeNetWorkLocation &&
100
+ location.locType != BDLocation.TypeOffLineLocation
101
+ ) {
102
+ ret.put("errorCode", location.locType)
103
+ ret.put("errorMessage", location.locTypeDescription)
104
+ }
105
+ } else {
106
+ // 定位失败
107
+ ret.put("latitude", 0)
108
+ ret.put("longitude", 0)
109
+ ret.put("errorCode", -1)
110
+ ret.put("errorMessage", "Failed to get location")
111
+ }
112
+
113
+ // 返回结果
114
+ call.resolve(ret)
115
+ }
116
+
117
+ /**
118
+ * 检查定位权限
119
+ * @param call 插件调用对象
120
+ */
121
+ @PluginMethod
122
+ fun checkPermission(call: PluginCall) {
123
+ val hasCoarsePermission =
124
+ context.checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
125
+ android.content.pm.PackageManager.PERMISSION_GRANTED
126
+ val hasFinePermission =
127
+ context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) ==
128
+ android.content.pm.PackageManager.PERMISSION_GRANTED
129
+
130
+ val ret = JSObject()
131
+ ret.put("granted", hasCoarsePermission && hasFinePermission)
132
+ call.resolve(ret)
133
+ }
134
+
135
+ /**
136
+ * 请求定位权限
137
+ * @param call 插件调用对象
138
+ */
139
+ @PluginMethod
140
+ fun requestPermission(call: PluginCall) {
141
+ requestPermissionForAlias("location", call, "locationPermissionCallback")
142
+ }
143
+
144
+ /**
145
+ * 定位权限请求回调
146
+ * @param call 插件调用对象
147
+ */
148
+ @PermissionCallback
149
+ private fun locationPermissionCallback(call: PluginCall) {
150
+ // 检查权限状态
151
+ val hasCoarsePermission =
152
+ context.checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
153
+ android.content.pm.PackageManager.PERMISSION_GRANTED
154
+ val hasFinePermission =
155
+ context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) ==
156
+ android.content.pm.PackageManager.PERMISSION_GRANTED
157
+
158
+ val ret = JSObject()
159
+ ret.put("granted", hasCoarsePermission && hasFinePermission)
160
+ call.resolve(ret)
161
+ }
162
+
163
+ /**
164
+ * 设置百度地图AK
165
+ * @param call 插件调用对象
166
+ */
167
+ @PluginMethod
168
+ fun setAK(call: PluginCall) {
169
+ val ak = call.getString("ak")
170
+ // 调用实现类的setAK方法,使用回调处理结果
171
+ implementation.setAK(ak, object : CPBaiduLocation.AKValidationCallback {
172
+ override fun onValidationResult(success: Boolean, errorCode: Int, errorMessage: String) {
173
+ val ret = JSObject()
174
+ ret.put("success", success)
175
+ if (!success) {
176
+ ret.put("errorCode", errorCode)
177
+ ret.put("errorMessage", errorMessage)
178
+ }
179
+ call.resolve(ret)
180
+ }
181
+ })
182
+ }
183
+
184
+ /**
185
+ * 检查AK验证状态
186
+ * @param call 插件调用对象
187
+ */
188
+ @PluginMethod
189
+ fun checkAKValidation(call: PluginCall) {
190
+ // 百度定位SDK没有提供直接检查AK验证状态的方法
191
+ // 这里我们简单返回true,实际验证会在定位时进行
192
+ val ret = JSObject()
193
+ ret.put("valid", true)
194
+ call.resolve(ret)
195
+ }
196
+
197
+ /**
198
+ * 设置坐标类型
199
+ * @param call 插件调用对象
200
+ */
201
+ @PluginMethod
202
+ fun setCoordinateType(call: PluginCall) {
203
+ val type = call.getString("type")
204
+ if (type.isNullOrEmpty()) {
205
+ call.reject("Coordinate type cannot be empty")
206
+ return
207
+ }
208
+ implementation.setCoordinateType(type)
209
+ val ret = JSObject()
210
+ ret.put("success", true)
211
+ call.resolve(ret)
212
+ }
213
+
214
+ /**
215
+ * 获取当前坐标类型
216
+ * @param call 插件调用对象
217
+ */
218
+ @PluginMethod
219
+ fun getCoordinateType(call: PluginCall) {
220
+ val type = implementation.getCoordinateType()
221
+ val ret = JSObject()
222
+ ret.put("type", type)
223
+ call.resolve(ret)
224
+ }
225
+ }
File without changes