Вы не можете предотвратить реверс-инжиниринг, но вы можете усложнить его, включив больше работы и дополнительных шагов, на которые не все способны.
Помещение констант в собственную библиотеку предотвращает их появление в декомпилированном java код. Подключение какой строки в скомпилированной библиотеке совпадает с тем, какое значение в конечном приложении не является тривиальным. Обычный метод включает в себя просто экспорт всех строк из собственной библиотеки и сопоставление их по контексту - например, поиск вещей, которые выглядят как ключи API. Если вы зашифруете эти константы и расшифруете их в самом приложении, это добавит еще один шаг к обратному инжинирингу, хотя, поскольку в приложении есть ключи шифрования, злоумышленник, безусловно, может сделать это самостоятельно.
Для быстрого и простого шифрования значений в NDK рассмотрим реализацию basi c salsa20 или chacha20 - для целей запутывания не требуется аутентификация, и ключи могут быть жестко закодированы.
Например, используя этот простой Salsa20 C реализация :
// hard-coded 128-bit key, can be anything
uint8_t k[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
// hard-coded nonce, can be anything
uint8_t n[8] = { 101, 102, 103, 104, 105, 106, 107, 108 };
// The s20_crypt() function encrypts/decrypts in place.
// During development, do this:
std::string myString = ...;
std::vector<uint8_t> vec(myString.begin(), myString.end());
s20_crypt(k, S20_KEYLEN_128, n, 0, vec.data(), vec.size());
// export the vector bytes somehow - you can run this on your computer and write then to a file or to stdout for example
// After you have the encrypted bytes:
Java_com_galaxy_mars_moon_MainActivity_getDefaultNegative(JNIEnv* env, jobject)
{
uint8_t[] defaultNegative = [...]; // the encrypted values
s20_crypt(k, S20_KEYLEN_128, n, 0, defaultNegative, sizeof(defaultNegative));
std::string decrypted(defaultNegative, defaultNegative+sizeof(defaultNegative));
return env->NewStringUTF(decrypted.c_str());
}