android 调用C/C++的互相调用,以及DLL的调用。

基于 Android NDK 的学习之旅----- C调用Java

转载地址:

http://www.cnblogs.com/luxiaofeng54/archive/2011/08/17/2142000.html

Android与c库调用的例子


  • Android与c库调用的例子,欢迎有兴趣的童鞋们下载学习。 
    ================================================================================================
    本资料共包含以下附件: 
    Android_And_C.rar 
    Android and C 文档.rar

http://down.51cto.com/data/356008

-==================================================

Android JNI 调用DLL

http://blog.csdn.net/small5e4444/article/details/7712906
不过最好是将源代码编译成.so动态库(linux动态库)

http://blog.csdn.net/keshuiyun/archive/2011/02/12/6180458.aspx

 

1.JNI
(1)Java call Native C
JNI的基本概念可以参考以下文献:
http://blog.csdn.net/believefym/archive/2007/06/08/1644635.aspx
    这里需要注意的是javah命令处理的是.class文件,而不是.java文件。你需要指定package的路径和package名。javap命令也有类似的要求。
例子很简单,可以从下面的网页获得,C++的代码没有配工程,将之编译成DLL即可。
http://www.namipan.com/d/21e857fd04fc086ce0b3ba90ba92f197e1b626ca55df0000

(2)Native C call Java
基本方法参考下列文献:
http://icepeer.itpub.net/post/3982/19158
注意事项:
使用构造函数时,JDK1.1的写法是:
    jmethodID mid = (*env)->GetMethodID(env,cls,"","(Ljava/lang/String;)V");
而JDK1.2的写法是:
    jmethodID mid = (*env)->GetMethodID(env,cls,"<init>","(Ljava/lang/String;)V");
例子的功能,和上面的例子类似,可以从下面的网页获得
http://www.namipan.com/d/688b2aca53531d0aeb236015f95fd36b594005392d520000

(3)Java call Native C & Native C callback Java
Android由于提供的是Java接口,所以这里最常见的情况是
1)Java启动程序。
2)Java调用Native C。
3)Native C回调Java。
有上面的编程经验,这个也不是太难的事,例子如下:
http://www.namipan.com/d/54782eb9fc9480904e4152adff6e1df28f648976f83f0000
    这个例子和(2)中的区别在于:(2)中的例子由于程序是用C启动的,所以在调用Java之前,需要启动JVM,并实例化相关的Java对象,而(3)中例子由于程序是用Java启动的,在C回调Java时,JVM已经启动,相关的Java对象实例也已存在,所以做法要简单的多。
    使用javah生成的.h文件中,函数的声明在Java中声明的参数之前,还有两个参数JNIEnv和jobject。env是调用Java方法的接口,它的功能非常多。jobject传入的是调用Native C的那个Java对象实例的引用。jobject指针不能在多个线程中共享. 就是说,不能直接在保存一个线程中的jobject指针到全局变量中,然后在另外一个线程中使用它.幸运的是,可以用
gs_object=env->NewGlobalRef(obj);
来将传入的obj保存到gs_object中,从而其他线程可以使用这个gs_object来操纵那个java对象了。

2.在Android上编译C程序
(1)风临左岸在这方面颇有建树,以下是他的blog:
http://blog.sina.com.cn/flza
    最简单的hello world程序可以参看下面这篇文章的做法。
Android原生(Native)C开发之一:环境搭建篇
http://blog.sina.com.cn/s/blog_4a0a39c30100auh9.html
    这里有个概念要弄清楚,之前的例子都是针对x86-win32平台的,而这里我们要在arm-linux下编程。我这里有个同事,曾将x86-win32下的dll放到Android模拟器中,然后抱怨无法使用JNI,这就是这类错误的一个典型的例子。
    还有一点需要注意的是,风临左岸使用的交叉编译工具,所编出的程序虽然可以在模拟器中运行,但却是无法直接用于JNI的,需要使用一定的技巧,可参见以下网页:
