Android JNI programming demo with Eclipse

用Eclipse 建立 JNI 的專案, 示範如何在 JAVA 調用 cpp 的函數.

我們將建立一個名稱為 jnidemo的專案, 在主Activity 將調用一個名為libHello.so 的 cpp 函數庫的 getVersion() 的函數, 將其返回字串寫在主Activity 的TextView 上.


首先用Eclipse建立一個新的 Android Activity 專案.  其他選項都用預設值就可以.

1. 稍微修改主活動配置 layout/activity_main.xml,  的在TextView 加入名為 title 的id(行12)以便稍候引用

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>



2. 在MainActivity.java加入載入函式庫的動作並增加一個native 函數名稱為 getVersion.

    改寫如下:

package com.example.jnidemo;

import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;

public class MainActivity extends Activity {
	static {
		System.loadLibrary("Hello"); // Hello.dll (Windows) or libHello.so (Unixes)
	}
	private native String getVersion();
		
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		TextView tv = (TextView) findViewById(R.id.title);
		tv.setText( getVersion());
		 
	}

}

3. 新增一個 jni 的目錄. 在jni 底下加入一個名為 HelloJni.cpp 的文件.

/jni/HelloJni.cpp 內容如下

#include <jni.h>
#include <stdio.h>


#define JNIREG_CLASS "com/example/jnidemo/MainActivity"//指定要注册的类

extern "C" JNIEXPORT jstring JNICALL native_getVersion(JNIEnv *env, jobject thisObj) {
   jstring szRet;
   szRet = env->NewStringUTF("V1.0");
   return szRet;
}

/**********************************************************************************/
static JNINativeMethod gMethods[] = {
		{ "getVersion", "()Ljava/lang/String;", (void*)native_getVersion },
};

/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
        JNINativeMethod* gMethods, int numMethods)
{
	jclass clazz;
	clazz = env->FindClass( className);
	if (clazz == NULL) {
		return JNI_FALSE;
	}
	if (env->RegisterNatives( clazz, gMethods, numMethods) < 0) {
		return JNI_FALSE;
	}

	return JNI_TRUE;
}
/*
* Register native methods for all classes we know about.
*/
static int registerNatives(JNIEnv* env)
{
	if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
                                 sizeof(gMethods) / sizeof(gMethods[0])))
		return JNI_FALSE;

	return JNI_TRUE;
}
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
	JNIEnv* env = NULL;
	jint result = -1;
	if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
		return -1;
	}
	if (!registerNatives(env)) {//注册
		return -1;
	}
	/* success -- return valid version number */
	result = JNI_VERSION_1_4;

	return result;
}

//onUnLoad方法,在JNI组件被释放时调用
extern "C" void JNI_OnUnload(JavaVM* vm, void* reserved){
}

4. 在jni 底下加入一個名為 Android.mk 的文件.

/jni/Android.mk 內容如下

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE    := libHello
LOCAL_SRC_FILES := HelloJni.cpp

include $(BUILD_SHARED_LIBRARY)

5.  專案的檔案結構如下:

Android JNI programming demo with Eclipse


6. 執行結果

Android JNI programming demo with Eclipse


延伸話題:

在cpp中如何把log 打印到logcat 的輸出呢? 在 cpp 檔及 Android.mk 要修改幾個地方

1. 在cpp 檔加入 ALOGD, ALOGE 等函數的定義

#include <android/log.h>
#define LOG_TAG "JniDemo"
#define ALOGE(...)     __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);
#define ALOGW(...)     __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__);
#define ALOGD(...)     __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__);
#define ALOGV(...)     __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__);

使用 debug level 的log輸出函數 ALOGD 範例如下

extern "C" JNIEXPORT jstring JNICALL native_getVersion(JNIEnv *env, jobject thisObj) {
   jstring szRet;
   szRet = env->NewStringUTF("V1.0");
   ALOGD("native_getVersion");
   return szRet;
}

2. 在 Android.mk 指定載入liblog.so 函數庫

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE    := libHello
LOCAL_SRC_FILES := HelloJni.cpp

LOCAL_LDLIBS := -llog 

include $(BUILD_SHARED_LIBRARY)




Android JNI programming demo with Eclipse,布布扣,bubuko.com

Android JNI programming demo with Eclipse

上一篇:Android代码混淆及项目发布步骤记录


下一篇:Python脚本日志系统