Eddy_He

  • 博客园

  • 首页

  • 新随笔

  • 联系

  • 订阅

  • 管理

随笔- 55 文章- 0 评论- 3

Android与JNI(一)

Android与JNI(一)

软件版本:
  ubuntu10.04
  java version "1.6.0_30-ea"
  eclipse
  android-ndk-r5b

目录:

  1. JNI 开发的基本步骤
  2. 创建一个 android 工程
  3. 生成 jni 的头文件
  4. 编写 c/c++ 代码
  5. 编译生成动态库
  6. 测试
  7. 参考资料

1. JNI 开发的基本步骤

  在 JAVA 程序中调用 c/c++ 函数的方法一般是:

  1、创建一个类(HelloWorld.java)或者在原来的类中声明本地方法。
  2、使用 javac 编译源文件 HollowWorld.java,生成 HelloWorld.class。
  3、使用 javah –jni 来生成头文件(HelloWorld.h),这个头文件里面包含了本地方法的函数原型。
  4、编写 c/c++ 代码(HelloWorld.c)实现头文件中的函数原型。
  5、将 HelloWorld.c 编译成一个动态库,生成 Hello-World.dll 或者 libHello-World.so。
  6、使用 java 命令运行 HelloWorld 程序,类文件 HelloWorld.class 和本地库(HelloWorld.dll 或者 libHelloWorld.so)在运行时被加载。

  如图所示:

2. 创建一个 android 工程

  创建一个新的 android 工程 HelloJNI 便于演示:

1packagecom.example.hellojni;23importandroid.os.Bundle;4importandroid.app.Activity;5importandroid.view.Menu;6importandroid.view.MenuItem;7importandroid.widget.TextView;8importandroid.support.v4.app.NavUtils;910publicclassHelloJNIextendsActivity{1112@Override13publicvoidonCreate(BundlesavedInstanceState){14super.onCreate(savedInstanceState);15setContentView(R.layout.hello_jni);16getActionBar().setDisplayHomeAsUpEnabled(true);1718/*CreateaTextViewandsetitscontent.19*thetextisretrievedbycallinganative20*function.21*/22TextViewtv=newTextView(this);23tv.setText(stringFromJNI());24setContentView(tv);25}2627@Override28publicbooleanonCreateOptionsMenu(Menumenu){29getMenuInflater().inflate(R.menu.hello_jni,menu);30returntrue;31}323334@Override35publicbooleanonOptionsItemSelected(MenuItemitem){36switch(item.getItemId()){37caseandroid.R.id.home:38NavUtils.navigateUpFromSameTask(this);39returntrue;40}41returnsuper.onOptionsItemSelected(item);42}4344/*Anativemethodthatisimplementedbythe45*'HelloJNI'nativelibrary,whichispackaged46*withthisapplication.47*/48publicnativeStringstringFromJNI();4950/*Thisisanothernativemethoddeclarationthatis*not*51*implementedby'HelloJNI'.Thisissimplytoshowthat52*youcandeclareasmanynativemethodsinyourJavacode53*asyouwant,theirimplementationissearchedinthe54*currentlyloadednativelibrariesonlythefirsttime55*youcallthem.56*57*Tryingtocallthisfunctionwillresultina58*java.lang.UnsatisfiedLinkErrorexception!59*/60publicnativeStringunimplementedStringFromJNI();6162/*thisisusedtoloadthe'HelloJNI'libraryonapplication63*startup.Thelibraryhasalreadybeenunpackedinto64*/data/data/com.example.HelloJni/lib/libHelloJNI.soat65*installationtimebythepackagemanager.66*/67static{68System.loadLibrary("HelloJNI");69}70}

  代码很简单,主要是调用本地方法返回一个字符串,显示在屏幕上。有两点需要针对说明一下:

1static{2System.loadLibrary("HelloJNI");3}

  上面这几行代码是用来加载动态库 libHelloJNI.so 。那么是在什么时候加载呢?当第一次使用到这个类的时候就会加载。

1publicnativeStringstringFromJNI();2publicnativeStringunimplementedStringFromJNI();

  使用关键字 native 声明本地方法,表明这两个函数需要通过本地代码 c/c++ 实现。

  通过 eclipse 编译代码,生成 .class 文件。为生成 jni 的头文件做好准备。

