JNI_Android項目中調用.so動態庫實現詳解

轉自:http://www.yxkfw.com/?p=7223php

1. 在Eclipse中建立項目:TestJNIjava

2. 新建立一個class:TestJNI.javaandroid

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 __cplusplus
extern "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.cppapp

#include "Add.h"

CAdd::CAdd() {

}

CAdd::~CAdd() {

}

int CAdd::Add(int x, int y) {
    return x + y;
}

com_wwj_jni_TestJNI.cpp的實現:eclipse

#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 := TestJNI

LOCAL_SRC_FILES := com_wwj_jni_TestJNI.cpp
LOCAL_SRC_FILES += Add.cpp

include $(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");
    }

    @Override
    protected 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();
    }
}

運行項目,效果圖以下:ide

相關文章
相關標籤/搜索