ndk学习笔记

1、简介(一些相关概念)

Android NDK是一组允许你将C或C++嵌入到Android应用中的工具。可用于:

1)在平台之间移植应用,用C/C++写的库可以方便的在其他嵌入式的平台上再次使用

2)重复使用现有库,或者提供其自己的库供重复使用

3)在某些情况下提高性能,特别是像游戏这种计算密集型应用

4)代码的保护,apk的java层代码很容易被反编译,而C/C++库反汇难度教大


交叉编译:指在一个平台上生成另一个平台可执行的代码

JNI(Java Native Interface):是Java和C/C++组件用以互相沟通的接口


JNI实现流程

1编写java类代码 -->.java

2)编译成字节代码-->.class

3)产生c头文件-->.h

4)编写JNI实现代码-->.c

5)编译成链接库文字-->.dll或.os

=======================================================================

2、下载NDK

可通过官网下载:

 https://developer.android.com/ndk/downloads/older_releases.html?hl=zh-cn#ndk-12b-downloads

可能需要文明上网

=======================================================================

3、配置NDK环境

把下载的NDK解压

然后依次右键我的电脑 -->属性-->更改设置-->高级-->环境变量-->在系统变量中找到PATH,在输入框中加入『;你的解压后的NDK的路径』。

比如我的NDK解压后路径为,配置为『;E:\mysoft\android-ndk-r12b-windows-x86_64\android-ndk-r12b』。

打开cmd,输入ndk-build,如果输出为如下所示,说明环境配置成功。

=======================================================================

4、开发第一个NDK项目

1)在eclipse中创建一个Android工程,在MainActivity中添加一个native方法

public static native String getStringFromC();
2)生成.h头文件

在项目中添加jni文件目录

 

打开cmd页面,使用cd指令跳转到你的项目路径下,比如我的:


接着在cmd中使用指令生成.h文件:javah -classpath bin/classes;D:\androidSDK\platforms\android-25\android.jar -d jni com.bajie.hellondk.MainActivity

其中『bin/classes』指要编译的class文件的路径;

『D:\androidSDK\platforms\android-25\android.jar』指androidsdk里面的一个android.jar的路径,注意『bin/classes』与『D:\androidSDK\platforms\android-25\android.jar』之间是一个『;』而不是『:』;

『jni』指生成的.h文件存放的路径,这个jni指我们刚刚添加的目录;

『com.bajie.hellondk.MainActivity』指要编译的类。

大家根据自己项目的实际情况改写以上指令,成功运行之后在eclipse中刷新一下项目,jni路径下将会生成一个.h文件


3)实现.h文件的方法

在jni目录中新建一个c文件,编写代码实现getStringFromC()方法:

#include <stdio.h>
#include <stdlib.h>
#include "com_bajie_hellondk_MainActivity.h"

JNIEXPORT jstring JNICALL Java_com_bajie_hellondk_MainActivity_getStringFromC
  (JNIEnv *evn, jclass jclass) {
	return (*evn)->NewStringUTF(evn, "Hello from JNI");
}
4)编写Android.mk

在jni目录中新建File,命名为Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE 	:= hello
LOCAL_SRC_FILES := hello.c

include $(BUILD_SHARED_LIBRARY)

其中,LOCAL_MODULE的值为要生成的.so文件的名称,LOCAL_SRC_FILES为要编译的.c文件的名称。

5)生成.so文件

在cmd中跳转到项目所在路径,然后执行ndk-build。执行完成后在eclipse中刷新项目,项目将新增一个obj目录,目录包含生成的.so文件




6)调用JNI方法

在MainActivity中使用一个静态块去加载生成的.so文件,然后用一个TextView去显示JNI方法返回的字符串。

package com.bajie.hellondk;

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

public class MainActivity extends Activity {

	static {
		System.loadLibrary("hello");
	}
	private TextView textView;
	
	public static native String getStringFromC();
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		textView = (TextView) findViewById(R.id.textView);
		textView.setText(getStringFromC());
	}
}
运行Android项目


自此,一个简单的ndk项目已经完成。

=======================================================================

5、在eclipse中配置ndk环境

上面开发NDK项目中,每次改变.c文件的内容,再去生成.so文件的时候,都需要打开控制台使用ndk-build命令行去生成,比较麻烦。通过配置eclipse的ndk环境,可以在运行项目的时候进行自动编译。

1)Window-->Preferences-->Android-->NDK,配置你的NDK目录


2)右键你的NDK项目-->Properties-->Builders-->New-->Program。在Location中点击BrowseFileSystem...,定位到你的ndk的一个ndk-build.cmd文件;在Working Directory中点击Browse Workspace...定位到你的项目。