Shared library "Hello World!" for Android
http://honeypod.blogspot.com/2007/12/shared-library-hello-world-for-android.html
    从这篇文章可以看出,风临左岸使用的交叉编译工具的动态库的默认格式,和Android平台的动态库的格式是不同的,这也是之前有人说Android无法使用JNI的原因。
    更好的办法是直接使用google提供的交叉编译工具。

(2)获得Android的源代码
    获得源代码的官方方法如下:
http://source.android.com/source/download.html
    虽然源代码在http://source.android.com下,但用浏览器是无法获得代码的,只能用上文提到的方法才行。
当然诸如www.androidin.com之类的网站也提供了非官方的源代码下载。
    源代码的大小有1G左右,解压源代码,在源代码的prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin文件夹下可以找到google提供的交叉编译工具。
    使用prebuilt工具编译C程序的方法可以参考以下文章:
http://www.j2medev.com/android/native/200901/20090119222445.html

3.Android JNI
    正统的做法可以参照以下网页:
http://www.j2medev.com/android/native/200901/20090119222617.html
    当然简单的做法也是有的,可以只解压源代码中的bionic、dalvik、prebuilt这三个文件夹。
需要注意的是,和第三方的交叉编译工具不同,prebuilt下只有相关的头文件而没有相应的.o或.a文件,所以用一般的makefile的话,没有办法编译静态可执行文件,但是动态库文件是可以编的。
    这里还有一个奇怪的地方,如果直接使用cc生成.so的话,会出错。而先cc生成.o,再ld生成.so就没问题。不知道这是什么原因,尚需高手指点。
    这里也提供一个例子,功能和例子1.(3)相同。使用时,将.apk和.so都放在/data/app下即可。
http://www.namipan.com/d/cb2c2eb8c1c6852eaf744e382b8d9805b44e5a2e7f660000
    这里需要指出一点,普通的JNI调用使用System.loadLibrary加载动态库,而Android平台要使用System.load加载动态库。这就是很多人套用PC上的语法,但却在Android上失败的原因。

4.关于一个语法现象
    AlertDialog dialog = new AlertDialog.Builder(SmartGuider.this)
           .setTitle("设置错误")
           .setMessage("GPS功能未开启,请先开启GPS后再使用本程序!/n/n点击Ok进入系统设置页面,点击Cancel退出程序。")
           .create();

    (此处省略1xx个字)


    在C语言中,其实也有类似的情况,例如
    char *strcpy(char *strDestination,const char *strSource);
为什么不写成
    void strcpy(char *strDestination,const char *strSource);
或者
    char *strcpy(const char *strSource);
呢?
    不采用第一种,是因为这样做可以使用诸如strlen(strcpy(...))之类的便捷写法。
    不采用第二种,当然是和内存分配有关了,这里就不多说了。

5.Activity生命周期初探
    Android SDK上关于Activity生命周期的图,无疑是权威的,但相关文档中并没有Android手机功能键对Activity生命周期所造成的改变的内容。
    我这里通过重载Activity派生类的相关函数,并输出日志的方法,探讨该问题。
    先说一下日志,可以使用android.util.Log类来输出日志,eclipse在Debug状态下可以看到输出的日志。输出日志的方法有很多种,他们并不是各自独立的,而是一种信息内容包含的关系,从最简略到最详细依次为ERROR, WARN, INFO, DEBUG, VERBOSE,也就是说ERROR中的日志一定在VERBOSE中也能看到。还有Android运行时生成的日志很多,可以自定义过滤器过滤无关的日志。
    这里仅对onCreate、onDestroy、onPause、onRestart、onResume、onStart、onStop进行重载,并输出日志。
1)启动程序
onCreate->onStart->onResume
2)重启动程序(按下左侧的主页键和左侧的拨号按钮,不会关闭当前的Activity)
onRestart->onStart->onResume
3)按下左侧的主页键和左侧的拨号按钮
onPause->onStop
4)按下右侧的返回键
onPause->onStop->onDestroy
5)右侧的挂机按钮
onPause

6.添加新的View
    利用向导生成的代码中只有一个View,相应的UI布局文件在res/layout/main.xml,找了半天也没找到如何快捷的添加View,于是只好自己手动添加相关的xml文件,好在eclipse可以定制添加的xml文件的模板,于是把main.xml复制一下,做成模板,以后添加就方便了。

