All Products
Search
Document Center

Web Application Firewall:Integrate the SDK into Harmony applications

Last Updated:Nov 21, 2025

Before you can configure anti-crawler rules for your Harmony apps in the Web Application Firewall (WAF) console, you must integrate the Anti-Bot SDK into the apps. This topic describes how to integrate the Anti-Bot SDK into Harmony apps. In this topic, the Anti-Bot SDK is referred to as the SDK.

Background information

The app protection SDK signs requests that are initiated from your app. The WAF service then verifies the signatures of these requests to detect threats and block malicious requests, which protects your app services.

Limits

  • The SDK must run on HarmonyOS Next 4.1 or later. The minimum supported API version is 12.

  • The init operation involves time-consuming actions. If you call the vmpSign operation immediately after the init operation, the vmpSign operation fails. Make sure that the vmpSign operation is called at least 2 minutes after the init operation.

  • You must call the cptCreate method on the main thread because the method involves UI operations.

  • Debugging on a simulator is not supported.

  • Only bytecode packaging is supported.

Prerequisites

  • The SDK for Harmony is obtained.

    To obtain the SDK for Harmony, you can submit a ticket.

    Note

    The SDK for Harmony package includes a HAR file whose name is HarmonyOS-AliTigerTally-X.Y.Z-date.har. X.Y.Z refers to the version number and date refers to the packaging date.

  • Obtain the SDK authentication key (appkey).

    After you enable Bot Management, navigate to the Bot Management > App Protection page and click Obtain and Copy AppKey to obtain the appkey. This key serves as a credential and is required to initialize the SDK in your application code.

    image

    Note

    Each Alibaba Cloud account is assigned a single, unique appkey that applies to all domains protected by WAF. This key is used for SDK integration across Android, iOS, and HarmonyOS apps.

    Sample appkey: ****OpKLvM6zliu6KopyHIhmneb_****u4ekci2W8i6F9vrgpEezqAzEzj2ANrVUhvAXMwYzgY_****vc51aEQlRovkRoUhRlVsf4IzO9dZp6nN_****Wz8pk2TDLuMo4pVIQvGaxH3vrsnSQiK****.

Step 1: Create a project

This topic uses DevEco Studio as an example. Create a Harmony project using the configuration wizard. The following figure shows the project directory.image.png

Step 2: Integrate a HAR package

  1. Decompress the HarmonyOS-AliyunTigerTally-X.Y.Z-date.tgz SDK package and copy the extracted HAR file to the required directory of the project.

    We recommend that you place the file in the libs directory as described in the official HarmonyOS documentation.image.png

  2. Open the oh-package.json5 file of your app and add the aliyuntigertally and captcha compilation dependencies in the dependencies section. Example:

    Important

    Replace X.Y.Z in aliyuntigertally-X.Y.Z-date.har with the version number of your HAR file.

    {
      ...
      "dependencies": {
        "aliyuntigertally": "file:../libs/aliyuntigertally-X.Y.Z-date.har",
        "captcha": "file:../libs/aliyuncaptcha-X.Y.Z-date.har",
        ...
      }
    }

Step 3: Obtain the required permissions for your app

The following table describes the required permissions to improve the performance of SDK-based protection.

Permission

Required

Description

ohos.permission.INTERNET

Yes

Allows the SDK to connect to the Internet. The SDK must connect to the Internet to run as expected.

ohos.permission.GET_NETWORK_INFO

Yes

Allows the SDK to obtain network status information. The SDK can provide better services based on the network status.

ohos.permission.STORE_PERSISTENT_DATA

No but recommended

Allows your app to store persistent data. This helps enhance device fingerprint stability.

ohos.permission.DISTRIBUTED_DATASYNC

No but recommended

Allows the SDK to detect the status of multiple devices to facilitate multi-device coordination. This helps enhance security.

ohos.permission.APP_TRACKING_CONSENT

No but recommended

Allows the SDK to obtain information about Identifiers for Advertisers (IDFAs). This helps enhance device ID stability.

Step 4: Add integration code

1. Add header files

import { TigerTallyAPI, TTCode } from 'aliyuntigertally';
import { TTCaptcha, TTCaptchaOption, TTCaptchaListener} from 'aliyuntigertally';

