Android——JNI On Android
来源:互联网 发布:php 按钮disable 编辑:程序博客网 时间:2024/05/23 13:36
1.为什么使用JNI
很长时间我就想写关于这方面的东西,其实弄android已经有段时间了,虽然不太喜欢它,但是还是有然我兴奋的地方,那就是JNI,因为那里有我熟悉的C和LInux。JNI简单的说就是一种能够让你在Java里使用C/C++代码的一种技术。
在Android里,Java代码运行在Java虚拟机里(应该是叫做Dalvik),这个虚拟机可以说是java世界的神,但同时也是拖android世界后退的家伙。但是android里你可以有另一种选择,那就是JNI技术,它可以让你在高速公路上尽情的玩耍,而不是乡间小路上。
这种机制允许你将耗时的工作使用C/C++来完成,剩余的部分使用Java,使用JNI来完成Java对C/C++的调用。
2.如何使用JNI
首先,你应该很明确,你为什么使用JNI,怎么学习JNI,当然互联网上有许多这样的教学,包括android NDK的实例。
JNI的基本思想很简单,你可以写一个C/C++文件,然后导出里面的方法,然后在Java的文件里进行调用这些方法。虽然很简单,但是为了完成这样的任务,你需要遵守一些约定。
一个好的开始就是通过一个简单的工程来演示这样技术:
首先是简单的java代码:(通用Activity在屏幕上写一些字符 )
很长时间我就想写关于这方面的东西,其实弄android已经有段时间了,虽然不太喜欢它,但是还是有然我兴奋的地方,那就是JNI,因为那里有我熟悉的C和LInux。JNI简单的说就是一种能够让你在Java里使用C/C++代码的一种技术。
在Android里,Java代码运行在Java虚拟机里(应该是叫做Dalvik),这个虚拟机可以说是java世界的神,但同时也是拖android世界后退的家伙。但是android里你可以有另一种选择,那就是JNI技术,它可以让你在高速公路上尽情的玩耍,而不是乡间小路上。
这种机制允许你将耗时的工作使用C/C++来完成,剩余的部分使用Java,使用JNI来完成Java对C/C++的调用。
2.如何使用JNI
首先,你应该很明确,你为什么使用JNI,怎么学习JNI,当然互联网上有许多这样的教学,包括android NDK的实例。
JNI的基本思想很简单,你可以写一个C/C++文件,然后导出里面的方法,然后在Java的文件里进行调用这些方法。虽然很简单,但是为了完成这样的任务,你需要遵守一些约定。
一个好的开始就是通过一个简单的工程来演示这样技术:
首先是简单的java代码:(通用Activity在屏幕上写一些字符 )
package com.Hello;import android.app.Activity;import android.os.Bundle;import android.widget.TextView;import android.util.Log;public class Hello extends Activity { static { try { Log.i("JNI", "Trying to load libHello.so"); System.loadLibrary("Hello"); } catch (UnsatisfiedLinkError ule) { Log.e("JNI", "WARNING: Could not load libHello.so"); } } // Important part : this method is native, as in imported from C++ native private int add(int a, int b); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Call simple native method int res = add(3,5); // Just print the result on screen TextView tv = new TextView(this); tv.setText("C++ tells you that 3+5 = " + res); setContentView(tv); }}代码很简洁,这里有两个新的东西一个是System.loadLibrary(“Hello”),它的意思就是加载Hello.so库;另个就是native关键字,这个关键字,告诉Java这里的add方法在额外的原生库中查找。将上面的文件保存为Hello.java文件。Android.mk文件内容如下:LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := samplesLOCAL_PACKAGE_NAME := HelloLOCAL_SRC_FILES := Hello.javaLOCAL_SDK_VERSION := currentinclude $(BUILD_PACKAGE)另外AndroidManifest.xml文件内容如下:<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.Hello"> <application android:label="Hello"> <activity android:name="Hello"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application></manifest>接下来放这3个文件到同一个目录,然后设置android编译环境如:(source build/envsetup.sh),之后在该目录下执行mm,这样你的Hello.apk就编译好了。接下来就是C++语言代码:#define LOG_TAG "Hello"#include "utils/Log.h"#include <stdlib.h>#include <string.h>#include <unistd.h>#include <assert.h>#include "jni.h"/* * Trivial method : add two numbers * */static jint Hello_add(JNIEnv* env, jobject thiz, jint a, jint b){ return (jint)(a + b);}/* * Array of methods. * * Each entry has three fields: the name of the method, the method * signature, and a pointer to the native implementation. */static const JNINativeMethod gMethods[] = { { "add", "(II)I", (void*)Hello_add }};/* * Explicitly register all methods for our class. * * Returns 0 on success. */static int registerMethods(JNIEnv* env) { static const char* const kClassName = "com/Hello/Hello"; jclass clazz; /* look up the class */ clazz = env->FindClass(kClassName); if (clazz == NULL) { LOGE("Can't find class %s\n", kClassName); return -1; } /* register all the methods */ if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK) { LOGE("Failed registering methods for %s\n", kClassName); return -1; } return 0;}/* * This is called by the VM when the shared library is first loaded. */jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed\n"); goto bail; } assert(env != NULL); if (registerMethods(env) != 0) { LOGE("ERROR: native registration failed\n"); goto bail; } /* success -- return valid version number */ result = JNI_VERSION_1_4;bail: return result;} 这里关于add函数很简单,相加后返回和。JNI的约定意味着该函数的前两个参数(JNIEnv是一个与线程相关的变量,实际上就是提供一些JNI系统函数,通过这些函数可以调用Java的函数,操作jobject)隐示从Java中传过来,Java代码仅仅调用 add(a,b)。 然后你需要声明这个方法在这个数组里面,当然这里有些奇怪的标签相关的内容可以看这里:http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html#wp16432。JNINativeMethod类中,地一个变量为函数的名称,第二个参数为参数和返回值的说明,第三个是JNI层对应的函数指针。这个数组最后通过这个类型的注册方法RegisterNatives注册到JNI层中。注册的时候首先通过它的名字(kClassName),获得它的类型名(clazz)。 当然这里还有一个问题,就是add方法在什么时候,什么地方被动态调用注册的呢?答案是:当Java层通过System.loadLibary加载JNI动态库后,紧接着查找一个叫做JNI_OnLoad的函数。如果有,就调用它,而动态注册工作就是在这里完成的也就是上面源码中JNI_OnLoad的作用。同样,Android.mk文件的内容如下:LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := samplesLOCAL_MODULE:= libHelloLOCAL_SRC_FILES:= Hello.c# Additional libraries, maybe more than actually neededLOCAL_SHARED_LIBRARIES := \ libandroid_runtime \ libnativehelper \ libcutils \ libutils# JNI headersLOCAL_C_INCLUDES += $(JNI_H_INCLUDE)LOCAL_PRELINK_MODULE := falseinclude $(BUILD_SHARED_LIBRARY)将这两文件放在同一个文件夹下面,然后运行mm,就生成libHello.so文件。3.运行: 首先安装Hello.apk到系统中,然后复制libHello.so到/system/lib目录下,或者使用System.load()代替System.loadLibrary(),通过指定完全路径,你可以将库放到任何你想放的目录下。前提是玩过Android我想你懂得!后继:1.上面是通过动态方法进行的JNI的调用,当然相对于动态还有一种就是静态,静态方法大致就先编译java代码,生成.class文件,然后使用javac -o output packagename.classname,这样就生成一个output.h的JNI层头文件,只要实现里面的对应的函数即可 2.另外在编译的时候,所放的目录是在android源码的某一个目录下,当然make,mmm都是可以的,make就是全编译,比较慢,mmm会将依赖全部编译,当然也不错。注:代码翻译自http://www.upche.org/doku.php?id=wiki:jni
- Android——JNI On Android
- Android——JNI
- Android—Jni初步
- Android JNI编程—JNI基础
- [转载] Android JNI编程—JNI基础
- android jni——helloworld
- Android JNI(一)————JNI介绍
- android中jni学习——jni的调用
- [JNI] Android JNI总结
- Replacing JNI Crashes by Exceptions on Android【转】
- Qt on Android:使用JNI与第三方jar包
- Qt on Android:使用JNI与第三方jar包
- android开发——关于编写JNI
- android开发——关于编写JNI
- Android之——JNI初探
- Android之——JNI初探
- 《Android框架揭秘》读书笔记——JNI
- Android——Jni使用总结
- reCAPTCHA:通过网络安全措施进行基于人类的的字符识别
- AsyncTask的基本使用
- 外部中断
- html知识点收集
- printf的用法
- Android——JNI On Android
- 改交叉编译器路径的注意点
- 拆机记事——显卡驱动
- [KMP或者暴力]POJ 3080 Blue Jeans
- Vbox上为 单实例oracle11gr2 部署Centos5.7 x64
- PE文件格式分析系列(文章1)----一个PE文件导入表数据的分析(MFC工程调试版)
- 使用Myeclipse进行java web开发的三种Tomcat部署方式
- flashfxp的使用要点
- FATAL: kernel too old