Mappls InTouch

InTouchKit for iOS

InTouchKit is a local Swift package for iOS 17 and newer. Add this directory as a local package in Xcode and link the InTouchKit product. The sample app is in InTouchLab.xcodeproj. Its checked-in project can be built directly. Developers changing the file layout can regenerate it with XcodeGen and project.yml.

Run the lab

  1. Start the repository's Docker service. The simulator reaches the Mac at http://127.0.0.1:8917.
  2. Boot an iPhone in Simulator. Find the UDID with xcrun simctl list devices booted.
  3. From this directory run python3 scripts/simulator.py YOUR_SIMULATOR_UDID. The launcher passes the local IOS_TOKEN and VIEW_TOKEN through the child process environment. You can also launch manually from Xcode and type the keys into the secure fields. Keys entered in the UI live in memory.
  4. Under Capture, enable the sensors you want and tap Start sensors and diagnostics. In Simulator, choose a location under Features → Location. Pause sensors stops acquisition. Send queued readings drains retained data on demand. Under Viewer, tap Refresh devices and readings and select a device. Tap a recorded clip to open the authenticated download.

Use python3 scripts/simulator.py YOUR_SIMULATOR_UDID --smoke on a dedicated simulator for an executable integration check. It grants the sample location permission, sets a simulated location in New Delhi, records native diagnostics, generates a silent one-frame MP4, and verifies viewer readback and exact clip bytes. The location setting and grant remain on that simulator. The result is also recorded in the app's Documents/smoke-result.txt. Keep the Docker API running during the check.

A physical phone must use an HTTPS origin it can reach and a provisioned device token. Provision your signing team in Xcode. Supply credentials to your own app through its enrollment flow and device Keychain. A device token binds the server-side identity. The SDK's deviceID names its local storage scope.

Integrate capture

Add NSLocationWhenInUseUsageDescription and NSMotionUsageDescription to your app's property list. Add camera and microphone descriptions if your app offers the sample's video recording workflow. Create and retain one client per device identity on the main actor. Start following an explicit user action and stop when the capture session ends.

import InTouchKit

@MainActor
func startSession(origin: URL, deviceToken: String, deviceID: String) throws -> DeviceClient {
    let client = try DeviceClient(origin: origin, token: deviceToken, deviceID: deviceID)
    client.onStatus = { message in print(message) }
    client.start(location: true, movement: true)
    // A connected BLE or input sensor can supply timestamped scalar channels.
    client.record(Reading("temperature", ["celsius": 19.4]))
    return client
}

Drivers collecting high-resolution or time-aligned readings can pass up to 256 timestamped readings to client.recordBurst(_:) in one SQLite transaction. A burst that exceeds remaining queue capacity is rejected as a unit.

Call try client.enqueueClip(mp4URL) to cache a user-approved MP4 and schedule upload. The returned ID identifies the clip in the viewer. The sample supports an eight-second camera recording on a supported phone or an MP4 selected through the system Files picker. Camera recording includes audio and starts in the system recorder under the user's control. Capturing a clip and sending telemetry have independent storage limits.

let viewer = try API(origin: origin, token: viewerToken)
let devices = try await viewer.devices()
let readings = try await viewer.samples(device: "ios-lab")
let clips = try await viewer.clips(device: "ios-lab")

Sampling, delivery and control

Stream Acquisition and units
Location Core Location when-in-use, 100 m requested accuracy and 10 m distance filter. Lat/lon are degrees, speed m/s, altitude and accuracy metres, course degrees. Unavailable fields are omitted.
Movement Core Motion user acceleration multiplied by standard gravity, in m/s² along iOS device axes.
Orientation Core Motion attitude unit quaternion x/y/z/w in its device-motion reference frame. The attitude reference depends on the device.
Diagnostics OS monotonic uptime, thermal state, low-power mode, queue and dropped reading counts, battery percentage when supplied. Captured on start and once a minute.
Incident Acceleration magnitude above the configured m/s² threshold emits an incident and requests a flush. A 10 s debounce limits repeated alerts.

The heartbeat returns desired revision, sampling/flush/heartbeat intervals and motion threshold. The next heartbeat reports the locally applied revision. A pending flush command is acknowledged after the queue drains. The SDK clamps the sample interval to 20–60,000 ms, slows movement sampling to at most 1 Hz in low-power mode, and requests location only when permitted. The SDK uses short HTTP requests and never opens a persistent media connection.

SQLite WAL holds up to 20,000 numeric readings, at most 4 KiB per encoded reading. The SDK reserves immutable batches of 64 and removes each after the server acknowledges its stable UUID. Time, size, local incidents, manual actions and remote flush requests can trigger an upload. Failed sends retain their data. Retries use exponential backoff with jitter, with at most eight batches drained per pass. Once the queue is full the client counts and rejects newly arriving readings. Media files are buffered separately, with a limit of 16 MiB per clip and 64 MiB total. Completed media upload removes the cached local copy.

The queue is scoped to API origin, device ID and a digest of the device credential. A fresh credential starts a new queue. Drain the prior identity before rotating a credential in this prototype. The app pauses collection on background entry and requires a user action to restart. iOS suspension, screen-locked collection, production credential rotation, streamed video and resumable media chunks require further integration. Simulator location, networking and generated video exercise software paths. Validate real camera, IMU, radio, thermal load, battery and background behavior on physical devices before setting production performance budgets.