
简介这是一款面向室内定位开发者的WiFi指纹采集工具适合从事室内导航、位置服务研究的学生与工程师使用。应用通过扫描周边WiFi网络记录MAC地址、信号强度、信噪比等参数构建特定环境下的WiFi指纹数据库并结合地图功能将信号数据与地理位置关联实现不依赖GPS的室内精确定位可应用于商场、机场、办公楼等场景。资源包共898个文件约5.2MB包含314个xml布局与配置、276个png图片资源、140个json数据文件、99个class与36个java源码以及jar依赖、gradle构建脚本和apk安装包覆盖完整Android工程结构便于直接编译运行或二次开发。目前已有484人学习下载。读者可从中获取WiFi指纹采集与匹配的完整实现思路包括信号扫描、数据上传、指纹库比对等核心模块适合作为室内定位项目的参考模板与排错依据。1. 拆开这个 WiFi 指纹采集包它到底能解决室内定位里的哪一段GPS 进了商场、机场、写字楼就基本歇菜这是做室内定位的人绕不开的第一道坎。你拿到的这个wifi收集数据app.rar核心不是定位算法本身而是一套 WiFi 信息采集 APP 加指纹数据落地的工具链——它负责把「某个坐标点上周围有哪些 AP、各自信号多强」这件事变成一条条能存进数据库、能拿去比对定位的 WiFi 指纹数据。包里能看到resources-debug.ap_、resources-debug-androidTest.ap_、controlPCPro-debug.apk这类产物还有一堆R$styleable.class、R$attr.class资源索引类说明它是个 Android 工程编译后的东西带测试包另外还有一个 PC 端控制程序。适合谁做室内定位 Demo 验证的、要给算法团队喂指纹数据的、以及想搞清楚 WiFi 采集 APP 从扫描到入库整条链路的人。它不承诺厘米级但能让你把「采集—建库—匹配」这条线先跑通。2. WiFi 指纹采集的原理与工程选型为什么不用 RSSI 直接算距离2.1 指纹定位和三角测距的分水岭很多人第一反应是拿三个 AP 的信号强度做三角定位公式一摆好像就能算距离。真到室内就翻车墙体遮挡、人体走动、多径反射RSSI 和距离根本不是稳定反比关系同一个点站左站右能差 10dBm。WiFi 指纹数据的思路是绕开这个玄学——不建模信号怎么衰减而是直接记录「这个位置看到的信号长什么样」定位时拿当前扫描结果去库里找最像的那条记录。这就是指纹定位和测距定位的本质区别前者靠查表匹配后者靠物理模型室内场景下前者鲁棒得多。这个采集 APP 干的就是建表这一步。它扫描周围 WiFi 网络把每个 AP 的 MAC 地址BSSID、信号强度RSSI、信噪比、频段这些参数记下来绑定到当前采集点的坐标上形成一条指纹。采集点铺得越密指纹库越细后面匹配越准。2.2 采集端为什么选 Android 原生工程从包结构看这是个标准 Android 工程编译产物。resources-debug.ap_是资源包resources-debug-androidTest.ap_是测试资源包controlPCPro-debug.apk是可直接安装的 debug 版 APK。选 Android 原生而不是跨平台框架主要因为 WiFi 扫描这块要拿到完整的ScanResult列表包括 BSSID、RSSI、frequency原生WifiManager的getScanResults()给得最全跨平台封装经常丢字段或者拿不到实时刷新。R$styleable.class、R$attr.class这些是编译期生成的资源索引说明工程里用了自定义 View 或自定义属性大概率是地图或采集界面的控件。采集频率上Android 对startScan()有节流前台大概几秒一次后台更慢。所以采集 APP 一般不会死等系统扫描回调而是自己控制节奏比如每 2 到 3 秒触发一次攒够一批再入库。2.3 指纹数据长什么样一条典型的 WiFi 指纹记录字段大致是这些字段含义采集时注意x, y采集点坐标地图坐标系要统一别混用像素和米bssidAP 的 MAC 地址唯一标识别用 SSID 代替ssid网络名仅作展示可能重名rssi信号强度 dBm负值越接近 0 越强frequency频段 MHz2.4G/5G 要区分timestamp采集时间用于后续时效过滤采集时同一个点通常要停留几秒对每个 AP 采多次取均值或中位数单次采样抖动太大直接入库后面匹配会飘。3. 把采集 APP 跑起来从安装到第一条指纹入库3.1 环境准备与安装先确认手机是 Android 且开了开发者模式。这个包是 debug 版直接装controlPCPro-debug.apk即可。装之前把旧版本卸干净debug 包签名不同覆盖安装会失败。# 通过 adb 安装 debug 版 APK adb install -r controlPCPro-debug.apk # 如果提示 INSTALL_FAILED_UPDATE_INCOMPATIBLE先卸载 adb uninstall 你的包名 adb install controlPCPro-debug.apk-r是替换安装保留数据如果签名冲突就得先卸。包名从adb shell pm list packages里找带 control 的那个。3.2 权限与扫描节流Android 6.0 以上WiFi 扫描要位置权限Android 10 以上还要精确定位权限否则getScanResults()返回空列表——这是最常见的「装了没数据」原因。!-- AndroidManifest.xml 里需要的权限 -- uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION/ uses-permission android:nameandroid.permission.ACCESS_WIFI_STATE/ uses-permission android:nameandroid.permission.CHANGE_WIFI_STATE/ uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION/注意Android 10 之后即使给了权限后台扫描频率也被限制。采集时保持 APP 在前台屏幕别熄。我一般会把屏幕常亮打开避免息屏后扫描回调变慢导致指纹点稀疏。3.3 采集流程与入库典型采集流程是加载室内地图 → 在地图上点选或走到某个坐标 → 触发扫描 → 停留几秒 → 保存该点指纹。核心扫描逻辑大致这样// 触发一次 WiFi 扫描并读取结果 WifiManager wifiManager (WifiManager) getSystemService(Context.WIFI_SERVICE); wifiManager.startScan(); // 触发扫描 // 扫描是异步的等回调或延迟后读取 ListScanResult results wifiManager.getScanResults(); for (ScanResult r : results) { String bssid r.BSSID; // AP 的 MAC int rssi r.level; // 信号强度 dBm int freq r.frequency; // 频段 // 绑定当前采集点坐标 (x, y) 后写入本地库 db.insertFingerprint(x, y, bssid, rssi, freq, System.currentTimeMillis()); }startScan()只是发起结果要等系统回调SCAN_RESULTS_AVAILABLE_ACTION或延迟几百毫秒再读。直接紧接着读getScanResults()可能拿到的是上一次的缓存。参数上rssi是负值-40 很强-90 基本是边缘frequency2400 段是 2.4G5000 段是 5G建库时最好分开存因为两者衰减特性不同。3.4 PC 端控制程序的作用包里那个controlPCPro从命名看是 PC 端控制程序常见做法是用它做采集任务的配置下发和数据回收——手机端负责扫PC 端负责把指纹数据汇总、可视化、导出成定位算法能吃的格式。如果你只拿到 APK 没拿到 PC 端源码可以先用手机端本地库导出 CSV再自己写脚本导入。导出格式建议统一成x,y,bssid,rssi,frequency,timestamp后面匹配脚本直接读。4. 指纹建库与匹配采集完之后数据怎么用4.1 从原始采集到指纹库原始采集是一堆带坐标的散点记录同一个 AP 在同一个点可能有多条。建库第一步是按(x, y, bssid)聚合RSSI 取中位数而不是均值——均值容易被偶发的强信号拉偏中位数更稳。import pandas as pd # 读取采集导出的 CSV df pd.read_csv(fingerprints.csv) # 按坐标和 AP 聚合RSSI 取中位数 fp df.groupby([x, y, bssid]).agg( rssi_median(rssi, median), freq(frequency, first) ).reset_index() # 每个坐标点存成一个指纹向量 fp.to_csv(fingerprint_db.csv, indexFalse)聚合后每个坐标点对应一组bssid - rssi_median的映射这就是指纹库的基本单元。freq取 first 是因为同一 AP 频段固定。4.2 在线匹配怎么算定位时手机再扫一次得到当前bssid - rssi列表拿去和库里每个坐标点的指纹比相似度。最常用的是欧氏距离或余弦相似度取距离最小的坐标作为估计位置。import numpy as np def match(current, db): # current: {bssid: rssi} 当前扫描 # db: 指纹库每条含坐标和 bssid-rssi best, best_dist None, float(inf) for point in db: common set(current) set(point[rssi]) if not common: continue # 只对共有的 AP 算欧氏距离 dist np.sqrt(sum((current[b] - point[rssi][b]) ** 2 for b in common)) if dist best_dist: best_dist, best dist, point return best[x], best[y]只对共有的 AP 算距离是因为不同位置能扫到的 AP 集合本来就不一样。共有 AP 太少比如少于 3 个时匹配结果不可信这种情况要么放弃这次定位要么扩大扫描等待时间多攒几个。4.3 影响精度的几个参数采集点间距是精度上限。间距 1 米定位最好也就 1 米级间距 5 米别指望亚米。AP 密度也关键一个点能稳定扫到 5 个以上 AP匹配才有区分度。另外采集时的朝向、手持姿势会影响人体遮挡建库时最好每个点换几个朝向各采一遍或者至少记录朝向后面匹配时做补偿。5. 避坑与排查采集 APP 最容易翻车的五个地方5.1 扫描结果为空现象APP 装好了权限也给了扫描列表就是空的。原因Android 10 以上只有精确定位权限ACCESS_FINE_LOCATION且定位开关打开时才返回结果粗略权限不够。解决检查系统定位是否开启权限里确认给的是「精确」而非「大致」部分机型还要在 WiFi 高级设置里允许扫描。5.2 指纹点稀疏、定位跳变现象定位结果在几个点之间乱跳。原因采集时停留时间太短每个点只扫到一两次RSSI 抖动大。解决每个采集点至少停留 3 到 5 秒攒够 3 次以上扫描再取中位数入库别采一次就存。5.3 同一位置不同时间数据对不上现象今天采的库明天在同一位置匹配不上。原因AP 可能被移动、关闭或换了信道RSSI 整体漂移。解决建库时记录 timestamp匹配时优先用近期数据定期重采或者对库做时效加权老数据降权。5.4 debug 包覆盖安装失败现象adb install报INSTALL_FAILED_UPDATE_INCOMPATIBLE。原因debug 包和已装版本签名不一致。解决先adb uninstall卸干净再装别用-r硬覆盖。数据要保留的话先导出本地库。5.5 5G 和 2.4G 混在一起匹配现象匹配距离算出来偏大定位不准。原因2.4G 和 5G 的 RSSI 量纲和衰减不同混在一个向量里算距离会互相干扰。解决建库和匹配时按频段分开或者只用一个频段做定位通常 5G 精度更高但覆盖小2.4G 覆盖广但更飘。6. 进阶把采集数据做成可复用的指纹库并验证精度采集跑通之后真正决定这套东西能不能用的是指纹库质量和验证方法。我一般会留出 20% 的采集点不参与建库专门做测试点用它们来算定位误差。验证流程这样走先把采集数据按坐标随机分成训练集和测试集训练集建库测试集逐条拿去匹配统计误差分布。from sklearn.model_selection import train_test_split # 按坐标点划分避免同一点既在训练又在测试 points fp[[x, y]].drop_duplicates() train_pts, test_pts train_test_split(points, test_size0.2, random_state42) train_db fp.merge(train_pts, on[x, y]) test_set fp.merge(test_pts, on[x, y]) errors [] for (x, y), group in test_set.groupby([x, y]): current dict(zip(group[bssid], group[rssi_median])) px, py match(current, train_db.to_dict(records)) errors.append(np.sqrt((px - x) ** 2 (py - y) ** 2)) print(平均误差:, np.mean(errors), 米) print(90 分位误差:, np.percentile(errors, 90), 米)看平均误差之外一定要看 90 分位因为定位体验差往往是被最差的那 10% 拖垮的。如果 90 分位误差远大于平均说明有些区域 AP 太少或者采集点太稀得回去补采。几个能明显提精度的技巧采集时每个点换 4 个朝向各采一轮匹配时对朝向做投票对 RSSI 做时间窗口平滑别用单次值AP 筛选上把出现频率低于 30% 的 AP 剔掉它们对区分位置贡献小还引入噪声。还有一点地图坐标系一定要在采集前定死我见过采了几百个点才发现地图缩放比例不对坐标全废只能重采这种后悔药没处买。从那以后我每次开采集任务前都强制先拿三五个点做一轮「采集—建库—匹配」的小闭环确认坐标、权限、入库格式全对再铺开采。希望帮到你。本文还有配套的精品资源点击获取