简单JNI使用demo

android中使用JNI的小例子,直接上代码。

首先是Java类JniClient,定义native方法,User实体类就不上代码了,就简单定义了三个属性,name、age、sex。


 1 package com.example.ndkdemo;
 2
 3 public class JniClient {
 4
 5     /
 6       通过JNI简单输出字符串
 7       @return
 8      */
 9     static public native String printStr();
10
11     /
12       通过JNI简单进行整形加法操作
13       @param a
14       @param b
15       @return
16      /
17     static public native int addInt(int a, int b);
18
19     /**
20       通过JNI输入JAVA对象信息
21       @param user
22       @return
23      /
24     static public native String printUser(User user);
25
26     /**
27       通过JNI创建java对象
28       @param name
29       @param age
30       @param sex
31       @return
32      /
33     static public native User newUser(String name, int age, String sex);
34
35     /**
36       通过JNI调用无参构造函数创建java对象并且设置相应属性值
37       @param name
38       @param age
39       @param sex
40       @return
41      */
42     static public native User newUserNoArgs(String name, int age, String sex);
43 }

 

然后使用cmd进入工程的classes目录通过javah命令生成c代码的头文件,命令:javah com.example.ndkdemo.JniClient ,这里生成的文件名字为:com_example_ndkdemo_JniClient.h

在工程下面新建一个jni目录,将生成的头文件拷贝到jni目录下面,创建com_example_ndkdemo_JniClient.c文件,在com_example_ndkdemo_JniClient.c文件里面实现各个native方法,代码如下:


  1 #include “com_example_ndkdemo_JniClient.h“
  2 #include 
  3 #include 
  4
  5 // 引入log头文件
  6 #include 
  7 // log标签
  8 #define TAG “jniCLient”
  9 // 定义info信息
 10 #define LOGI(…) android_log_print(ANDROID_LOG_INFO,TAG,VA_ARGS)
 11 // 定义debug信息
 12 #define LOGD(…) android_log_print(ANDROID_LOG_DEBUG, TAG, VA_ARGS)
 13 // 定义error信息
 14 #define LOGE(…) android_log_print(ANDROID_LOG_ERROR,TAG,VA_ARGS)
 15
 16
 17 #ifdef cplusplus
 18 extern “C“
 19 {
 20 #endif
 21 /
 22   Class:     com_example_ndkdemo_JniClient
 23   Method:    printStr
 24   Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
 25  /
 26 JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_JniClient_printStr
 27   (JNIEnv env, jclass arg)
 28 {
 29     jstring str = (env)->NewStringUTF(env, “HelloWorld from JNI !“);
 30     LOGI(“log from jni“);
 31     return str;
 32 }
 33
 34 /
 35  Class:     com_example_ndkdemo_JniClient
 36  Method:    AddInt
 37  Signature: (II)I
 38 /
 39 JNIEXPORT jint JNICALL Java_com_example_ndkdemo_JniClient_addInt
 40   (JNIEnv env, jclass arg, jint a, jint b)
 41 {
 42     return a + b;
 43 }
 44
 45 /
 46   printUser
 47   jclass arg:因为方法为static,所以需要传入jclass参数,表明是哪个类的方法
 48  /
 49 /
 50  1)如果是C++代码,则用(env),如果是C代码,则用env,否则报错: request for member ‘GetObjectClass’ in something not a structure or union
 51  2)所有方法都加了一个参数env,否则报错:too few arguments to function ‘(env)->GetObjectClass’
 52  3)不能把.C文件改成.CPP文件,否则没有规则可以创建“out/apps/JNI_0529/armeabi/objs/JNI_0529/android_jni_MyJNINative.o”需要的目标“apps/JNI_0529/project/jni/android_jni_MyJNINative.c”
 53   一个小例子错误真多啊!!NDK不简单啊!!
 54  /
 55 JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_JniClient_printUser
 56   (JNIEnv env, jclass arg, jobject obj)
 57 {
 58     LOGI(“add from jni–打印用户信息–“);
 59     //获得obj对象的类
 60     jclass cls_objClass = (env)->GetObjectClass(env, obj);
 61     /
 62       获得obj对象中特定方法getName的id
 63       env
 64       cls_objClass         方法所属类
 65       getName              方法名字
 66       ()Ljava/lang/String; 方法签名
 67      /
 68     jmethodID nameMethodId = (env)->GetMethodID(env, cls_objClass, “getName“, “()Ljava/lang/String;“);
 69     /
 70       调用obj对象的特定方法getName
 71       obj      调用方法的目标对象
 72       nameMethodId   调用方法的方法名
 73       …    后面还可以添加方法需要的参数
 74      /
 75     jstring js_name = (jstring)(env)->CallObjectMethod(env, obj, nameMethodId);
 76     //将jstring转为c中的字符数组
 77     const char  name = (char )(env)->GetStringUTFChars(env, js_name, 0);
 78
 79     jmethodID ageMethodId = (env)->GetMethodID(env, cls_objClass, “getAge“, “()I“);
 80     jint ji_age = (env)->CallIntMethod(env, obj, ageMethodId);
 81
 82     jmethodID sexMethodId = (env)->GetMethodID(env, cls_objClass, “getSex“, “()Ljava/lang/String;“);
 83     jstring js_sex = (jstring)(env)->CallObjectMethod(env, obj, sexMethodId);
 84     const char  sex = (char )(env)->GetStringUTFChars(env, js_sex, 0);
 85
 86     //打印信息
 87     LOGI(“user info—-name:%s, age:%d, sex:%s.“, name, ji_age, sex);
 88
 89     //释放资源
 90     (env)->ReleaseStringUTFChars(env, js_name, name);
 91     (env)->ReleaseStringUTFChars(env, js_sex, sex);
 92 //    printf(“%s”, str);
 93     return js_name;
 94 }
 95
 96 /
 97   创建一个对象(调用有参构造函数)
 98  /
 99 JNIEXPORT jobject JNICALL Java_com_example_ndkdemo_JniClient_newUser
