You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android(Kotlin)中使用Beacons获取用户当前经纬度?

在Kotlin Android应用中利用Beacons获取设备经纬度

首先明确:Beacon本身无法直接获取设备的GPS经纬度,它的核心逻辑是:预存每个Beacon硬件的精确经纬度,通过设备扫描到的Beacon信号数据(如RSSI),结合定位算法估算设备相对Beacon的位置,最终推导设备的经纬度。

前置准备

  • 部署Beacon硬件:在目标区域放置若干Beacon,记录每个Beacon的UUID、Major、Minor以及对应的精确经纬度(可存储在本地Room数据库或后端服务)。
  • 配置Android权限:在AndroidManifest.xml中声明必要权限:
    <!-- 位置权限 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!-- Android 12+ 蓝牙权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <!-- 后台扫描权限(可选) -->
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    

集成Beacon扫描库

推荐使用AltBeacon的Android Beacon Library,在模块级build.gradle.kts中添加依赖:

dependencies {
    implementation "org.altbeacon:android-beacon-library:2.21.4"
}

实现核心逻辑

1. 动态申请权限

在Activity/Fragment中处理权限申请:

private val PERMISSION_REQUEST_CODE = 1001

private val requiredPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    arrayOf(
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.BLUETOOTH_SCAN,
        Manifest.permission.BLUETOOTH_CONNECT
    )
} else {
    arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
}

private fun requestPermissions() {
    ActivityCompat.requestPermissions(this, requiredPermissions, PERMISSION_REQUEST_CODE)
}

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == PERMISSION_REQUEST_CODE && grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
        startBeaconScanning()
    }
}

2. 初始化Beacon扫描并监听结果

private lateinit var beaconManager: BeaconManager

private fun initBeaconManager() {
    beaconManager = BeaconManager.getInstanceForApplication(this)
    // 设置要扫描的Beacon布局(以iBeacon为例)
    beaconManager.beaconParsers.add(BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"))
    // 设置扫描回调
    beaconManager.addRangeNotifier { beacons, _ ->
        if (beacons.isNotEmpty()) {
            calculateDeviceLocation(beacons)
        }
    }
}

private fun startBeaconScanning() {
    val region = Region("my-beacon-region", null, null, null)
    try {
        beaconManager.startRangingBeacons(region)
    } catch (e: RemoteException) {
        e.printStackTrace()
    }
}

private fun stopBeaconScanning() {
    val region = Region("my-beacon-region", null, null, null)
    try {
        beaconManager.stopRangingBeacons(region)
    } catch (e: RemoteException) {
        e.printStackTrace()
    }
}

// 在生命周期中管理扫描
override fun onResume() {
    super.onResume()
    if (hasPermissions()) {
        startBeaconScanning()
    }
}

override fun onPause() {
    super.onPause()
    stopBeaconScanning()
}

private fun hasPermissions(): Boolean {
    return requiredPermissions.all {
        ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
    }
}

3. 基于Beacon数据计算设备经纬度

这里采用加权平均算法(根据信号强度权重计算,信号越强权重越高),首先需要预存Beacon的位置数据:

// 模拟预存的Beacon数据,实际应从数据库/后端获取
data class BeaconLocation(
    val uuid: String,
    val major: Int,
    val minor: Int,
    val latitude: Double,
    val longitude: Double
)

private val preStoredBeacons = listOf(
    BeaconLocation("YOUR_BEACON_UUID", 1, 1, 39.9042, 116.4074),
    BeaconLocation("YOUR_BEACON_UUID", 1, 2, 39.9052, 116.4084)
)

private fun calculateDeviceLocation(beacons: Collection<Beacon>) {
    var totalWeight = 0.0
    var weightedLatitude = 0.0
    var weightedLongitude = 0.0

    beacons.forEach { scannedBeacon ->
        // 匹配预存的Beacon数据
        val storedBeacon = preStoredBeacons.find {
            it.uuid == scannedBeacon.id1.toString() &&
            it.major == scannedBeacon.id2.toInt() &&
            it.minor == scannedBeacon.id3.toInt()
        } ?: return@forEach

        // 将RSSI转换为权重(信号越强,RSSI越接近0,权重越高)
        val rssi = scannedBeacon.rssi
        val weight = if (rssi < -100) 0.1 else (rssi + 100).toDouble()

        totalWeight += weight
        weightedLatitude += storedBeacon.latitude * weight
        weightedLongitude += storedBeacon.longitude * weight
    }

    if (totalWeight > 0) {
        val deviceLatitude = weightedLatitude / totalWeight
        val deviceLongitude = weightedLongitude / totalWeight
        // 得到设备估算经纬度,可用于业务逻辑
        Log.d("BeaconLocation", "估算位置: $deviceLatitude, $deviceLongitude")
    }
}

注意事项

  • 精度优化:建议部署至少3个Beacon来提升定位精度,同时可结合GPS数据进行互补校准。
  • 耗电控制:避免长时间后台扫描,可调整扫描间隔和周期,或在进入特定区域时才启动扫描。
  • 环境干扰:Beacon信号易受墙壁、金属等障碍物影响,需在实际场景中测试调整权重算法。

内容的提问来源于stack exchange,提问作者hds

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 11:55:18