Android Integration

Overview

This section elaborates on the integration steps of the EdgeOne client attestation SDK in an Android project, including SDK import, permission configuration, initialization, engine startup, challenge handling, and token usage in API requests.

Integration Step

Note:
Before starting the integration, ensure you have read and understood the Mobile Terminal Integration Overview and learned about the basic attestation process for mobile terminals.

1. Adding EdgeOne SDK to Your Project

Integrating the EdgeOne client attestation SDK into your Android project is the first step. You can import the SDK through Maven. Add the Maven repository in your setting.gradle or project build.gradle:
// setting.gradle or project build.gradle
repositories {
// Add the following maven configuration
maven { url 'https://repo.maven.apache.org/maven2/' } // Example Maven repository, replace with actual SDK provision
}
Add the dependency to your application module build.gradle:
// app/build.gradle
dependencies {
implementation 'com.tencent.cloud:clientattestation:latest.release'
}

2. Configure AndroidManifest.xml Permissions

The SDK requires basic network access to execute the attestation process. Please add the following permission declaration in your project AndroidManifest.xml file to ensure the SDK can perform network communication normally:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Meanwhile, to support specific native libraries inside the SDK, you may need to configure the supported CPU architecture. Add the following in app/build.gradle under defaultConfig:
android {
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "arm64-v8a" // Optional: armeabi-v7a or arm64-v8a
}
}
}
If your project uses ProGuard to perform code obfuscation, add the following obfuscation rules in your ProGuard configuration file (usually proguard-rules.pro) to prevent SDK inner classes from being obfuscated:
-keep class com.**.TNative$aa { public *; }
-keep class com.**.TNative$aa$bb { public *; }
-keep class com.**.TNative$bb { *; }
-keep class com.**.TNative$bb$I { *; }

3. Initializing SDK

Before using any attestation feature, you need to initialize EdgeOne SDK with your service domain and optional log level. This operation is usually executed only once in your Application class or at application startup.
import com.tencent.cloud.clientattestation.TCBas;
import com.tencent.cloud.clientattestation.TCBasOptions;

public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
SDK initialization
String baseUrl = "www.example.com"; // Set to business domain
TCBas.init(getApplicationContext(), new TCBasOptions.Builder().baseUrl(baseUrl).build());

// Option: Set log level
// TCBas.init(getApplicationContext(), new TCBasOptions.Builder()
// .baseUrl(baseUrl)
// .logLevel(LOG_LEVEL_DEBUG) // Option: Set log level
// .build());
}
}
Parameter description:
baseUrl: Your EdgeOne service domain name, such as www.example.com.
logLevel: Optional parameter used to control the SDK log output level. Optional values include:
LOG_LEVEL_NONE: Close log (default)
LOG_LEVEL_DEBUG: Enable logs at debug level and above
LOG_LEVEL_INFO: Enable logs at info level and above
LOG_LEVEL_WARN: Enable logs at warning level and above
LOG_LEVEL_ERROR: Enable logs at error level and above

4. Starting the Attestation Engine

After the SDK initialization is completed, you need to start the client attestation engine so that the SDK can begin acquisition and manage attestation tokens. This operation starts the necessary background process inside the SDK.
import com.tencent.cloud.clientattestation.ClientAttestation;

// Start the client attestation engine
ClientAttestation.getInstance().start();
Note: After the attestation engine starts, the SDK will be ready to handle attestation challenges and manage attestation tokens.

5. Executing Client Attestation Challenge

Attestation challenge is a key step to obtain an attestation token. This process involves getting the challenge ID and sending it to the SDK. The SDK will display necessary UI (such as showing a verification code in WebView) as needed and compute the attestation token. This is done via the attestWithParams() method provided by the SDK.
import com.tencent.cloud.clientattestation.AttestCallback;
import com.tencent.cloud.clientattestation.AttestParams;
import android.webkit.WebView;

// attestId
// Get from console when actively initiating a challenge
// Get from the 'EO-Attest-Challenge' header field in the http response when passively triggering a Challenge
String attestId = "your-attestId";
AttestParams params = new AttestParams.Builder()
.attestId(attestId)
.webView(yourWebViewInstance) // WebView used to display the verification code interface. If graphic verification is not required, this parameter is unused.
.reqTimeoutMillis(60000) // Optional, request timeout, unit: ms, default 60s
.build();

ClientAttestation.getInstance().attestWithParams(params, new AttestCallback() {
@Override
public void onSuccess(String token) {
// Return the risk invoice, place the invoice in the 'EO-Attest-Token' header field of the http request
// For example, you can resend the failed request here with a new token.
}

@Override
public void onError(int errorCode, String msg) {
// Error message returned
// errorCode: error code
// msg: error info
}
});
Parameter description:
attestId: Configure the challenge ID, get from console or request result return.
webView: Optional parameter, a WebView instance. You must provide this parameter when the authenticator requires user interaction (such as Captcha). If UI interaction is not required, the WebView can be hidden.
reqTimeoutMillis: Optional parameter, set request timeout, unit: ms, default 60s.

6. Include Attestation Token in API Request

