项目实战:JNI-Java与C的交互(简单加密解密)

JNI,Java NativeInterface,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。

最好的学习手册就是官方原文档,链接奉上:

http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html(Java Native Interface SpecificationContents

有了之前的“Hello World”基础后,现在开发就容易很多了。

先在.h中添加:

#include <stdio.h>
#include <String.h>

 之后要用到,不然有的是坑等着你。

在.c文件中添加加密函数,源代码如下,看了就秒懂。

JNIEXPORT jstring JNICALL Java_com_quan_car_qmeeting_JniUtils_encodeFromC
        (JNIEnv *env, jobject obj,jstring passWord,jint length){
    //生成native的char指针
    const char* c = (*env)->GetStringUTFChars(env,passWord,NULL);
    char* cStr = c;
    int i ;
    for(i = 0;i < length;i++){
        *(cStr + i) += 1;
    }
    //将c语言字符串转化为java字符串
    return (*env)->NewStringUTF(env, c);
}

这里需要注意的是2个方法的使用,大大减小了开发工作量。

const char * GetStringUTFChars(JNIEnv *env, jstring string,

jboolean *isCopy);

Returns a pointer to an array of bytes representing the string in modified UTF-8 encoding. This array is valid until it is released by ReleaseStringUTFChars().

If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy is made; or it is set to JNI_FALSE if no copy is made.


jstring NewStringUTF(JNIEnv *env, const char *bytes);

Constructs a new java.lang.String object from an array of characters in modified UTF-8 encoding.

详情可见开发手册。


底层工作到此结束。

回到上层。


在JniUtils中添加本地方法:

    //加密本地方法
    public static native String encodeFromC(String text, int length);
    //解密本地方法
    public static native String decodeFromC(String text, int length);

之后在MainActivity.java和xml布局文件中做相应修改,直接调用就ok啦。


MainActivity.java源代码奉上。

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

    private EditText userName_et_main;
    private EditText passWord_et_main;
    private Button login_btn_main;
    private Button regist_btn_main;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

        login_btn_main.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String userName = userName_et_main.getText().toString();
                if(TextUtils.isEmpty(userName)){
                    Toast.makeText(getApplication(), "用户名不能为空!", Toast.LENGTH_SHORT).show();
                }
                Log.d("权兴权意-userName:",userName);
                String passWord = passWord_et_main.getText().toString();
                if(TextUtils.isEmpty(passWord)){
                    Toast.makeText(getApplication(), "密码不能为空!", Toast.LENGTH_SHORT).show();
                }
                Log.d("权兴权意-passWord:",passWord);
                Log.d("encodeFromC(passWord):",JniUtils.encodeFromC(passWord,passWord.length()));
                String encodePassWord = JniUtils.encodeFromC(passWord,passWord.length());
                Log.d("decodeFromC(passWord):",JniUtils.decodeFromC(encodePassWord,encodePassWord.length()));
            }
        });

        regist_btn_main.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setClass(MainActivity.this, RegistActivity.class);
                startActivity(intent);
            }
        });


    }

    private void initView() {
        userName_et_main = (EditText) findViewById(R.id.userName_et_main);
        passWord_et_main = (EditText) findViewById(R.id.passWord_et_main);
        login_btn_main = (Button) findViewById(R.id.login_btn_main);
        regist_btn_main = (Button) findViewById(R.id.regist_btn_main);
    }
}

jniutils.c源代码奉上:

//
// Created by 权兴权意 on 2016/8/17.
//

#include "com_ndkjnidemo_quan_ndkjnidemo_JniUtils.h"
/*
* Class:     Java_com_ndkjnidemo_quan_ndkjnidemo_JniUtils
* Method:    getStringFormC
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_ndkjnidemo_quan_ndkjnidemo_JniUtils_getStringFormC
        (JNIEnv *env, jobject obj){
    return (*env)->NewStringUTF(env, "权兴权意-这里是来自C的string");
}

JNIEXPORT jstring JNICALL Java_com_ndkjnidemo_quan_ndkjnidemo_JniUtils_updateString
        (JNIEnv *env, jobject obj,jstring js){
    //jstring js
    //生成native的char指针
    const char* c = (*env)->GetStringUTFChars(env,js,NULL);
//    if(c != NULL){
//        LOGV("from Java const char*%s",c);
//    }
//    if(js != NULL){
//        //LOGV("from Java jstring%s",js);
//        return (*env)->NewStringUTF(env, js);
//    }
    return (*env)->NewStringUTF(env, c);
    //return (*env)->NewStringUTF(env, "权兴权意-来自updateString");
}

JNIEXPORT jstring JNICALL Java_com_ndkjnidemo_quan_ndkjnidemo_JniUtils_encodeFromC
        (JNIEnv *env, jobject obj,jstring passWord,jint length){
    //生成native的char指针
    const char* c = (*env)->GetStringUTFChars(env,passWord,NULL);
    char* cStr = c;
    int i ;
    for(i = 0;i < length;i++){
        *(cStr + i) += 1;
    }
    //将c语言字符串转化为java字符串
    return (*env)->NewStringUTF(env, c);
}

JNIEXPORT jstring JNICALL Java_com_ndkjnidemo_quan_ndkjnidemo_JniUtils_decodeFromC
        (JNIEnv *env, jobject obj,jstring passWord,jint length){
    //生成native的char指针
    const char* c = (*env)->GetStringUTFChars(env,passWord,NULL);
    char* cStr = c;
    int i ;
    for(i = 0;i < length;i++){
        *(cStr + i) -= 1;
    }
    return (*env)->NewStringUTF(env, c);
}



小贴士:


1.遇到类似error: '***'undeclared (first use in this function)的错误,

如果你按我说的做就不会遇到,错误原因是少了相应的头文件,添加即可。

 

2.遇到类似A/libc﹕ Fatalsignal 11 (SIGSEGV) at 0x00000000 (code=1), thread 25427 (pool-1-thread-2)的错误,

看上去很吓人,这个问题往往出在使用的so库里面。需要用ndk-stack工具来定位错误。

但一般也没那么复杂,凭着自己的C和JNI功底,调试源代码,重新编译即可解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值