加入收藏 | 设为首页 | 会员中心 | 我要投稿 源码网 (https://www.900php.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

NDK开发 - JNI数组数据处理

发布时间:2021-03-11 11:11:48 所属栏目:大数据 来源:网络整理
导读:副标题#e# 很多时候利用 NDK 开发都是为了对数据进行加密操作,因为单纯的 Java 太容易被反编译了,加密算法也就很容易被破解,而利用 C/C++ 开发可以加大破解难度。文件的数据加密就需要通过 byte 数组传给 JNI。 传送门:NDK开发 - JNI数组数据处理 JNI
副标题[/!--empirenews.page--]

很多时候利用 NDK 开发都是为了对数据进行加密操作,因为单纯的 Java 太容易被反编译了,加密算法也就很容易被破解,而利用 C/C++ 开发可以加大破解难度。文件的数据加密就需要通过 byte 数组传给 JNI。

传送门:NDK开发 - JNI数组数据处理

JNI 中的数组分为基本类型数组和对象数组,它们的处理方式是不一样的,基本类型数组中的所有元素都是 JNI 的基本数据类型,可以直接访问。而对象数组中的所有元素是一个类的实例或其它数组的引用,和字符串操作一样,不能直接访问 Java 传递给 JNI 层的数组,必须选择合适的 JNI 函数来访问和设置 Java 层的数组对象。

访问基本类型数组

Java 代码:

//调用数组
byte array[] = {'A','B','C','D','E'};
byte[] resutl = NativeMethod.getByteArray(array);
for (int i = 0; i < array.length; i++) {
    Log.d(TAG,"ARRAY : " + array[i] + "->" + resutl[i]);
}

native 代码:

JNIEXPORT jbyteArray JNICALL Java_com_example_gnaix_ndk_NativeMethod_getByteArray
        (JNIEnv *env,jclass object,jbyteArray j_array){
    //1. 获取数组指针和长度
    jbyte *c_array = env->GetByteArrayElements(j_array,0);
    int len_arr = env->GetArrayLength(j_array);

    //2. 具体处理
    jbyteArray c_result = env->NewByteArray(len_arr);
    jbyte buf[len_arr];
    for(int i=0; i<len_arr; i++){
        buf[i] = c_array[i] + 1;
    }

    //3. 释放内存
    env->ReleaseByteArrayElements(j_array,c_array,0);

    //4. 赋值
    env->SetByteArrayRegion(c_result,len_arr,buf);
    return c_result;
}

运行结果:

NDK开发 - JNI数组数据处理

  示例中,从 Java 层中传进去了一个数组,参数类型是 byte[],对应 JNI 中 jbyteArray 类型。利用 GetByteArrayElements 函数获取数组指针,第二个参数返回的数组指针是原始数组,还是拷贝原始数据到临时缓冲区的指针,如果是 JNI_TRUE:表示临时缓冲区数组指针,JNI_FALSE:表示临时原始数组指针。开发当中,我们并不关心它从哪里返回的数组指针,这个参数填 NULL 即可,但在获取到的指针必须做校验。
类似的函数还有 GetIntArrayElements,GetFloatArrayElements,GetDoubleArrayElements 等。
  然后对数据进行了处理,并且释放了数组内存。ReleaseByteArrayElements 是与 GetByteArrayElements 对应使用的。

  除了上述方法还可以用 JNI 中的 GetXXArrayRegion 函数进行实现数据操作,对应的 SetXXArrayRegion 上述也有提到过。

JNIEXPORT jint JNICALL Java_com_example_gnaix_ndk_NativeMethod_getByteArray
        (JNIEnv *env,jbyteArray j_array){
    jbyte *c_array;
    jint len_arr;

    //1. 获取数组长度
    len_arr = env->GetArrayLength(j_array);

    //2. 申请缓冲区
    c_array = (jbyte *) malloc(sizeof(jbyte) * len_arr);

    //3. 初始化缓冲区
    memset(c_array,sizeof(jbyte)*len_arr);

    //4. 拷贝java数组数据
    env->GetByteArrayRegion(j_array,c_array);

    //5. 计算总和
    int sum = 0;
    for(int i=0; i<len_arr; i++){
        sum += c_array[i];
    }

    //6. 释放缓冲区
    free(c_array);
    return sum;
}

访问引用类型数组

  JNI 提供了两个函数来访问对象数组,GetObjectArrayElement 返回数组中指定位置的元素,SetObjectArrayElement 修改数组中指定位置的元素。与基本类型不同的是,我们不能一次得到数据中的所有对象元素或者一次复制多个对象元素到缓冲区。因为字符串和数组都是引用类型,只能通过 Get/SetObjectArrayElement 这样的 JNI 函数来访问字符串数组或者数组中的数组元素。
  下面的例子同调用 Native 方法 创建一个对象数组,返回后打印这个数组内容:

//返回对象数组
Person persons[] =  NativeMethod.getPersons();
for(Person person : persons){
    person.toString();
}

Person 类:

/**
 * 名称: Person
 * 描述:
 *
 * @author xiangqing.xue
 * @date 16/3/10
 */
public class Person {
    private String TAG = "Person";

    public String name;
    public int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String toString(){
        String result =  "Name: " + name + ",age: " + age;
        Log.d(TAG,result);
        return result;
    }
}

Native 方法:

JNIEXPORT jobjectArray JNICALL Java_com_example_gnaix_ndk_NativeMethod_getPersons
        (JNIEnv *env,jclass object){
    jclass clazz = NULL;
    jobject jobj = NULL;
    jmethodID mid_construct = NULL;
    jfieldID fid_age = NULL;
    jfieldID fid_name = NULL;
    jstring j_name;

    //1. 获取Person类的Class引用
    clazz = env->FindClass("com/example/gnaix/ndk/Person");
    if(clazz == NULL){
        LOGD("clazz null");
        return NULL;
    }

    //2. 获取类的默认构造函数ID
    mid_construct = env->GetMethodID(clazz,"<init>","()V");
    if(mid_construct == NULL){
        LOGD("construct null");
        return NULL;
    }

    //3. 获取实例方法ID和变量ID
    fid_name = env->GetFieldID(clazz,"name","Ljava/lang/String;");
    fid_age = env->GetFieldID(clazz,"age","I");
    if(fid_age==NULL || fid_name==NULL){
        LOGD("age|name null");
        return NULL;
    }

    //4. 处理单个对象并添加到数组
    int size = 5;
    jobjectArray obj_array = env->NewObjectArray(size,clazz,0);
    for(int i=0; i<size; i++){
        jobj = env->NewObject(clazz,mid_construct);
        if(jobj == NULL){
            LOGD("jobject null");
            return NULL;
        }
        env->SetIntField(jobj,fid_age,23 + i);
        j_name = env->NewStringUTF("gnaix");
        env->SetObjectField(jobj,fid_name,j_name);
        env->SetObjectArrayElement(obj_array,i,jobj);
    }


    //5. 释放局部变量
    env->DeleteLocalRef(clazz);
    env->DeleteLocalRef(jobj);
    return obj_array;
}

运行结果:

NDK开发 - JNI数组数据处理

(编辑:源码网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读