When your Android application initiates an API request to a backend service protected by EdgeOne, must include an attestation token in the request header. You can readily obtain the current effective attestation token by calling the getAttestationToken() method provided by the SDK.
Note:
After each successful call to attestWithParams(), the SDK generates or updates the attestation token. Before attaching the token to request headers, be sure to call getAttestationToken() again to get the latest token. Each time you need to use token data, please retrieve new token data. Do not save or reuse the token data returned by getAttestationToken().
// Get client attestation invoice
String attestToken = ClientAttestation.getInstance().getAttestationToken();

// Example: Add the token to your network request header
// Suppose you are using OkHttp or another network library
if (attestToken != null) {
// OkHttp example
// Request originalRequest = new Request.Builder()
// .url("https://your-backend-api.com/data")
// .build();
// Request.Builder requestBuilder = originalRequest.newBuilder();
// requestBuilder.header("EO-Attest-Token", attestToken);
// Request request = requestBuilder.build();
// // Continue sending the request
}
Important notice: Ensure each API request requiring attestation includes this token. The SDK automatically manages the token lifecycle. You just need to get the latest token before sending a request.

7. Handling Server Response and Challenges

When your backend service (protected by EdgeOne) receives a client request, it checks if the request contains a valid attestation token. If attestation is required but no valid token is carried, the server will return HTTP status code 428, indicating the client needs additional attestation. This is a key link for developers to proactively adapt in Android client integration.
Your Android application needs to implement a mechanism to capture and handle these HTTP 428 responses. For the specific workflow, refer to reobtain the attestation token or renew the expired attestation token (handling HTTP 428 challenge).
Here is a simplified example of handling the 428 challenge (using OkHttp as an example):
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import android.webkit.WebView;

public class ApiClient {

private OkHttpClient client = new OkHttpClient();
private WebView webViewInstance; // assume that you have a WebView instance

public ApiClient(WebView webView) {
this.webViewInstance = webView;
}

public void makeProtectedRequest(String url) {
Request request = new Request.Builder()
.url(url)
.header("EO-Attest-Token", ClientAttestation.getInstance().getAttestationToken())
.build();

client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// Handle network request fail
e.printStackTrace();
}

@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.code() == 428) {
Headers headers = response.headers();
String challengeId = headers.get("EO-Attest-Challenge");
if (challengeId != null) {
// Received 428 challenge, execute attestation
AttestParams params = new AttestParams.Builder()
.attestId(challengeId)
.webView(webViewInstance) // input WebView instance
.build();

ClientAttestation.getInstance().attestWithParams(params, new AttestCallback() {
@Override
public void onSuccess(String token) {
// attestation succeeded, send request again
makeProtectedRequest(url); // re-initiate raw request
}

@Override
public void onError(int errorCode, String msg) {
// attestation fail
System.err.println("attestation fail: " + msg);
}
});
} else {
System.err.println("428 response does not contain EO-Attest-Challenge header");
}
} else if (response.isSuccessful()) {
// Request successful, process business data
System.out.println("Request successful: " + response.body().string());
} else {
// Handle other HTTP errors
System.err.println("Request failure: " + response.code() + " " + response.message());
}
}
});
}
}

8. (Optional) Using WebView for Interactive Attestation (And JS attestation)

In some client attestation scenarios, the authenticator may need user interaction (e.g., interactive Captcha) or execute computation-intensive tasks (e.g., encryption proof-of-work). At this point, EdgeOne SDK requires specific environment support. On mobile platforms, WebView (Android platform) is a key component to implement these features.
When the authenticator needs to render an interactive CAPTCHA or run a JavaScript-based Proof-of-Work challenge, the SDK requires a WebView instance to be provided when calling the attestWithParams() method. This means developers must allocate a WebView instance in advance in the application and pass it as an argument to the SDK when calling the attestation API.

Interactive Attestation Scenario

Some authenticators (e.g., TC-CAPTCHA using embedded or pop-up interaction settings) require a WebView instance to render their interactive interface. The WebView instance will display the verification code webpage internally, so it must be preset to ensure correct display.
Embedded Interactive attestation: The verification code interface displays in a fixed block on the device screen. To ensure the UI displays correctly without affecting user experience, developers must preset the rendering window size, layering sequence, and alignment mode. Please note, the embedded attestation GUI does not scale with the screen view. For example, TC-CAPTCHA embedded mode recommends reserving at least 300x230 pixel space to get the best rendering effect and user interaction experience.
Pop-up Interactive attestation: The verification code interface appears as a floating window on the device screen when attestation is triggered. Similar to embedded attestation, the rendering window size, layering sequence, and alignment mode must be preset. The pop-up attestation feature is that when the screen view is less than a specific threshold, the pop-up attestation GUI automatically scales to adapt to different screen sizes. For example, TC-CAPTCHA pop-up mode has an initial rendering chunk size of 360x360 pixels.

JavaScript-Based Attestation Scenario

Some authenticators (such as TC-CAPTCHA in no-UI mode) require a WebView instance as the JavaScript runtime environment, primarily for executing proof-of-work (PoW) challenges. In this case, the WebView instance provides only a JavaScript execution sandbox, with no need to render any visible UI. Therefore, the passed-in WebView instance does not need to be visible, and the SDK will not use it for UI rendering.