100   (JNIEnv env, jclass arg, jstring name, jint age, jstring sex)
101 {
102     //创建一个class的引用,使用类的全包名
103     jclass cls = (env)->FindClass(env, “com/example/ndkdemo/User“);
104     //注意这里方法的名称是”“,它表示这是一个构造函数
105     jmethodID id = (env)->GetMethodID(env, cls, ““, “(Ljava/lang/String;ILjava/lang/String;)V“);
106     //获得一实例,后面接构造函数参数
107 //    jobject obj = (env)->NewObject(env, cls, id, name, age, sex);
108     jstring jname = (env)->NewStringUTF(env, “jni-liuling“);
109     jstring jsex = (env)->NewStringUTF(env, “jni-男“);
110     jobject obj = (env)->NewObject(env, cls, id, jname, 18L, jsex);
111
112     return obj;
113 }
114
115 /
116   创建一个对象(调用无参构造函数)
117  /
118 JNIEXPORT jobject JNICALL Java_com_example_ndkdemo_JniClient_newUserNoArgs
119   (JNIEnv env, jclass arg, jstring name, jint age, jstring sex)
120 {
121     //创建一个class的引用,使用类的全包名
122     jclass cls = (env)->FindClass(env, “com/example/ndkdemo/User“);
123     //注意这里方法的名称是”“,它表示这是一个构造函数
124     jmethodID id = (env)->GetMethodID(env, cls, ““, “()V“);
125     //获得一实例,后面接构造函数参数
126     jobject obj = (env)->NewObject(env, cls, id);
127     jstring jname = (env)->NewStringUTF(env, “jni-liuling“);
128     jstring jsex = (env)->NewStringUTF(env, “jni-男“);
129
130     //获取jfieldID
131     jfieldID nameId = (env)->GetFieldID(env, cls, “name“, “Ljava/lang/String;“);
132     jfieldID ageId = (env)->GetFieldID(env, cls, “age“, “I“);
133     jfieldID sexId = (env)->GetFieldID(env, cls, “sex“, “Ljava/lang/String;“);
134     (env)->SetObjectField(env, obj, nameId, jname);
135     (env)->SetIntField(env, obj, ageId, 18L);
136     (env)->SetObjectField(env, obj, sexId, jsex);
137
138     return obj;
139 }
140
141 #ifdef __cplusplus
142 }
143 #endif


 

代码注释写的很详细,就不多讲了。

下面创建在jni目录下面创建编译文件Android.mk,内容如下:


1 LOCAL_PATH := $(call my-dir)
2 include $(CLEAR_VARS)
3 LOCAL_MODULE := NDKDemo
4 LOCAL_SRC_FILES := com_example_ndkdemo_JniClient.c
5 LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
6 include $(BUILD_SHARED_LIBRARY)

编译过程可以参考网上的,网上很多。下面是在android中调用的代码:

 1 package com.example.ndkdemo;
 2
 3 import android.os.Bundle;
 4 import android.support.v7.app.ActionBarActivity;
 5 import android.util.Log;
 6 import android.view.View;
 7 import android.view.View.OnClickListener;
 8 import android.widget.Button;
 9 import android.widget.EditText;
10 import android.widget.Toast;
11
12 public class MainActivity extends ActionBarActivity {
13
14     static {
15         System.loadLibrary(“NDKDemo”);
16     }
17
18     @Override
19     protected void onCreate(Bundle savedInstanceState) {
20         super.onCreate(savedInstanceState);
21         setContentView(R.layout.activity_main);
22         findViewById(R.id.button).setOnClickListener(new OnClickListener() {
23             @Override
24             public void onClick(View v) {
25                 //调用jni返回字符串
26                 //Toast.makeText(MainActivity.this, JniClient.printStr(), Toast.LENGTH_LONG).show();
27                 User user = new User(“刘玲”, 25, “男hahaah”);
28                 String name = JniClient.printUser(user);
29                 Log.e(“name”, name + “”);
30 //                User user = JniClient.newUser(“liuling”, 18, “男”);
31 //                User user = JniClient.newUserNoArgs(“liuling”, 18, “男”);
32 //                Toast.makeText(MainActivity.this, user.toString(), Toast.LENGTH_LONG).show();
33             }
34         });
35         final EditText num1 = (EditText) findViewById(R.id.num1);
36         final EditText num2 = (EditText) findViewById(R.id.num2);
37         final EditText result = (EditText) findViewById(R.id.result);
38         Button addBtn = (Button) findViewById(R.id.addBtn);
39
40         addBtn.setOnClickListener(new OnClickListener() {
41             @Override
42             public void onClick(View v) {
43                 int n1 = Integer.valueOf(num1.getText().toString().trim());
44                 int n2 = Integer.valueOf(num2.getText().toString().trim());
45                 int n3 = JniClient.addInt(n1, n2);
46                 result.setText(n3 + “”);
47             }
48         });
49
50     }
51
52
53 }

这里要注意14-16行,一定要加载so文件。

上一篇:「镁客早报」法拉第未来出售洛杉矶总部;德国开卖5G频谱,强调不会排除特定企业


下一篇:关于masm不能直接call imm的问题!