Registration (iOS)¶
How Registration Works¶
The Surfmeter Mobile Quality SDK uses a license-based registration system to manage access. Before your app sends any measurement data to the Surfmeter server, the device must be registered against it using a registration key provided by AVEQ.
A registration key controls:
- How many devices can register with it (a finite counter, or unlimited)
- How long each device may use the SDK after registering (optional usage limit in days)
- When the key is valid ("valid until" – a time window). This controls when new registrations are accepted, but does not affect already-registered devices
When a device registers, the server decrements the key's registration counter, creates a client record, and returns a unique device identity, consisting of a UUID and a secret. The SDK stores these credentials on the device and uses them to authenticate all subsequent API calls.
Registration is required before any test can run
Building a test on a device that is not registered fails, the same way it does on Android. Credentials on their own are not enough either: the server has to have confirmed them, which happens when the device authenticates. So your app has to register, and wait for that to succeed, before it measures anything.
Registration Example¶
Use the Registry class and call registerClient with your license key. Registration is a one-time process per device, since the credentials are persisted on the device.
import SurfmeterQualitySDK
let registry = Registry(apiEndpoint: "https://your-server.aveq.info/client_api/v1")
// hasRegisteredBefore is your own state, see the notes below
if !registry.isClientRegistered() && !hasRegisteredBefore {
registry.registerClient(
registrationKey: "REPLACE_WITH_YOUR_REGISTRATION_KEY",
label: "device-001", // optional, must be unique across all your clients
tags: ["production", "eu-west"] // optional
) { result in
switch result {
case .success:
hasRegisteredBefore = true
print("Client registered")
case .failure(let error):
// log or display an error
print("Registration failed: \(error.localizedDescription)")
}
}
}
The apiEndpoint is the client API base URL of your Surfmeter server, for example https://your-server.aveq.info/client_api/v1. A trailing slash is stripped, so either form works.
Notes on the above:
- The registration request runs on a background queue, and the completion handler is called on that same background queue. Dispatch back to the main queue before touching your UI from it.
- The completion only reports success once the device has also authenticated with its new credentials, so by the time it says so, tests can run.
- Your implementing application has to store the state that the client is registered, and register only when that state says it never has.
isClientRegistered()is not enough on its own: the SDK clears the credentials of a device the server has dropped, and registering such a device again takes a second slot of your key. See Disabled Devices. - The registration key is provided by AVEQ. If it does not work, please contact us.
Checking the Registration State¶
There are two questions, and they have different answers. isClientRegistered() tells you whether credentials are stored on the device. isRegistrationValid() tells you whether the server has confirmed them and that confirmation has not run out, which is what a test actually needs:
if registry.isRegistrationValid() {
// tests can run, and their results are being sent
} else if registry.isClientRegistered() {
// registered earlier, but the confirmation has run out; authenticate to renew it
registry.authenticate { result in /* ... */ }
} else if hasRegisteredBefore {
// the server dropped this device; see Disabled Devices below
} else {
// never registered
}
The SDK renews the confirmation on its own whenever it has a reason to reach the server, so most apps only have to handle the first and last case.
You can also read the client UUID, which is useful for support requests and for identifying the device in the Surfmeter Dashboard:
To discard the stored credentials locally, for example when a user logs out or resets the app, call:
This also throws away any measurement still waiting to be sent, since a measurement is uploaded under the identity that took it and there is no longer one.
Clearing credentials does not return the license
clearRegistrationInfo() only removes the credentials from the device. It does not tell the server, so the registration slot stays taken. To free a slot, disable the client in the Surfmeter Dashboard, or send us the device UUIDs so we can free the slots for you. A server-side unregistration call, as the Android SDK offers, is not yet available on iOS.
Where the Credentials Are Stored¶
The SDK stores the UUID and secret in UserDefaults, under the keys com.surfmeter.qualitysdk.clientUuid and com.surfmeter.qualitysdk.secret, along with the confirmation window and the capability.
Editing these by hand does not get anyone a working SDK. Only the server can grant the confirmation a test needs, and it only does so for credentials it issued itself. Credentials it does not recognise are refused and then discarded from the device.
This has two consequences worth planning for:
- The credentials are included in iCloud and iTunes backups of the app. A device restored from a backup of another device carries the same UUID, so both devices would report under one identity. If that matters for your deployment, exclude the app from backup, or clear the credentials and register again on first launch after a restore.
- Deleting the app removes the credentials, so a reinstall registers again and consumes another slot from the key.
Billing Implications¶
Registered devices are counted toward your license usage.
For keys with a per-device usage limit, the server returns the slot to the pool automatically when the device's usage window elapses, even if the app is never opened again.
For keys without a usage limit, the device keeps holding its slot until it is disabled server-side. Please let us know, or use the Surfmeter Dashboard, when devices are decommissioned so the slots can be reused.
Authentication¶
You do not normally call this yourself, but for completeness: measurements are authenticated with a short-lived JWT that the SDK fetches from the server with the stored credentials.
registry.authenticate { result in
switch result {
case .success(let jwt):
print("Got token")
case .failure(let error):
print("Authentication failed: \(error.localizedDescription)")
}
}
ClientApi does this on its own and keeps the token for as long as the server said it is good for, so measurement sync needs no token handling on your side.
Authenticating does two further things. It sets how long this device may keep running tests, up to seven days and shortened by the registration key's own validity and by any per-device usage limit. And it refreshes the capability below, along with whether the device is still enabled, so a change AVEQ makes takes effect without the device registering again.
If the server refuses the device, the SDK discards the stored credentials and everything the queue is still holding, and the device stops measuring. There are three reasons it does so:
- The credentials are not ones the server issued.
- The usage window has elapsed. The server has already returned the license slot to the pool, so registering again with the same key is what you want here.
- The device has been disabled in the Surfmeter Dashboard. Registering again is what you do not want here, see below.
Disabled Devices¶
A device that is disabled in the Surfmeter Dashboard stops measuring. The SDK finds out the next time it reaches the server, which happens with every upload, and then clears the device's credentials along with anything still queued. From that point isClientRegistered() is false and building a test fails.
Registering again is your app's decision, and it is the one thing that should not happen here: a device that registers again becomes a new client, enabled, holding a second slot of your key. So keep track of whether this install has ever registered, and use that rather than isClientRegistered() to decide:
if registry.isClientRegistered() {
// measuring normally
} else if hasRegisteredBefore {
// the server dropped this device, most likely disabled; do not register again
} else {
registry.registerClient(registrationKey: key) { _ in hasRegisteredBefore = true }
}
The demo app in the release archive does exactly this, in SurfmeterPipeline.swift.
Disabling is not immediate
A device only learns that it has been disabled when it next reaches the server. One that is offline, or that has been asleep for a while, keeps measuring on the session it already holds until that session runs out, which is at most seven days.
What a Device May Measure¶
A registration key can be restricted to certain measurement types and subjects. A device registered with such a key cannot build a test outside them: it fails with an error naming the type and subject that were refused.
if let capability = registry.getCapability() {
let canRunVideo = capability.allows(type: "VIDEO", subject: "avplayer")
let canRunWeb = capability.allows(type: "WEB", subject: "website")
}
getCapability() returns nil when the key does not restrict anything, which means the device may run everything. A forbidden entry always beats an allowed one, and an empty allowed list means "everything that is not forbidden".
Differences from Android¶
The iOS Registry covers registration, authentication, capabilities and expiry. One part of the Android registration system is not implemented on iOS yet:
- Server-side unregistration (
unregisterClientAsyncon Android)
Expiry is handled differently, and better: rather than counting down a usage limit on the device as Android does, the iOS SDK asks the server how long the device may keep measuring, so a clock changed on the device makes no difference.
If you rely on server-side unregistration, please get in touch with us before you build against the iOS SDK.