7.编译Froyo(部分转贴)
--------------------------------------------------------------------------------------------------------------------------
    说点题外话,这个Blog本来打算完全写些自己的原创内容,对于转贴只给链接,但链接这东西,有利有弊。常常过上几个月,原来的链接就不好使了。所以只好有选择的粘贴一些了。
--------------------------------------------------------------------------------------------------------------------------
    Froyo出来有一阵子了,一时兴起,从官网上git了代码,打算编译。不料根据出错信息得知,Froyo及其以后的版本需要64-bit的OS才能编译。所以只好重新安装64-bit的Ubuntu。

    按照官网上的步骤一步一步的做,然后卡在apt-get install sun-java5-jdk上了。出错信息告诉我,找不到这个包。Google了一下,找到以下解决方法:
9.10/10.04 add ubuntu 9.04 line to you /etc/apt/sources.list

deb http://us.archive.ubuntu.com/ubuntu/ jaunty multiverse
deb http://us.archive.ubuntu.com/ubuntu/ jaunty-updates multiverse

#sudo apt-get update
#sudo apt-get install sun-java5-jdk
(注意安装会一直停留在阅读sun的同意书上,使劲按确定都没反应的(确定是文本不是按钮),后来按键盘Tab解决。)

更改预设jdk的方法如下:同理,更改 默认的javac,方法为
#update-alternatives --config java
#update-alternatives --config javac

显示如下,然后键入java-1.5.0-sun的 编号:
有 2 个选项可用于替换项 java (提供 /usr/bin/java)。

  选择       路径                                    优先级  状态
------------------------------------------------------------
* 0            /usr/lib/jvm/java-6-openjdk/jre/bin/java   1061      自动模式
  1            /usr/lib/jvm/java-1.5.0-sun/jre/bin/java   53        手动模式
  2            /usr/lib/jvm/java-6-openjdk/jre/bin/java   1061      手动模式

  Selection    Path                                   優先級  Status
------------------------------------------------------------
  0            /usr/lib/jvm/java-6-openjdk/bin/javac   1061      auto mode
  1            /usr/bin/ecj                            143       manual mode
  2            /usr/bin/gcj-wrapper-4.4                1044      manual mode
* 3            /usr/lib/jvm/java-1.5.0-sun/bin/javac   53        manual mode
  4            /usr/lib/jvm/java-6-openjdk/bin/javac   1061      manual mode

查看当前的java版本:
#java -version

java version "1.5.0_22"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_22-b03)
Java HotSpot(TM) Client VM (build 1.5.0_22-b03, mixed mode, sharing)
最郁闷的是,在安装好sun-java5-jdk之后,make的时候,出错信息告诉我,Froyo已经改用Java 1.6了。 大哭 

make一切顺利,之后在out/host/linux-x86/bin下找到emulator,但却无法执行,提示缺少AVD device,使用export ANDROID_PRODUCT_OUT=~/android/out/target/product/generic解决之。

3.Android JNI
    正统的做法可以参照以下网页:
http://www.j2medev.com/android/native/200901/20090119222617.html
    当然简单的做法也是有的,可以只解压源代码中的bionic、dalvik、prebuilt这三个文件夹。
需要注意的是,和第三方的交叉编译工具不同,prebuilt下只有相关的头文件而没有相应的.o或.a文件,所以用一般的makefile的话,没有办法编译静态可执行文件,但是动态库文件是可以编的。
    这里还有一个奇怪的地方,如果直接使用cc生成.so的话,会出错。而先cc生成.o,再ld生成.so就没问题。不知道这是什么原因,尚需高手指点。
    这里也提供一个例子,功能和例子1.(3)相同。使用时,将.apk和.so都放在/data/app下即可。
http://www.namipan.com/d/cb2c2eb8c1c6852eaf744e382b8d9805b44e5a2e7f660000
    这里需要指出一点,普通的JNI调用使用System.loadLibrary加载动态库,而Android平台要使用System.load加载动态库。这就是很多人套用PC上的语法,但却在Android上失败的原因。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值