android JNI 经验分享

9 篇文章 0 订阅
1 篇文章 0 订阅

转载请注明出处:http://blog.csdn.net/jack_chen_00/article/details/37522883

Demo所使用的源码地址:http://download.csdn.net/detail/chenjianjk/7604969


第一次接触JNI,网上相关资料零零散散,经过几天的实践终于算是会用了,总结下今天的经验分享给大家,希望对初学者有所帮助。

    

环境搭建

      早期NDK编译环境的搭建是需要Cygwin + NDK配合才行,最初我也是按照这个方案来执行,环境搭建之繁琐真是让人无语,还好找到了更好的环境搭建方法,只需要用到    NDK 就可以,以下是我的搭建方法:

     1.下载NDK。

    在Google的官方下载最新版的NDK,以下是下载网址
    http://developer.android.com
      www.android-doc.com
      www.toolib.net
      

     2.Eclips的安装与配置。

      我使用的IDE工具是Eclips,为了方便开发,需要安装CDT/ADT插件,如果你还没有学会怎么使用Eclips,你可以网上搜索以下Eclips的安装、使用方法,这里不做细节的介绍。
      

     3.JNI 数据类型。

      JNI的目的是实现Java调用本地的C/C++方法,但是Java中的数据类型与C/C++的数据类型存在差异,不能直接使用,所以需要统一定义Java与C/C++的数据类型。
      JNI数据类型对照表参考网址:http://blog.csdn.net/zjc0888/article/details/6288602
      

      4.Android.mk

      在Android工程下的JNI目录中需要有一个Android.mk的文件,用来规定C/C++的编译规则,Android.mk与Linux下的Makefile功能类似,Android.mk是GNU Makefile的一部分,用过Makefile的人都知道,它是管理、编译、维护一个大型的源码工程必不可少的工具。Android.mk是Android定义的一种代码编译方式,它也有自己的一套编写规范,代码编译的规则都存放在Android.mk的文件里。
      想要使用JNI,就必须了解最基本的Android.mk的编写规范,读者可以参数下面的网址自学如果编写Android.mk文件。
      参考网址:http://blog.csdn.net/cuijpus/article/details/5627248
      

创建Android工程

    1. 创建应用程序。

    在Eclips创建一个名称为JNI_DEMO的Android应用程序,在布局文件中新增一个按钮方便触发JNI 调用。

public class MainActivity extends Activity implements OnClickListener {

	Button mButton;
	private String TAG = "TEST";

	int i = 1;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);
		mButton = (Button)findViewById(R.id.button1);
		mButton.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		Log.d(TAG, NativeUtils.getLocomotiveName());
		Log.d(TAG, NativeUtils.init(38400,"SD")+"");
		Log.d(TAG, NativeUtils.unInit()+"");
		Log.d(TAG, NativeUtils.start(0)+"");
		Log.d(TAG, NativeUtils.stop(0)+"");
		Log.d(TAG, NativeUtils.getStatus(1, 2)+"");
	}

}

    2.声明本地方法

package com.android.sms.util;

public class NativeUtils {

	static {
		//读取代码库,需要先读取代码库才能调用库文件中的本地方法
		System.loadLibrary("test-jni");
	}

	public static native String getLocomotiveName();
	public static native int init(int baudRate, String storagePath);
	public static native int unInit();
	public static native int start(int fileId);
	public static native int stop(int fileId);
	public static native int getStatus(int cmd,int data);
}

     3.编写本地代码(C/C++)

    在app工程目录下新建一个jni目录,在jni目录中新建testjni.c

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <jni.h>
#include <assert.h>
#include<android/log.h>


#define TAG "myDemo-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型

JNIEXPORT jstring JNICALL native_getLocomotiveName(JNIEnv *env, jclass clazz)
{
	LOGD("native_getLocomotiveName.\n");
	return (*env)->NewStringUTF(env, "Hello world");
}

JNIEXPORT jint JNICALL native_init(JNIEnv *env, jclass clazz,jint baudRate, jstring storagePath)
{
	LOGD("native_init.\n");
	return baudRate;
}


JNIEXPORT jint JNICALL native_unInit(JNIEnv *env, jclass clazz)
{
	LOGD("native_unInit.\n");
	return 2;
}

JNIEXPORT jint JNICALL native_start(JNIEnv *env, jclass clazz, jint fileid)
{
	LOGD("native_start.\n");
	return 3;
}

JNIEXPORT jint JNICALL native_stop(JNIEnv *env, jclass clazz, jint fileid)
{
	LOGD("native_stop.\n");
	return 4;
}

JNIEXPORT jint JNICALL native_getStatus(JNIEnv *env, jclass clazz, jint cmd, jint data)
{
	LOGD("native_getStatus.\n");
	return 5;
}

#define JNIREG_CLASS "com/android/sms/util/NativeUtils"
/**
* Table of methods associated with a single class.
*/
static JNINativeMethod gMethods[] = {
	{ "getLocomotiveName", "()Ljava/lang/String;", (void*)native_getLocomotiveName },
	{ "init", "(ILjava/lang/String;)I", (void*)native_init },
	{ "unInit", "()I", (void*)native_unInit },
	{ "start", "(I)I", (void*)native_start },
	{ "stop", "(I)I", (void*)native_stop },
	{ "getStatus", "(II)I", (void*)native_getStatus },

};

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

/*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
	JNIEnv* env = NULL;
	jint result = -1;

	if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
		return -1;
	}
	assert(env != NULL);

	if (!registerNatives(env)) {
		return -1;
	}
	/* success -- return valid version number */
	result = JNI_VERSION_1_4;

	return result;
}


    4.编写Android.mk

   在jni目录中新建Android.mk文件。

#
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# This makefile supplies the rules for building a library of JNI code for
# use by our example of how to bundle a shared library with an APK.

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

LOCAL_MODULE_TAGS := optional

LOCAL_MODULE:= libtest-jni

LOCAL_SRC_FILES:= testjni.c

LOCAL_LDLIBS :=-llog 

LOCAL_SHARED_LIBRARIES := \
	libutils

LOCAL_STATIC_LIBRARIES :=

LOCAL_C_INCLUDES += \
	$(JNI_H_INCLUDE)

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

配置Eclips编译环境

    1.解压已经下载好NDK压缩包

    2.新建一个编译器

    新建的编译器用于编译C/C++本地代码,新建编译器方法选中app工程目录 -> 右键选择Properties -> 选中Builders -> 点击New -> 双击Program -> 定义编译器。



    3.编译代码

    如果NDK编译器构建成功,在编译app的时候会在工程目录下自动生成一个obj的文件,里面有生成的*.so的动态库和一个编译生成的*.o中中间文件。如果配置不成功会有相应的错误提示。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值