然后在当前页面点选选项卡Build Options,点选During auto builds。

点击Apply-->OK。然后修改.c文件的内容,直接运行项目,无须另外运行ndk-build命令行,eclipse会自己编译生成.so文件。


=======================================================================

6、JNI交互的字符串处理

1)在第一个NDK项目的MainActivity中添加一个native方法。

public static native void updateFile(String path);
2)使用指令『javah -classpath bin/classes;D:\androidSDK\platforms\android-25\android.jar -d jni com.bajie.hellondk.MainActivity』生成.h头文件。指令的具体含义上文有介绍。

3)在.c文件中编写实现native层实现代码。

JNIEXPORT void JNICALL Java_com_bajie_hellondk_MainActivity_updateFile
  (JNIEnv *env, jclass jclass, jstring path) {
	// 生成native的char指针
	const char * file_path = (*env)->GetStringUTFChars(env, path, NULL);
	if(file_path != NULL) {
		LOGV("from c file_path %s", file_path);
	}
	// 打开文件
	FILE* file = fopen(file_path, "a+");
	if(file != NULL) {
		LOGV("from c open file success");
	}
	char data[] = "I am a girl";
	// 写文件
	int count = fwrite(data, strlen(data), 1, file);
	if(count > 0) {
		LOGV("from c write file success");
	}
	if(file != NULL) {
		// 关闭文件
		fclose(file);
	}
	// 释放指针
	(*env) -> ReleaseStringUTFChars(env, path, file_path);
}
4)在MainActivity中调用该native方法

updateFile("/mnt/sdcard/hellondk.txt");
5)运行Android程序,成功后,打开.txt『/mnt/sdcard/hellondk.txt』文件,文件内容为『I am a girl』

=======================================================================

7、JNI交互的数组处理

以下例子步骤都和上个例子都一样,下面例子只重点给出.c文件的代码,其他步骤省略

JNI关于数组的处理主要分两种方式

1)第一种方式是生成native层的数组拷贝

.c代码

JNIEXPORT jintArray JNICALL Java_com_bajie_hellondk_MainActivity_updateIntArray
  (JNIEnv * env, jclass jclass, jintArray array) {
	jint nativeArray[5];
	// 把java层的array数据拷贝到native层的nativeArray
	(*env) -> GetIntArrayRegion(env, array, 0, 5, nativeArray);

	int j;
	for(j = 0; j < 5; j ++) {
		nativeArray[j] += 5;
		LOGV("from c int %d", nativeArray[j]);
	}
	// 把native层的nativeArray数据拷贝到java层的array
	(*env) -> SetIntArrayRegion(env, array, 0, 5, nativeArray);
	return array;
}
在MainActivity中调用native方法:

int[] data = {1,2,3,4,5};
int[] result = updateIntArray(data);
for(int i : result) {
	Log.i("nate", "i = " + i);
}
运行结果:


2)第二种方式是直接调用数组指针进行操作

.c代码:

JNIEXPORT jintArray JNICALL Java_com_bajie_hellondk_MainActivity_updateIntArray
  (JNIEnv * env, jclass jclass, jintArray array) {

	// 生成字符指针
	jint *data = (*env) -> GetIntArrayElements(env, array, NULL);
	jsize len = (*env) -> GetArrayLength(env, array);
	int j;
	for(j = 0; j < len; j ++) {
		data[j] += 5;
		LOGV("from c int %d", data[j]);
	}
	// 释放资源
	(*env) -> ReleaseIntArrayElements(env, array, data, 0);
	return array;
}

=======================================================================

8、配置在eclipse中生成native方法对应的.h文件

在我们之前的使用中,都是使用javah命令行来生成.h文件,现在通过配置,可以让eclipse直接生成.h文件

Run-->ExternalTools->External Tools Configurations-->右键Program->New,输入如下:


其中Location:${system_path:javah}

Working Directory:${project_loc}\jni

Arguments:-classpath "${project_loc}\bin\classes;D:\androidSDK\platforms\android-19\android.jar" -d "${project_loc}\jni" ${java_type_name}

然后点击你要生成.c文件对应的.java文件,再点击如下:


刷新项目,jni目录下会生成一个对应的.h文件,测试成功。

=======================================================================

9、在eclipse中编写C++代码时展开提示

1)右键项目-->Android Tools-->Add Native Support-->Finish

2)右键项目-->Properties-->C/C++ General-->Paths and Symbols-->Add-->File system-->定位到你的ndk的platforms\任意一个android版本\arch-arm\usr\include-->按照提示完成配置。





















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值