Android Native SDK

Welcome to our android native plugin designed to seamlessly integrate with the Bureau's Device Intelligence, enhancing the functionality of mobile apps or webpages.

Getting Started

To integrate our native SDK into your project, follow the comprehensive documentation provided below. Ensure a seamless implementation and unlock the full potential of Device Intelligence for your application.

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" />
PERMISSIONUSAGE STATUS
USE_BIOMETRICREQUIRED
READ_GSERVICESREQUIRED
ACCESS_WIFI_STATEREQUIRED
ACCESS_NETWORK_STATEREQUIRED
ACCESS_COARSE_LOCATIONREQUIRED
ACCESS_FINE_LOCATIONOPTIONAL

Integration Steps

At its core, the solution functions through three straightforward steps:

  1. Start by embedding Device Intelligence SDK with your mobile application.
  2. 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.
  3. 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.

  1. sessionKey and userid are generated / retrieved by the client backend and sent to your application
  2. Your mobile application initialises our SDK through the init function by setting these attributes -
    1. Session ID (mandatory unique UUID)
    2. User ID (optional)
    3. Flow (optional)
  3. Invoke the submit function in SDK to pass the data to Bureau backend.
  4. Upon successful submission of the parameters, a callback is received in the SDK. The next steps can be taken based on the callback (success/failure).
  5. If the callback is successful, your mobile application relays the success to your backend
  6. Invoke Bureau's backend API /v1/suppliers/device-fingerprint to fetch insights
    1. Input :sessionId
  7. Based on the insights provided (fingerprint, and risk signals), you can determine the next steps for the user, such as allowing, blocking, or redirecting them.

Step 1 - SDK Implementation

Add 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 following lines in your module level build.gradle.

The latest version is 2.3.10

dependencies {
//add the following dependency in your gradle file
    implementation 'id.bureau:corelib:2.3.10'
}

This library also uses some common android libraries. So if you are not already using them then make sure you add these libraries to your module level build.gradle

  • androidx.appcompat:appcompat:1.2.0

Step 2 - Initialise SDK

The SDK is initialised in the client app.

import com.bureau.devicefingerprint.BureauAPI
import com.bureau.base.Environment

//Get SDK Instance with Client Id and Environment
val bureauAPI : BureauAPI  = BureauAPI.init(
            this,
            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

//Get SDK Instance with Client Id and Environment
String sessionId = UUID.randomUUID().toString()
BureauAPI bureauAPI  = BureauAPI.init(
            this,
            YOUR_CLIENT_ID,
            Environment.ENV_SANDBOX
        ) 
        
        		bureauApi.setSessionId(SESSION_ID)//mandatory

						bureauAPI.setFlow(YOUR_FLOW_NAME)//mandatory
            
            bureauAPI.setUserId(YOUR_USER_ID)//mandatory

📘

Note

  • To initialise the SDK we need to provide CREDENTIAL_ID.
  • Session ID i.e. is mandatory and unique for each submission.
  • To obtain the fingerprint Id query Bureau backend.
  • The default environment is production. If you want to run on UAT pass ENV_SANDBOX in getBureauApiInstance function.

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)
            }
        }}
bureauAPI.submit((new DataCallback() {
   public void onError(@NotNull ErrorResponse errorMessage) {
       //implement your own logic
   }

   public void onResult(@NotNull SubmitResponse message) {
       //implement your own logic
   }
}));

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
}

5. 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 is 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 device.
  • Debugger attached: Indicates if 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) {
                        
                    }
                });

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.