標籤:android jni
JNI_Android項目中調用.so動態庫
2014年6月3日 JNI學習
參考:http://blog.sina.com.cn/s/blog_4298002e01013zk8.html
上一篇筆者介紹了如何使用Java代碼調用DLL動態庫中的C/C++方法,似乎已經是很久以前的做法了,遇到的錯誤筆者還未找到解決方案,但動態庫著實是找到的,只是無法調用相應的方法。本篇部落格來介紹一下如何在Android項目當中使用NDK產生.so動態連結程式庫,並在程式中使用。
1. 在Eclipse中建立項目:TestJNI
2. 新建立一個class:TestJNI.java
package com.wwj.jni;public class TestJNI {public native boolean Init();public native int Add(int x, int y);public native void Destory();}
以上代碼聲明三個本地方法。
3. 編譯JNI找到Android項目中bin目錄下,會有classes檔案夾,Eclipse自動為我們產生的位元組碼檔案就在這個目錄下。我們在該路徑下,使用javah命令,產生我們想要得到的.h標頭檔,如所示:
執行javah -jni com.wwj.jni.TestJNI命令之後,會在classes目錄下產生標頭檔:com_wwj_jni_TestJNI.h將它複製到jni檔案夾下,開啟如下:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_wwj_jni_TestJNI */#ifndef _Included_com_wwj_jni_TestJNI#define _Included_com_wwj_jni_TestJNI#ifdef __cplusplusextern "C" {#endif/* * Class: com_wwj_jni_TestJNI * Method: Init * Signature: ()Z */JNIEXPORT jboolean JNICALL Java_com_wwj_jni_TestJNI_Init (JNIEnv *, jobject);/* * Class: com_wwj_jni_TestJNI * Method: Add * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_wwj_jni_TestJNI_Add (JNIEnv *, jobject, jint, jint);/* * Class: com_wwj_jni_TestJNI * Method: Destory * Signature: ()V */JNIEXPORT void JNICALL Java_com_wwj_jni_TestJNI_Destory (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
以上代碼就是通過javah命令產生jni層代碼。
4. 使用C/C++實現JNI在jni檔案夾下,建立com_wwj_jni_TestJNI.h對應的cpp檔案:com_wwj_jni_TestJNI.cpp
我們再添加兩個檔案Add.h,Add.cpp,具體實現放在這兩個檔案中來完成。Add.h
#ifndef _TEST_JNI_ADD_H_#define _TEST_JNI_ADD_H_class CAdd {public:CAdd();~CAdd();int Add(int x, int y);};#endif
Add.cpp
#include "Add.h"CAdd::CAdd() {}CAdd::~CAdd() {}int CAdd::Add(int x, int y) {return x + y;}
com_wwj_jni_TestJNI.cpp的實現:
#include <stdio.h>#include <stdlib.h>#include "com_wwj_jni_TestJNI.h"#include "Add.h"CAdd *pCAdd = NULL;JNIEXPORT jboolean JNICALL Java_com_wwj_jni_TestJNI_Init(JNIEnv *env,jobject obj) {if (pCAdd == NULL) {pCAdd = new CAdd;}return pCAdd != NULL;}JNIEXPORT jint JNICALL Java_com_wwj_jni_TestJNI_Add(JNIEnv *env, jobject obj,jint x, jint y) {int res = -1;if (pCAdd != NULL) {res = pCAdd->Add(x, y);}return res;}JNIEXPORT void JNICALL Java_com_wwj_jni_TestJNI_Destory(JNIEnv *env, jobject obj){if (pCAdd != NULL){pCAdd = NULL;}}
5. 建立mk檔案,並使用ndk-build命令產生.so動態連結程式庫檔案在jni目錄下建立Android.mk檔案如下:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := TestJNILOCAL_SRC_FILES := com_wwj_jni_TestJNI.cppLOCAL_SRC_FILES += Add.cppinclude $(BUILD_SHARED_LIBRARY)
其中LOCAL_PATH是C/C++代碼所在目錄,也就是我們的jni目錄。
LOCAL_MODULE是要編譯的庫的名稱。編譯器會自動在前面加上lib,在後面加上.so。
LOCAL_SRC_FILES是要編譯的C/C++檔案。
然後我還需要在Android項目根目錄下建立Application.mk檔案:
APP_PROJECT_PATH := $(call my-dir)APP_MODULES := TestJNI
寫完了這兩個mk檔案,我們就可以用ndk來為我們產生相應的動態連結程式庫了。前提你需要下載NDK,並把NDK路徑配置到path環境變數中去,筆者配置的路徑是:D:\Cocos2dx\android-ndk-r9d,具體視個人情況而定。進入Application.mk檔案所在目錄,在命令列中使用ndk-build產生.so檔案
編譯成功後會在工程目錄的libs/armeabi目錄下產生一個libTestJNI.so檔案。
項目結構會變成如下:
6. 在Java中調用JNI
package com.wwj.jni;import android.os.Bundle;import android.widget.TextView;import android.app.Activity;public class TestJNIActivity extends Activity {private TextView textView;static {// 載入動態庫System.loadLibrary("TestJNI");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView = (TextView) findViewById(R.id.textview);TestJNI testJNI = new TestJNI();// 調用native方法boolean init = testJNI.Init();if (init == true) {// 調用Add函數int sum = testJNI.Add(100, 150);textView.setText("你真是個" + sum);} else {textView.setText("你比二百五還要二百五");}testJNI.Destory();}}
運行項目,如下:
代碼:http://download.csdn.net/detail/wwj_748/7442791