Native & Hybrid App
Major Changes in the SDK's API
This article covers the major changes in the SDK's API.
Bye Bye PerimeterX... Hello HumanSecurity
-
SDK Name Change:
- The SDK name has been changed from PerimeterX to HUMAN.
- Android:
import com.humansecurity.mobile_sdk.HumanSecurity
- iOS:
import HUMAN
- Android:
- The SDK name has been changed from PerimeterX to HUMAN.
-
Repository Update for Android:
- Update your
build.gradle
file to use the new SDK repository location:https://jfrog.humansecurity.com/artifactory/human-android-sdk/
- Update your
-
Class Renaming:
- The main class has been renamed from
PerimeterX
toHumanSecurity
. - All SDK classes now have the
HS
prefix instead ofPX
.
- The main class has been renamed from
-
Function Relocation:
- Some functions previously in
PerimeterX
have been moved toHSBotDefender
andHSAccountDefender
classes based on their context.
- Some functions previously in
-
Delegate Renaming:
PerimeterXDelegate
has been renamed toHSBotDefenderDelegate
.
-
Error Handling:
- Error query functions have been consolidated into the
HSBotDefender/errorType(error:)
function.
- Error query functions have been consolidated into the
-
Removal of
HSTimeoutInterceptor
(Android):- The
HSTimeoutInterceptor
class has been removed. - You can now set different timeouts directly in the OkHttp client configuration.
- The
The Policy
-
Policy Object Structure:
- Before: The policy object was a single-level object that included all SDK configurations.
- Now: The policy object includes the following nested objects:
HSAutomaticInterceptorPolicy
- Configurations for "Automatic Interceptor".HSHybridAppPolicy
- Configurations for "Hybrid App".HSDetectionPolicy
- Configurations related to the SDK's detection mechanisms.HSDoctorAppPolicy
- Configurations for the "Doctor App".
-
Server Domain Configuration:
- Before: You had to set your server(s) domain(s) for both "Automatic Interceptor" and "Hybrid App" within the same function.
- Now: There are separate functions for setting domains for each policy.
Bot Defender
headersForURLRequest
Function:- Before: The
HSBotDefender/headersForURLRequest(forAppId:)
function returnednil
ornull
if called beforeHumanSecurity/start(appId:policy:)
. - Now: This function will always return a value (never empty). However, it must be called after
HumanSecurity/start(appId:policy:)
.
- Before: The
Hybrid App
- Enabling Hybrid App:
- To enable "Hybrid App," call the
HSHybridAppPolicy/set(webRootDomains:forAppId:)
function. - Note: You should set the web root domain (e.g.,
.example.com
).
- To enable "Hybrid App," call the
New in iOS
-
Manual Integration:
- The
HumanSecurity/setupWebView(webView:navigationDelegate:)
function allows for manual "Hybrid App" integration, unlike the automatic method available in previous versions.
- The
-
Automatic Setup Option:
- The
HSHybridAppPolicy/automaticSetup
option enables the same automatic "Hybrid App" integration that was available in previous versions.
- The
Environment
Android
-
SDK Build Specifications:
- The SDK is now built for API 34 and Kotlin 2.0.0.
-
New Dependencies:
-
The SDK has a new list of dependencies (see below). When fetching the SDK from our Artifactory, these dependencies are automatically included.
-
Note: If you need to change the version of some dependencies, you may integrate the SDK manually and select the exact versions that work for your app.
implementation 'androidx.core:core-ktx:1.13.1' // Any version (select 1.10.1 if your app targets API 33) implementation 'androidx.lifecycle:lifecycle-process:2.8.2' // Min v2.6.0 implementation 'androidx.datastore:datastore-preferences:1.1.1' // Any version (select 1.0.0 if your app targets API 33) implementation 'com.google.android.material:material:1.12.0' // Min v1.6.0 implementation 'com.fasterxml.uuid:java-uuid-generator:4.3.0' // Min v3.0.0 implementation 'io.ktor:ktor-client-okhttp:2.3.11' // Min v2.2.1
-
Was This Article Helpful?
If you found this article helpful, please let us know! Your feedback helps us improve our documentation.
Feel free to reach out if you need any further adjustments!
Further Improved Markdown
Based on your request, here's the refined version of your next article:
Integrating the SDK into Your Native iOS/Android App
Introduction
In this article, we will learn how to integrate the SDK into your native iOS or Android app.
Highlights
- Fast Integration: The quickest way to integrate the SDK with minimal integration points.
- URL Request Interception: The SDK intercepts your URL requests.
- Handling Blocked Requests: Manage blocked requests effectively.
Note:
- Android: Requires your app to use OkHttp which supports Interceptors.
- iOS: Requires your app to use
URLSession
or any third-party library based on it.
Topics Covered
- How to Start the SDK
- Bot Defender Integration
- Adding SDK's HTTP headers to your URL requests
- Handling blocked requests
- Presenting a challenge to the user
- Setting custom parameters (optional)
- Account Defender Integration
- Enabling Account Defender
- Notifying HUMAN's backend on outgoing URL requests
- Setting additional data (optional)
Important Notice About iOS
The SDK uses a custom URL protocol to manipulate your URL requests by creating a new URLSession
object. As a result, there are a few limitations to be aware of before integration:
- If you implement the
urlSession(_:didReceive:completionHandler:)
method in yourURLSessionDelegate
, it will not be called, and the default OS logic will apply to your URL requests. - The SDK's
URLSession
object is configured withURLSessionConfiguration.default
. Any custom configuration on your side will not apply. - The SDK does not support caching in your URL requests.
How to Start the SDK
- Initialize Early: Start the SDK as soon as possible in your app's lifecycle to ensure all URL requests include the SDK's HTTP headers. Starting the SDK late may result in requests being blocked by HUMAN's Enforcer.
- Android: Initialize in the
Application
'sonCreate
method. - iOS: Initialize in the
AppDelegate
'sdidFinishLaunchingWithOptions
method.
- Android: Initialize in the
- Main Thread: Start the SDK on the main thread.
- Domain Specification: Specify which domains the SDK should intercept. If no domains are specified, all domains will be intercepted. The SDK checks if the URL's domain ends with one of the specified domains (e.g.,
example.com
also interceptswww.example.com
andapi.example.com
).
Example Implementation
Android
Kotlin:
import android.app.Application
import com.humansecurity.mobile_sdk.HumanSecurity
import com.humansecurity.mobile_sdk.main.policy.HSPolicy
import com.humansecurity.mobile_sdk.main.policy.HSAutomaticInterceptorType
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
startHumanSDK()
}
private fun startHumanSDK() {
try {
val policy = HSPolicy().apply {
automaticInterceptorPolicy.interceptorType = HSAutomaticInterceptorType.INTERCEPT
automaticInterceptorPolicy.setInterceptedDomains(setOf("example.com"), "<APP_ID>")
}
HumanSecurity.start(this, "<APP_ID>", policy)
} catch (exception: Exception) {
println("Exception: ${exception.message}")
}
}
}
Java:
import android.app.Application;
import android.util.Log;
import java.util.HashSet;
import com.humansecurity.mobile_sdk.HumanSecurity;
import com.humansecurity.mobile_sdk.main.policy.HSPolicy;
import com.humansecurity.mobile_sdk.main.policy.HSAutomaticInterceptorType;
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
startHumanSDK();
}
void startHumanSDK() {
try {
HSPolicy policy = new HSPolicy();
policy.getAutomaticInterceptorPolicy().setInterceptorType(HSAutomaticInterceptorType.INTERCEPT);
HashSet<String> domains = new HashSet<>();
domains.add("example.com");
policy.getAutomaticInterceptorPolicy().setInterceptedDomains(domains, "<APP_ID>");
HumanSecurity.INSTANCE.start(this, "<APP_ID>", policy);
} catch (Exception exception) {
Log.e("MainApplication", "Exception: " + exception.getMessage());
}
}
}
iOS
Swift:
import UIKit
import HUMAN
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
startHumanSDK()
return true
}
func startHumanSDK() {
do {
let policy = HSPolicy()
policy.automaticInterceptorPolicy.interceptorType = .intercept
policy.automaticInterceptorPolicy.set(interceptedDomains: ["example.com"], forAppId: "<APP_ID>")
try HumanSecurity.start(appId: "<APP_ID>", policy: policy)
} catch {
print("Error: \(error)")
}
}
}
Objective-C:
@import HUMAN;
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self startHumanSDK];
return YES;
}
- (void)startHumanSDK {
HSPolicy *policy = [[HSPolicy alloc] init];
policy.automaticInterceptorPolicy.interceptorType = HSAutomaticInterceptorTypeIntercept;
[policy.automaticInterceptorPolicy setWithInterceptedDomains:[NSSet setWithObject:@"example.com"] forAppId:@"<APP_ID>"];
NSError *error = nil;
[HumanSecurity startWithAppId:@"<APP_ID>" policy:policy error:&error];
if (error != nil) {
NSLog(@"Error: %@", error);
}
}
@end
Explanation of the Code
- Initialization: Start the SDK as early as possible on the main thread to ensure all URL requests include the necessary HTTP headers.
- Policy Configuration: Create an
HSPolicy
instance to configure the SDK's behavior. Set theHSAutomaticInterceptorPolicy.interceptorType
toHSAutomaticInterceptorType.INTERCEPT
to enable automatic interception of URL requests. - Starting the SDK: Call the
HumanSecurity.start(appId:policy:)
function with the application instance (Android only), your AppID, and the configured policy.
Notes:
- iOS: The Automatic Interception uses
URLSessionConfiguration.default
. If your app uses a custom configuration, set it in the policy usingHSAutomaticInterceptorPolicy.urlSessionConfiguration
. - Multiple AppIDs: If your app communicates with multiple servers having different AppIDs, use the
HumanSecurity.start(appIds:policy:)
function to pass an array of AppIDs and specify the relevant AppID for each API call.
Bot Defender Integration
Adding SDK’s HTTP Headers and Handling Blocked Requests
- Automatic Header Addition: The SDK automatically adds its HTTP headers to your URL requests. No manual addition is required.
- Automatic Handling of Blocked Requests: The SDK handles blocked requests and presents a challenge to the user automatically.
- Custom Error Responses: The SDK provides a custom error response directly to your request handler.
Example Implementation
Android
Kotlin (OkHttp):
import com.humansecurity.mobile_sdk.HumanSecurity
import com.humansecurity.mobile_sdk.main.HSBotDefenderErrorType
import com.humansecurity.mobile_sdk.main.HSInterceptor
import okhttp3.OkHttpClient
import okhttp3.Request
class MyHttpClient {
private val okHttpClient: OkHttpClient = OkHttpClient.Builder()
.addInterceptor(HSInterceptor()) // SHOULD BE THE LAST INTERCEPTOR
.build()
fun sendRequest(url: String) {
try {
val request: Request = Request.Builder().url(url).build()
okHttpClient.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
response.body?.string()?.let { responseBody ->
when (HumanSecurity.BD.errorType(responseBody)) {
HSBotDefenderErrorType.REQUEST_WAS_BLOCKED -> {
println("Request was blocked")
}
else -> {
println("Unknown error")
}
}
}
}
}
} catch (exception: Exception) {
println("Request failed. Exception: $exception")
}
}
}
Kotlin (Ktor):
import com.humansecurity.mobile_sdk.HumanSecurity
import com.humansecurity.mobile_sdk.main.HSBotDefenderErrorType
import com.humansecurity.mobile_sdk.main.HSInterceptor
import io.ktor.client.*
import io.ktor.client.call.body
import io.ktor.client.engine.okhttp.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
class MyHttpClient {
private val httpClient: HttpClient = HttpClient(OkHttp) {
engine {
addInterceptor(HSInterceptor()) // SHOULD BE THE LAST INTERCEPTOR
}
}
suspend fun sendRequest(url: String) {
try {
val response: HttpResponse = httpClient.request(url) {}
val responseBody = response.body<String>()
when (HumanSecurity.BD.errorType(responseBody)) {
HSBotDefenderErrorType.REQUEST_WAS_BLOCKED -> {
println("Request was blocked")
}
else -> {
println("Unknown error")
}
}
} catch (exception: Exception) {
println("Request failed. Exception: $exception")
}
}
}
Java:
import com.humansecurity.mobile_sdk.HumanSecurity;
import com.humansecurity.mobile_sdk.main.HSInterceptor;
import android.util.Log;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class MyHttpClient {
private final OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new HSInterceptor()) // SHOULD BE THE LAST INTERCEPTOR
.build();
void sendRequest(String url) {
Runnable r = () -> {
try {
Request request = new Request.Builder().url(url).build();
Response response = httpClient.newCall(request).execute();
ResponseBody responseBody = response.body();
String responseString = null;
if (responseBody != null) {
responseString = responseBody.string();
response.close();
}
if (!response.isSuccessful() && responseString != null) {
switch (HumanSecurity.INSTANCE.getBD().errorType(responseString)) {
case REQUEST_WAS_BLOCKED:
Log.i("MyInterceptor", "Request was blocked");
break;
default:
Log.i("MyInterceptor", "Unknown error");
break;
}
}
} catch (Exception exception) {
Log.i("MyHttpClient", "Request failed. Exception: " + exception);
}
};
new Thread(r).start();
}
}
iOS
Using URLSession
:
Swift:
import HUMAN
class MyHttpClient {
func sendUrlRequest(url: URL) {
var request = URLRequest(url: url)
// Configure your request...
let dataTask = URLSession.shared.dataTask(with: request) { data, response, error in
if let error {
let errorType = HumanSecurity.BD.errorType(error: error)
switch errorType {
case .requestWasBlocked:
print("Request was blocked")
default:
break
}
}
}
dataTask.resume()
}
}
Objective-C:
@import HUMAN;
@implementation MyHttpClient
- (void)sendUrlRequest:(NSURL *)url {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// Configure your request...
NSURLSessionDataTask *dataTask = [NSURLSession.sharedSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error != nil) {
HSBotDefenderErrorType errorType = [HumanSecurity.BD errorTypeWithError:error];
switch (errorType) {
case HSBotDefenderErrorTypeRequestWasBlocked:
NSLog(@"Request was blocked");
break;
default:
break;
}
}
}];
[dataTask resume];
}
@end
Using Alamofire:
Swift:
import Alamofire
import HUMAN
class MyHttpClient {
func sendUrlRequest(url: URL) {
AF.request(url).response { response in
if let error = response.error?.underlyingError {
let errorType = HumanSecurity.BD.errorType(error: error)
switch errorType {
case .requestWasBlocked:
print("Request was blocked")
default:
break
}
}
}
}
}
Explanation of the Code
- Android Only: Configure the HTTP client to include the
HSInterceptor
. This interceptor must be the last interceptor in the list. - Send URL Request: Execute the URL request using the configured HTTP client.
- Check for Blocked Requests: Use the SDK to determine if the received error is a "blocked request error."
Note: While your request handler is called, the SDK presents a challenge to the user.
What to Do When a Request Is Blocked
- Handle as a Failure: Treat blocked requests as failures. Ensure that your app's UI reflects that the action can be retried after the challenge is solved or canceled by the user. If the request was triggered by a user's action, inform the user that they may retry the same action.
Setting Custom Parameters (Optional)
You can configure HUMAN's backend with additional parameters by setting custom parameters.
- Android: Use a
HashMap
. - iOS: Use a
Dictionary
.
Key Format: Use keys in the format custom_param[x]
, where [x]
is a number between 1-10
.
Important: Call the HSBotDefender/setCustomParameters(parameters:forAppId:)
function only after the HumanSecurity/start(appId:policy:)
function has been called.
Example Implementation
Android
Kotlin:
import com.humansecurity.mobile_sdk.HumanSecurity
fun setCustomParametersForBotDefender() {
try {
val customParameters = HashMap<String, String>().apply {
put("custom_param1", "hello")
put("custom_param2", "world")
}
HumanSecurity.BD.setCustomParameters(customParameters, "<APP_ID>")
} catch (exception: Exception) {
println("Exception: ${exception.message}")
}
}
Java:
import com.humansecurity.mobile_sdk.HumanSecurity;
import java.util.HashMap;
import android.util.Log;
void setCustomParametersForBotDefender() {
try {
HashMap<String, String> customParameters = new HashMap<>();
customParameters.put("custom_param1", "hello");
customParameters.put("custom_param2", "world");
HumanSecurity.INSTANCE.getBD().setCustomParameters(customParameters, "<APP_ID>");
} catch(Exception exception) {
Log.e("MainApplication","Exception: " + exception.getMessage());
}
}
iOS
Swift:
import HUMAN
func setCustomParametersForBotDefender() {
do {
let customParameters: [String: String] = [
"custom_param1": "hello",
"custom_param2": "world"
]
try HumanSecurity.BD.setCustomParameters(parameters: customParameters, forAppId: "<APP_ID>")
} catch {
print("Error: \(error)")
}
}
Objective-C:
@import HUMAN;
- (void)setCustomParametersForBotDefender {
NSMutableDictionary<NSString *, NSString *> *customParameters = [[NSMutableDictionary alloc] init];
customParameters[@"custom_param1"] = @"hello";
customParameters[@"custom_param2"] = @"world";
NSError *error = nil;
[HumanSecurity.BD setCustomParametersWithParameters:customParameters forAppId:@"<APP_ID>" error:&error];
if (error != nil) {
NSLog(@"Error: %@", error);
}
}
Account Defender Integration
Enabling Account Defender in Your App
To enable Account Defender, set the UserID
of the currently logged-in user in the SDK.
Example Implementation
Android
Kotlin:
import com.humansecurity.mobile_sdk.HumanSecurity
fun onUserLoggedIn(userID: String) {
try {
HumanSecurity.AD.setUserId(userID, "<APP_ID>")
} catch (exception: Exception) {
println("Exception: ${exception.message}")
}
}
Java:
import com.humansecurity.mobile_sdk.HumanSecurity;
import android.util.Log;
void onUserLoggedIn(String userID) {
try {
HumanSecurity.INSTANCE.getAD().setUserId(userID, "<APP_ID>");
} catch(Exception exception) {
Log.e("MainApplication","Exception: " + exception.getMessage());
}
}
iOS
Swift:
import HUMAN
func onUserLoggedIn(userID: String) {
do {
try HumanSecurity.AD.setUserId(userId: userID, forAppId: "<APP_ID>")
} catch {
print("Error: \(error)")
}
}
Objective-C:
@import HUMAN;
- (void)onUserLoggedIn:(NSString *)userID {
NSError *error = nil;
[HumanSecurity.AD setUserIdWithUserId:userID forAppId:@"<APP_ID>" error:&error];
if (error != nil) {
NSLog(@"Error: %@", error);
}
}
Notifying HUMAN's Backend on Outgoing URL Requests
To enable Account Defender to protect the user's account, your app must provide the SDK with outgoing URL requests.
- Automatic Collection: With the SDK's interceptor enabled, outgoing URL requests are collected automatically. No manual API calls are required.
Setting Additional Data (Optional)
You can provide additional data to configure HUMAN's backend with extra parameters.
- Android: Use a
HashMap
. - iOS: Use a
Dictionary
.
Important: Call the HSAccountDefender/setAdditionalData(parameters:forAppId:)
function only after the HumanSecurity/start(appId:policy:)
function has been called.
Example Implementation
Android
Kotlin:
import com.humansecurity.mobile_sdk.HumanSecurity
fun setAdditionalDataForAccountDefender() {
try {
val additionalData = HashMap<String, String>().apply {
put("my_key1", "hello")
put("my_key2", "world")
}
HumanSecurity.AD.setAdditionalData(additionalData, "<APP_ID>")
} catch (exception: Exception) {
println("Exception: ${exception.message}")
}
}
Java:
import com.humansecurity.mobile_sdk.HumanSecurity;
import java.util.HashMap;
import android.util.Log;
void setAdditionalDataForAccountDefender() {
try {
HashMap<String, String> additionalData = new HashMap<>();
additionalData.put("my_key1", "hello");
additionalData.put("my_key2", "world");
HumanSecurity.INSTANCE.getAD().setAdditionalData(additionalData, "<APP_ID>");
} catch(Exception exception) {
Log.e("MainApplication","Exception: " + exception.getMessage());
}
}
iOS
Swift:
import HUMAN
func setAdditionalDataForAccountDefender() {
do {
let additionalData: [String: String] = [
"my_key1": "hello",
"my_key2": "world"
]
try HumanSecurity.AD.setAdditionalData(parameters: additionalData, forAppId: "<APP_ID>")
} catch {
print("Error: \(error)")
}
}
Objective-C:
@import HUMAN;
- (void)setAdditionalDataForAccountDefender {
NSMutableDictionary<NSString *, NSString *> *additionalData = [[NSMutableDictionary alloc] init];
additionalData[@"my_key1"] = @"hello";
additionalData[@"my_key2"] = @"world";
NSError *error = nil;
[HumanSecurity.AD setAdditionalDataWithParameters:additionalData forAppId:@"<APP_ID>" error:&error];
if (error != nil) {
NSLog(@"Error: %@", error);
}
}
Updated 7 days ago