一.配置NDK开发环境
1.下载NDK
http://developer.android.com
1.配置Cygwin环境
下载cygwin配置模拟Linux环境,http://cygwin.com/
2.设置cygwin
----cygwin安装目录/home/用户名/.bash_profile文件
----编辑:在文件末尾加入以下代码
NDK = /cygdrive/安装磁盘/ndk安装目录
很重要 /home/ccp/.bash_profile添加如下代码,将NDK代码加入后,可以直接cd $NDK就到了NDK的安装目录下 NDK=/cygdrive/e/NDK/AndroidNDK export NDK |
注:我的安装目录是E:\NDK\AndroidNDK |
配置Cygwin的环境变量------不重要,可以不配置 cygwinPath E:/NDK/CygWin/bin; NDKROOT E:\NDK\AndroidNDK |
二.使用NDK进行开发
1.运行Cygwin.bat程序-----一定是cygwin.bat程序才能进行jni开发
Cygwin内容如下 @echo off
E: chdir E:\NDK\CygWin\bin set NDK=/cygdrive/e/NDK/AndroidNDK bash --login -i |
注:chdir为转换目录命令 步骤:转换到E:盘,在转换到Cygwin的bin目录下,并且设置NDK的路径于其中 ,最后bash启动程序 |
2.转到项目的根目录下
helloJni----E:/AndroidStudy/Workspace/AdrWorkspace/HellowJni-路径
在cygwin中输入
cd E:/AndroidStudy/Workspace/AdrWorkspace/HellowJni
3.编译jni形成*.so动态库文件
$NDK/ndk-build
注:$NDK---转到ndk的安装目录下运行ndk-build程序 来编译项目形成so动态库文件
4.编译项目
在eclipse中运行项目,
三.如何编写JNI程序
1.先编写与声明JNI方法有关的java代码
新建一个Jni的类
package com.ccp.wj;
public class Jni { public Jni(){ } public native String getString(); }
|
注:在java中使用关键字native来声明JNI方法,比如在Jni中声明了native方法getString()则,getString()方法将由C语言来实现,我们只是在java代码中调用jni的C/C++方法。 |
2.使用JNI方法
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = (TextView)findViewById(R.id.tv); tv.setText(new Jni().getString()); } static{ System.loadLibrary("jni"); } } |
注:在这个类中调用了native方法,但是注意,要调用native方法必须要先引入我们由native声明方法编译后所生成的*.so动态库文件,使用的是 Static{ System.loadLibrary(“库名”); } 使用的是静态块,先于任何方法包括构造函数。 |
|
3.生成native方法的头文件*.h
编译项目,生成相关的class文件==》在工程根目录新建一个jni文件夹用于存放生成的头文件和c文件==》使用javah生成头文件,格式:javah -classpath bin -d jni,其中-classpath bin表示类路径,-d jni 表示生成的头文件存放目录,如有需要可以看帮助javah -help
方法一: javah -classpath bin -d jni 命令模式下的相关命令 (A)cd .. 返回到上一个目录 (B)-o 对文件重命名 (C)-d <dir> 文件的输出目录 注:具体步骤如下 -----例如:com.ccp.wj.TestJni==>输出class目录:out/production/Mate/com.ccp.wj.TestJni Javah -o 文件名 -classpath类所在的根目录 要转换的类路径( 包名.类名) 转至production目录,此时Mate/com.ccp.wj.TestJni在production目录下 注:-classpath后跟的是类所在的根目录(即Mate) 此时:javah -o test.h -classpath Mate com.ccp.wj.TestJni(不需要知道类的class后缀) 或者通过全路径: javah -o NContext.h -jni com.ccp.wj.TestJni.testClass(此处路径位于class目录的根目录下,而testClass为jni类,不需指定后缀)
方法二:利用ADT来实现 ----打开 Run|External Tools|External Tools Configurations... ----配置一个javah程序利用javah.exe来实现编译头文件 ----双击左侧边栏的Program新建一个program ----Name:javah(名字随便写) ----Location:windows--${env_var:Java_Home}\bin\javah.exe Linux---/usr/bin/javah ---Working directory:指定要被生成头文件的类所在文件夹,在项目的bin/classes目录下 ${workspace_loc:/JNI/bin/classes} ---Argument:在命令行模式下的命令参数,如 javah -d <dir> -d ${workspace_loc:/JNI/jni} com.example.jni.JNI 指定com.example.jni.JNI类所生成的头文件位于项目的jni文件夹下
|
|
4.编写C文件
1)可以直接将*.h文件改成*.c文件并添加相应的代码,将方法实现
2)将*.h文件复制到*.c文件中并实现代码
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_ccp_wj_Jni */
#ifndef _Included_com_ccp_wj_Jni #define _Included_com_ccp_wj_Jni #ifdef __cplusplus extern "C" { #endif /* * Class: com_ccp_wj_Jni * Method: getString * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_ccp_wj_Jni_getString (JNIEnv *env, jobject obj){ (*env)->NewStringUTF(env,"Hellow-jni------"); }
#ifdef __cplusplus } #endif #endif
|
注:要记住如下jni文件中的格式 <returnType> Java_<com_mypackage>_<class>_<methodName>(JNIEnv*penv,parms.....) 第一个参数总是JNIEnv 易出错误:生成的头文件的函数中相应的参数只有类型,无参数,所以在实现方法时要将参数添上 JNIEXPORT jstring JNICALL Java_com_example_jni_JNI_getString (JNIEnv *, jobject ); |
5.生成相应的库
编写Android.mk的makefile文件
LOCAL_PATH := $(call my-dir)---用于开发树中查找源文件,返回当前路径
include $(CLEAR_VARS)------清除许多的LOCALXXXXX
LOCAL_MODULE := jni------编译的目标对象,即动态库名 LOCAL_SRC_FILES := jni.c----编译的c/c++源文件,和makefile差不多的隐式依赖
include $(BUILD_SHARED_LIBRARY)---表示生成的是shared_library动态库,BUILD_STATIC_LIBRARY生成静态库,BUILD_EXECUTABLE生成可执行文件 |
注: 更多关于Makefile --在项目根目录下新建jni文件夹,*.mk文件命名为Android.mk并且放于能让ndk-build自动搜寻到,和linux下编程差不多(命名为makefile能自动搜寻) -- |
2)生成动态库
转到项目根目录下==》$NDK/ndk-build生成库 |
6.编译项目,生成apk