1. 怎樣用 jni來交互java與 c/c++
JNI是Java Native Interface的縮寫,中文為JAVA本地調用。使用JNI可以很方便的用我們的Java程序調用C/C++程序。很多時候,某些功能用Java無法實現,比如說涉及到底層驅動的一些功能,這時候我們就可以利用JNI來調用C或者C++程序來實現,這就是JNI的強大之處。但是JNI也有它的缺點,使用java與本地已編譯的代碼交互,通常會喪失平台可移植性。
下面是一個JNI例子,調用C++輸出"hello world":
第一步:創建Java類,在裡面定義一個本地方法(用native關鍵字修飾的方法)
public native void sayHello();
第二步:使用javah命令(javah 類的全路徑)生成本地方法的C++頭文件
在DOS窗口中進入工程所在目錄,然後執行javah com.test.TestNative命令,執行完之後就會在當前目錄生成一個後綴名為.h的頭文件,如com_test_TestNative.h,這個頭文件是根據包名和類名來命名的。
1 /* DO NOT EDIT THIS FILE - it is machine generated */
2 #include <jni.h>
3 /* Header for class com_test_TestNative */
4
5 #ifndef _Included_com_test_TestNative
6 #define _Included_com_test_TestNative
7 #ifdef __cplusplus
8 extern "C" {
9 #endif
10 /*
11 * Class: com_test_TestNative
12 * Method: sayHello
13 * Signature: ()V
14 */
15 JNIEXPORT void JNICALL Java_com_test_TestNative_sayHello
16 (JNIEnv *, jobject);
17
18 #ifdef __cplusplus
19 }
20 #endif
21 #endif
15、16行是對TestNative類中的本地方法sayHello()的聲明。這個h文件相當於我們在java裡面的介面,這里聲明了一個 Java_com_test_TestNative_sayHello (JNIEnv *, jobject);方法,然後在我們的本地方法裡面實現這個方法,也就是說我們在編寫C/C++程序的時候所使用的方法名必須和這里的一致。
第三步:編寫C/C++本地代碼,生成動態鏈接庫文件
首先在VC6.0(當然也可以用其他工具)中創建一個dll工程---Win32 Dynamic-Link Library工程。然後將上面生成的頭文件com_test_TestNative.h添加到該工程中,然後創建一個源文件引用該頭文件並且實現頭文件中本地函數的功能:
1 #include<iostream.h>
2 #include"com_test_TestNative.h"
3
4 JNIEXPORT void JNICALL Java_com_test_TestNative_sayHello(JNIEnv *env, jobject obj)
5 {
6 cout<<"hello world!"<<endl;
7 }
這里因為com_test_TestNative.h中引入了jni.h所以要將jni.h加入到VC6.0安裝目錄下的Include目錄中。jni.h在JDK安裝目錄下的include中,同時得件include/win32中的兩個頭文件jawt_md.h、jni_md.h也導入到VC6.0中。
將所依賴的頭文件導入之後,我們就可以構建該工程了,按F7就行了,完了會在工程目錄中的Degug目錄下生成一個動態鏈接庫文件,我這里生成的是NativeCode.dll。我們就可以將該dll文件拷貝到環境變數path所包含的目錄下給咱們的Java程序調用了,為了方便,我們也可以將dll所在的工程目錄加入到環境變數path中去,這樣可以避免每次都要拷貝的麻煩。注意修改環境變數之後要重啟myeclipse。
第四步:Java調用本地函數
1 package com.test;
2
3 public class TestNative {
4 public native void sayHello();
5
6 /**
7 * @param args
8 */
9 public static void main(String[] args) {
10 System.loadLibrary("NativeCode");
11 TestNative tNative = new TestNative();
12 tNative.sayHello();
13 }
14 }
第10行是載入動態鏈接庫,JVM只需要載入一次就可以調用了,「NativeCode」是上面生成的動態鏈接庫的名字,不含後綴名。
運行該程序,成功列印輸出了"hello world"。
2. ndk生成的so怎麼在java調用
1. 自己寫.c文件,然後生成so庫
2. 引用別人的靜態庫,或者動態庫來生成新的jni調用庫。
我們先來看最簡單的編寫一個jni調用的so庫,包含一個獲取字元串的方法,通過這個列子,我們主要是了解怎麼在android的工程中調用jni的庫,以及要注意的問題。
第一步:首先我們來看下我們的工程的目錄
jni目錄是我們生成庫的文件,裡麵包含了一個.mk編譯文件以及一系列的.c文件
libs目錄是我們編譯jni目錄下的mk文件動態生成的。
當我們寫好了jni下面的庫文件以後,在當前目錄下執行ndk-build則會自動生成我們需要調用的.so庫文件。
第二步: java裡面怎麼調用jni的庫文件,我們先看代碼
public class MainActivity extends Activity {
/* A native method that is implemented by the
* 'hello-jni' native library, which is packaged
* with this application.
*/
public native String stringFromJNI();
/* this is used to load the 'hello-jni' library on application
* startup. The library has already been unpacked into
* /data/data/com.example.HelloJni/lib/libhello-jni.so at
* installation time by the package manager.
*/
static {
System.loadLibrary("hello-jni");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String str = stringFromJNI();
System.out.println("*****str:" + str);
}
}
在java文件中要做到調用jni文件生成的so庫,需要做到2步
3. Android NDK Jni 開發C和C++的區別
Android NDK Jni 開發C和C++的區別
由於Android官方NDK例子大多使用C語言編寫,所以當我們想用C++進行開發時,會出現種種錯誤。下面簡單說說幾點不同之處,代碼中用紅色標出了不同之處:
1.先來一個用C寫的例子:
(1)hello.c文件。在C中沒有引用,傳遞的env是個兩級指針,用(*env)->調用方法且方法中要傳入env.
1 #include <jni.h>
2
3 jstring Java_com_example_Hello_hello(JNIEnv* env, jobject thiz) {
4 return (*env)->NewStringUTF(env,"Hello Jni---->C!");
5 }
(2)Android.mk文件,更改後綴名為.c
復制代碼
1 LOCAL_PATH := $(call my-dir)
2
3 include $(CLEAR_VARS)
4
5 LOCAL_MODULE := hello
6 LOCAL_SRC_FILES := hello.c
7
8 include $(BUILD_SHARED_LIBRARY)
復制代碼
2.再來一個用C++寫的例子:
(1)hello.cpp文件。C++中env為一級指針,用env->調用方法,無需傳入env;C++語言在編譯的時候為了解決函數的多態問題,會將函數名和參數聯合起來生成一個中間的函數名稱,而C語言則不會,因此會造成鏈接時找不到對應函數的情況,此時C函數就需要用extern "C"進行鏈接指定,這告訴編譯器,請保持我的名稱,不要給我生成用於鏈接的中間函數名;exter "C"{jni代碼}。
復制代碼
復制代碼
1 #include <jni.h>
2
3 #ifdef __cplusplus
4 extern "C" {
5 #endif
6 jstring Java_com_example_Hello_hello(JNIEnv* env, jobject thiz) {
7 return env->NewStringUTF("Hello Jni---->C++!");
8 }
9 #ifdef __cplusplus
10 }
11 #endif
復制代碼
復制代碼
(2)Android.mk文件,更改後綴名為.cpp
復制代碼
1 LOCAL_PATH := $(call my-dir)
2
3 include $(CLEAR_VARS)
4
5 LOCAL_MODULE := hello
6 LOCAL_SRC_FILES := hello.cpp
7
8 include $(BUILD_SHARED_LIBRARY)
4. JAVA和c++是怎麼進行通訊的
1. Java Native Interface(JNI)
中文為JAVA本地調用, 從Java1.1開始,Java Native Interface(JNI)標准成為java平台的一部分,它允許Java代碼和其他語言寫的代碼進行交互。JNI一開始是為了本地已編譯語言,尤其是C和C++而設計的,但是它並不妨礙你使用其他語言,只要調用約定受支持就可以了。
2. Socket通信
3. Web service
5. android studio中怎麼使用JNI之靜態庫
這里介紹過Android.mk如何使用靜態庫,這里介紹的是通過動態庫調用靜態庫的使用方法 1、首先修改第一篇介紹的.c文件
1、首先修改.c文件
2、屏蔽或刪除掉下面這句
3、修改android.mk文件
4、編譯
5、到此步就編譯成功了,so文件也生成了,也沒報錯
6、最好在手機上運行一下
7、運行成功,到此使用動態庫調用靜態庫成功
注意事項:
android.mk對格式非常敏感,一不小心就報錯,有時復制粘貼都出錯,注意空格啥的。
6. clion編譯jni,找不到jni.h的解決辦法
在windows環境下畢陪生成的動態庫是 dll
在linux下生成so
在mac下生成的是dylib
所以對於Android的開發者來說,還是要用ndk的工具
把在idea生成的.h文件粘貼到clion的項目中就可以了,
如果找不到jni.h可以在CMakeList.txt中添加對jni.h文件的引用
如下:
後面三行根據jdk的實際位置填寫,作用是導入jni相關的頭文件;其他的操作系統可能不完全一致
復制.h頭文件 com_shenby_jni_JniExample.h
實現該文件定義的函數 com_shenby_jni_JniExample.c
在CMakeList.txt中添加生成動態共項庫
add_library:生成一個庫,add_executable:生成一個可執行文件
hello:是生成共享庫的名字,前面會自動加上lib前綴,如這里windows生成的是 libhello.dll
SHARED:庫的類型為動態,windows上生成.dll,而STATIC 則是生成靜態庫,windows生成.a文件
com_shenby_jni_JniExample.c :c源文件,頌隱多個文件就添加在後面,切記不手櫻蠢能添加上面的com_shenby_jni_JniExample.h
文件,否則生成的庫中的函數為空
結果如下
就可以把該dll文件粘貼到idea的項目根目錄中運行了