2. Set data signatures

  1. Specify a user ID to facilitate protection rule configuration in WAF.

    /**
     * Set the user account.
     *
     * @param account Account
     * @return Error code
     */
    public static setAccount(account: string): number
    • Parameters:

      • account: A string that identifies a user. Data type: string. We recommend that you use a desensitized format.

    • Return value: Indicates whether the setting is successful. Data type: number. A value of 0 indicates success, and a value of -1 indicates failure.

    • Sample code:

      // A guest does not need to call setAccount and can directly initialize the SDK. After a user logs on, you must call setAccount and re-initialize the SDK.
      let account: string = "user001";
      TigerTallyAPI.setAccount(account);
  2. Initialize the SDK and perform an initial collection.

    An initialization collection means that the device information is collected once. You can call the init function again to perform another initialization collection if needed.

    /**
     * Initialization callback.
     */
    export interface TTInitListener {
      /**
       * SDK status code callback.
       * @param code
       */
      onInitFinish: (code: number) => void;
    }
    
    /**
     * SDK initialization with callback.
     *
     * @param ctx
     * @param userAppKey
     * @param options Various parameters.
     * @param listener
     */
    public static init(ctx: Context, userAppKey: string,
                       options: Map<string, string> | null,
                       listener: TTInitListener | null): number
    • Parameters:

      • ctx: specifies the context that is passed to your app. Data type: context.

      • userAppkey: specifies the SDK authentication key. Data type: string.

      • options: Optional parameters for information collection. Data type: Map<String,String>. The default value is null. The following table describes the optional parameters.

        Parameter

        Description

        Example

        IPv6

        Specifies whether to use IPv6 domain names to report device information. Valid values:

        1. 0 (default): IPv4 domain names are used.

        2. 1: IPv6 domain names are used.

        1

        Intl

        Specifies whether to use domain names registered outside the Chinese mainland to report device information. Valid values:

        1. 0: Report to the Chinese mainland (default value).

        2. 1. Reporting from outside the Chinese mainland.

        1

      • listener: The SDK initialization callback interface. Data type: TTInitListener. You can check the specific status of the initialization result in the callback. The default value is null.

        TTCode

        Code

        Description

        TT_SUCCESS

        0

        The SDK is initialized.

        TT_NOT_INIT

        -1

        The SDK is not initialized.

        TT_NOT_PERMISSION

        -2

        The basic Harmony permissions required by the SDK are not fully granted.

        TT_UNKNOWN_ERROR

        -3

        An unknown system error occurred.

        TT_NETWORK_ERROR

        -4

        A network error occurred.

        TT_NETWORK_ERROR_EMPTY

        -5

        A network error occurred and the return value is an empty string.

        TT_NETWORK_ERROR_INVALID

        -6

        The format of the response is invalid.

        TT_PARSE_SRV_CFG_ERROR

        -7

        The system failed to parse the server settings.

        TT_NETWORK_RET_CODE_ERROR

        -8

        The gateway failed to return a response.

        TT_APPKEY_EMPTY

        -9

        The appkey parameter is empty.

        TT_PARAMS_ERROR

        -10

        Other parameters are invalid.

        TT_FGKEY_ERROR

        -11

        The system failed to calculate the key.

        TT_APPKEY_ERROR

        -12

        The SDK version does not match the app key version.

    • Return value: The initialization result. Data type: number. A value of 0 indicates success, and a value of -1 indicates failure.

    • Sample code:

      // The appkey parameter specifies the authentication key that is assigned by Alibaba Cloud.
      const appkey: string = "******";
      // Optional parameters. You can specify whether to use IPv6 domain names or domain names registered outside the Chinese mainland to report device information.
      let options: Map<string, string> = new Map<string, string>();
      options.set("IPv6", "0");// Use IPv6 domain names.
      options.set("Intl", "0");// Use domain names registered in the Chinese mainland.
      
      // Initial collection. If you want to collect device information in subsequent tasks, call the init function again.
      let ret: number = TigerTallyAPI.init(getContext(this), appkey, options, null);
  3. Sign data.

    Signs the input data and returns a wToken string for request authentication.

    /**
     * Sign data.
     *
     * @param type  Data type
     * @param input Data to be signed
     * @return wToken
     */public static vmpSign(type: number, input: string): string
    • Parameters:

      • type: specifies the type of the data to sign. Data type: number. Set the value to 0.

      • input: specifies the data to sign. Data type: string. We recommend that you specify a request body.

    • Return value: indicates a wToken string.

    • Sample code:

      let body: string = "i am the request body, encrypted or not!";
      let wtoken: string = TigerTallyAPI.vmpSign(0, body);
      Note
      1. If one of the following wToken strings is returned, an exception occurred during initialization:

        1. you must call init first: The init function is not called.

        2. you must input correct data: The input data is invalid.

        3. you must input correct type: The type of the input data is invalid.

        4. inner error: An internal system error occurred.

