您的位置:首页 > 其它

Finalement——Hello from&nbsp…

2013-11-20 16:13 274 查看
今天下午开始到现在,除了晚上大概有2个多小时陪女朋友出去吃饭外,都在努力去理解搞懂JNI。因为是根据《细说Android 4.0
NDK编程》来学的,所以不能不说该书在这一部分还有写得还并不是特别利于理解的地方。

Java通过JNI机制和C/C++沟通的具体步骤:

1、编写包含native本地方法的Java类

2、通过javah工具生成C/C++语言的头文件

3、使用C/C++语言实现头文件

4、使用交叉编译工具对C/C++本地代码进行编译,最后通过链接生成*.so可执行的C/C++库

5、实际执行Java代码去和本地的C/C++代码相互沟通

Android NDK通过JNI调用C的步骤和上述5步基本类似。

一、首先需要建立一个Android Prj,在这个Prj中需要有调用native方法的Java类。在这里我试过两种不同的方式,一是像书上的做法,包含native方法的类独立出来,另一种方式是直接在Activity中写一个native方法。事实证明,第二种方法在用javah生成C头文件的时候会有问题,需要一些处理,这个在下一步中再详述。包含native方法的类的写法基本如下:

public class Hello {

public native String stringFromJNI();

static {

System.loadLibrary("a");
//这里需要加载的C库名字随意,但是需要和后面的.mk文件中的MODULE对应

}

}

这里代码很简单,但是我当初的一个疑问是,这里用System.loadLibrary加载的C库文件,是如何让程序知道它要加载的是哪个库?这里对它的命名有什么规则和类名有什么关系么?总之,我刚开始的时候很纠结到底程序是如何知道要加载哪个库的,现在才知道是和.mk文件是有关系的,如上注释。

二、写好带有native方法后,接下来就是用javah命令生成本地C代码的Java类字节码的头文件。这时,一般先在Android
Prj的根目录下新建一个jni文件夹,用于存放后续产生的文件。javah可能是个比较少见的指令,大家熟悉的是javac和java,具体可以直接看help,我觉得需要注意的是
are specified with their fully qualified names
虽然这句也是会在help里头出现的。

因为后续产生的文件一般是存放在jni文件夹下的,所以打开cmd后,先进到jni目录下。因为想将文件放在jni文件夹下,而源class文件是放在Prj相应目录下的,所以需要用javah的-classpath
参数,eg:D:\WorkSpace\HelloJni\jni>javah -classpath
../bin/classes com.company.hellojni.Hello
这是我的情况。这样产生的.h文件就会在jni文件夹下。在这一步过程中,如果你在第一步中是直接在Activity中写的native方法,那么你就会有麻烦了,系统会报如下错误:



from NDK through JNI" TITLE="Finalement鈥斺擧ello from NDK through JNI" />


cannot access
android.app.Activity的错误。当然这就是我自己碰到的问题...我在网上搜了下,网友的解决方案是附加android.jar库的地址,具体见:http://blog.csdn.net/cupidove/article/details/8024596 我没有试过这个解决方法,因为我觉得应该把Activity和相应功能的java class分开写似乎会好些,便于程序其他部分调用,也比较符合面向对象的思想。

三、困了。。。根据产生的C头文件,编写C代码实现相应的函数功能。这步没什么好说的,而且我现在实现的也只是return一个string而已。

四、生成*.so文件。这里也有两种方法,一种是直接在Cygwin下面去build产生.so文件,一种是在Eclipse中对Prj的Builders properties进行配置,将NDK和Cygwin集成在Eclipse中直接编译。两种方法从开发调试的角度来看毫无疑问是第二种比较好,但是在入门阶段,我还是觉得第一种方法更好,就像刚开始学java的时候肯定是用editPlus敲比用Eclipse好,因为可以更清楚知道它每一步是怎么走的。随便说一句,虽然editPlus是棒子的,虽然我很讨厌棒子,但我还是比较喜欢editPlus而不喜欢ultraedit,我也不知道为什么。具体的过程不详述,主要需要说明的是.mk文件,这是一个神奇的文件。。。

# Copyright (C) 2009 The Android Open Source Project

#

# Licensed under the Apache License, Version 2.0 (the
"License");

# you may not use this file except in compliance with the
License.

# You may obtain a copy of the License at

#

# http://www.apache.org/licenses/LICENSE-2.0
#

# Unless required by applicable law or agreed to in writing,
software

# distributed under the License is distributed on an "AS IS"
BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.

# See the License for the specific language governing permissions
and

# limitations under the License.

#

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := a

LOCAL_SRC_FILES := com_company_hellojni_Hello.c

include $(BUILD_SHARED_LIBRARY)

上面是我的.mk文件。其中LOCAL_PATH := $(call
my-dir)的意思是将Android.mk所在的目录定义为NDK编译的目录。include
$(CLEAR_VARS)这句是清除NDK中所有的预定义变量。后面的MODULE是重点,它是NDK编译系统中一系列相关代码的集合,这个就是你调用的本地C库的标识。在下面的SRC_FILE就不用说了。这里.mk文件中各行代码的意思在《细说》里头一点都没提起,只说复制原来sample中的.mk文件做些修改,然后就是贴出修改后的图片。因为.mk文件一般接触的比较少,而对于整个程序来说至关重要,就是它连接了java和C,所以我觉得应该重点介绍。而且《细说》中,这里开始就是复制Prj下的文件到sample中。。。balabala,让我第一感觉就是难道只有复制到sample下才能编译?编译后再复制回去,这不是坑爹么?!但是《细说》中,哪怕是后面一章中的例子都是这样复制来去编译,再复制回去运行程序的。。。要是NDK真的这么弱,Google也真是nc一回了。事实证明,Google没有nc。我不知道是《细说》作者复制来复制去的方式,是因为出书的时候那个NDK-r5的问题,还是其他。。。

五、上一步如果成功,会在Prj根目录下出现一个libs文件夹,中间有个.so文件。然后!你就可以运行你的程序了,然后你就可以知道你是否需要jumpTo(一)重新开始repeat了。。。哈哈,贴下我最后成功的***G图片~



from NDK through JNI" TITLE="Finalement鈥斺擧ello from NDK through JNI" />


哇!开心,当然现在是非常困了。。。写这篇blog前,刚调出来时候的兴奋已经是很久没有过的感觉了,追求的只是这么一瞬间的快感。bonne
nuit tout le monde et je vais me lever tot
demain...putain...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: