[jni] 08_真实开发中如何使用jni

Android 4.0

真实开发中如何使用jni

如阿里旺旺 :登陆的具体实现 c/c++
安全性要求很高:socket http
步骤:
 1、C工程师编写核心的登陆实现
int login(char* username,char * password){
    //取每一个字符和正确是字符进行比较
   //开启一个socket 连接服务器 , 把username 和 password传给服务器.
   //服务器返回 200 登陆成功
   //服务器返回404 登陆失败
}
2、Java中声明native方法
 public native int callLogin(String username, String pwd);
 
3、javah 生成native方法的签
 
4、在android工程目录中,建立jni目录,根据ndk文档,编写android.mk文件,编写c代码,在生成签名的c代码中,调用c工程师写好的login方法
jint Java_xxx_xxx_xxx_xxx_Login(JNIENV* env , jobject obj , jstring username, jstring pwd){
   char*  cusername = JStr2Cstr();
   char*  cpwd = JStr2Cstr();
   int result = login(cusername ,cpwd);
    if(result == 200){
    }
}
5、在Android工程中,就可以通过调用native方法callLogin()来调用c代码实现登录
代码:
1、myLogin.c-C工程师写的核心登录代码和java调用的代码
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
#include <jni.h>
#include "cn_zengfansheng_realdevp_LoginNative.h"
#define LOG_TAG "System.out.c" //在LogCat上打印出来的Tag
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

//0、工具类:返回值 char* 这个代表char数组的首地址
//Jstring2CStr 把java中的jstring的类型转化成一个c语言中的char 字符串
charJstring2CStr(JNIEnv* env, jstring jstr) {
    char* rtn = NULL;
    jclass clsstring = (*env)->FindClass(env, "java/lang/String"); //String
    jstring strencode = (*env)->NewStringUTF(env, "GB2312"); // 得到一个java字符串 "GB2312"
    jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes",
            "(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312");
    jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid,
            strencode); // String .getByte("GB2312");
    jsize alen = (*env)->GetArrayLength(env, barr); // byte数组的长度
    jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
    if (alen > 0) {
        rtn = (char*) malloc(alen + 1);         //"\0"
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
    (*env)->ReleaseByteArrayElements(env, barr, ba, 0);  //
    return rtn;
}

//1、登录核心,用C代码实现
int login(char* username, char* password) {
    //1、取每一个字符和真实密码的字符进行比较
    char* realuser = "hacket";
    char* realpwd = "123456";
    int i = 0;
    for (; *(realuser + i) != '\0'; i++) {
        if (*(username + i) != *(realuser + i)) { //如果有一个字符不相等,返回404;
            return 404;
        }
    }
    printf("----------------\n");
    int j = 0;
    for (; *(realpwd + j) != '\0'; j++) {
        if (*(password + j) != *(realpwd + j)) {
            return 404;
        }
    }
    return 200;
}
//2、java调用的登录代码
JNIEXPORT jint JNICALL Java_cn_zengfansheng_realdevp_LoginNative_callLogin(
        JNIEnv *env, jobject obj, jstring juser, jstring jpwd) {

    //1、将java的字符串转成c语言中的char*
    char* cuser = Jstring2CStr(env, juser);
    char* cpwd = Jstring2CStr(env, jpwd);
    LOGD("cuser=%s", cuser);
    LOGD("cpwd=%s", cpwd);

    //2、调用login进行登录
    int resultcode = login(cuser, cpwd);
    LOGD("resultcode=%d", resultcode);

    //3、返回给java上层调用
    return resultcode;
}
2、android.mk
LOCAL_PATH :$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := MyLogin
LOCAL_SRC_FILES := myLogin.c
#查看ndk官方文档:LOCAL_LDLIBS := -lz
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
3、LoginNative-java中声明的本地native方法
package cn.zengfansheng.realdevp;
public class LoginNative {
    public native int callLogin(String username, String pwd);
}
4、MainActivity.java-java中调用本地native方法
package cn.zengfansheng.realdevp;
import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {

    private EditText et_user;
    private EditText et_pwd;

    static {
        // libMyLogin.so
        System.loadLibrary("MyLogin");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_user = (EditText) this.findViewById(R.id.et_username);
        et_pwd = (EditText) this.findViewById(R.id.et_password);
    }
    public void loginFromC(View view) {
        String username = et_user.getText().toString();
        String password = et_pwd.getText().toString();
        if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
            Toast.makeText(this"用户名或密码不能为空·", Toast.LENGTH_LONG).show();
            return;
        }
        LoginNative loginNative = new LoginNative();
        int resultCode = loginNative.callLogin(username, password);
        if (resultCode == 200) {
            Toast.makeText(this"登录成功~", Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(this"用户名或密码不能为空:" + resultCode, Toast.LENGTH_LONG).show();
        }
    }
}
结果: