Native Core
The Core source is platform-native Swift and does not import React. The React Native bridge is a separate layer and is not part of this API.
Integrate encrypted geofence checks, continuous verification, persisted fingerprints, and native device signals directly in a Swift application.
GeoFenceClient.shared is the high-level native entry point. It owns configuration, encryption, pings, continuous checks, and fingerprint submission. GeoFenceCore.shared exposes lower-level permissions, location, device, and marker collection.
The Core source is platform-native Swift and does not import React. The React Native bridge is a separate layer and is not part of this API.
Use the shared client, start it before calling ping or training methods, and destroy it when the integration is no longer needed.
The iOS Core SDK is not currently distributed as a standalone public CocoaPods artifact. There is no public pod installation command to use.
Core subspec, but that does not constitute a public release.The source configuration sets an iOS 13.0 minimum, Swift 5.7, and links Foundation, CoreLocation, CoreMotion, SystemConfiguration, Network, Security, and DeviceCheck.
After Kade supplies the native package, add it to the application target using the delivery-specific instructions. Do not add the React Native bridge to a native-only target.
Build your application target to verify the delivered package:
xcodebuild \
-workspace YourApp.xcworkspace \
-scheme YourApp \
-sdk iphonesimulator \
buildGeoFenceSdk pod name. The import name may differ if Kade supplies Core in another form; follow the package-specific instructions you receive.Start the shared client asynchronously, then issue a ping only after configuration succeeds.
import GeoFenceSdk
let client = GeoFenceClient.shared
let config = GeoFenceConfig(
apiToken: "your-api-token",
regionId: 123
)
client.start(config: config) { result in
switch result {
case .success:
let options = PingOptions(
userId: "player-123",
source: "login",
email: "player@example.com"
)
client.ping(options: options) { pingResult in
switch pingResult {
case .success(let response):
if response.blocked == true {
print("Blocked:", response.code ?? "unknown")
} else {
print("Inside:", response.inside)
print("Area:", response.area?.name ?? "none")
}
case .failure(let error):
print("Kade ping failed:", error)
}
}
case .failure(let error):
print("Kade startup failed:", error)
}
}start(config:completion:) derives the encryption key on a background queue and invokes its completion with a Swift Result. Do not assume the client is ready immediately after calling start.Add a user-facing location purpose string to the host application's Info.plist, then use GeoFenceCore to inspect and request authorization.
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your location is used to verify availability in your region.</string>let core = GeoFenceCore.shared
switch core.getLocationPermissionStatus() {
case .granted:
beginVerification()
case .notDetermined:
core.requestLocationPermission { status in
DispatchQueue.main.async {
if status == .granted {
beginVerification()
} else {
showLocationUnavailable()
}
}
}
case .denied, .restricted:
showLocationUnavailable()
}The native permission states are granted, denied, restricted, and notDetermined. If your policy permits a server-side check without device location, set skipLocation: true on PingOptions; confirm that policy with Kade.
These are native Swift signatures from the Core layer, not React Native bridge methods.
notInitialized if startup has not completed.onPingResponse and onPingError.visitorId.let core = GeoFenceCore.shared
let status = core.getLocationPermissionStatus()
let device = core.getDeviceInfo()
let jailbreak = core.getJailbreak()
let developerMode = core.getDeveloperMode()
let mockLocation = core.getMockLocation()
let locationSource = core.getLocationSource()
let vpn = core.getVpn()
let battery = core.getBattery()
core.getCurrentLocation(
accuracy: .high,
timeoutMs: 10_000,
maxAgeMs: 120_000
) { result in
// Result<GeoLocation, Error>
}Core also exposes sensor collection, integrity attestation, aggregate mobile markers, persisted fingerprint ID accessors, and explicit location watcher controls. Most integrations should prefer GeoFenceClient for policy checks.
| Field | Type and default | Behavior |
|---|---|---|
apiToken | String, required | Workspace API token. |
serverUrl | String, https://api.videntrix.com | API base URL. |
regionId | Int?, nil | Default region; ping-level value overrides it. |
signingSecret | String?, nil | Enables request signing when non-empty. |
locationStrategy | LocationStrategy, .race | Location retrieval strategy. |
locationMaxAgeMs | Int, 120,000 | Maximum preferred cached-fix age. |
locationMaxStalenessRadius | Double, 100 | Staleness radius used by location selection. |
locationAccuracy | LocationAccuracy, .high | .high, .balanced, or .low. |
debug | Bool, false | Enables verbose SDK logging. |
let options = PingOptions(
userId: "player-123",
silent: false,
skipLocation: false,
source: "deposit",
regionId: 123,
email: "player@example.com",
firstName: "Player",
lastName: "One"
)Every option has a default. source is a free-form flow tag, regionId overrides configuration for that ping, and identity fields are associated with the server-side client record.
Register handlers before starting continuous checks, retain no second client instance, and stop checks when the protected flow ends.
let client = GeoFenceClient.shared
client.onPingResponse = { response in
DispatchQueue.main.async {
updateAccessState(using: response)
}
}
client.onPingError = { error in
DispatchQueue.main.async {
showVerificationError(error)
}
}
client.startContinuousPing(
options: PingOptions(userId: "player-123", source: "session")
)
// When the verified flow ends:
client.stopContinuousPing()
// When disposing the entire integration:
client.destroy()startContinuousPing does nothing before successful startup.stop() and stopContinuousPing() stop continuous checks; destroy() also clears Core and configuration state.Branch on blocked first, tolerate optional fields, and keep transport failures separate from server verdicts.
func handle(_ response: PingResponse) {
if response.blocked == true {
denyAccess(
code: response.code,
message: response.message
)
return
}
if response.inside {
allowAccess(areaName: response.area?.name)
} else {
showOutsideRegion(distance: response.distanceToBorder)
}
if response.requestLocation == true {
// Revisit the permission/location flow before the next check.
}
}| Field | Type | Meaning |
|---|---|---|
inside | Bool | Whether the server resolved the client inside the relevant geofence. |
status | Int | Server response status value. |
message, code | String? | Optional response detail and machine-readable code. |
interval | Int | Server-provided interval used by continuous checks. |
distanceToBorder | Double | Distance value returned by the server. |
regionId | Int? | Resolved region when present. |
area | PingArea? | Matched area with id and name. |
blocked | Bool? | Explicit block decision when supplied. |
requestLocation | Bool? | Whether the response asks the client to obtain location. |
deviceTrustTtl | Int? | Optional device-trust lifetime supplied by the server. |
Talk to Kade for SDK access, approved packaging, credentials, and integration guidance for your application.