Asdoos/SonyGpsApp

GitHub: Asdoos/SonyGpsApp

一款通过 BLE 将手机 GPS 坐标无中介传输至索尼相机的 Android 工具,绕过官方应用实现隐蔽定位注入。

Stars: 0 | Forks: 0

# Sony GPS Link [![Release](https://img.shields.io/github/v/release/Asdoos/SonyGpsApp?style=flat-square)](https://github.com/Asdoos/SonyGpsApp/releases/latest) [![Build](https://img.shields.io/github/actions/workflow/status/Asdoos/SonyGpsApp/release.yml?style=flat-square&label=build)](https://github.com/Asdoos/SonyGpsApp/actions) [![Android](https://img.shields.io/badge/Android-8.0%2B-green?style=flat-square&logo=android)](https://developer.android.com) [![Kotlin](https://img.shields.io/badge/Kotlin-1.9-purple?style=flat-square&logo=kotlin)](https://kotlinlang.org) [![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE) 一款通过蓝牙低功耗(BLE)将智能手机 GPS 坐标传输到索尼相机的 Android 应用程序——无需使用原始的 Sony Creators App。 **[⬇ Download latest APK](https://github.com/Asdoos/SonyGpsApp/releases/latest)** ## 功能概述 | 功能 | 说明 | |---|---| | BLE 相机发现 | 扫描索尼设备(制造商 ID 301) | | GPS 传输 | WGS-84,每 5 秒发送一次,91 或 95 字节数据包 | | APO 保持活跃 | 防止相机进入休眠模式,每 9 秒发送一次 | | 自动重连 | 在意外断开后最多尝试 10 次重连 | | 前台服务 | GPS + BLE 持续运行,即使应用关闭 | ## 支持的相机 所有支持索尼专有 BLE GPS 协议(`LocationInfoFromSmartPhone_1_0` / `_1_1`)的索尼相机,包括: - Sony ZV-E1、ZV-E10、ZV-1 II - Sony ILCE 系列(α7 IV、α7C、α7R V、α6700、...) - Sony FX3、FX30 相机必须**通过 Android 系统蓝牙设置**与手机配对,才能在此应用中使用。 ## 工作原理 ### 1. 相机发现(BLE 扫描) 索尼相机的 BLE 广告中始终包含**制造商 ID 301**(`0x012D` = Sony Corporation, per Bluetooth SIG)。应用仅过滤此 ID: ``` ScanFilter: ManufacturerData(companyId = 301, data = []) ScanMode: SCAN_MODE_LOW_LATENCY ``` 发现的设备会以列表形式展示给用户,显示名称、MAC 地址和信号强度(RSSI)。 ### 2. BLE GATT 协议(索尼专有) 索尼相机暴露一个专有 GATT 协议,包含两个相关服务: #### 服务 1 — 相机控制(`CC00`) ``` UUID: 8000CC00-CC00-FFFF-FFFF-FFFFFFFFFFFF ``` | 特征(Prefix) | 类型 | 内容 | |---|---|---| | `0000CC02` | 写入 | 通用相机控制命令(包括 APO 避免) | #### 服务 2 — GPS / 位置(`DD00`) ``` UUID: 8000DD00-DD00-FFFF-FFFF-FFFFFFFFFFFF ``` | 特征(Prefix) | 类型 | 内容 | |---|---|---| | `0000DD01` | 通知 | 相机 → 手机:传输禁用信号 `{3,1,2,0}` | | `0000DD11` | 写入 | GPS 载荷(91 或 95 字节) | | `0000DD21` | 读取 | 能力标志:字节[4] & `0x02` → 时区支持 | | `0000DD30` | 写入 | 锁定:`{0x01}` = 获取,`{0x00}` = 释放 | | `0000DD31` | 写入 | 位置传输:`{0x01}` = 开启,`{0x00}` = 关闭 | | `0000DD32` | 读取 | 时间校正设置(信息性) | | `0000DD33` | 读取 | 区域调整设置(信息性) | ### 3. 连接协议(握手序列) 在 GATT 连接和服务发现后,执行以下序列: ``` ① enableNotify(DD01) — camera can abort transfer at any time ↓ CCCD descriptor written ② write {0x01} → DD30 — acquire exclusive lock ↓ write callback OK ③ write {0x01} → DD31 — enable GPS transfer on camera ↓ write callback OK ④ read DD32 — read time correction setting ↓ read callback ⑤ read DD33 — read area adjustment setting ↓ read callback ⑥ read DD21 — read capability flags ↓ read callback: byte[4] & 0x02 → timezoneSupport = true/false ⑦ → onReady(): start GPS updates + APO keepalive timer ``` 所有 GATT 操作通过基于 `ArrayDeque` 的操作队列**串行化**执行,因为 BLE 仅允许一个并发操作。每个操作仅在前一个操作的回调收到后才开始。 ### 4. GPS 数据包格式 来源:`BluetoothLeUtil.setLocationAndTime()` + `TransferringLocationInfoWithLockState.onLocationUpdated()` GPS 坐标以**大端二进制数据包**形式写入特征 `DD11`。根据相机能力存在两种格式: #### 格式 A — 91 字节(不支持时区) #### 格式 B — 95 字节(支持时区,当 `DD21[4] & 0x02 != 0`) **坐标编码:** `(double) 度数 × 1e7` → `toInt()` → `ByteBuffer.allocate(4).putInt(...)` **时间戳:** UTC 时区,基于 `location.getTime()` 通过 `Calendar.getInstance(UTC)` 获取 **验证:** 超过 **10 秒** 旧的 GPS 定位将被丢弃(基于 `elapsedRealtimeNanos` 差值) ### 5. APO 保持活跃(自动断电避免) 相机在约 30 秒不活动(待机/休眠模式)后会断开 BLE 连接。 因此原始索尼应用每 **9 秒** 发送一次保持活跃命令: ``` Service: 8000CC00-CC00-FFFF-FFFF-FFFFFFFFFFFF Characteristic: 0000CC02-... Value: {0x03, 0x08, 0x10, 0x00} Interval: 9,000 ms ``` 保持活跃**独立于** GPS 更新运行,通过相同的操作队列,并在每次成功写入回调后重新调度。写入失败不会中止会话——下一次尝试将在固定间隔进行,因为单次失败是非关键性的。 ### 6. 自动重连 在意外连接丢失(相机休眠尽管有保持活跃、超出范围等)时,应用自动尝试重连: - **延迟:** 尝试之间间隔 4 秒 - **最大尝试次数:** 10 次 - **计数器重置:** 成功完成握手(`onReady`)时重置 - **不重连:** 如果用户手动点击“停止”(`userStopped` 标志) ### 7. 前台服务与能效 #### 为何需要前台服务? | Android 机制 | 无服务时的影响 | 使用前台服务时 | |---|---|---| | Doze Light(屏幕关闭约 3 分钟) | GPS 回调被批处理/延迟 | 豁免 | | Doze Deep(深度空闲) | `Handler.postDelayed` 冻结 → APO 保持活跃失效 | 豁免 | | 内存压力 | 进程被杀死 | `START_STICKY`:系统自动重启 | #### 服务类型声明(Android 14+ / API 34 必需) ``` android:foregroundServiceType="location|connectedDevice" ``` - `location` — 授予前台服务中的 GPS 访问权限 - `connectedDevice` — 授予前台服务中的 BLE 访问权限 #### 功耗估算(屏幕关闭时) | 组件 | 平均电流 | |---|---| | GPS 芯片(`HIGH_ACCURACY`,5 秒间隔) | ~40–60 mA | | BLE(连接 + ~6 次写入/10 秒) | ~2–4 mA | | CPU(回调、数据包组装) | ~1–2 mA | | APO 保持活跃(包含在 BLE 中) | ~0.1 mA | | **应用增量总计** | **~45–65 mA** | | **实际包含系统基线** | **~75–90 mA** | → **每小时约消耗 4–7% 电量**(在典型 4000 mAh 设备上) → 类似于 Strava 等后台运行 GPS 追踪应用 ### 8. 架构 ``` ┌─────────────────────────────────┐ │ MainActivity │ │ ┌──────────────┐ │ │ │ BLE Scan │ (short-lived)│ │ └──────┬───────┘ │ │ │ device selected │ │ ┌──────▼───────────────────┐ │ │ │ startForegroundService │ │ │ │ bindService (Binder) │ │ │ └──────────────────────────┘ │ │ StatusListener (UI updates) │ └────────────┬────────────────────┘ │ Binder (LocalBinder) ┌────────────▼────────────────────┐ │ GpsForegroundService │ ← runs persistently in background │ │ │ FusedLocationProviderClient │ GPS every 5 s │ Handler (APO timer, reconnect) │ │ │ │ ┌──────────────────────────┐ │ │ │ SonyCameraGatt │ │ │ │ ┌──────────────────┐ │ │ │ │ │ ArrayDeque │ │ │ Serialised op-queue │ │ │ (Op-Queue) │ │ │ │ │ └──────────────────┘ │ │ │ │ GATT Callback │ │ │ └──────────────────────────┘ │ │ │ │ Persistent Notification │ "Stop" action directly in notification └─────────────────────────────────┘ │ BLE GATT ┌────────────▼────────────────────┐ │ Sony Camera │ │ Service CC00 (Control) │ ← APO keepalive {3,8,16,0} every 9 s │ Service DD00 (GPS) │ ← GPS packet (91/95 B) every 5 s └─────────────────────────────────┘ ``` ## 项目结构 ``` SonyGpsApp/ ├── app/src/main/ │ ├── java/com/example/sonygps/ │ │ ├── GpsForegroundService.kt Foreground service: GPS + BLE session management │ │ ├── MainActivity.kt UI: BLE scan, camera selection, service binding │ │ ├── SonyCameraGatt.kt BLE GATT client: handshake, op-queue, APO keepalive │ │ └── SonyGpsPacket.kt GPS packet assembly (91/95 bytes, Sony format) │ ├── res/ │ │ ├── layout/activity_main.xml │ │ ├── drawable/ic_launcher_*.xml │ │ ├── mipmap-anydpi-v26/ │ │ └── values/themes.xml, colors.xml │ └── AndroidManifest.xml ├── gradle/ │ ├── libs.versions.toml │ └── wrapper/gradle-wrapper.properties ├── build.gradle.kts ├── settings.gradle.kts ├── gradle.properties android.useAndroidX=true └── gradlew / gradlew.bat ``` ## 构建与安装 ### 要求 - Android Studio Hedgehog(2023.1.1)或更新版本 - Android SDK 34 - Kotlin 1.9.x - 运行 Android 8.0+(API 26)并支持 BLE 的物理设备 ### 步骤 1. 在 Android Studio 中打开 `SonyGpsApp/` 文件夹 2. 等待 Gradle 同步完成(所有依赖自动下载) 3. 通过 USB 连接设备 4. **运行**(`Shift+F10`) ## 权限 | 权限 | 用途 | 所需最低 API | |---|---|---| | `ACCESS_FINE_LOCATION | GPS 坐标 | API 1 | | `ACCESS_COARSE_LOCATION` | 备用位置 | API 1 | | `BLUETOOTH_SCAN` | BLE 扫描 | API 31 | | `BLUETOOTH_CONNECT` | GATT 连接 | API 31 | | `BLUETOOTH` + `BLUETOOTH_ADMIN` | BLE(旧版) | API ≤ 30 | | `FOREGROUND_SERVICE` | 启动前台服务 | API 28 | | `FOREGROUND_SERVICE_LOCATION` | 前台服务中的 GPS 访问 | API 34 | | `FOREGROUND_SERVICE_CONNECTED_DEVICE` | 前台服务中的 BLE 访问 | API 34 | | `POST_NOTIFICATIONS` | 显示服务通知 | API 33 | ## 已知限制 - **需要配对:** 相机必须通过 Android 系统蓝牙设置配对(不能通过本应用)。未实现 Sony 应用的配对协议。 - **仅支持 BLE GPS 协议:** 不支持 WiFi(PTP/IP,端口 15740)和 USB(PTP/MTP)。 - **无实时取景器:** 仅传输 GPS 数据,未实现相机控制和图像传输。 - **GPS 精度:** `PRIORITY_HIGH_ACCURACY` 使用硬件 GPS 芯片。在室内或信号弱条件下,超过 10 秒的旧定位将被自动丢弃。 ## 资料来源与逆向工程 | 文件(从 Sony Creators App v3.3.1 反编译) | 发现 | |---|---| | `BluetoothLeUtil.java` | GPS 数据包编码(`setLocationAndTime`) | | `TransferringLocationInfoWithLockState.java` | 握手序列、数据包结构、字节布局 | | `ExecutingApoAvoidanceState.java` | APO 保持活跃命令 `{3,8,16,0}`,间隔 9,000 毫秒 | | `BluetoothGattUtil.java` | UUID 常量、所有命令的字节常量 | | `EnumCameraInfo.java` | 时区支持标志(格式 A 与格式 B) | | `BluetoothLeUtil.startLeScanWithLowPower()` | BLE 扫描过滤器(制造商 ID 301) |
标签:Android, Android 8.0, APO保持活跃, BLE, DSL, GPS, IoT, Kotlin, Sony相机, WGS-84, 位置传输, 低延迟扫描, 制造商数据过滤, 前台服务, 后台服务, 开源, 无线传输, 物联, 相机控制, 索尼相机, 自动重连, 蓝牙, 蓝牙低功耗, 设备发现