为什么使用ndk开发了,就是 稍微将代码隐藏一下。。Android 虽然打包能混淆,但是有些东西是不能混淆的,如下图,压缩密码把直勾勾的下载代码中。下面手把手稍微优化下。

將操作密码的部分我们通过 jni开发,在C++里面操作。

打开APP build.gradle进行配置NDK信息,配置CMake.

 defaultConfig {externalNativeBuild {cmake {cppFlags '-std=c++11'abiFilters "arm64-v8a", "armeabi-v7a"}}}
android{externalNativeBuild {cmake {path file('src/main/cpp/CMakeLists.txt') //这里可以使任意路径,我就放在跟Java代码同级了version '3.10.2'}}ndkVersion '21.0.6113669' //自己选一个你本机安装过的 ndk版本}

接下来创建CMake文件,如果包含多个的话,就多赋值几个lib就好了。

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html# Sets the minimum version of CMake required to build the native library.cmake_minimum_required(VERSION 3.10.2)# Declares and names the project.project("RiverwayApplication")# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.add_library( # Sets the name of the library.xm-lib# Sets the library as a shared library.SHARED# Provides a relative path to your source file(s).xm-lib.cpp)# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.find_library( # Sets the name of the path variable.log-lib# Specifies the name of the NDK library that# you want CMake to locate.log)# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.target_link_libraries( # Specifies the target library.xm-lib# Links the target library to the log library# included in the NDK.${log-lib})

基本配置好了我们接下来就开始写cpp了。

首先创建好我们的Java类,并设置好native方法,

下面是C++代码!!通过反射调用,这样我们就把密码隐藏到C中!本人只是在学习c++中,可能这里还有优化的地方!!!

extern "C"
JNIEXPORT void JNICALL
Java_com_xm_j_XmJni_inputPassword(JNIEnv *env, jclass clazz, jobject zip_file) {//拿到调用的对象实例,根据实例 获取class,在根据class获取 isEncrypted方法,()Z 返回布尔型不懂的话就多百度看看方法签名jmethodID isEncryptedMethod = env->GetMethodID(env->GetObjectClass(zip_file), "isEncrypted","()Z");//执行方法验证jboolean isEncrypted = env->CallBooleanMethod(zip_file, isEncryptedMethod);if (isEncrypted) {std::string str = "258258258";//密码写在这里。cin >> str;int len = str.size() + 1;char *arr = new char[len];strcpy(arr, str.c_str());//1.反射Java类中的setPassword方法,(根据对象拿到class,根据class拿方法)jmethodID setPassword = env->GetMethodID(env->GetObjectClass(zip_file), "setPassword","([C)V");//2.因为调用Java方法,所以需要将密码转正 jchar。jcharArray array = env->NewCharArray(len);jchar *pArray;pArray = (jchar *) calloc(len, sizeof(jchar));for (int i = 0; i < len; i++) {*(pArray + i) = *(arr + i);}env->SetCharArrayRegion(array, 0, len, pArray);//3.反射调用方法。env->CallVoidMethod(zip_file, setPassword, array);free(pArray);delete[] arr;}
}

下面是我个人学习的Java类和完整的C++代码。后续有补充在说吧。

Java类。包名:com.xm.j

public class XmJni {static {System.loadLibrary("xm");}public static native long callTime();//这里的application 子类都行。你可以自定义更换这里的applicationpublic static native Application getApp();public static native void numberFunctionAddStr();public static native void cppPointer();//指针和应用相关。public static native void dataType();//c++数据结构public static native void jstring2char(String j);public static native void fstream();}

c++类有点杂乱无章自己凑合看吧:

#include <jni.h>
#include <string>
#include <sstream>
#include <android/log.h>using namespace std;#include <iostream>#include "cmath"static const char *kTAG = "xiaoma_JNI";#ifndef FINENGINE_LOG_H
#define FINENGINE_LOG_H
//#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,kTAG,__VA_ARGS__)
//#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,kTAG,__VA_ARGS__)
#define  MLog(...)  __android_log_print(ANDROID_LOG_ERROR,kTAG,__VA_ARGS__)
#endifextern "C"
JNIEXPORT void JNICALL
Java_com_xm_j_XmJni_inputPassword(JNIEnv *env, jclass clazz, jobject zip_file) {//拿到调用的对象实例,根据实例 获取class,在根据class获取 isEncrypted方法,()Z 返回布尔型不懂的话就多百度看看方法签名jmethodID isEncryptedMethod = env->GetMethodID(env->GetObjectClass(zip_file), "isEncrypted","()Z");//执行方法验证jboolean isEncrypted = env->CallBooleanMethod(zip_file, isEncryptedMethod);if (isEncrypted) {std::string str = "258258258";//密码写在这里。cin >> str;int len = str.size() + 1;char *arr = new char[len];strcpy(arr, str.c_str());//1.反射Java类中的setPassword方法,(根据对象拿到class,根据class拿方法)jmethodID setPassword = env->GetMethodID(env->GetObjectClass(zip_file), "setPassword","([C)V");//2.因为调用Java方法,所以需要将密码转正 jchar。jcharArray array = env->NewCharArray(len);jchar *pArray;pArray = (jchar *) calloc(len, sizeof(jchar));for (int i = 0; i < len; i++) {*(pArray + i) = *(arr + i);}env->SetCharArrayRegion(array, 0, len, pArray);//3.反射调用方法。env->CallVoidMethod(zip_file, setPassword, array);free(pArray);delete[] arr;}
}//使用int64_t 接收。这样才是java层的long!!
//unsigned 无符号正数,, signed有符号,+ - 是正数的一半
string longToString(int64_t t) {std::string result;stringstream ss;ss << t;ss >> result;return result;
}extern "C"
JNIEXPORT jlong JNICALL
Java_com_xm_j_XmJni_callTime(JNIEnv *env, jclass clazz) {jclass j = env->FindClass("java/util/Date");jmethodID jm = env->GetMethodID(j, "<init>", "()V");jobject jNewObject = env->NewObject(j, jm);jmethodID jmetthodIdTime = env->GetMethodID(j, "getTime", "()J");jlong jresultTime = env->CallLongMethod(jNewObject, jmetthodIdTime);//如果类型对不上的话。那么看到的值肯定就是错误的。。一定要先确认类型对的上。通过Java反射创建的对象获取的long。。对应c++的 int64_tMLog("打印的%s", longToString(jresultTime).c_str());unsigned int d = 0;unsigned long f = 0;MLog("d定义,自定初始化%d,%lu", d, f);std::string s1 = "xiao ming";std::string s2 = "wo cao";MLog("%s", (s1 +s2).c_str()); //如果要传递给某个函数时候。则调用  some_c_api(s.c_str(), s.size());   some_c_api(char const *input, size_t length);//    for (unsigned int i = 1, countI = 9; i <= countI; i++) {
//        for (unsigned int j = 1, countJ = i; j <= countJ; j++) {
//            MLog("%d * %d = %d", i, j, i * j);
//        }
//    }return jresultTime;
}extern "C"
JNIEXPORT jobject JNICALL
Java_com_xm_j_XmJni_getApp(JNIEnv *env, jclass clazz) {jclass activityThread = env->FindClass("android/app/ActivityThread");jmethodID currentActivityThread = env->GetStaticMethodID(activityThread,"currentActivityThread","()Landroid/app/ActivityThread;");jobject at = env->CallStaticObjectMethod(activityThread, currentActivityThread);//获取Application,也就是全局的ContextjmethodID getApplication = env->GetMethodID(activityThread, "getApplication","()Landroid/app/Application;");jobject context = env->CallObjectMethod(at, getApplication);return context;
}extern "C"
JNIEXPORT void JNICALL
Java_com_xm_j_XmJni_numberFunctionAddStr(JNIEnv *env, jclass clazz) {//数学函数,Java也提供了    https://www.runoob.com/cplusplus/cpp-numbers.htmlint i, j;// 设置用时间做随机种子srand((unsigned) time(NULL));/* 生成 10 个随机数 */for (i = 0; i < 3; i++) {// 生成实际的随机数j = rand();MLog("当前随机数:%d", j);}//c++ 连接字符串std::string hello = "hello word";hello.append("111");MLog("c++的String类更简单%s", hello.c_str());//c 链接字符串char str1[] = "hello ";char str2[] = "word";//方法一char str3[strlen(str1) + strlen(str2) + 1];str3[0] = '\0';//没有初始化,第一个元素设置为空!!这样的话就不需要像下面那样 设置足够大的值了。strcat(str3, str1);strcat(str3, str2);//str2 追加到 str1里面。str1需要足够大!!!方法二
//    char *s = strcat(str1, str2);MLog("链接后的字符串:%s", str3);char *cat = strstr(str3, "wo"); //如果没有找到返回null,找到了就是返回这个字符串的指针if (cat == NULL) {MLog("查找字符串:%s,没有找到这个字符串", cat);} else {MLog("查找到字符串:%s", cat);}}
extern "C"
JNIEXPORT void JNICALL
Java_com_xm_j_XmJni_jstring2char(JNIEnv *env, jclass clazz, jstring s) {//直接jni层就提供了。直接返回jstring 转到 c++的指针const char *rtn = env->GetStringUTFChars(s, NULL);MLog("jstring to char %s", rtn);
}// 函数声明,求数组的平局值!!先定义在使用,在实现
double getAverage(const int *arr, int count);//跟Java一模一样方法重载。根据形参不同
double getAverage(const int *arr);extern "C"
JNIEXPORT void JNICALL
Java_com_xm_j_XmJni_cppPointer(JNIEnv *env, jclass clazz) {//学习c++指针//###################认识什么什么是指针地址,16进制的内存地址int var1;char var2[10];MLog("var1 变量的地址%p", &var1);MLog("var2 变量的地址%p", &var2);//######################### 操作指针!操作变量 var 或者操作 *ip 指针都是操作的一个东西//总结,在= 右边 &:取出内存地址。。。。。         * :取值。int var = 20;   // 实际变量的声明int *ip;        // 指针变量的声明ip = &var;       //将var的指针交给ip。此时 指针变量ip和 变量var指向的是同一块内存MLog("var 变量的值%d", var);MLog("var 变量的指针地址%p", &var);MLog("ip 指针变量的值%d", *ip);var = 15;//改变变量MLog("var 直接改变:变量的值%d", var);MLog("ip 直接改变:指针变量的值%d", *ip);*ip = 10;MLog("var 通过指针改变:变量的值%d", var);MLog("ip 通过指针改变:指针变量的值%d", *ip);//结尾用-1表示,判断个数的时候也是用 -1 来判断,,你不允许出现-1的值int varArr[] = {100, 200, 30, 50, 60, 0, 50, -1};
//    double average = getAverage(varArr, 5); //明确知道个数的这样处理。double average = getAverage(varArr);MLog("varArr 的平局值%f", average);//#####################################引用。 通过使用引用来替代指针,会使 C++ 程序更容易阅读和维护 类型后面跟&  是引用// 在 = 左边的  &:是引用。 后面操作这个变量都是直接操作实际的值int &update = varArr[0];update = 50;average = getAverage(varArr);MLog("varArr 修改第一个引用的的平局值%f", average);int *j = &varArr[5];//从第六个元素取出指针!average = getAverage(j);MLog("varArr 从第6个元素开始算平局值%f", average);time_t now = time(0);tm *time = localtime(&now);MLog("1970到现在的秒数%ld", now);MLog("当前时间:%d-%d-%d %d:%d:%d", time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,time->tm_hour,time->tm_min,time->tm_sec);
}double getAverage(const int *arr, int count) {int sum = 0;for (int i = 0; i < count; ++i) {sum += arr[i];}return double(sum) / count;
}double getAverage(const int *arr) {int sum = 0;int count = 0;while (arr[count] != -1) {count++;}for (int i = 0; i < count; ++i) {sum += arr[i];}return double(sum) / count;
}//定义了数据结构
struct Books {char title[50];char author[50];char subject[100];int book_id;
};//定义了数据结构!! class全部都是private,但是你可以通过添加public 为公开的!
class BookClass {
public://公开的字写在最上面就是全公开,将不需要公开的写在上面char title[50];char author[50];char subject[100];
protected:int book_id = 10;//private:  //访问修饰符,默认是private!
//protected:
//public:
//    virtual char *toString(){ //virtual 必须有继承关系,默认调用子类的函数!
//
//    }
//virtual 多态,=0 纯虚函数,子类必须实现不然编译器报错!!也可以放方法体虚函数,这个写法有点像Java的方法(abstract)virtual char *toString() = 0;
};class NumberBookClass : public BookClass {
public:int passNumber;NumberBookClass(const char *t = "未知书籍", const char *a = "未知作者") {//构造方法。。如果没有值就使用默认值。循环添加到 父类的变量中int count = 0;while (t[count] != '\0') {title[count] = t[count];count++;}title[count] = '\0';count = 0;while (a[count] != '\0') {author[count] = a[count];count++;}author[count] = '\0';}~NumberBookClass() {//析构函数。当被调用delet的时候。}//将父类被保护的 book_id指针返给调用者int *getSuperBookId() {return &book_id;}char *toString() {std::string str = std::string("passNumber:") + std::to_string(passNumber) +std::string(",书名:") + std::string(title) +std::string(",作者:") + std::string(author) +std::string(",book_id:") + std::to_string(book_id);return const_cast<char *>(str.c_str());}
};#include <stdbool.h>extern "C"
JNIEXPORT void JNICALL
Java_com_xm_j_XmJni_dataType(JNIEnv *env, jclass clazz) {//初步看有点像 Java的 JavaBeanBooks book1;strcpy(book1.title, "童话故事");strcpy(book1.author, "小马");strcpy(book1.subject, "这是可爱的童话故事哟");book1.book_id = 12345;//定义的数据类型直接可以 . 来进行操作他和赋值。。MLog("这本:%s的,作者是:%s,书的基本描述:%s", book1.title, book1.author, book1.subject);//如果交给指针后。则必须用 -> 来使用struct Books *p_book1 = &book1;MLog("这本:%s的,作者是:%s,书的基本描述:%s", p_book1->title, p_book1->author, p_book1->subject);// typedef 给 数据类型 1、重新定义一个新名字,2、简化声明(隐藏指针什么的)//    typedef long int *pint32;//    pint32 x, y, z;  // x, y 和 z 都是指向长整型 long int 的指针。typedef Books B;B b;NumberBookClass numberBookClass = NumberBookClass("c++", "小马");numberBookClass.passNumber = 60;//60分及格//因为父类是被保护的。只有子类才能获取。。我本来没办法修改,但是我通过子类获取到父类的成员变量指针,我就可以修改了int *protectedBookId = numberBookClass.getSuperBookId();MLog("通过子类派生类 的方法获取了指针:%d", *protectedBookId);*protectedBookId = 1314520;MLog("获取指针,非子类赋值:%d", *protectedBookId);MLog("这是子类拼接的\n%s", numberBookClass.toString());
}extern "C"
JNIEXPORT void JNICALL
Java_com_xm_j_XmJni_fstream(JNIEnv *env, jclass clazz) {}

Android NDK jni开发,适当的给Android 代码加密相关推荐

  1. Android NDK JNI开发3

    换个浏览器来发,IE10不能够上传图片,兼容问题. 还是和上一篇一样的步骤,不过这次函数带了参数: <1> : eclipse新建一个hellojnidemo3工程,然后将cgywin切换 ...

  2. Android NDK JNI 简单例子1 : Android NDK配置和下载

    转载请标明出处: http://blog.csdn.net/michael1112/article/details/55004944 江东橘子的博客 下载和配置NDK: --请使用AS2.2 或更高版 ...

  3. Android NDK开发之旅(2):一篇文章搞定Android Studio中使用CMake进行NDK/JNI开发

    Android NDK开发之旅(2):一篇文章搞定android Studio中使用CMake进行NDK/JNI开发 (码字不易,转载请声明出处:http://blog.csdn.NET/andrex ...

  4. Java(JNI)Android使用JNI开发

    目录 交叉编译 jni开发工具 步骤: jni开发中的常见错误 jni简便开发流程 C代码中向logcat输出内容 define LOGI(...) android_log_print(ANDROID ...

  5. Android中JNI开发之常见错误

    JNI开发中的常见问题 1. C文法声明与java中native方法声明,不对应时,报如下异常: java.lang.IllegalStateException: Could not execute ...

  6. 实现Android底层驱动开发并裁剪定制Android操作系统

    毕业论文 题   目实现Android底层驱动开发并裁剪定制Android操作系统 学   院电子信息与电气工程学院 姓   名牛xxx民 专   业电子信息科学与技术 学   号2012xxxxxx ...

  7. android ndk: aborting . stop,编译时出现android ndk aborting stop怎么破

    编译时出现android ndk aborting stop怎么破 更新时间:2019-10-26 10:26 最满意答案 在报错行前加入: $(call import-add-path, cocos ...

  8. Android NDK JNI 的简单使用

    为什么80%的码农都做不了架构师?>>>    1.why: 为啥学 NDK开发,其实是为了项目需要调用底层的一些C/C++的一些东西:另外就是为了效率更加高些: Android n ...

  9. android ndk 界面开发教程,Android NDK开发之入门教程

    JNI(Java Native Interface, Java本地化方法)使得Java能与其它语言(如C.C++)的动态库进行交互. 在Android 项目中,经常看到地图,统计,推送之类的第三方平台 ...

最新文章

  1. 几行 Python 代码实现邮件解析,超赞~
  2. 支付开发填坑记之支付宝
  3. java i 什么时候变_Java中i++与++i的区别(效率分析)
  4. JAVA15.JDK15新特性.4 TextBlock
  5. java outofmemory 处理_java.lang.OutOfMemoryError处理错误
  6. bootstrapt学习指南_TensorFlow 2.0深度强化学习指南
  7. Golang闭包的典型应用
  8. FydeOS v11 发布,全新 Linux 终端提供更多功能
  9. PDF虚拟打印机是如何打印文件的
  10. 《软件工程与实践》 |(一)软件工程基础概述 知识梳理
  11. python 图像检索_深度学习图像检索
  12. 商业的本质 + 社交电商思考
  13. Windows 禁用U盘
  14. XP系统无法访问\\192.168.1.104无法访问。你可能没有权限使用网络资源。与这台服务器的管理员联系以查明你是否有访问权限
  15. matlab用imshow显示为纯白图像问题
  16. 安鑫 阿里、腾讯、百度,谁将成为互联网的老大
  17. 复数中的运算符重载(续)
  18. 有什么好用的苹果群控软件?
  19. HTML_hao123
  20. 四川途志:刚注册的抖音号运营需要养号吗?

热门文章

  1. 终身 服务器_阿里云VS腾讯云618年中活动云服务器价格对比哪个更优惠?
  2. 爆笑笑话集锦,亲们,笑喷你
  3. Windows 8 和 Office 15 截图泄漏(多图)
  4. SQL Server 2008 R2自定义快捷键快捷查询表的内容
  5. 学生专用计算机怎么发出声音,计算机技巧-如何使显示器的内置扬声器发出声音...
  6. windows 2003 远程桌面没有声音解决方法
  7. 职场黑话大全(互联网公司百科版)
  8. windows服务在哪里找
  9. 转: 网页设计中的一些色彩搭配技巧
  10. Nagios Core 复现