Android与JNI(一)

 

返回主页

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)在运行时被加载。

  如图所示:

Android与JNI(一)_第1张图片

2. 创建一个 android 工程

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

复制代码

 1 package com.example.hellojni; 2  3 import android.os.Bundle; 4 import android.app.Activity; 5 import android.view.Menu; 6 import android.view.MenuItem; 7 import android.widget.TextView; 8 import android.support.v4.app.NavUtils; 9 10 public class HelloJNI extends Activity {11 12     @Override13     public void onCreate(Bundle savedInstanceState) {14         super.onCreate(savedInstanceState);15         setContentView(R.layout.hello_jni);16         getActionBar().setDisplayHomeAsUpEnabled(true);17         18         /* Create a TextView and set its content.19          * the text is retrieved by calling a native20          * function.21          */22         TextView  tv = new TextView(this);23         tv.setText( stringFromJNI() );24         setContentView(tv);25     }26 27     @Override28     public boolean onCreateOptionsMenu(Menu menu) {29         getMenuInflater().inflate(R.menu.hello_jni, menu);30         return true;31     }32 33     34     @Override35     public boolean onOptionsItemSelected(MenuItem item) {36         switch (item.getItemId()) {37             case android.R.id.home:38                 NavUtils.navigateUpFromSameTask(this);39                 return true;40         }41         return super.onOptionsItemSelected(item);42     }43 44     /* A native method that is implemented by the45      * 'HelloJNI' native library, which is packaged46      * with this application.47      */48     public native String  stringFromJNI();49 50     /* This is another native method declaration that is *not*51      * implemented by 'HelloJNI'. This is simply to show that52      * you can declare as many native methods in your Java code53      * as you want, their implementation is searched in the54      * currently loaded native libraries only the first time55      * you call them.56      *57      * Trying to call this function will result in a58      * java.lang.UnsatisfiedLinkError exception !59      */60     public native String  unimplementedStringFromJNI();61 62     /* this is used to load the 'HelloJNI' library on application63      * startup. The library has already been unpacked into64      * /data/data/com.example.HelloJni/lib/libHelloJNI.so at65      * installation time by the package manager.66      */67     static {68         System.loadLibrary("HelloJNI");69     }70 }

复制代码

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

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

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

1 public native String stringFromJNI();2 public native String unimplementedStringFromJNI();

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

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

3. 生成 jni 的头文件 

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

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

$javah -classpath bin/classes -d jni com.example.hellojni.HelloJNI

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

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

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

$lsAndroidManifest.xml  assets  bin  gen  ic_launcher-web.png  jni  libs  obj  proguard-project.txt  project.properties  res  src

复制代码

 1 /* DO NOT EDIT THIS FILE - it is machine generated */ 2 #include <jni.h> 3 /* Header for class com_example_hellojni_HelloJNI */ 4  5 #ifndef _Included_com_example_hellojni_HelloJNI 6 #define _Included_com_example_hellojni_HelloJNI 7 #ifdef __cplusplus 8 extern "C" { 9 #endif10 /*11  * Class:     com_example_hellojni_HelloJNI12  * Method:    stringFromJNI13  * Signature: ()Ljava/lang/String;14  */15 JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJNI_stringFromJNI16   (JNIEnv *, jobject);17 18 /*19  * Class:     com_example_hellojni_HelloJNI20  * Method:    unimplementedStringFromJNI21  * Signature: ()Ljava/lang/String;22  */23 JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJNI_unimplementedStringFromJNI24   (JNIEnv *, jobject);25 26 #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) 2009 The Android Open Source Project 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); 5  * you may not use this file except in compliance with the License. 6  * You may obtain a copy of the License at 7  * 8  *      http://www.apache.org/licenses/LICENSE-2.0 9  *10  * Unless required by applicable law or agreed to in writing, software11  * distributed under the License is distributed on an "AS IS" BASIS,12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13  * See the License for the specific language governing permissions and14  * limitations under the License.15  *16  */17 #include <string.h>18 #include <jni.h>19 #include "com_example_hellojni_HelloJNI.h"20 21 /* This is a trivial JNI example where we use a native method22  * to return a new VM String. See the corresponding Java source23  * file located at:24  *25  *   apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java26  */27 jstring Java_com_example_hellojni_HelloJNI_stringFromJNI(JNIEnv *env, jobject this)28 {29     return (*env)->NewStringUTF(env, "Hello from JNI !");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) 2009 The Android Open Source Project 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 #      http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software10 # distributed under the License is distributed on an "AS IS" BASIS,11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12 # See the License for the specific language governing permissions and13 # limitations under the License.14 #15 LOCAL_PATH := $(call my-dir)16 17 include $(CLEAR_VARS)18 19 LOCAL_MODULE    := HelloJNI20 LOCAL_SRC_FILES := HelloJNI.c21 22 include $(BUILD_SHARED_LIBRARY)

复制代码

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

$ndk-build 
Compile thumb  : HelloJNI <= HelloJNI.c
SharedLibrary  : libHelloJNI.so
Install        : libHelloJNI.so => libs/armeabi/libHelloJNI.so

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

6. 测试

Android与JNI(一)_第2张图片

  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

    你可能感兴趣的:(Android与JNI(一))