使用Eclipse和NDK开发Android JNI工程

6 篇文章 1 订阅
3 篇文章 0 订阅

基本流程:
1.新建Android工程
2.Java文件中创建调用接口声明代码
3.javah生成C/C++的.h文件
4.编写C/C++实现代码
5.编写Android.mk脚本
6.编写Application.mk脚本
7.使用ndk编译工程生成.so动态库
8.编写加载库的代码载入.so文件
9.调用动态库的接口方法

详细流程:
1.新建工程,并对ndk进行配置

工程AndroidJniTest

右键选择工程属性,按照图中1,2,3步骤

右键选择工程属性

双击工程Builder,选择ndk-build.cmd所在路径以及工程的工作目录

这里写图片描述

按照如图所示配置ndk执行

这里写图片描述

这里写图片描述

点击Specify Resources按钮

这里写图片描述

2.创建com.example.jni包,并创建TestJNI.java文件,声明接口,内容如下:

package com.example.jni;

public class TestJNI {
     public native boolean init();
     public native int add (int x, int y);
     public native void destroy();
}

3.使用命令:javah -classpath bin/classes -d jni com.example.jni.TestJNI
生成jni调用的.h文件,叫com_example_jni_TestJNI.h
参数解释:
-classpath 使用类的位置
-d jni需要生成jni的类,包括包名+类名
这个.h文件里面的内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_jni_TestJNI */

#ifndef _Included_com_example_jni_TestJNI
#define _Included_com_example_jni_TestJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_jni_TestJNI
 * Method:    init
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_com_example_jni_TestJNI_init
  (JNIEnv *, jobject);

/*
 * Class:     com_example_jni_TestJNI
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_jni_TestJNI_add
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_example_jni_TestJNI
 * Method:    destroy
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_jni_TestJNI_destroy
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

4.编写实现这些接口的C++代码
首先是Add.h,代码如下:

#ifndef JNI_TEST_ADD
#define JNI_TEST_ADD
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_example_jni_TestJNI.cpp,代码如下:
PS:最好先把.h的代码先复制下来,然后再进行改动,防止缺少什么。
比如缺少jni.h和extern”C”都会有相应的问题(JNI_EXPORT/Native method not found等),导致不能编译成功

#include<stdio.h>
#include <stdlib.h>
#include <jni.h>
#include "Add.h"

#ifndef _Included_com_example_jni_TestJNI
#define _Included_com_example_jni_TestJNI
#ifdef __cplusplus
extern "C" {
#endif

CAdd *pcAdd = NULL;

/*
 * Class:     com_example_jni_TestJNI
 * Method:    init
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_com_example_jni_TestJNI_init
  (JNIEnv *env, jobject object){
     if(pcAdd==NULL){
           pcAdd = new CAdd;
     }
     return pcAdd!=NULL;
}

/*
 * Class:     com_example_jni_TestJNI
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_jni_TestJNI_add
  (JNIEnv *env, jobject object, jint x, jint y){
     jint res = -1;
     if(pcAdd != NULL){
           res = pcAdd->add(x,y);
     }
     return res;
}

/*
 * Class:     com_example_jni_TestJNI
 * Method:    destroy
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_jni_TestJNI_destroy
  (JNIEnv *env, jobject object){
     if(pcAdd != NULL){
            delete pcAdd;
           pcAdd = NULL;
     }
}

#ifdef __cplusplus
}
#endif
#endif

5.编写Android.mk和Application.mk文件
(Android.mk和.cpp可以通过右键项目->Android Tools->Add Native Support生成)

Android.mk内容:

LOCAL_PATH := $(call my-dir) #Android.mk的目录路径

include $(CLEAR_VARS) #清理LOCAL_xxx避免相互影响

LOCAL_MODULE    : = TestJNI #要生成的动态库名称

### Add all source file names to be included in lib separated by a whitespace
LOCAL_SRC_FILES := com_example_jni_TestJNI.cpp\
Add.cpp #要编译的jni和底层源码

include $(BUILD_SHARED_LIBRARY) #生成动态库

Application.mk内容:

APP_STL := gnustl_static #使用STL库
APP_CPPFLAGS += -fpermissive #忽略一些语法错误,兼容老语法使其通过

makefile文件参数的解释:
Android NDK学习 <二> Android.mk的制作
Android NDK开发指南(一) Application.mk文件

Android.mk告诉NDK Build系统关于Source的信息。Android.mk将是GNU Makefile的一部分,且将被Build System解析一次或多次。所以,尽量少的在Android.mk中声明变量,也不要假定任何东西不会在解析过程中定义。

LOCAL_PATH := $(call my-dir)

每个Android.mk文件必须以定义LOCAL_PATH为开始。它用于在开发tree中查找源文件。
宏my-dir 则由Build System提供。返回包含Android.mk的目录路径。

include $(CLEAR_VARS)

CLEAR_VARS 变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx.
例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等。但不清理LOCAL_PATH. 这个清理动作是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能避免相互影响。

LOCAL_MODULE := TestJNI

LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格。Build System会自动添加适当的前缀和后缀。例如,foo,要产生动态库,则生成libfoo.so.
但请注意:如果模块名被定为:libfoo.则生成libfoo.so. 不再加前缀。

LOCAL_SRC_FILES := 
com_example_jni_TestJNI.cpp\ #\和回车隔开
Add.cpp

LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码。不必列出头文件,build System 会自动帮我们找出依赖文件。
缺省的C++源码的扩展名为.cpp. 也可以修改,通过LOCAL_CPP_EXTENSION。

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY:是Build System提供的一个变量,指向一个GNU Makefile Script。它负责收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定编译为什么。

APP_STL :默认,NDK构建系统提供由Android系统给出的最小C++运行时库(/system/lib/libstdc++.so)的C++头文件。
然而,NDK带有另一个C++实现,你可以在你自己的应用程序中使用或链接它。
定义APP_STL以选择它们其中的一个:
APP_STL := stlport_static –> static STLport library
APP_STL := stlport_shared –> shared STLport library
APP_STL := system –> default C++ runtime library

APP_CFLAGS : 一个C编译器开关集合,在编译任意模块的任意C或C++源代码时传递。
它可以用于改变一个给定的应用程序需要依赖的模块的构建,而不是修改它自身的Android.mk文件

6.编译工程,生成动态链接库.so文件
一般改完会自动编译,如果没有反应可以在cmd中跳转到jni目录,使用ndk-build对工程进行编译,这一方法在Android Studio中同样适用。

7.调用.so文件,运用在Activity中
其MainActivity.java内容如下:

package com.example.androidjnitest;

import com.example.jni.TestJNI;

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

public class MainActivity extends Activity {

     static{
           System. loadLibrary("TestJNI");
     }

     TextView tv_test;

     @Override
     protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
           setContentView(R.layout. activity_main);

           InitView();
           TestJNI jni = new TestJNI();
           jni.init();
            tv_test.setText( "1+1="+jni.add(1,1));
     }

     void InitView(){
            tv_test = (TextView) findViewById(R.id. tv_test);
     }
}

将其发布到手机或者Android虚拟机上即可看见结果。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值