3. 生成 jni 的头文件

  现在的问题是要怎么样实现 stringFromJNI 和 unimplementedStringFromJNI 这两个函数呢?这两个函数要怎么命名?直接用这两个名字行不行?要解决这些疑问,就要用到 javah 这个命令。

  在你新建成的工程根目录下,键入以下命令:

$javah-classpathbin/classes-djnicom.example.hellojni.HelloJNI

  先简单说一下这个命令有什么用。这个命令是用来生成与指定 class 想对应的本地方法的头文件。

  -classpath:指定类的路径。
  -d:输出目录名。
  com.example.hellojni.HelloJNI:完整的类名。

  命令的结果是在本地生成一个名为 jni 的目录,里面有一个名为 com_example_hellojni_HelloJNI.h 的头文件。这个文件就是我们所需要的头文件,他声明了两个函数

$lsAndroidManifest.xmlassetsbingenic_launcher-web.pngjnilibsobjproguard-project.txtproject.propertiesressrc

1/*DONOTEDITTHISFILE-itismachinegenerated*/2#include<jni.h>3/*Headerforclasscom_example_hellojni_HelloJNI*/45#ifndef_Included_com_example_hellojni_HelloJNI6#define_Included_com_example_hellojni_HelloJNI7#ifdef__cplusplus8extern"C"{9#endif10/*11*Class:com_example_hellojni_HelloJNI12*Method:stringFromJNI13*Signature:()Ljava/lang/String;14*/15JNIEXPORTjstringJNICALLJava_com_example_hellojni_HelloJNI_stringFromJNI16(JNIEnv*,jobject);1718/*19*Class:com_example_hellojni_HelloJNI20*Method:unimplementedStringFromJNI21*Signature:()Ljava/lang/String;22*/23JNIEXPORTjstringJNICALLJava_com_example_hellojni_HelloJNI_unimplementedStringFromJNI24(JNIEnv*,jobject);2526#ifdef__cplusplus27}28#endif29#endif

  上面代码中的 JNIEXPORT 和 JNICALL 是 jni 的宏,在 android 的 jni 中不需要,当然写上去也不会有错。

  函数名比较长,不过是有规律的,按照:java_pacakege_class_method 形式来命名。调用 stringFromJNI() 就会执行 JNICALL Java_com_example_hellojni_HelloJNI_stringFromJNI() 。

  还有一个地方需要注意一下,那就是第13行

  Signature: ()Ljava/lang/String;
  
()表示函数的参数为空(这里为空是指除了JNIEnv *, jobject 这两个参数之外没有其他参数,JNIEnv* 和 jobject 是所有 jni 函数必有的两个参数,分别表示 jni 环境和对应的 java 类(或对象)本身);
  Ljava/lang/String; 表示函数的返回值是 java 的 String 对象。

4. 编写 c/c++ 代码

  按照 com_example_hellojni_HelloJNI.h 中声明的函数名,在 jni 目录下建立一个 HelloJNI.c 文件实现其函数体。

1/*2*Copyright(C)2009TheAndroidOpenSourceProject3*4*LicensedundertheApacheLicense,Version2.0(the"License");5*youmaynotusethisfileexceptincompliancewiththeLicense.6*YoumayobtainacopyoftheLicenseat7*8*http://www.apache.org/licenses/LICENSE-2.09*10*Unlessrequiredbyapplicablelaworagreedtoinwriting,software11*distributedundertheLicenseisdistributedonan"ASIS"BASIS,12*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.13*SeetheLicenseforthespecificlanguagegoverningpermissionsand14*limitationsundertheLicense.15*16*/17#include<string.h>18#include<jni.h>19#include"com_example_hellojni_HelloJNI.h"2021/*ThisisatrivialJNIexamplewhereweuseanativemethod22*toreturnanewVMString.SeethecorrespondingJavasource23*filelocatedat:24*25*apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java26*/27jstringJava_com_example_hellojni_HelloJNI_stringFromJNI(JNIEnv*env,jobjectthis)28{29return(*env)->NewStringUTF(env,"HellofromJNI!");30}

  这里只实现了 Java_com_example_hellojni_HelloJNI_stringFromJNI() ,函数很简单,返回一个字符串。但是由于函数定义中的返回值是 java 的 String 类,所以不能简单的返回一个字符串,需要通过 JNI 函数 NewStringUTF 在本地创建一个新的 java.lang.String 对象。这个新创建的字符串对象拥有一个与给定的 UTF-8 编码的 C 类型字符串内容相同的 Unicode 编码字符串。这里抛出了一个问题,就是说我们在写 JNI 的时候,有些数据类型是需要做转换的。

