Android Native SDK
Learn how to integrate Bureau's Android Native Device Intelligence SDK in your application.
Enhance your app's security by integrating Bureau's Android Native Device Intelligence SDK. Detect compromised devices, emulated devices, rooted devices, and repackaged apps effortlessly. Safeguard your application and users against threats and bot traffic.
Minimum Requirements
- SDK Minimum Version 21
- Kotlin Minimum Version: 1.6.21
- Java Minimum Version: 8
- AndroidX
- The XML below is a representation of the permissions required. Please refer to the table below.
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> //OPTIONAL
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.location" />
App Permissions Required
The table below contains the device permissions our SDK requires.
PERMISSION | USAGE STATUS |
---|---|
USE_BIOMETRIC | REQUIRED |
READ_GSERVICES | REQUIRED |
ACCESS_WIFI_STATE | REQUIRED |
ACCESS_NETWORK_STATE | REQUIRED |
ACCESS_COARSE_LOCATION | REQUIRED |
ACCESS_FINE_LOCATION | OPTIONAL |
Integration Steps
At its core, the solution functions through three straightforward steps:
- Start by embedding Device Intelligence SDK with your mobile application.
- Initialize the SDK using either the Client ID or Credential ID. This enables us to gather user and device data. We will then thoroughly analyze and enhance the collected data in the background.
- You can then utilize our API to access insights, aiding you in deciding the subsequent actions for your user, whether it's permitting, obstructing, or redirecting them.
Flow Diagram
This diagram shows the interactions between a merchant's mobile app and Bureau's SDK.
sessionId
anduserid
are generated/retrieved by the client backend and sent to your application- Your mobile application initializes our SDK through the
init
function by setting these attributes -- Session ID (mandatory unique UUID)
- User ID (optional)
- Flow (optional)
- Invoke the
submit
function in SDK to pass the data to Bureau backend. - Upon successful submission of the parameters, a
callback
is received in the SDK. The next steps can be taken based on thecallback
(success/failure). - If the callback is successful, your mobile application relays the
success
to your backend - Invoke Bureau's backend API
/v1/suppliers/device-fingerprint
to fetch insights- Input:
sessionId
- Input:
- Based on the insights provided (fingerprint and risk signals), you can determine the user's next steps, such as allowing, blocking, or redirecting them.
Step 1 - SDK Implementation
Add the following lines in your root build.gradle.
Properties properties = new Properties()
properties.load(new FileInputStream(project.rootProject.file('local.properties')))
buildscript {
.....
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://packages.bureau.id/api/packages/Bureau/maven" }
}
}
Latest Version
Add the following lines in your module-level build.gradle.
The latest version is 3.0.0
dependencies {
//add the following dependency in your gradle file
implementation 'id.bureau:deviceintel:3.0.0'
}
This library also uses some common Android libraries. So if you are not already using them, add the below libraries to your module-level build.gradle.
- androidx.appcompat:appcompat:1.2.0
Step 2 - Initialise SDK
The SDK is initialized in the client app.
import com.bureau.devicefingerprint.BureauAPI
import com.bureau.base.Environment
//init SDK Instance with Client Id and Environment
BureauAPI.init(
YOUR_CLIENT_ID,
SESSION_ID, //mandatory
Environment.ENV_SANDBOX,
)
BureauAPI.setFlow(YOUR_FLOW_NAME)//mandatory
BureauAPI.setUserId(YOUR_USER_ID)//mandatory
import com.bureau.devicefingerprint.BureauAPI
import com.bureau.base.Environment
//init SDK Instance with Client Id and Environment
BureauAPI.init(
YOUR_CLIENT_ID,
SESSION_ID, //mandatory
Environment.ENV_SANDBOX,
)
BureauAPI.setFlow(YOUR_FLOW_NAME)//mandatory
BureauAPI.setUserId(YOUR_USER_ID)//mandatory
Note
- SDK Initialization: Your unique
CLIENT_ID
is required to initialize the SDK.- Session ID: You must generate a unique
SESSION_ID
for each end-user session.- Device Fingerprint: Obtain the unique device fingerprint and other deivce intelligence parameters collected by us using the Device Intelligence API.
- Environment Selection: The default environment is production.
- To use the Sandbox environment, pass
Environment.ENV_SANDBOX
in theinit
function during initialization.
Step 3 - Submit SDK
Once the submit function is called, the data relating to the user and device is automatically synced in the background.
import com.bureau.devicefingerprint.models.ErrorResponse
import com.bureau.devicefingerprint.models.SubmitResponse
import com.bureau.devicefingerprint.tools.DataCallback
//Submit data to Bureau's backend using the submit function
BureauAPI.submit(object :
DataCallback {
override fun onError(errorMessage: ErrorResponse) {
}
override fun onResult(message: SubmitResponse) {
}
})
import com.bureau.devicefingerprint.models.ErrorResponse
import com.bureau.devicefingerprint.models.SubmitResponse
import com.bureau.devicefingerprint.tools.DataCallback
//Start collecting and submit data to Bureau's backend using the submit function
BureauApi.submit((new DataCallback() {
public void onError(@NotNull ErrorResponse errorMessage) {
//implement your own logic
}
public void onResult(@NotNull SubmitResponse message) {
//implement your own logic
}
}));
Response returned from the SDK
The DataCallback added in the Submit function returns whether the device data has been registered or not.
object :DataCallback{
override fun onError(errorMessage: ErrorResponse) {
//Failure Callback
Log.w(TAG,"Error "+errorMessage)
}
override fun onResult(message: SubmitResponse) {
//Success Callback
Log.w(TAG,"Success "+message)
}
}}
new DataCallback() {
public void onError(@NotNull ErrorResponse errorMessage) {
//implement your own logic
}
public void onResult(@NotNull SubmitResponse message) {
//implement your own logic
}
};
Error Codes
The table below lists a few error codes returned by Bureau's SDKs.
HTTP Error Code | Description | Possible Cause | Recommended Action |
---|---|---|---|
420 | HTTP exception | Indicates a server-side issue. This can include errors such as: - Rate limiting, server overload, or application error - Firewall or network restrictions - Server-side scripting errors - Third-party services | - Check your server logs to help identify the cause. - Implement rate limiting or load balancing if necessary. - Check firewall rules and network settings to ensure they are not interfering with the connection. - Inspect server logs for any specific error messages or warnings. - Contact the service provider for assistance or look for alternative solutions. |
421 | Network error | - Too many connections from a single IP address - DNS resolution issues - Load balancer issues - Client-side issues (browser extensions, network configurations) | - Reduce the number of simultaneous connections. Consider using a load balancer. - Try flushing your DNS cache or using a different DNS server. - Check the load balancer's status and logs for any problems. - Try disabling extensions or using a different network connection. |
432 | A general, unexpected exception or error occurred. | Various reasons such as: - Programming errors - Unexpected input - System failures | 1. Review the code for potential errors or logic issues. 2. Check if the input data is valid and meets the expected format. 3. If the error persists, check our SDK documentation or our contact Support Team. |
433 | The required session ID is missing or empty. | The session ID was not provided or was not passed correctly. | 1. Ensure that the session ID is included in the API request and is not empty. 2. Refer to the API documentation for the correct format and usage of the session ID. |
434 | The eaIV or eaKey is empty. These are essential for decrypting encrypted data. | The required encryption parameters, eaIV (Initialization Vector) and eaKey (Encryption Key) are missing or invalid. | - Verify that the eaIV and eaKey are provided and correct. - Ensure they are generated using a secure method and are not compromised. |
Step 4 - Invoke API for Insights
To access insights from users and devices, including device fingerprint, and risk signals, integrating with Bureau's backend API for Device Intelligence insights.
Sample Request and Response
Below is a sample request and response for our Device Intelligence API. Refer to our Device Intelligence API documentation for more details.
Contact our support team at [email protected] to get your API keys and the production endpoint for the API.
curl --location --request POST 'https://api.sandbox.bureau.id/v1/suppliers/device-fingerprint' \
--header 'Authorization: Basic MzNiNxxxx2ItZGU2M==' \
--header 'Content-Type: application/json' \
--data-raw '{
"sessionKey": "697bb2d6-1111-1111-1111-548d6a809360"
}'
{
"GPSLocation": {
"city": "",
"country": "",
"latitude": 0,
"longitude": 0,
"region": ""
},
"IP": "106.51.82.180",
"IPLocation": {
"city": "Bengaluru",
"country": "India",
"latitude": 12.976229667663574,
"longitude": 77.60328674316406,
"region": "Karnataka"
},
"IPSecurity": {
"VPN": false,
"isCrawler": false,
"isProxy": false,
"isTor": false,
"threatLevel": "LOW"
},
"IPType": "v4",
"OS": "android",
"accessibilityEnabled": false,
"adbEnabled": false,
"behaviouralRiskLevel": "UNKNOWN",
"confidenceScore": 100,
"createdAt": 1712573578096,
"debuggable": false,
"developerMode": false,
"deviceRiskLevel": "MEDIUM",
"deviceRiskScore": 25.56,
"emulator": false,
"factoryResetRisk": "LOW",
"factoryResetTime": null,
"fingerprint": "6db7755c-1232-4f9d-ae1e-52bd952fac68",
"firstSeenDays": 9,
"googlePlayStoreInstall": true,
"isAppCloned": true,
"isAppTampered": null,
"isDebuggingEnabled": false,
"isOEMUnlockAllowed": false,
"isSimPresent": true,
"merchantId": "org_4KRtr8n6xKTsONjo",
"mitmAttackDetected": false,
"mockgps": false,
"model": "A063",
"networkInformation": {
"ipType": "HOME",
"isp": "Atria Convergence Technologies Pvt. Ltd."
},
"package": "id.bureau.sdkdemo",
"remoteDesktop": false,
"requestId": "7a83b0fa-daad-41d9-bd49-2c5ae6ba84fd",
"riskCauses": [
"IS_APP_CLONED"
],
"riskLevel": "MEDIUM",
"riskScore": 25.56,
"rooted": false,
"sessionId": "3ad55d53-08be-46d5-8103-a8d0b570d6f5",
"statusCode": 200,
"timestamp": 1713356555368,
"totalUniqueUserId": 5,
"userId": "dhruvMultiple",
"voiceCallDetected": false
}
Enable Local Suspicious Signals (Optional)
By enabling local signals, our SDK can detect information about the end user's Android device that could indicate potential security risks, such as:
- Mock GPS: Indicates if the device is using a simulated location instead of the actual GPS.
- Debuggable: Indicates if the app is running in debug mode, which can expose vulnerabilities.
- Rooted: Indicates if the device is rooted, potentially allowing unauthorized modifications.
- Developer: Indicates if developer mode is enabled in settings.
- ADB enabled: Indicates if the device is connected to another device using ADB.
- Bootloader unlocked: Indicates if the bootloader is unlocked in the device potentially compromising system integrity.
- App cloning: Indicates if the app is a cloned application.
- VPN enabled: Indicates if VPN is enabled in the device.
- Debugger attached: Indicates if the debugger is attached to the Android application.
Call the method setSuspiciousOfflineSignalsMonitoring
with required callback and check mode. Use SuspiciousSignalCheckMode.CONTINUOUS
as check mode for continuous monitoring and SuspiciousSignalCheckMode.INSTANT
for one time check.
Example Implementation
Below is an example of how to implement the setSuspiciousOfflineSignalsMonitoring
.
BureauAPI.setSuspiciousOfflineSignalsMonitoring(
object : SuspiciousSignalCallback {
override fun onDeveloperModeStatusChanged(status: Boolean) {
}
override fun onADBEnabledStatusChanged(status: Boolean) {
}
override fun onDeviceRooted() {
}
override fun onBootLoaderUnlocked() {
}
override fun onMockGpsStatusChanged(status: Boolean) {
}
override fun onPackageDebuggable() {
}
override fun onAppCloningDetected() {
}
override fun onVPNStatusChanged(status: Boolean) {
}
override fun onDebuggerStatusChanged(status: Boolean) {
}
},
SuspiciousSignalCheckMode.CONTINUOUS,
)
BureauAPI.setSuspiciousOfflineSignalsMonitoring(new SuspiciousSignalCallback {
public void onDeveloperModeStatusChanged(Boolean status) {
}
public void onADBEnabledStatusChanged(Boolean status) {
}
public void onDeviceRooted() {
}
public void onBootLoaderUnlocked() {
}
public void onMockGpsStatusChanged(Boolean status) {
}
public void onPackageDebuggable() {
}
public void onAppCloningDetected() {
}
public void onVPNStatusChanged(Boolean status) {
}
public void onDebuggerStatusChanged(Boolean status) {
}
},
);
Detecting auto clicker (optional)
We also provide methods to detect any active auto clicker during your application session.
- To use it, call
registerDetectingAutoClick()
in activityonCreate()
or fragmentonViewCreated()
or any place where you want the SDK to start detecting auto clicker. - Call
unregisterDetectingAutoClick()
where you want the SDK to stop auto clicker detection.
Example Implementation
Below is an example of how to implement the registerDetectingAutoClick()
.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
BureauApi.registerDetectingAutoClick(
object : AutoClickDetectorCallback {
override fun onAutoClickDetected() {
}
}
}
@Override
public void onViewCreated(View view,Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState)
BureauApi.registerDetectingAutoClick(activity,new AutoClickDetectorCallback{
@Override
public void onAutoClickDetected(){
}
})
}
Verifying App Integrity with Signature Hash
Before going live, we must ensure your app hasn't been tampered with. This helps protect both you and your users.
Here's how you can verify your app's integrity:
Gather Information
- Package Name: This is the unique identifier for your app on the platform (e.g.,
com.yourcompany.myapp
). It typically follows a reverse domain name structure, such as:com.<yourcompany>.<appname>
com.<yourcompany>.<appname>:<servicename>
(if using sub-organizations)
- Signature Hash Code: This code is generated from your app's signing certificate and helps verify its authenticity.
Get the Signature Hash Code
Most development environments provide built-in tools for obtaining the signature hash code. Below is a common way (using the GET_SIGNING_CERTIFICATES
permission):
- Access your project's settings in the PackageManager.
- Look for the permission section and ensure you have the
GET_SIGNING_CERTIFICATES
permission enabled. - Once enabled, follow the specific instructions provided by your development environment to retrieve the signature hash code. It's usually found within a property like
signingInfo.signingCertificateHistory
and will be a byte array representation of the hash.
You can also retrieve the signature hash using the below code snippet (refer to your development environment's documentation for specific implementation details).
Note
This is a code example, and the actual implementation might differ based on your development environment.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
context.packageManager.getPackageInfo(
context.packageName,
PackageManager.GET_SIGNING_CERTIFICATES,
).signingInfo.signingCertificateHistory
} else {
context.packageManager
.getPackageInfo(
context.packageName,
PackageManager.GET_SIGNATURES,
).signatures
}
- The above code snippet checks the Android SDK version to determine the appropriate method for retrieving the signature information.
- For Android versions 9 (Pie) and above, it uses getPackageInfo with the GET_SIGNING_CERTIFICATES flag and accesses the signingCertificateHistory property.
- For older versions, it uses getPackageInfo with the GET_SIGNATURES flag and accesses the signatures property.
Share the Information
Once you have your package name and signature hash code, please share them with us before launching your app live. This allows us to verify the app's authenticity and protect both you and your users.
Updated 1 day ago