Overview
Protect sensitive AppTrove SDK credentials (SDK Key, Secret ID, Secret Key) by storing them securely using the Native Development Kit (NDK). This prevents keys from being exposed in plain text within your app's source code, reducing the risk of unauthorized access.
Two methods are provided:
- Using the
com.klaxit.hiddensecrets
Gradle plugin for automated key hiding - Manual NDK setup with JNI for custom control
Purpose
Key hiding is essential for securing your AppTrove SDK integration:
- Safeguard SDK Key, Secret ID, and Secret Key from reverse engineering
- Available methods:
- Method 1: Use
com.klaxit.hiddensecrets
plugin to automate key encryption in C++ - Method 2: Manually create JNI C files for custom key storage
- Method 1: Use
Prerequisites
- AppTrove SDK: Version
com.trackier:android-sdk:1.6.68
or later - Android: API 19+ (Android 4.4)
- NDK: Installed via Android Studio (Tools > SDK Manager > SDK Tools > NDK)
- CMake: Installed for Method 1 (same menu as NDK)
- Trackier Panel: SDK Key, Secret ID, and Secret Key retrieved (see SDK Signing)
- Permissions: Internet access
Method 1: Keys Hiding with com.klaxit.hiddensecrets
Plugin
Use the com.klaxit.hiddensecrets
Gradle plugin to automate key hiding in native C++ code, generating a Secrets
class to access keys securely.
Setup
-
Add Plugin: In your module-level build.gradle (e.g., app/build.gradle):
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.klaxit.hiddensecrets' version '0.2.0'
} -
Sync Project:
- Click "Sync Project with Gradle Files" in Android Studio
- Verify the
hideSecret
task appears in Gradle tasks (View > Tool Windows > Gradle)
-
Hide Keys: Run the following commands in the terminal (from your project root):
./gradlew hideSecret -Pkey=YOUR_SDK_KEY -PkeyName=SDKKey
./gradlew hideSecret -Pkey=YOUR_SECRET_ID -PkeyName=SecretId
./gradlew hideSecret -Pkey=YOUR_SECRET_KEY -PkeyName=SecretKey- Replace
YOUR_SDK_KEY
,YOUR_SECRET_ID
,YOUR_SECRET_KEY
with actual values from the Trackier Panel keyName
is optional; defaults to a random name if omitted
- Replace
-
Enable CMake: Add CMake configuration to your module-level build.gradle:
android {
// ...
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
} -
Verify Secrets Class: After running
hideSecret
, aSecrets
class is generated in your project (e.g.,app/src/main/java/com/example/myapp/Secrets.kt
):
- Java
- Kotlin
public class Secrets {
static {
System.loadLibrary("secrets");
}
public native String getSDKKey(String packageName);
public native String getSecretId(String packageName);
public native String getSecretKey(String packageName);
}
class Secrets {
companion object {
init {
System.loadLibrary("secrets")
}
}
external fun getSDKKey(packageName: String): String
external fun getSecretId(packageName: String): String
external fun getSecretKey(packageName: String): String
}
Implementation
Use the Secrets
class to retrieve hidden keys and initialize the AppTrove SDK.
- Java
- Kotlin
package com.example.myapp;
import android.app.Application;
import com.trackier.sdk.TrackierSDK;
import com.trackier.sdk.TrackierSDKConfig;
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// Retrieve hidden keys
Secrets secrets = new Secrets();
String sdkKey = secrets.getSDKKey(getPackageName());
String secretId = secrets.getSecretId(getPackageName());
String secretKey = secrets.getSecretKey(getPackageName());
// Configure SDK
TrackierSDKConfig sdkConfig = new TrackierSDKConfig(this, sdkKey, "development");
sdkConfig.setAppSecret(secretId, secretKey);
sdkConfig.disableOrganicTracking(true); // Optional
// Initialize SDK
TrackierSDK.initialize(sdkConfig);
}
}
import android.app.Application
import com.trackier.sdk.TrackierSDK
import com.trackier.sdk.TrackierSDKConfig
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
// Retrieve hidden keys
val secrets = Secrets()
val sdkKey = secrets.getSDKKey(packageName)
val secretId = secrets.getSecretId(packageName)
val secretKey = secrets.getSecretKey(packageName)
// Configure SDK
val sdkConfig = TrackierSDKConfig(this, sdkKey, "development").apply {
setAppSecret(secretId, secretKey)
disableOrganicTracking(true) // Optional
}
// Initialize SDK
TrackierSDK.initialize(sdkConfig)
}
}
Method 2: Keys Hiding with Custom NDK and JNI
Manually create JNI C files to store keys in native code, offering full control over the implementation.
Setup
-
Create JNI Folder: In your project, create a folder:
app/src/main/jni
-
Add JNI Files: Create the following files in
app/src/main/jni
:Android.mkLOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := keys
LOCAL_SRC_FILES := keys.c
include $(BUILD_SHARED_LIBRARY)Application.mkAPP_ABI := all
keys.c#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_myapp_MainApplication_getSDKKey(JNIEnv *env, jobject instance) {
return (*env)->NewStringUTF(env, "YOUR_SDK_KEY");
}
JNIEXPORT jstring JNICALL
Java_com_example_myapp_MainApplication_getSecretId(JNIEnv *env, jobject instance) {
return (*env)->NewStringUTF(env, "YOUR_SECRET_ID");
}
JNIEXPORT jstring JNICALL
Java_com_example_myapp_MainApplication_getSecretKey(JNIEnv *env, jobject instance) {
return (*env)->NewStringUTF(env, "YOUR_SECRET_KEY");
}- Replace
YOUR_SDK_KEY
,YOUR_SECRET_ID
,YOUR_SECRET_KEY
with actual values - Update the JNI function names to match your package (
com_example_myapp
)
- Replace
-
Configure NDK Build: Add NDK configuration to your module-level build.gradle:
android {
// ...
externalNativeBuild {
ndkBuild {
path "src/main/jni/Android.mk"
}
}
} -
Sync Project: Sync Gradle to compile the native library
Implementation
Load the native library and call JNI methods to retrieve keys.
Kotlin Code (MainApplication.kt
):
- Java
- Kotlin
package com.example.myapp;
import android.app.Application;
import com.trackier.sdk.TrackierSDK;
import com.trackier.sdk.TrackierSDKConfig;
public class MainApplication extends Application {
static {
System.loadLibrary("keys");
}
public native String getSDKKey();
public native String getSecretId();
public native String getSecretKey();
@Override
public void onCreate() {
super.onCreate();
// Retrieve hidden keys
String sdkKey = getSDKKey();
String secretId = getSecretId();
String secretKey = getSecretKey();
// Configure SDK
TrackierSDKConfig sdkConfig = new TrackierSDKConfig(this, sdkKey, "development");
sdkConfig.setAppSecret(secretId, secretKey);
sdkConfig.disableOrganicTracking(true); // Optional
// Initialize SDK
TrackierSDK.initialize(sdkConfig);
}
}
import android.app.Application
import com.trackier.sdk.TrackierSDK
import com.trackier.sdk.TrackierSDKConfig
class MainApplication : Application() {
companion object {
init {
System.loadLibrary("keys")
}
}
external fun getSDKKey(): String
external fun getSecretId(): String
external fun getSecretKey(): String
override fun onCreate() {
super.onCreate()
// Retrieve hidden keys
val sdkKey = getSDKKey()
val secretId = getSecretId()
val secretKey = getSecretKey()
// Configure SDK
val sdkConfig = TrackierSDKConfig(this, sdkKey, "development").apply {
setAppSecret(secretId, secretKey)
disableOrganicTracking(true) // Optional
}
// Initialize SDK
TrackierSDK.initialize(sdkConfig)
}
}