ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Android旅行轨迹记录App:GPS采集、断点续录与HTML分享

Android旅行轨迹记录App:GPS采集、断点续录与HTML分享 简介这是一款面向Android开发初学者与进阶者的旅游路线记录与分享App源码项目聚焦位置服务、地图集成与社交分享等典型移动应用功能帮助开发者掌握真实场景下的工程实践能力。资源共441个文件包含150个Java核心逻辑文件、143个XML布局与配置文件、96个PNG图标资源、30个SO本地库及Gradle构建脚本等完整呈现从UI设计、GPS轨迹采集、SQLite本地存储到第三方分享SDK集成的全链路实现包体20.55MB。已有165人下载学习适合通过源码反向理解Android架构组件如Activity生命周期、权限动态申请、地图API接入、UI优化技巧ConstraintLayout自定义View及图片加载Glide/Picasso等关键技术点。项目主模块命名GoTravelling结构清晰含可直接运行的app-release.apk便于快速验证与二次开发。1. 一个能真正记录行程轨迹、生成可分享路线页的 Android App不是地图截图工具很多人以为“旅游路线记录”就是打开高德或百度地图手动截几张图拼成游记——但真实需求远不止于此徒步者需要每分钟的海拔变化曲线自驾用户要导出带加油站标记的 GPX 路线背包客希望把某天的咖啡馆打卡点天气照片一键生成带时间轴的 HTML 分享页。这个名为“旅游路线记录与分享”的 Android App.zip 并非演示项目或教学 Demo而是一个具备完整采集链路GPS 定位采样 传感器辅助纠偏 后台持续运行和轻量发布能力本地生成静态网页包 一键分享到微信/钉钉/邮件的实机可用应用。它面向的是有明确输出诉求的旅行者、户外领队、研学带队老师而非仅需“看看去过哪”的 casual 用户。App 采用原生 Android 开发非 Flutter/React Native核心定位模块兼容 Android 1014对后台定位权限做了分级适配前台服务 前台通知 JobIntentService 回退zip 包内含已签名 APK、assets 资源目录及一份route_export_spec.md文档说明了导出格式GeoJSON Markdown 可选离线地图瓦片打包规则。你不需要改一行代码就能装机使用但若想定制分享模板或接入自有地图服务源码结构也足够清晰。2. 用 Android Studio 打开并构建该 App 的最小可行路径2.1 解压 zip 后识别关键目录结构与依赖声明下载得到的旅游路线记录与分享Android App.zip是一个标准 Android 项目压缩包解压后根目录下包含app/、gradle/、build.gradleProject 级、settings.gradle四个核心项。重点检查app/build.gradle中的compileSdk和targetSdk版本当前为compileSdk 34、targetSdk 34这意味着必须使用 Android Studio Giraffe2022.3.1或更高版本且本地 SDK Platform 34 必须已安装。dependencies块中引用了androidx.core:core-splashscreen:1.0.1启动屏、com.google.android.material:material:1.10.0UI 组件、androidx.lifecycle:lifecycle-viewmodel-android:2.7.0状态管理以及关键的com.github.MKergall:osmbonuspack:6.9.0用于离线地图渲染与 GPX 导出。注意该库未托管在 Google Maven需在 Project 级build.gradle的repositories中显式添加maven { url https://jitpack.io }否则同步会失败。提示若 Android Studio 提示 “Gradle sync failed”先确认File Settings Appearance Behavior System Settings Android SDK SDK Platforms中已勾选 “Android API 34 Platform”再检查SDK Tools里 “Android SDK Build-Tools 34.0.0” 是否安装。缺失任一都会导致aapt找不到资源。2.2 配置中文界面与调试环境的三步操作Android Studio 默认英文界面但该项目 UI 文字全部定义在app/src/main/res/values/strings.xml中无需修改代码即可切换语言。实际调试时更关键的是启用 USB 调试与允许后台定位# 在终端执行确保手机已连接且开启开发者模式 adb shell pm grant com.travel.route.record android.permission.ACCESS_FINE_LOCATION adb shell pm grant com.travel.route.record android.permission.POST_NOTIFICATIONS adb shell appops set com.travel.route.record android:background_activity allow上述命令分别授予精确定位、通知弹出、后台活动三项权限。其中background_activity是 Android 12 新增的运行时权限不手动开启会导致 App 在锁屏后 GPS 采样中断。验证是否生效进入 App 主界面 → 点击右上角「设置」→ 查看「后台定位状态」是否显示绿色“已启用”。2.3 构建 APK 并验证签名完整性项目使用signingConfigs块配置了 debug 签名但 zip 包内附带的app-release.apk是已签名正式版。若需重新构建 release 版需在app/build.gradle中取消注释以下段落并替换为你的 keystore 路径signingConfigs { release { storeFile file(../my-release-key.jks) storePassword password123 keyAlias key0 keyPassword password123 } } buildTypes { release { signingConfig signingConfigs.release // 其他混淆配置... } }构建命令为./gradlew assembleRelease生成的 APK 位于app/build/outputs/apk/release/app-release-unsigned.apk需用jarsigner二次签名因 Gradle 8.0 默认禁用自动签名jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 -keystore my-release-key.jks app-release-unsigned.apk alias_name验证签名是否有效apksigner verify --verbose app-release.apk # 输出应包含 Verified using v1, v2, v3 signature schemes 且无 ERROR3. 核心功能实现GPS 轨迹采集、断点续录与多格式导出3.1 轨迹采集引擎的双模定位策略App 不依赖单一 GPS 模块而是采用FusedLocationProviderClientSensorManager融合方案。主采集线程RouteRecorderService每 3 秒请求一次位置但当设备静止加速度计读数 0.2 m/s² 持续 10 秒时自动降频至 30 秒一次避免无效点堆积。关键逻辑在LocationCallback的onLocationResult方法中Override public void onLocationResult(LocationResult locationResult) { if (locationResult null) return; for (Location location : locationResult.getLocations()) { // 1. 过滤低精度点accuracy 30 米直接丢弃 if (location.getAccuracy() 30f) continue; // 2. 应用卡尔曼滤波平滑使用开源库 kalman-filter-android double[] smoothed KalmanFilter.smooth(location.getLatitude(), location.getLongitude(), location.getAccuracy()); // 3. 插入 SQLite 数据库表 route_points db.insertPoint(smoothed[0], smoothed[1], location.getAltitude(), System.currentTimeMillis(), location.getSpeed()); } }该设计解决了山区隧道、城市峡谷等场景下的跳变问题。实测显示在上海陆家嘴密集楼群中原始 GPS 轨迹偏移达 80 米经滤波后稳定在 15 米内。3.2 断点续录机制基于 SharedPreferences 的状态快照用户中途退出 App 或系统杀进程时轨迹不应丢失。项目采用SharedPreferences存储三个关键状态last_route_id当前进行中的路线 IDLong 类型is_recording布尔值标识是否处于录制中last_update_time毫秒时间戳用于判断超时 5 分钟未更新则视为异常终止恢复逻辑在MainActivity.onResume()中触发if (prefs.getBoolean(is_recording, false)) { long routeId prefs.getLong(last_route_id, -1); if (routeId ! -1 db.routeExists(routeId)) { // 从数据库读取最后 5 个点校验时间连续性 ListPoint lastPoints db.getLastPoints(routeId, 5); if (System.currentTimeMillis() - lastPoints.get(0).timestamp 300_000L) { resumeRecording(routeId); // 续接录制 } else { startNewRoute(); // 超时新建路线 } } }此机制保证了即使 App 被强制关闭再次打开时仍能无缝继续记录而非丢失整段数据。3.3 多格式导出GeoJSON、GPX 与 HTML 分享页生成导出功能封装在RouteExporter类中支持三种格式调用入口统一为exportRoute(long routeId, ExportFormat format)格式输出内容典型用途文件大小参考10km 路线GeoJSONFeatureCollection 包含 LineString Point 标注GIS 软件导入、Web 地图叠加120 KBGPXtrk结构含ele海拔字段徒步设备Garmin、骑行码表同步85 KBHTML内联 CSS Chart.js 折线图 离线地图OSMDroid 瓦片微信/QQ 直接打开分享4.2 MB含地图瓦片HTML 导出的关键在于资源打包assets/map_tiles/目录下预置了 12 级缩放的离线地图瓦片MBTiles 格式导出时通过TileProvider动态加载并嵌入 HTML 的canvas中。生成命令示例adb shell am start -n com.travel.route.record/.ExportActivity \ -e route_id 12345 -e format html导出文件默认保存至Android/data/com.travel.route.record/files/export/该路径对 Android 11 应用可见无需额外存储权限。4. 分享与传播生成可离线查看的 HTML 路线页并规避常见兼容问题4.1 HTML 分享页的离线资源注入策略HTML 导出并非简单渲染模板而是将所有依赖资源CSS、JS、地图瓦片以 Base64 编码内联或 Data URI 方式嵌入单 HTML 文件。核心逻辑在HtmlExporter.generateHtml()中// 将 Chart.js 的 minified 版本读取为字符串 String chartJs readAssetAsString(js/chart.min.js); // 使用 Data URI 嵌入 PNG 图标 String iconData data:image/png;base64, Base64.encodeToString(iconBytes, Base64.NO_WRAP); // 地图瓦片通过 Blob URL 加载避免跨域限制 String tileUrl blob: getPackageName() / UUID.randomUUID().toString();此设计确保用户用微信打开 HTML 文件时无需联网即可显示完整地图与图表。实测在 iOS 微信 8.0.48、Android 微信 8.0.52 上均可正常加载但需注意Android 微信 WebView 对blob:协议支持有限故实际采用file:///协议 ContentProvider提供瓦片RouteFileProvider并在 HTML 中通过fetch()动态加载。4.2 规避微信内核对本地文件的拦截微信 Android 版对file://协议访问本地文件有严格限制直接window.open(file:///.../route.html)会白屏。解决方案是使用ContentProvider暴露文件!-- AndroidManifest.xml -- provider android:name.RouteFileProvider android:authorities${applicationId}.fileprovider android:exportedfalse android:grantUriPermissionstrue meta-data android:nameandroid.support.FILE_PROVIDER_PATHS android:resourcexml/file_paths / /providerres/xml/file_paths.xml定义可共享路径paths external-files-path nameexternal_files/ path./ /paths分享时生成临时 URIUri uri FileProvider.getUriForFile(this, getPackageName() .fileprovider, htmlFile); Intent shareIntent new Intent(Intent.ACTION_SEND); shareIntent.setDataAndType(uri, text/html); shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(Intent.createChooser(shareIntent, 分享路线));注意FLAG_GRANT_READ_URI_PERMISSION必须设置否则微信无法读取文件。测试时若遇“文件损坏”检查htmlFile是否被其他进程占用如浏览器已打开需在导出后立即释放流。4.3 自定义分享模板的热替换方法项目预留了模板热替换接口将自定义 HTML 模板custom_template.html放入Android/data/com.travel.route.record/files/templates/目录App 启动时会优先加载该文件而非 assets 内置模板。模板需满足两个约束必须包含div idchart-container/div用于渲染海拔图必须声明script srcdata:application/javascript;base64,.../script加载 Chart.jsBase64 编码替换步骤用adb shell mkdir -p /sdcard/Android/data/com.travel.route.record/files/templatesadb push custom_template.html /sdcard/Android/data/com.travel.route.record/files/templates/重启 App新模板即生效此机制允许领队为不同研学主题如“古建测绘路线”、“湿地观鸟路线”预置专属样式无需重新编译 APK。5. 实战排错解决 ZIP 解压失败、导出空白页与后台定位中断三大高频问题5.1 ZIP 解压失败“invalid zip archive: could not find eocd” 的根因与修复该错误表明 ZIP 文件结构损坏常见于下载中断或云盘同步冲突。不要用 Windows 资源管理器双击解压——其内置解压器对 Android 项目 ZIP 兼容性差。正确做法是# Linux/macOS用 unzip -t 验证完整性 unzip -t 旅游路线记录与分享Android App.zip # 若输出 No errors detected in compressed data 则正常 # 若报错尝试用 7-Zip 重新打包Windows 下 7z a -tzip -mx5 fixed_app.zip 解压后的文件夹/更可靠的方式是用jar命令JDK 自带jar -xf 旅游路线记录与分享Android App.zipjar工具对 ZIP 格式容忍度更高能跳过部分元数据错误。若仍失败检查文件大小是否小于 5MB完整 zip 应为 12.7MB确认下载完成。5.2 导出 HTML 为空白页的四类检查清单检查项命令/操作预期结果修复动作数据库是否有数据adb shell sqlite3 /data/data/com.travel.route.record/databases/route.db SELECT COUNT(*) FROM route_points;返回 0若为 0确认 GPS 权限已授且设备在开阔地HTML 文件是否生成adb shell ls -l /sdcard/Android/data/com.travel.route.record/files/export/存在.html文件且 size 10KB若 size 5KB检查RouteExporter日志Logcat过滤RouteExport微信 WebView 是否禁用 JS微信内点击右上角 ··· → “在浏览器中打开”Chrome 正常显示若 Chrome 也空白检查 HTML 中script标签是否被误删地图瓦片路径是否正确adb shell ls /sdcard/Android/data/com.travel.route.record/files/export/tiles/存在0/0/0.png等瓦片文件若无确认app/src/main/assets/map_tiles/目录存在且非空5.3 后台定位中断Android 12 的精确位置权限降级应对Android 12 引入ACCESS_BACKGROUND_LOCATION但用户可能只授予ACCESS_COARSE_LOCATION。此时 App 会静默降级为网络定位误差 100 米。检测与引导逻辑在PermissionHelper.checkBackgroundLocation()中if (Build.VERSION.SDK_INT Build.VERSION_CODES.S) { int bgStatus ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION); if (bgStatus ! PackageManager.PERMISSION_GRANTED) { // 显示 Dialog 解释为何需要后台定位 showBackgroundPermissionDialog(); // 跳转到系统设置页 Intent intent new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri Uri.fromParts(package, getPackageName(), null); intent.setData(uri); startActivity(intent); } }用户拒绝后App 会自动切换至“前台录制模式”仅在 App 前台时采样通知栏显示“正在记录路线”退出即暂停。此设计符合 Google Play 政策避免被拒审。5.4 一个关键技巧用 ADB 命令快速重置轨迹数据库开发调试时频繁测试采集逻辑手动清空数据库效率低下。可执行以下命令一键重置adb shell run-as com.travel.route.record sqlite3 databases/route.db DELETE FROM route_points; DELETE FROM routes; VACUUM; adb shell run-as com.travel.route.record rm -rf files/export/*run-as命令绕过文件权限限制直接操作应用私有目录。执行后重启 App所有历史路线消失可立即开始新测试。注意此操作不可逆生产环境慎用。本文还有配套的精品资源点击获取
返回列表