Hybrid App integration

What is a Hybrid App

A Hybrid App uses both native URL requests and web views to communicate with your server. In the context of HUMAN, it's crucial to ensure that both native requests and web views are synchronized to provide the expected behavior for end users.

How Do I Know if My App is a Hybrid App

Your app is considered a Hybrid App if it has ALL of the following:

  1. A web view component (WKWebView on iOS or WebView on Android) that loads your website.
  2. Your website is protected by HUMAN (Bot Defender or Account Defender).

On iOS, if your app uses SFSafariViewController, please let us know, and we will guide you through a specific integration.

How to Enable Hybrid App Support in My App

Integrate the SDK (Native)

You should integrate the SDK into your native app. You may choose one of the following methods:

  1. Easiest Implementation
  2. Basic Implementation
  3. Advanced Functionality

Enable Hybrid App Support

When starting the SDK, declare your website's root domain in the policy. This should be the domain where the SDK will set cookies.

The SDK enables Hybrid App support ONLY for the specified domains. It checks if the website's domain ends with one of the specified domains. For example, setting example.com will also support www.example.com and api.example.com.

You should pass the WebView instance to the SDK using the following functions:

  • iOS: HumanSecurity.setupWebView(webView:navigationDelegate:)
  • Android: HumanSecurity.setupWebView(webView:webViewClient:)

Important: Do not set the navigationDelegate (iOS) or webViewClient (Android) properties after calling the setupWebView function.

On iOS, you can enable automatic detection and setup of WKWebViews by setting HSHybridAppPolicy.automaticSetup to true. This eliminates the need to manually call setupWebView for each instance.

Example Implementation

Android

Kotlin:

import android.app.Application
import com.humansecurity.mobile_sdk.HumanSecurity
import com.humansecurity.mobile_sdk.main.policy.HSPolicy

class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        startHumanSDK()
    }

    private fun startHumanSDK() {
        try {
            val policy = HSPolicy().apply {
                // Configure the policy...
                automaticInterceptorPolicy.interceptorType = HSAutomaticInterceptorType.INTERCEPT_WITH_DELAYED_RESPONSE // or INTERCEPT_AND_RETRY_REQUEST
                hybridAppPolicy.setWebRootDomains(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();
            // Configure the policy...
            policy.getAutomaticInterceptorPolicy().setInterceptorType(HSAutomaticInterceptorType.INTERCEPT_WITH_DELAYED_RESPONSE); // or INTERCEPT_AND_RETRY_REQUEST

            HashSet<String> domains = new HashSet<>();
            domains.add(".example.com");
            policy.getHybridAppPolicy().setWebRootDomains(domains, "<APP_ID>");

            HumanSecurity.INSTANCE.start(this, "<APP_ID>", policy);
        } catch (Exception exception) {
            Log.e("MainApplication", "Exception: " + exception.getMessage());
        }
    }
}

Kotlin (Activity):

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.webkit.WebView
import com.humansecurity.mobile_sdk.HumanSecurity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val webView = findViewById<WebView>(R.id.web_view)
        val webViewClient = MyWebViewClient()
        HumanSecurity.setupWebView(webView, webViewClient)

        // Load your website in the web view...
    }
}

Java (Activity):

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.humansecurity.mobile_sdk.HumanSecurity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        WebView webView = findViewById(R.id.web_view);
        MyWebViewClient webViewClient = new MyWebViewClient();
        HumanSecurity.INSTANCE.setupWebView(webView, webViewClient);

        // Load your website in the web view...
    }
}

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()
            // Configure the policy...
            policy.hybridAppPolicy.set(webRootDomains: [".example.com"], forAppId: "<APP_ID>")
            HSAutomaticInterceptorPolicy.urlSessionRequestTimeout = 10 // Set the timeout you would like for your requests.

            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];
    // Configure the policy...
    [policy.hybridAppPolicy setWithWebRootDomains:[NSSet setWithObject:@".example.com"] forAppId:@"<APP_ID>"];
    HSAutomaticInterceptorPolicy.urlSessionRequestTimeout = 10; // Set the timeout you would like for your requests.

    NSError *error = nil;
    [HumanSecurity startWithAppId:@"<APP_ID>" policy:policy error:&error];
    if (error != nil) {
        NSLog(@"Error: %@", error);
    }
}

@end

Explanation of the Code

  1. Adding Web Root Domains:
    • Specify your website's root domain (e.g., .example.com) in the policy's webRootDomains. This ensures that the SDK only intercepts requests to these domains.
  2. Starting the SDK:
    • Initialize the SDK as early as possible on the main thread to ensure all URL requests include the necessary HTTP headers.
  3. Setting Up Web Views:
    • Android: Use HumanSecurity.setupWebView(webView:webViewClient:) to set up the WebView with the SDK's WebViewClient. Do not set the WebViewClient directly after this.
    • iOS: Use HumanSecurity.setupWebView(webView:navigationDelegate:) to set up the WKWebView with the SDK's navigationDelegate. Do not set the navigationDelegate directly after this.

Notes:

  • iOS Automatic Setup: If you enable HSHybridAppPolicy.automaticSetup, the SDK will automatically detect and set up all WKWebView instances without needing to call setupWebView for each one.
  • 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.

Apple Pay on the Web

If your website uses Apple Pay on the Web, you should disable JavaScript evaluation by the SDK. To protect the security of Apple Pay transactions in WKWebView, Apple Pay cannot be used alongside script injection APIs (relevant for iOS 13-15). Disable JavaScript evaluation by setting the SDK's policy accordingly.

Note: If your app targets only iOS 16 or above, you don't need to disable JavaScript evaluation by the SDK.

Swift:

policy.hybridAppPolicy.allowJavaScriptEvaluation = false

Objective-C:

policy.hybridAppPolicy.allowJavaScriptEvaluation = NO;

External Web Views (Available from v4.0.1)

If your app uses web views that are created outside the native side of the app but are still based on Apple's WKWebView or Android's WebView (e.g., react-native-webview), you should enable support for them in the SDK's policy.

Android

Kotlin:

policy.hybridAppPolicy.supportExternalWebViews = true

Java:

policy.getHybridAppPolicy().setSupportExternalWebViews(true);

iOS

Swift:

policy.hybridAppPolicy.supportExternalWebViews = true

Objective-C:

policy.hybridAppPolicy.supportExternalWebViews = YES;