5. 编译生成动态库

  如果你还没有下载 ndk 的话,请到这里来下载。ndk 有什么用?就是用来编译 jni 代码的。安装方法很简单,只要把 ndk-build 命令加入到环境变量 PATH 中就可以使用了。验证方法就是键入 ndk-build 命令后,不会出现 command not found 的字样。

  在 jni 目录下创建一个名为 Android.mk 的文件,并输入以下内容:

1#Copyright(C)2009TheAndroidOpenSourceProject2#3#LicensedundertheApacheLicense,Version2.0(the"License");4#youmaynotusethisfileexceptincompliancewiththeLicense.5#YoumayobtainacopyoftheLicenseat6#7#http://www.apache.org/licenses/LICENSE-2.08#9#Unlessrequiredbyapplicablelaworagreedtoinwriting,software10#distributedundertheLicenseisdistributedonan"ASIS"BASIS,11#WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.12#SeetheLicenseforthespecificlanguagegoverningpermissionsand13#limitationsundertheLicense.14#15LOCAL_PATH:=$(callmy-dir)1617include$(CLEAR_VARS)1819LOCAL_MODULE:=HelloJNI20LOCAL_SRC_FILES:=HelloJNI.c2122include$(BUILD_SHARED_LIBRARY)

  然后在 jni 目录下输入 ndk-build 命令就可以编译了。

$ndk-buildCompilethumb:HelloJNI<=HelloJNI.cSharedLibrary:libHelloJNI.soInstall:libHelloJNI.so=>libs/armeabi/libHelloJNI.so

  将会在 HelloJNI/libs/armeabi 目录下生成一个名为 libHelloJNI.so 的动态库。编译生成 apk 时会把这个库一起打包。

6. 测试

  7. 参考资料

  [1]. Android: NDK编程入门笔记
  [2]. JNI及Android JNI 开发基本知识和具体操作步骤
  [3]. 如何在Android下使用JNI

分类: Android

标签: android, jni

绿色通道: 好文要顶 关注我 收藏该文与我联系

Eddy_He
关注 - 7
粉丝 - 2

+加关注

0

0

(请您对文章做出评价)

« 上一篇:推理题-爸爸的生日-答案分析
» 下一篇:Android与JNI(二)

posted @ 2012-08-08 17:23 Eddy_He 阅读(1759) 评论(0) 编辑 收藏

刷新评论刷新页面返回顶部

注册用户登录后才能发表评论,请 登录 或 注册,访问网站首页。

【推荐】50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
融云,免费为你的App加入IM功能——让你的App“聊”起来!!

<DIV style="BORDER-BOTTOM: 0pt; BORDER-LEFT: 0pt; BORDER-TOP: 0pt; BORDER-RIGHT: 0pt" id=google_ads_iframe_/1090369/cnblogs_blogpost_C1_sitehome_0__container__ name="google_ads_iframe_/1090369/cnblogs_blogpost_C1_sitehome_0__container__"><IFRAME style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; VERTICAL-ALIGN: bottom; BORDER-TOP: 0px; BORDER-RIGHT: 0px" id=google_ads_iframe_/1090369/cnblogs_blogpost_C1_sitehome_0 height=250 marginHeight=0 src="javascript:""" frameBorder=0 width=300 allowTransparency name=google_ads_iframe_/1090369/cnblogs_blogpost_C1_sitehome_0 marginWidth=0 scrolling=no>

最新IT新闻:
· 冯仑:创业就是失去现在要未来
· Chrome 42发布,向用户推送通知和禁用Java
· iOS开发者:苹果你深深的伤害了我,还不让我说
· 最低499元iPhone官翻不给中低端安卓活路
· 调查显示:微软比苹果更具社会责任感
» 更多新闻...

<DIV style="BORDER-BOTTOM: 0pt; BORDER-LEFT: 0pt; BORDER-TOP: 0pt; BORDER-RIGHT: 0pt" id=google_ads_iframe_/1090369/cnblogs_blogpost_C2_0__container__ name="google_ads_iframe_/1090369/cnblogs_blogpost_C2_0__container__"><IFRAME style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; VERTICAL-ALIGN: bottom; BORDER-TOP: 0px; BORDER-RIGHT: 0px" id=google_ads_iframe_/1090369/cnblogs_blogpost_C2_0 height=60 marginHeight=0 src="javascript:""" frameBorder=0 width=468 allowTransparency name=google_ads_iframe_/1090369/cnblogs_blogpost_C2_0 marginWidth=0 scrolling=no>

