当前位置: 代码迷 >> Android >> android JNI 心得分享
  详细解决方案

android JNI 心得分享

热度:360   发布时间:2016-04-28 04:53:24.0
android JNI 经验分享

转载请注明出处: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 := optionalLOCAL_MODULE:= libtest-jniLOCAL_SRC_FILES:= testjni.cLOCAL_LDLIBS :=-llog LOCAL_SHARED_LIBRARIES := \	libutilsLOCAL_STATIC_LIBRARIES :=LOCAL_C_INCLUDES += \	$(JNI_H_INCLUDE)LOCAL_PRELINK_MODULE := falseinclude $(BUILD_SHARED_LIBRARY)

配置Eclips编译环境

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

    2.新建一个编译器

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



    3.编译代码

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





  相关解决方案