3. Secondary verification

  1. Check the result.

    Determine whether to perform two-factor authentication based on the cookie and body fields in the response. The header may contain multiple Set-Cookie fields.

    /**
     * Check whether two-factor authentication is required.
     *
     * @param cookie  cookie
     * @param body    body
     * @return 0: not required. 1: required.
     */
    public static cptCheck(cookie: string, body: string): number
    • Parameters:

      • cookie: specifies all cookies in the response. Data type: string.

      • body: specifies the body in the response. Data type: string.

    • Return value: indicates whether two-factor authentication is required. A value of 0 indicates that two-factor authentication is not required. A value of 1 indicates that two-factor authentication is required. Data type: number.

    • Sample code:

      let cookie: string = "key1=value1;kye2=value2;";
      let body: string = "....";
      let recheck: number = TigerTallyAPI.cptCheck(cookie, body);
  2. Create a slider.

    Determine whether to create a slider object based on the result returned by cptCheck. The TTCaptcha object provides the show and dismiss methods, which correspond to showing and hiding the slider window. TTCaptchaOption encapsulates the configurable parameters of the slider, and TTCaptchaListener contains two callback states for the slider.

    /**
     * Create a slider.
     *
     * @param ctx
     * @param option The parameters.
     * @param listener The callback functions.
     * @return The slider.
     */
    public static cptCreate(ctx: UIContext, option: TTCaptchaOption, listener: TTCaptchaListener): TTCaptcha
    
      
    /**
     * The slider.
     */
    export class TTCaptcha {
        /**
         * Show the slider.
         */
        public show(): void
    
        /**
         * Hide the slider.
         */
        public dismiss(): void
    }
    
    /**
     * The parameters of the slider.
     */
    export class TTCaptchaOption {
      // Specify whether the slider can be hidden by clicking on an empty area.
      cancelable: boolean;
    
    }
    
    /**
     * The callback functions.
     */
    export interface TTCaptchaListener {
      /**
       * Verification success.
       *
       * @param captcha The slider.
       * @param code The default value is the trace ID.
       */
      success: (captcha: TTCaptcha, code: string) => void;
    
      /**
       * Verification failure or exception.
       *
       * @param captcha The slider.
       * @param code The error code.
       */
      fail: (captcha: TTCaptcha, code: string) => void;
    }
    
    • Parameters:

      • ctx: specifies the UI context of the current page. Data type: UIContext.

      • option: specifies the parameters of the slider. Data type: TTCaptchaOption.

      • listener: specifies the callback functions for the slider status. Data type: TTCaptchaListener.

    • Return value: indicates the slider. Data type: TTCaptcha.

    • Sample code:

      let option: TTCaptchaOption = new TTCaptchaOption();
      // option.cancelable = false;
      
      let captcha: TTCaptcha = TigerTallyAPI.cptCreate(this.getUIContext(), option, {
        success: (captcha: TTCaptcha, code: string) => {
          console.log("captcha success:", code);
          captcha.dismiss();
        },
        fail: (captcha: TTCaptcha, code: string) => {
          console.log("captcha failed:", code);
          captcha.dismiss();
        }
      });
      captcha.show();
      Note
      • You must call the cptCreate method on the main thread because the method involves UI operations.

      • A verification exception indicates that an exception is detected when the slider is loaded. A verification failure indicates that an exception is detected after the verification is complete. The following list describes the error codes:

        • 1001: The verification failed.

        • 1002: A system error occurred.

        • 1003: A parameter error occurred.

        • 1005: The verification is canceled.

        • 8001: A slider invocation error occurred.

        • 8002: A verification exception occurred.

        • 8004: A network error occurred.