最新知识库文章:

· 谈“测试驱动的开发”
· 好团队不可能凭空出现,赢在Leader的可行规划
· 移动应用测试——打造完美应用的秘诀
· 什么是对象,为什么要面向对象,怎么才能面向对象?
· 驱动方法不能改变任何事情

» 更多知识库文章...

公告

昵称:Eddy_He
园龄:3年1个月
粉丝:2
关注:7

+加关注

< 2012年8月 >
29 30 31 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 1
2 3 4 5 6 7 8

搜索

常用链接

  • 我的随笔

  • 我的评论

  • 我的参与

  • 最新评论

  • 我的标签

  • 更多链接

    我的标签

    • vim(16)

    • git(6)

    • ubuntu(5)

    • linux(5)

    • android(3)

    • cache(2)

    • eclipse(2)

    • jni(2)

    • file(1)

    • ubuntu ibus 中文(1)

    • 更多

    随笔分类

    • Android(2)

    • C(2)

    • git(6)

    • JAVA(1)

    • linux(11)

    • office(1)

    • shell(2)

    • ubuntu(10)

    • vim(23)

    • 逻辑推理(1)

    随笔档案

    • 2013年5月 (1)

    • 2012年11月 (1)

    • 2012年9月 (13)

    • 2012年8月 (3)

    • 2012年7月 (5)

    • 2012年6月 (3)

    • 2012年5月 (4)

    • 2012年4月 (2)

    • 2012年3月 (23)

    文章分类

    • C

    • git

    • linux

    • office

    • shell

    • ubuntu

    最新评论

    • 1. Re:vim-project

    • 请问下,图中的vim配色方案是什么啊?谢谢!

    • --山本二十八

    • 2. Re:git-分支管理

    • 感谢分享

    • --FMN

    阅读排行榜

    • 1. git-commit(8908)

    • 2. E: Sub-process /usr/bin/dpkg returned an error code (1) 解决方案(8664)

    • 3. Android与JNI(二)(3497)

    • 4. ubuntu-ubuntu10.04使用wine安装SourceInsight(2968)

    • 5. git-忽略指定文件(2502)

    评论排行榜

    • 1. git-分支管理(1)

    • 2. vim-echofunc(1)

    • 3. vim-project(1)

    推荐排行榜

    • 1. git-分支管理(1)

    Copyright ©2015 Eddy_He

    更多相关文章

    1. 箭头函数的基础使用
    2. Python技巧匿名函数、回调函数和高阶函数
    3. android hidl简单实例1
    4. 向Eclipse导入linux编译生成的jar包,调试android原生app
    5. 关于Android的keystore生成和查看keystore
    6. 命令行开发、编译、打包Android应用程序
    7. android新建项目时gen目录下的R文件没有自动的生成
    8. android 命令介绍
    9. Android输入子系统之InputReader读取键盘消息过程分析

    随机推荐

    1. flutter 学习总结
    2. 可信执行环境(TEE)技术介绍
    3. Android知识点(自己版)
    4. android_1
    5. Android(安卓)选择文件并获取路径
    6. Android文件存储--采用SharedPreferences
    7. 【Android】菜单功能的实现:弹出Popup菜单
    8. Error:Execution failed for task ':demo
    9. SpringSource通过Spring for Android(安
    10. android OTG