Android中调用jni的方法
-
JIN简介
- JNI是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。
- 首先通过一个实例来随意感受下
- 环境说明: windows7 X86 ,jdk1.8,VS2013
- 程序清单:HelloWorld.java
public class HelloWorld{ static{ System.loadLibrary("HelloWorld"); } public native String SayHello(); //声明native方法 public static void main(String[] args){ HelloWorld hello = new HelloWorld(); System.out.println(hello.SayHello()); //调用native方法 } }
-
命令:javac HelloWorld.java
-
javah –jni HelloWorld
-
我们会发现在工作目录除了常见的HelloWorld.class外,还生成了HelloWorld.c。这个头文件是由javah –jni HelloWorld这个命令生成的
-
javah –help
-
用法:
javah [options] <classes>
其中, [options] 包括:
-o <file> 输出文件 (只能使用 -d 或 -o 之一)
-d <dir> 输出目录
-v -verbose 启用详细输出
-h --help -? 输出此消息
-version 输出版本信息
-jni 生成 JNI 样式的标头文件 (默认值)
-force 始终写入输出文件
-classpath <path> 从中加载类的路径
-cp <path> 从中加载类的路径
-bootclasspath <path> 从中加载引导类的路径
<classes> 是使用其全限定名称指定的
(例如, java.lang.Object)。如果是引入包名的java文件,还有一些需要注意的地方,具体请参见:http://www.cnblogs.com/charley_yang/archive/2011/03/13/1983038.html
-
这个头文件主要是为了让C++代码包含进去的,看看生成后的文件大概长啥样
-
程序清单:HelloWorld.h
-
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloWorld */ #ifndef _Included_HelloWorld #define _Included_HelloWorld //防止重复引用 #ifdef __cplusplus extern "C" { //按照C语言方式编译和连接的外部变量 #endif /* * Class: HelloWorld * Method: SayHello * Signature: ()Ljava/lang/String; //返回值类型 */ JNIEXPORT jstring JNICALL Java_HelloWorld_SayHello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
创建一个控制台工程,选择dll项目,把上述生成的HelloWorld.h拷贝到工程文件夹下并添加到项目中,添加包含目录\jdk1.8.0_25\include;\jdk1.8.0_25\include\win32
程序清单:HelloWorld.cpp#include "HelloWorld.h" //**************************************************************** // //功能:c++字符转换成jstring // //思路: // //参数: // //返回:TURE or FALSE // //作者:zhangzq // //日期:2014/11/06 // //**************************************************************** jstring stoJstring(JNIEnv* env, const char* pat) { jclass strClass = env->FindClass("Ljava/lang/String;"); jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V"); jbyteArray bytes = env->NewByteArray(strlen(pat)); env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat); jstring encoding = env->NewStringUTF("utf-8"); return (jstring)env->NewObject(strClass, ctorID, bytes, encoding); } JNIEXPORT jstring JNICALL Java_HelloWorld_SayHello(JNIEnv * env, jobject) { jstring jstrRe = stoJstring(env, "Hello Java Native Interface"); return jstrRe; }
编译一下,OK,生成HelloWorld.dll。把该dll拷贝到java的工具目录中,我们来试试效果:
-
-
Android环境测试
安装jdk(测试版本1.8)
下载并解压带android sdk版本的Eclipse,下载地址:https://dl.google.com/android/adt/adt-bundle-windows-x86-20140702.zip
下载并解压ndk,下载地址:
http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86.zip
使用Eclipse创建Android工程
-
右击工程文件夹,RunAs->Android Application,测试是否能正常使用编译Android程序
-
右击工程文件夹,Android Toos->Add Native Support(如果无此菜单项,到Eclipse mark中下载Android Develop Toolkit插件),,然后输入要新建的so文件名
-
创建完成后,文件目录大概是这个样子的
-
修改MyJni文件中的内容
-
程序清单:MyJni.cpp
#include <jni.h> #include<string.h> extern "C" //如果不加这个,会引起native method错误 { jstring //返回值是java类型的字符串 //********************************************************** //函数名命名规则: //1. 在首部加上Java_,注意首字母大写 //2.使用该函数的java源码所在的文件路径,目录之间用"_"分割 //3.去掉文件的后缀名,加上被java中调用的函数名 // //*********************************************************** Java_com_sunjor_testjni_MainActivity_SayHello( JNIEnv* env, jobject thiz ) { //return (*env)->NewStringUTF(env, "Hello from JNI !"); //后缀名为.c时使用 return env->NewStringUTF((char*) "Hello from JNI !"); //后缀名为.cpp时使用 } }
修改自动生成的MainActivity.java中的代码
package com.sunjor.testjni; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /* Create a TextView and set its content. * the text is retrieved by calling a native * function. */ TextView tv = new TextView(this); tv.setText( SayHello() ); setContentView(tv); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } /* A native method that is implemented by the * 'MyJni' native library, which is packaged * with this application. */ public native String SayHello(); /* this is used to load the 'MyJni' library on application * startup. The library has already been unpacked into * /data/data/com.sunjor.TestJni/lib/libMyJni.so at * installation time by the package manager. */ static { System.loadLibrary("MyJni"); } }
重新再试一次,看下效果-.-