Example

import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';

import { TigerTallyAPI, TTCode } from 'aliyuntigertally';
import { TTCaptcha, TTCaptchaOption, TTCaptchaListener} from 'aliyuntigertally';

@Entry
@Component
struct Index {
  
  build() {
    ...
  }
  
  aboutToAppear() {
    this.onTest();
  }

  async onTest() {
    
    const APP_KEY: string = "xxxxxx";
    const APP_URL: string = "xxxxxx";
    const APP_HOST: string = "xxxxxx";
    
    // Initialize the SDK.
    let options: Map<string, string> = new Map<string, string>();
    options.set("IPv6", "0");// Use IPv6 domain names.
    options.set("Intl", "0");// Use domain names registered in the Chinese mainland.
    let retCode: number = TigerTallyAPI.init(getContext(this), APP_KEY, options, null);
    console.log("TigerTally init:", retCode);

    // Forbid synchronous calls of the SDK.
    const sleep = (duration: number) => {
      return new Promise<void>(resolve => setTimeout(resolve, duration));
    };
    await sleep(2000);

    // Sign data.
    let data: string = "i am the request body, encrypted or not!";
    let wtoken: string = TigerTallyAPI.vmpSign(0, data);
    console.log("TigerTally vmpSign:", wtoken);

    // Call the required operation.
    this.doPost(APP_URL, APP_HOST, wtoken, data, (code, cookie, body) => {
      // Check whether to display a slider.
      let recheck: number = TigerTallyAPI.cptCheck(cookie, body);
      console.log("TigerTally captcha check:", recheck);

      if (recheck === 0) return;
      this.doShow();
    });
  }

  // Display a slider.
  async doShow() {
    console.log("Slider display");

    let option: TTCaptchaOption = new TTCaptchaOption();
    // option.cancelable = false;

    let captcha: TTCaptcha = TigerTallyAPI.cptCreate(this.getUIContext(), option, {
      success: (captcha: TTCaptcha, code: string) => {
        console.log("captcha success:", code);
        captcha.dismiss();
      },
      fail: (captcha: TTCaptcha, code: string) => {
        console.log("captcha failed:", code);
        captcha.dismiss();
      }
    });
    captcha.show();
  }

  // Send a request.
  async doPost(url: string, host: string, wtoken: string, body: string,
    callback: (code: number, cookie: string, body: string) => void): Promise<void> {
    let response_code: number = 0;
    let response_body: string = "";
    let response_cookie: string = "";

    try {
      let httpRequest = http.createHttp();
      let response: http.HttpResponse = await new Promise<http.HttpResponse>((resolve, reject) => {
        httpRequest.request(
          url,
          {
            method: http.RequestMethod.POST,
            header: {
              "Content-Type": "text/x-markdown",
              "User-Agent": "",
              "Host": host,
              "wToken": wtoken,
            },
            extraData: body.length > 0 ?  body : undefined,
            connectTimeout: 12000,
          },
          (err: BusinessError, data: http.HttpResponse) => {
            if (!err) {
              resolve(data);
            } else {
              reject(err);
            }
            httpRequest.destroy();
          }
        );
      });

      if (response != null) {
        response_code = response.responseCode;
        let success: boolean = (response_code === 200);

        if (success) {
          response_body = response.result ?  response.result.toString() : "";
          response_cookie = response.header["set-cookie"] ?  response.header["set-cookie"].join(";") : "";
        } else {
          response_body = response.result ?  response.result.toString() : "";
        }
      } else {
        response_code = -1;
      }

      console.log("response code:", response_code);
      console.log("response body:", response_body);
      console.log("response cookie:", response_cookie);

    } catch (error) {
      console.log("response error:", error.code, error.message);
      response_code = -1;
      response_body = error.message;
    } finally {
      if (callback != null) {
        callback(response_code, response_cookie, response_body);
      }
    }
  }
}