注意: 写该文章主要帮助自己记忆,贴出来希望可以给有同样问题的人解惑,不喜勿喷,可以提意见哦。
一、需要了解的知识点:
(1)NDK:允许Java的代码与其他语言的代码进行交互的开发包
(2)jni:java与本地代码(c/c++)通过jni交互
(3)常见使用NDK的平台,TV——电视机,STB——机顶盒,IVI——车载系统,AR——虚拟现实,手机端游戏等。
二、为什么需要NDK
(1)标准的Java虚拟机不支持应用需要的平台相关的功能,例如添加了新的硬件设备。
(2)已经存在使用C/C++等其他语言开发好的库,需要使用JNI来访问他们,例如游戏引擎Cocos2d-X
(3)需要优化其中一部分的源代码,提升整体性能。
三、搭建开发环境
(1)Windows开发环境搭建
首先在http://developer.android.com/tools/sdk/ndk/index.html下载ndk
在http://www.cygwin.com下载Cygwin1.7并安装,Cygwin1.7安装需要注意如下两个地方,选择make和vim,只用勾选红框中的的内容。


四、在开发工具eclipse上使用NDK,实现一个简单的减法操作,目的是学会Java与本地代码的交互。
(1)首先需要在Java代码中声明一个本地方法sub()。
package com.example.main;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends Activity {
//static{
// System.loadLibrary("main");
//}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private native int sub(int a,int b); //关键字native表示该方法需要在本地代码中实现
}
(2)使用NDK用C/C++实现add方法
1、打开之前安装的Cygwin, 输入命令cd e: 进入如下目录cygdrive,进入该目录是本机的cygwin装在了e目录。注意,一定要进入cygdrive目录,然后在该目录下进入不同的目录。

2、进入x项目Main所在的目录,例如:D:\lcb\work\Main,输入如下命令:

3、利用ndk生成Main.java的头文件,进入src目录,输入命令javah -d ../jni com.example.main.MainActivity。javah表示生成头文件的命令,-d 表示生成到指定的目录,../jni 表示src的上一个目录,即main目录下生成文件夹jni, com.example.main.MainActivity 表示生成MainActivity的头文件。
Administrator@MS-20170524EUSY /cygdrive/d/lcb/work/Main/src
$ javah -d ../jni com.example.main.MainActivity
在工作目录下对应生成了jni目录,如下所示:

4、生成头文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_main_MainActivity */
#ifndef _Included_com_example_main_MainActivity
#define _Included_com_example_main_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_main_MainActivity
* Method: sub
* Signature: (II)I
*/
//Java关键字+类所在的包名+类名+方法名。.换成下划线。
JNIEXPORT jint JNICALL Java_com_example_main_MainActivity_sub
(JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
5、创建本地方法sub.c,可以直接在本地创建一个文件,命名为sub.c,方法名需要跟头文件中生成的对应。
#include "com_example_main_MainActivity.h" //这里引用4生成的头文件
JNIEXPORT jint JNICALL Java_com_example_main_MainActivity_sub(JNIEnv *evn,
jobject object, jint a, jint b) {
return a - b;}
6、创建Android.mk编译文件。
LOCAL_PATH:= $(call my-dir)
//$(call my-dir),指带本应用的D:\lcb\work\Main\jni目录
include $(CLEAR_VARS)
//清除前面所定义的变量
LOCAL_MODULE :=main
//这里main指java语言中加载的so库名字
LOCAL_SRC_FILES := sub.c
//当前需要编译的本地代码名称
include $(BUILD_SHARED_LIBRARY)
//表示需要编译一个动态库
7、编译动态库
进入
Administrator@MS-20170524EUSY /cygdrive/d/lcb/work/Main/jni目录,执行如下命令:ndk-build.cmd
命令执行完毕后,在lib目录下就会对应生成so文件,如下所示:

8、在java代码中加载so库文件,到这里就完成了java代码使用本地代码的全过程。
package com.example.main;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends Activity {
static{
System.loadLibrary("main");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private native int sub(int a,int b);
}
四、在开发工具Android Studio上使用NDK,实现一个简单的加法操作,目的是学会Java与本地代码的交互。
1、首先进入Project Structure目录下的SDK Location,如下所示,在红框中引用已经下载好的ndk。

2、在Java代码中声明一个本地方法add()
package com.hwatong.meidaplayer;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class USBMediaPlayer extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private native int add(int a,int b);
}
3、打开android Studio的控制台,进入项目所在的目录,输入编译头文件的命令,编译后就会生成对应的目录。
E:\USBMusicPlayer_a12_Activity\src>javah -d ../jni com.hwatong.meidaplayer.USBMediaPlayer

4、创建add.c文件,如下所示
#include "com_hwatong_meidaplayer_USBMediaPlayer.h"
JNIEXPORT jint JNICALL
Java_com_hwatong_meidaplayer_USBMediaPlayer_add
(JNIEnv *, jobject, jint, jint){
return a+b;
}
5、创建Android.mk编译文件
LOCAL_PATH:= $(call my-dir)
//$(call my-dir),指带本应用的D:\lcb\work\Main\jni目录
include $(CLEAR_VARS)
//清除前面所定义的变量
LOCAL_MODULE :=main
//这里main指java语言中加载的so库名字
LOCAL_SRC_FILES := add.c
//当前需要编译的本地代码名称
include $(BUILD_SHARED_LIBRARY)
//表示需要编译一个动态库
6、切换到控制台,进入jni目录,输入命令ndk-build,则会在lib目录生成对应的so库。
E:\USBMusicPlayer_a12_Activity\jni>ndk-build
[arm64-v8a] Compile : main <= add.c
[arm64-v8a] SharedLibrary : libmain.so
[arm64-v8a] Install : libmain.so => libs/arm64-v8a/libmain.so
[x86_64] Compile : main <= add.c
...

7、在java代码中应用so库。
package com.hwatong.meidaplayer;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class USBMediaPlayer extends Activity {
static{
System.loadLibrary("main");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private native int add(int a,int b);
}
网友评论