Client to Server
For this integration method, the DeviceAssure library collects device data and automatically sends it to the DeviceAssure API for validation. Results are returned directly to your application via callbacks.
This is the recommended approach as it automatically uses the nearest DeviceAssure service endpoint for optimal response time.
Note: A valid licence key is required for Client to Server integration.
Overview
There are three main steps to validate a device:
- Initialize the DeviceAssure library with the application context
- Call the
check()method with your licence key and callback handler - Handle the validation results returned via the callback
Implementation
Step 1: Initialize the Library
Initialize DeviceAssure in your Application class's onCreate() method:
Step 2: Define the Callback Interface
Create a delegate interface to handle responses:
Step 3: Create a Callback Handler
import com.deviceassure.android.library.Callback
import org.json.JSONObject
class DeviceAssureCallback(private val delegate: DeviceAssureDelegate) : Callback {
override fun taskComplete(result: JSONObject) {
delegate.onResponse(result)
}
override fun handleError(errorStr: String) {
delegate.onError(errorStr)
}
override fun progressUpdate(percent: Int?) {
// Track progress if needed
}
}
import org.json.JSONObject;
import com.deviceassure.android.library.Callback;
public class DeviceAssureCallback implements Callback {
private DeviceAssureDelegate delegate;
public DeviceAssureCallback(DeviceAssureDelegate delegate) {
this.delegate = delegate;
}
@Override
public void taskComplete(JSONObject result) {
delegate.onResponse(result);
}
@Override
public void handleError(String errorStr) {
delegate.onError(errorStr);
}
@Override
public void progressUpdate(Integer percent) {
// Track progress if needed
}
}
Note:
Callbackalso declares two deprecated hooks,statusUpdate()and a no-argumenttaskComplete(). The library never calls either and they do not need to be implemented.
Step 4: Perform Validation
Call the check() method from anywhere in your application:
Complete Example
import android.app.Application
import android.util.Log
import com.deviceassure.android.library.DeviceAssure
import org.json.JSONObject
class MyApplication : Application(), DeviceAssureDelegate {
override fun onCreate() {
super.onCreate()
// Initialize the library
DeviceAssure.init(applicationContext)
// Perform validation
DeviceAssure.check("<LICENCE_KEY>", DeviceAssureCallback(this))
}
override fun onResponse(json: JSONObject) {
Log.d(TAG, "Validation result: $json")
// Check the "result" field for AUTHENTIC, NON-AUTHENTIC, etc.
}
override fun onError(error: String) {
Log.e(TAG, "Validation error: $error")
}
companion object {
private const val TAG = "DeviceAssure"
}
}
import android.app.Application;
import android.util.Log;
import org.json.JSONObject;
import com.deviceassure.android.library.DeviceAssure;
public class MyApplication extends Application implements DeviceAssureDelegate {
private static final String TAG = "DeviceAssure";
@Override
public void onCreate() {
super.onCreate();
// Initialize the library
DeviceAssure.init(this.getApplicationContext());
// Perform validation
DeviceAssure.check("<LICENCE_KEY>", new DeviceAssureCallback(this));
}
@Override
public void onResponse(JSONObject json) {
Log.d(TAG, "Validation result: " + json.toString());
// Check the "result" field for AUTHENTIC, NON-AUTHENTIC, etc.
}
@Override
public void onError(String error) {
Log.e(TAG, "Validation error: " + error);
}
}
The Suspending API
Kotlin callers can use checkAsync() instead of a callback. It suspends until the validation completes and returns a ValidationResult, so the outcome is handled at the call site rather than in a separate class.
Note: The suspending API is for Kotlin callers. A
suspendfunction compiles to a method that takes aContinuationparameter, which is not a usable API from Java, so Java integrators use the callback API shown above — it runs the same validation and reports the same outcomes.
Call it from any coroutine scope — for example an Activity's lifecycleScope:
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.deviceassure.android.library.DeviceAssure
import com.deviceassure.android.library.ValidationResult
import kotlinx.coroutines.launch
class ValidationActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
when (val result = DeviceAssure.checkAsync("<LICENCE_KEY>")) {
is ValidationResult.Success -> Log.d(TAG, "Validation result: ${result.response}")
is ValidationResult.Error -> Log.e(TAG, "Validation error: ${result.message}")
}
}
}
companion object {
private const val TAG = "DeviceAssure"
}
}
Note: This example uses two dependencies you need to declare yourself, for different reasons:
launchcomes fromorg.jetbrains.kotlinx:kotlinx-coroutines-android— the library already supplies this at runtime, but not on your compile classpath, so writing this code needs your own compile-time declaration too — andlifecycleScopefromandroidx.lifecycle:lifecycle-runtime-ktx, which the library does not use at all. See Runtime Dependencies for the coroutines compile-classpath requirement.
ValidationResult is a sealed type with exactly two cases, so a when over it needs no else branch:
| Case | Property |
|---|---|
ValidationResult.Success | response - the JSON response from the DeviceAssure API |
ValidationResult.Error | message - the reason the validation did not complete |
It also provides convenience accessors, so you do not have to branch explicitly:
| Member | Behaviour |
|---|---|
isSuccess / isError | Whether the validation completed |
getOrNull() | The response, or null on error |
getOrThrow() | The response, or throws ValidationException on error |
onSuccess { } / onError { } | Runs the given action for that case, and returns the result so calls can be chained |
For example:
lifecycleScope.launch {
DeviceAssure.checkAsync("<LICENCE_KEY>")
.onSuccess { response -> Log.d(TAG, "Validation result: $response") }
.onError { message -> Log.e(TAG, "Validation error: $message") }
}
When to Call Validation
The check() method can be called from anywhere in the application, but it is recommended to call it:
- On application install
- On application create (
onCreate())
Exception: If certain permissions are required before calling the library (e.g., to allow collection of the TAC), wait until those permissions are granted.
Performance Notes
- The library uses a background thread to avoid blocking the main UI thread
- If background processing doesn't complete within 10 seconds, it terminates and returns data collected up to that point
- For best results, request necessary permissions before calling validation
See Also
- Server to Server - Validate via your backend server instead
- How It Works - Client to Server and Server to Server models
- API Responses - Understanding validation results and classifications