VectorGuard is an advanced iOS motion and sensor framework designed for real-time device behavior analysis.
- Real-time motion analysis (accelerometer + gyroscope fusion)
- Device theft / grab detection
- Jiggle and rapid-movement classification
- Compass heading change detection
- Barometric altitude change detection
- Multi-subscriber
AsyncStreamevent API - Raw sensor monitoring stream (
monitorSensors()) - Filtered event subscriptions (
subscribe(where:)) - Throttled sensor stream for SwiftUI (
monitorSensors(throttle:)) - Sensitivity presets:
.sensitive,.balanced,.relaxed - Point-in-time status snapshot (
VectorGuard.shared.status) - Zero dependencies — CoreMotion + CoreLocation only
- Native Swift,
@MainActorsafe - Easy Swift Package Manager integration
| Sensor | Permission key |
|---|---|
| Accelerometer + Gyroscope | NSMotionUsageDescription |
| Barometer | None |
| Compass (heading) | NSLocationWhenInUseUsageDescription |
Add the relevant keys to your app’s Info.plist:
<!-- Required for accelerometer / gyroscope -->
<key>NSMotionUsageDescription</key>
<string>Motion data is used to detect device movement and anti-theft events.</string>
<!-- Required only if compass heading events are needed -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Heading data is used for compass analysis.</string>The barometer requires no Info.plist key.
.package(
url: "https://github.com/yourname/VectorGuard.git",
branch: "main"
)import VectorGuard
// AppDelegate or SwiftUI @main init()
VectorGuard.configure(autoStart: true)Pass optional parameters to tune sensitivity or wire a delegate:
VectorGuard.configure(
configuration: VectorGuardConfiguration(rapidMovementThreshold: 2.0),
delegate: self,
autoStart: true
)Task {
for await event in VectorGuard.shared.subscribe() {
switch event {
case .devicePickedUp:
triggerAlarm()
case .stateChanged(_, let new):
print("State →", new)
case .accelerationSpike(let mag, _):
print("Spike:", mag, "g")
default:
break
}
}
}class BaseViewController: UIViewController, VectorGuardDelegate {
func vectorGuard(_ guard: VectorGuard, didDetect event: VectorGuardEvent) {
switch event {
case .accelerationSpike(let magnitude, let vector):
print("magnitude -> \(magnitude)")
print("vector -> \(vector)")
default: break
}
}
}VectorGuard.shared.stopMonitoring()It combines data from multiple hardware sensors including:
- Accelerometer
- Gyroscope
- Magnetometer
- Device Motion
- Compass
- Barometer
- Detect when a device is grabbed or moved unexpectedly
- Trigger protection workflows
- Identify suspicious physical interactions
- Activity detection
- Movement classification
- Orientation tracking
- Stability monitoring
| Event | When it fires |
|---|---|
.devicePickedUp |
Device transitions from idle → moving or grabbed suddenly |
.devicePutDown |
Device transitions from moving/rapid-movement/jiggling → idle |
.accelerationSpike(magnitude:vector:) |
Sharp linear-acceleration above threshold (grab / drop / throw) |
.rotationSpike(magnitude:vector:) |
Sharp angular-velocity spike (rapid twist or flip) |
.jigglingDetected |
Repeated direction reversals — someone is shaking the device |
.headingChanged(current:delta:threshold:) |
Cumulative compass rotation crossed one of the configured tiers |
.attitudeChanged(current:delta:) |
Device orientation (pitch/roll/yaw) changed beyond threshold |
.altitudeChanged(delta:pressure:) |
Relative altitude changed beyond threshold (barometer) |
.stateChanged(from:to:) |
Any motion-state transition |
VectorGuard tracks rotation from two independent sources, each with its own tunables:
-
Compass heading (
headingChanged) — absolute rotation relative to magnetic/true north. Raw compass readings are noisy, so VectorGuard smooths them on the unit circle (no discontinuity at the 0°/360° wrap) before measuring deltas — tune the strength withheadingSmoothingFactor(0...1; lower = steadier but slower to react). Rather than a single on/off threshold,headingChangeThresholdsaccepts an ascending list of degree values (default[15, 45, 120]); the emitted event reports the highest tier the cumulative rotation reached, so one subscription can distinguish a small drift from a sharp spin viaevent'sthresholdpayload. -
Device attitude (
attitudeChanged) — pitch / roll / yaw fromCMDeviceMotion, exposed asDeviceAttitude(degrees). Useful for orientation changes a compass can't see, e.g. a phone flipped face-down or tipped out of a pocket. Fires when the combined per-axis change (Euclidean norm) exceedsattitudeChangeThreshold(default20°).
Task {
for await event in VectorGuard.shared.subscribe() {
switch event {
case .headingChanged(let current, let delta, let threshold):
print("Rotated \(delta)° (now \(current)°) — crossed the \(threshold)° tier")
case .attitudeChanged(let current, _):
print("Orientation → pitch \(current.pitch)°, roll \(current.roll)°, yaw \(current.yaw)°")
default:
break
}
}
}status.lastHeading / lastTrueHeading / lastHeadingAccuracy and status.lastAttitude
expose the current readings as a point-in-time snapshot — see VectorGuardStatus.
Motion states exposed via VectorGuard.shared.status.currentState:
.idle // at rest
.moving(intensity: Double) // steady movement; intensity in g
.rapidMovement(vector: SensorVector) // sudden high-g spike
.jiggling // repeated directional reversalsVectorGuard uses a multi-layer sensor fusion pipeline:
- Raw Sensor Collection
- Motion Normalization
- Pattern Analysis
- Threat Detection
- Event Dispatching
- iOS 16+
- Swift 5.9+
- Xcode 16+
- Machine learning motion profiles
- Watch connectivity
- Anti-theft mode
- Behavioral biometrics
- Motion anomaly scoring
- Dashboard visualizer
MIT License
Petar Lemajic
Galahador
