1.如何在Android下使用JNI
Android中JNI是编译so库的源代码,编译成功后会生成SO库,android中最终是使用SO库的。
1.android的NDK开发需要在linux下进行: 因为需要把C/C++编写的代码生成能在arm上运行的.so文件,这就需要用到交叉编译环境,而交叉编译需要在linux系统下才能完成。2.安装android-ndk开发包,这个开发包可以在google android 官网下载: 通过这个开发包的工具才能将android jni 的C/C++的代码编译成库3.android应用程序开发环境: 包括eclipse、java、android sdk、adt等。
NDK编译步骤:1.选择 ndk 自带的例子 hello-jni ,我的位于E:\android-ndk-r5\samples\hello-jni( 根据具体的安装位置而定 ) 。2.运行 cygwin ,输入命令 cd /cygdrive/e/android-ndk-r5/samples/hello-jni ,进入到 E:\android-ndk-r5\samples\hello-jni 目录。
3.输入 $NDK/ndk-build ,执行成功后,它会自动生成一个 libs 目录,把编译生成的 .so 文件放在里面。 ($NDK是调用我们之前配置好的环境变量, ndk-build 是调用 ndk 的编译程序 )4.此时去 hello-jni 的 libs 目录下看有没有生成的 .so 文件,如果有,ndk 就运行正常啦。
2.在android平台下写得JNI放在项目哪里呢,JNI后缀名是什么
原java语言编写的类仍放工程的src文件目录下,方法用native关键字进行修饰,编译后生成.class文件,在java类中通过静态块引入其调用的本地方法,引入如下:
public class Test{
static {
system.loadlibrary("name"); //引入动态库的名字
}
public native int hello(String str[]);
}
通过用C语言编写的JNI方法的头文件要包含java类通过java -h进行编译后的头文件。编写完JNI方法后,通过编译工具生成动态库文件(name.dll文件或name.so文件)(例如可把其放到jdk\bin目录下,也可把动态库放到工程同classes同文件夹的目录下),把该文件放于系统环境变量path中路径所在文件中,即可引入。
3.如何在Android下使用JNI
1.引言 我们知道,Android系统的底层库由c/c++编写,上层Android应用程序通过Java虚拟机调用底层接口,衔接底层c/c++库与Java应用程序间的接口正是JNI(JavaNative Interface)。
本文描述了如何在ubuntu下配置AndroidJNI的开发环境,以及如何编写一个简单的c函数库和JNI接口,并通过编写Java程序调用这些接口,最终运行在模拟器上的过程。 2.环境配置 2.1.安装jdk1.6 (1)从jdk官方网站下载jdk-6u29-linux-i586.bin文件。
(2)执行jdk安装文件 [html] view plaincopyprint? 01.$chmod a+x jdk-6u29-linux-i586.bin 02.$jdk-6u29-linux-i586.bin $chmod a+x jdk-6u29-linux-i586.bin $jdk-6u29-linux-i586.bin (3)配置jdk环境变量 [html] view plaincopyprint? 01.$sudo vim /etc/profile 02.#JAVAEVIRENMENT 03.exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29 04.exportJRE_HOME=$JAVA_HOME/jre 05.exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH 06.exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH $sudo vim /etc/profile #JAVAEVIRENMENT exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29 exportJRE_HOME=$JAVA_HOME/jre exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH 保存后退出编辑,并重启系统。 (4)验证安装 [html] view plaincopyprint? 01.$java -version 02.javaversion "1.6.0_29" 03.Java(TM)SE Runtime Environment (build 1.6.0_29-b11) 04.JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode) 05.$javah 06.用法:javah[选项]<类> 07.其中[选项]包括: 08.-help输出此帮助消息并退出 09.-classpath<路径>用于装入类的路径 10.-bootclasspath<路径>用于装入引导类的路径 11.-d<目录>输出目录 12.-o<文件>输出文件(只能使用-d或-o中的一个) 13.-jni生成JNI样式的头文件(默认) 14.-version输出版本信息 15.-verbose启用详细输出 16.-force始终写入输出文件 17.使用全限定名称指定<类>(例 18.如,java.lang.Object)。
$java -version javaversion "1.6.0_29" Java(TM)SE Runtime Environment (build 1.6.0_29-b11) JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode) $javah 用法:javah[选项]<类> 其中[选项]包括: -help输出此帮助消息并退出 -classpath<路径>用于装入类的路径 -bootclasspath<路径>用于装入引导类的路径 -d<目录>输出目录 -o<文件>输出文件(只能使用-d或-o中的一个) -jni生成JNI样式的头文件(默认) -version输出版本信息 -verbose启用详细输出 -force始终写入输出文件 使用全限定名称指定<类>(例 如,java.lang.Object)。2.2.安装android应用程序开发环境 ubuntu下安装android应用程序开发环境与windows类似,依次安装好以下软件即可: (1)Eclipse (2)ADT (3)AndroidSDK 与windows下安装唯一不同的一点是,下载这些软件的时候要下载Linux版本的安装包。
安装好以上android应用程序的开发环境后,还可以选择是否需要配置emulator和adb工具的环境变量,以方便在进行JNI开发的时候使用。配置步骤如下: 把emulator所在目录android-sdk-linux/tools以及adb所在目录android-sdk-linux/platform-tools添加到环境变量中,android-sdk-linux指androidsdk安装包android-sdk_rxx-linux的解压目录。
[plain] view plaincopyprint? 01.$sudo vim /etc/profile 02.exportPATH=~/software/android/android-sdk-linux/tools:$PATH 03. exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH $sudo vim /etc/profile exportPATH=~/software/android/android-sdk-linux/tools:$PATH exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH 编辑完毕后退出,并重启生效。 2.3.安装NDK NDK是由android提供的编译android本地代码的一个工具。
(1)从androidndk官网下载ndk,目前最新版本为android-ndk-r6b-linux-x86.tar.bz2. (2)解压ndk到工作目录: [plain] view plaincopyprint? 01.$tar -xvf android-ndk-r6b-linux-x86.tar.bz2 02.$sudo mv android-ndk-r6b /usr/local/ndk $tar -xvf android-ndk-r6b-linux-x86.tar.bz2 $sudo mv android-ndk-r6b /usr/local/ndk (3)设置ndk环境变量 [plain] view plaincopyprint? 01.$sudo vim /etc/profile 02.exportPATH=/usr/local/ndk:$PATH $sudo vim /etc/profile exportPATH=/usr/local/ndk:$PATH 编辑完毕后保存退出,并重启生效 (4)验证安装 [plain] view plaincopyprint? 01.$ cd/usr/local/ndk/samples/hello-jni/ 02.$ ndk-build 03.Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver 04.Gdbsetup : libs/armeabi/gdb.setup 05.Install : libhello-jni.so => libs/armeabi/libhello-jni.so $ cd/usr/local/ndk/samples/hello-jni/ $ ndk-build Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver Gdbsetup : libs/armeabi/gdb.setup Install : libhello-jni.so => libs/armeabi/libhello-jni.so 3.JNI实现 我们需要定义一个符合JNI接口规范的c/c++接口,这个接口不用太复杂,例如输出一个字符串。接下来。
4.android studio 怎样进行jni开发
方法如下:
1.添加如下代码在MainActivity类内
static {
System.loadLibrary("hello_jni");
}
public native String getstringfromC();
2.打开终端,android studio已经提供了终端
3.首先进入java目录执行命令:
javah -d ../jni com.example.root.ndk_sample.MainActivity
com.example.root.ndk_sample.MainActivity是native函数的所在的包名和类名,中间使用“.”号分开
4.添加*.c文件在jni目录中
5.编写Android.mk和Application.mk 放在jni目录下面
6.Android.mk文件的内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE :=hello_jni
LOCAL_SRC_FILES := hello_jni.c
include $(BUILD_SHARED_LIBRARY)
Application.mk 文件内容为:
APP_ABI := all
APP_OPIM :=debug
5.如何在android源码中添加自己的jni方法
1,、项目实现了一个简单的四则运算,项目的目录层次如下:AndroidManifest.xml Android.mk jni res src资源文件简简单单,一个布局文件,稍后会有demo的下载地址主要记录备忘的内容如下:MainActivity.Java[html] view plain copypublic native int add(int x, int y);public native int substraction(int x, int y);public native float multiplication(int x, int y);public native float division(int x, int y);static{System.loadLibrary("arithmetic");}2、生成lib的名称为libarithmetic.so.注意load的时候写"arithmetic"jni 目录下有两个文件,一个是Android.mk,一个是c++源文件long.cppjni/Android.mk如下:[html] view plain copyLOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_MODULE:= libarithmeticLOCAL_SRC_FILES:= \long.cppLOCAL_SHARED_LIBRARIES := \libutilsLOCAL_STATIC_LIBRARIES :=LOCAL_C_INCLUDES += \$(JNI_H_INCLUDE)LOCAL_CFLAGS +=LOCAL_PRELINK_MODULE := falseinclude $(BUILD_SHARED_LIBRARY)3、注释:LOCAL_PATH(必须定义,而且要第一个定义),宏函数'my-dir', 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录);include $( CLEAR_VARS),CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等。)
除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的;LOCAL_MODULE_TAGS :=user eng tests optionaluser: 指该模块只在user版本下才编译eng: 指该模块只在eng版本下才编译tests: 指该模块只在tests版本下才编译optional:指该模块在所有版本下都编译LOCAL_MODULE(必须定义),标识你在Android.mk文件中描述的每个模块。
名称必须是唯一的,而且不包含任何空格。Note:编译系统会自动产生合适的前缀和后缀,例如:arithmetic编译成功后将生成libarithmetic.so库文件LOCAL_SRC_FILES 变量必须包含将要编译打包进模块中源代码文件。
不用在这里列出头文件和包含文件。LOCAL_SHARED_LIBRARIES中加入所需要链接的动态库(*.so)的名称LOCAL_STATIC_LIBRARIES加入所需要链接的静态库(*.a)的名称LOCAL_CFLAG可选的编译器选项,用法之一是定义宏,例如LOCAL_CFLAGS := -Werror作用是编译警告也作为错误信息LOCAL_PRELINK_MODULE:=false,不作prelink处理,默认是要prelink操作的,有可能造成地址空间冲突(这地方目前还不明白) long.cpp源代码如下:[html] view plain copy#define LOG_TAG "LongTest2 long.cpp"#include#include#include "jni.h"jint add(JNIEnv *env, jobject thiz, jint x, jint y){return x + y;}jint substraction(JNIEnv *env, jobject thiz, jint x, jint y){return x - y;}jfloat multiplication(JNIEnv *env, jobject thiz, jint x, jint y){return (float)x * (float)y;}jfloat division(JNIEnv *env, jobject thiz, jint x, jint y){return (float)x/(float)y;}static const char *classPathName = "com/inspur/test2/MainActivity";static JNINativeMethod methods[]= {{"add", "(II)I", (void*)add},{"substraction", "(II)I", (void*)substraction},{"multiplication", "(II)F", (void*)multiplication},{"division", "(II)F", (void*)division},};typedef union{JNIEnv* env;void* venv;}UnionJNIEnvToVoid;static int registerNativeMethods(JNIEnv* env, const char* className,JNINativeMethod* gMethods, int numMethods){jclass clazz;clazz = env->FindClass(className);if (clazz == NULL)return JNI_FALSE;if (env->RegisterNatives(clazz, gMethods, numMethods)<0)return JNI_FALSE;return JNI_TRUE;}static int registerNatives(JNIEnv *env){if (!registerNativeMethods(env, classPathName,methods, sizeof(methods)/sizeof(methods[0]))){return JNI_FALSE;}return JNI_TRUE;}jint JNI_OnLoad(JavaVM* vm, void* reserved){UnionJNIEnvToVoid uenv;uenv.venv = NULL;jint result = -1;JNIEnv *env = NULL;if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK){goto bail;}env = uenv.env;env = uenv.env;if (registerNatives(env) != JNI_TRUE){goto bail;}result = JNI_VERSION_1_4;bail:return result;}除了利用 编写native JAVA类,通过javah生成.h文件,根据.h文件编写.c/cpp文件 方法外(名字像老太太的裹脚步,又臭又长,而且不灵活),Android还可以通过引用JNI_Onload方式实现。
jint JNI_onLoad(JavaVM* vm, void* reverced),改方法在so文件被加载时调用。JNI_OnLoad()有两个重要的作用:指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI,例如JNI 1.4版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_4(该常量定义在jni.h中) 来告知VM。
初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_。
6.Android Studio怎么用JNI编写出Hello World
第一步:
在自己项目中创建一个包含native的方法类HelloWorld.java -->包名com.ningso.ningsodemo
public class HelloWorld {
public native String sayHello(String name); // 1.声明这是一个native函数,由本地代码实现
static {
System.loadLibrary("hello"); // 2.加载实现了native函数的动态库,只需要写动态库的名字
}
}
第二步:
在终端执行javac命令将.java源文件编译成.class字节码文件
执行javac命令
-d 表示将编译后的class文件放到指定的文件夹下面
结果图:
编译后的字节码文件
以上也可以直接执行./gradlew build 不过文件就要自己去找了,该class在你的/app/build/intermediates/classes/debug文件夹对应的包名下
第三步:
继续在终端执行javah -jni命令 根据class文件生产.h头文件
Paste_Image.png
注意:-d和-o只能使用其中一个参数。
参数说明:classpath:类搜索路径,这里表示从当前的 bin 目录下查找
-d:将生成的头文件放到当前的 jni 目录下
-o: 指定生成的头文件名称,默认以类全路径名生成(包名+类名.h)
7.android开发 如何在jni本地代码 访问自己写的类
jclass GpsInfoClass = env->FindClass("com/parser/GPSINFO");
jfieldID ID_bValid = env->GetFieldID(GpsInfoClass,"bValid","I");
jfieldID ID_bSpeed = env->GetFieldID(GpsInfoClass,"bSpeed","I");
env->SetIntField(_obj,ID_bValid,(jint)info.bValid);
env->SetIntField(_obj,ID_bSpeed,(jint)info.bSpeed);
return _obj;
以上就可以了。但是不知道你的BYTE是自定义的什么类型,如果是char之类的,就另外想办法转换成jint。其中 _obj 变量是public native GPSINFO getGpsInfo();这个本地方法在C代码中的参数:JNIEXPORT jobject JNICALL Java_com_parser_GPSINFO_ getGpsInfo(JNIEnv *env, jobject _obj)
8.在android平台下写得JNI放在项目哪里呢,JNI后缀名是什
原java语言编写的类仍放工程的src文件目录下,方法用native关键字进行修饰,编译后生成。
class文件,在java类中通过静态块引入其调用的本地方法,引入如下:public class Test{ static { system。 loadlibrary("name"); //引入动态库的名字 }public native int hello(String str[]);}通过用C语言编写的JNI方法的头文件要包含java类通过java -h进行编译后的头文件。
编写完JNI方法后,通过编译工具生成动态库文件(name。dll文件或name。
so文件)(例如可把其放到jdkin目录下,也可把动态库放到工程同classes同文件夹的目录下),把该文件放于系统环境变量path中路径所在文件中,即可引入。
9.如何在Android下使用JNI
第一步: 使用Java编写HelloWorld 的Android应用程序: 复制代码 package com.lucyfyr; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class HelloWorld extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.v("dufresne", printJNI("I am HelloWorld Activity")); } static { //加载库文件 System.loadLibrary("HelloWorldJni"); } //声明原生函数 参数为String类型 返回类型为String private native String printJNI(String inputStr); } 复制代码 这一步我们可以使用eclipse来生成一个App; 因为eclipse会自动为我们编译此Java文件,后面要是用到。
第二步: 生成共享库的头文件: 进入到eclipse生成的Android Project中 :/HelloWorld/bin/classes/com/lucyfyr/ 下: 可以看到里面后很多后缀为.class的文件,就是eclipse为我们自动编译好了的java文件,其中就有: HelloWorld.class文件。 退回到classes一级目录:/HelloWorld/bin/classes/ 执行如下命令: javah com.lucyfyr.HelloWorld 生成文件:com_lucyfyr_HelloWorld.h 复制代码 /* DO NOT EDIT THIS FILE - it is machine generated */ #include
当然函数名太长,可以在.c文件中通过函数名映射表来实现简化。 第三步: 实现JNI原生函数源文件: 新建com_lucyfyr_HelloWorld.c文件: 复制代码 #include
(*env)->ReleaseStringUTFChars(env, inputStr, (const char *)str ); return (*env)->NewStringUTF(env, "Hello World! I am Native interface"); } /* This function will be call when the library first be load. * You can do some init in the libray. return which version jni it support. */ jint JNI_OnLoad(JavaVM* vm, void* reserved) { void *venv; LOGI("dufresne----->JNI_OnLoad!"); if ((*vm)->GetEnv(vm, (void**)&venv, JNI_VERSION_1_4) != JNI_OK) { LOGE("dufresne--->ERROR: GetEnv failed"); return -1; } return JNI_VERSION_1_4; } 复制代码 onl oadJava_com_lucyfyr_HelloWorld_printJNI 函数里面做一些log输出 注意JNI中的log输出的不同。 JNI_OnLoad函数JNI规范定义的,当共享库第一次被加载的时候会被回调, 这个函数里面可以进行一些初始化工作,比如注册函数映射表,缓存一些变量等, 最后返回当前环境所支持的JNI环境。
本例只是简单的返回当前JNI环境。 第四步: 编译生成so库 编译com_lucyfyr_HelloWorld.c成so库可以和app一起编译,也可以都单独编译。
在当前目录下建立jni文件夹:HelloWorld/jni/ 下建立Android.mk ,并将com_lucyfyr_HelloWorld.c和 com_lucyfyr_HelloWorld.h 拷贝到进去 编写编译生成so库的Android.mk文件: 复制代码 LOCAL_PATH:= $(call my-dir) # 一个完整模块编译 include $(CLEAR_VARS) LOCAL_SRC_FILES:=com_lucyfyr_HelloWorld.c LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) LOCAL_MODULE := libHelloWorldJni LOCAL_SHARED_LIBRARIES := libutils LOCAL_PRELINK_MODULE := false LOCAL_MODULE_TAGS :=optional include $(BUILD_SHARED_LIBRARY) 复制代码 系统变量解析: LOCAL_PATH - 编译时的目录 $(call 目录,目录….) 目录引入操作符 如该目录下有个文件夹名称 src,则可以这样写 $(call src),那么就会得到 src 目录的完整路径 include $(CLEAR_VARS) -清除之前的一些系统变量 LOCAL_MODULE - 编译生成的目标对象 LOCAL_SRC_FILES - 编译的源文件 LOCAL_C_INCLUDES - 需要包含的头文件目录 LOCAL_SHARED_LIBRARIES - 链接时需要的外部库 LOCAL_PRELINK_MODULE - 是否需要prelink处理 include$(BUILD_SHARED_。
转载请注明出处育才学习网 » android怎么写jni