今天下午开始到现在,除了晚上大概有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
一、首先需要建立一个Android
public class Hello {
public native String stringFromJNI();
static {
System.loadLibrary("a");
}
}
这里代码很简单,但是我当初的一个疑问是,这里用System.loadLibrary加载的C库文件,是如何让程序知道它要加载的是哪个库?这里对它的命名有什么规则和类名有什么关系么?总之,我刚开始的时候很纠结到底程序是如何知道要加载哪个库的,现在才知道是和.mk文件是有关系的,如上注释。
二、写好带有native方法后,接下来就是用javah命令生成本地C代码的Java类字节码的头文件。这时,一般先在Android Prj的根目录下新建一个jni文件夹,用于存放后续产生的文件。javah可能是个比较少见的指令,大家熟悉的是javac和java,具体可以直接看help,我觉得需要注意的是 are specified with their fully qualified names 虽然这句也是会在help里头出现的。
cannot access android.app.Activity的错误。当然这就是我自己碰到的问题...我在网上搜了下,网友的解决方案是附加android.jar库的地址,具体见:http://blog.youkuaiyun.com/cupidove/article/details/8024596
三、困了。。。根据产生的C头文件,编写C代码实现相应的函数功能。这步没什么好说的,而且我现在实现的也只是return一个string而已。
四、生成*.so文件。这里也有两种方法,一种是直接在Cygwin下面去build产生.so文件,一种是在Eclipse中对Prj的Builders
# 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了。。。哈哈,贴下我最后成功的AVG图片~
哇!开心,当然现在是非常困了。。。写这篇blog前,刚调出来时候的兴奋已经是很久没有过的感觉了,追求的只是这么一瞬间的快感。bonne nuit tout le monde et je vais me lever tot demain...putain...