JAVA调用C语言写的SO文件

  JAVA调用C语言写的SO文件

  因为工作需要写一份SO文件,作为手机硬件IC读卡和APK交互的桥梁,也就是中间件,看了网上有说到JNI接口技术实现,这里转载了一个实例

 1 // 用JNI实现
 2 // 实例:
 3
 4 // 创建HelloWorld.java
 5 class HelloWorld
 6 {
 7     private native void print();
 8     public static void main(String[] args)
 9     {
10         new HelloWorld().print();
11     }
12
13     static
14     {
15         System.loadLibrary("HelloWorld");
16     }
17 }
18 // 注意print方法的声明,关键字native表明该方法是一个原生代码实现的。另外注意static代码段的System.loadLibrary调用,这段代码表示在程序加载的时候,自动加载libHelloWorld.so库。
19 // 编译HelloWorld.java
20 // 在命令行中运行如下命令:
21 javac HelloWorld.java
22 // 在当前文件夹编译生成HelloWorld.class。
23 // 生成HelloWorld.h
24 // 在命令行中运行如下命令:
25 javah -jni HelloWorld
26 // 在当前文件夹中会生成HelloWorld.h。打开HelloWorld.h将会发现如下代码:
27 /* DO NOT EDIT THIS FILE - it is machine generated */
28 #include <jni.h>
29 /* Header for class HelloWorld */
30
31 #ifndef _Included_HelloWorld
32 #define _Included_HelloWorld
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 /*
37  * Class:     HelloWorld
38  * Method:    print
39  * Signature: ()V
40  */
41 JNIEXPORT void JNICALL Java_HelloWorld_print
42 (JNIEnv *, jobject);
43
44 #ifdef __cplusplus
45 }
46 #endif
47 #endif
48 // 该文件中包含了一个函数Java_HelloWorld_print的声明。这里面包含两个参数,非常重要,后面讲实现的时候会讲到。
49 // 实现HelloWorld.c
50 // 创建HelloWorld.c文件输入如下的代码:
51 #include <jni.h>
52 #include <stdio.h>
53 #include "HelloWorld.h"
54
55 JNIEXPORT void JNICALL
56 Java_HelloWorld_print(JNIEnv *env, jobject obj)
57 {
58     printf("Hello World!\n");
59 }
60 // 注意必须要包含jni.h头文件,该文件中定义了JNI用到的各种类型,宏定义等。
61 // 另外需要注意Java_HelloWorld_print的两个参数,本例比较简单,不需要用到这两个参数。但是这两个参数在JNI中非常重要。
62 // env代表java虚拟机环境,Java传过来的参数和c有很大的不同,需要调用JVM提供的接口来转换成C类型的,就是通过调用env方法来完成转换的。
63 // obj代表调用的对象,相当于c++的this。当c函数需要改变调用对象成员变量时,可以通过操作这个对象来完成。
64 // 编译生成libHelloWorld.so
65 // 在Linux下执行如下命令来完成编译工作:
66 cc -I/usr/lib/jvm/java-6-sun/include/linux/
67 -I/usr/lib/jvm/java-6-sun/include/
68 -fPIC -shared -o libHelloWorld.so HelloWorld.c
69 // 在当前目录生成libHelloWorld.so。注意一定需要包含Java的include目录(请根据自己系统环境设定),因为Helloworld.c中包含了jni.h。
70 // 另外一个值得注意的是在HelloWorld.java中我们LoadLibrary方法加载的是“HelloWorld”,可我们生成的Library却是libHelloWorld。这是Linux的链接规定的,一个库的必须要是:lib+库名+.so。链接的时候只需要提供库名就可以了。
71 // 运行Java程序HelloWorld
72 // 大功告成最后一步,验证前面的成果的时刻到了:
73 java HelloWorld
74 // 如果你这步发生问题,如果这步你收到java.lang.UnsatisfiedLinkError异常,可以通过如下方式指明共享库的路径:
75 java -Djava.library.path=‘.‘ HelloWorld
76 // 当然还有其他的方式可以指明路径请参考《在Linux平台下使用JNI》。
77 // 我们可以看到久违的“Hello world!”输出了。

  试着去完成,自己生成了一份com_test_GetMsg.h头文件,并完成test.c,生成libtest.so文件,JAVA调用SO文件时,屡次报:

failed: Cannot load library: load_library(linker.cpp:761): not a valid ELF executable: /data/app-lib/com.example.iccommtest-libtest.so

  也就是提供的SO无法load,是valid的。

  后来比对刚才的实例,发现问题既然是com_test_GetMsg.h的文件名,因为com_test是类名,而GetMsg是方法名,但是方法名的命名各种是这样: 

1 1 /*
2 2  * Class:     com_test
3 3  * Method:    GetMsg
4 4  * Signature: ()V
5 5  */
6 6 JNIEXPORT jstring JNICALL Java_com_test_GetMsg
7 7 (JNIEnv *, jobject);

  这里问题来了,方法名的‘_‘是特殊符号,这样java在load编写的SO文件时,以为com是类名,test是方法名,所以一直load失败。好吧,是粗心惹的祸!

  重新生成test.h文件,方法名这样:

1 1 /*
2 2  * Class:     test
3 3  * Method:    GetMsg
4 4  * Signature: ()V
5 5  */
6 6 JNIEXPORT jstring JNICALL Java_test_GetMsg
7 7 (JNIEnv *, jobject);

  这样问题解决了!

  我非专业JAVA开发的,写的有点不顺,欢迎JAVA牛人吐槽

时间: 11-07

JAVA调用C语言写的SO文件的相关文章

java调用C/C++写的dll(转)

源:java调用C/C++写的dll Java语言本身具有跨平台性,如果通过Java调用DLL的技术方便易用,使用Java开发前台界面可以更快速,也能带来跨平台性. Java调用C/C++写好的DLL库时,由于基本数据类型不同.使用字节序列可能有差异,所以在参数传递过程中容易出现问题,DLL中可能需要做相应的转换. 使用Java调用DLL动态链接库的方案通常有三种:JNI, Jawin, Jacob. 其JNI(Java Native Interface)是Java语言本身提供的调用本地已编译的

关于 php 调用 其他语言写的Web Service SOAP 接口的参数传递问题

关于 php 调用 其他语言写的Web Service SOAP 接口的参数传递问题,有需要的朋友可以参考下. php调用java写的soap接口经验: 场景一: java是以数组的形式接收参数的,我使用的方法如下: 方法一: require_once ROOT_PATH . '/libraries/nusoap/nusoap.php';//引入nusoap类库文件$client = new nusoap_client("$WSDL_URL",true);$client->dec

java调用dll或so动态库文件(c++/c)

java调用dll或so动态库文件(c++/c) 博客分类: 工作 CC#C++JavaEclipse java调用dll或so动态库文件(c++/c)开发平台:Eclipse3.3.1.1+CDT(cdt-master-4.0.3)+MinGW(MinGW-5.1.4) 一:下面是java调用dll(C++) 1:下载并安装cdt :http://www.eclipse.org/cdt/downloads.php  :选择自己eclipse 支持的cdt插件,下载,并且 通过eclipse--

Java调用R语言

R是统计计算的强大工具,JAVA是做应用系统的主流语言.JAVA负责系统的构建,R用来做运算引擎,从而实现应用型和分析性相结合的系统. 一.Rserve(远程通信模式) Rserve是一个基于TCP/IP的服务器,通过二进制协议传输数据,可以提供远程连接,使得客户端语言能够调用R. Rserve作为一个package发布在CRAN上,可以直接使用install.packages("Rserve")进行安装.需要使用时在R控制台下加载该包,然后输入命令Rserve(),开启服务器就可以供

java 调用命令行执行ruby ruby文件必须放在项目跟目录

import java.io.BufferedReader;import java.io.InputStreamReader; public class CMD_RUBY { private static String exeCmd(String commandStr) { BufferedReader br = null; try { Process p = Runtime.getRuntime().exec(commandStr); br = new BufferedReader(new I

Java调用C++动态链接库dll,有详细过程。VS2015+Eclipse以及失败解决方案

背景 由于之前一直没有接触过用Java调用C++,目前正在考虑用C++写主要的算法,然后用Java来调用.通过查找资料,发现要嘛用通信的方式,要嘛就使用JNI,也就是Java Native Interface的简称,中文是"Java本地调用".通常在Java程序中的函数可以调用Native语言写的函数,Native一般指的是C/C++编写的函数. Native程序中的函数可以调用Java层的函数,也就是说在C/C++程序中可以调用Java的函数.使用JNI的目的是为了屏蔽不同操作系统平

java调用dll-JNA

介绍 给大家介绍一个最新的访问本机代码的 Java 框架 —JNA . JNA(Java Native Access) 框架是一个开源的 Java 框架,是 SUN 公司主导开发的,建立在经典的 JNI 的基础之上的一个框架. JNA 项目地址: https://jna.dev.java.net/ 非常强大.易用,功能上类似与 .NET 的 P/Invoke . 不堪回首的 JNI 我们知道,使用 JNI 调用 .dll/.so 共享类库是非常非常麻烦和痛苦的. 如果有一个现有的 .dll/.s

在Windows Phone项目中调用C语言DLL

在Windows Phone项目中调用C语言写的DLL 最近接到一个需求,需要在WP里调用一个C语言写的DLL,并且说Android和iOS都可以,问我WP是否可以这样? 我说我调研一下,就有了下面的文章. 在传统C# WinForm 里调用Win32 DLL都不容易(可能用惯了C#),要用P/Invoke,然后DllImport什么什么,那WP里不是更麻烦? 先看看网上有没有可用的文章,结果还真找到devdiv中的文章,但其中有两处错误,所以我fix bug并且整理一下,然后展示给大家. 1.

Android 学习JNI,用JAVA调用C

首先必须知道JNI是什么东东? JNI(Java Native Interface)是java本地语言接口,也就是提供一种方法可以用JAVA调用底层语言(C/C++).一般如果项目必须使用C语言操作底层的硬件,那就必须用到JNI技术. 那既然要使用JAVA调用C语言,那必须要解决几个问题? 1:JAVA是面向对象的语言,而C是面向过程的语言 2:JAVA中的Object,String类型,Boolean类型,在C中都是没有的,那C语言是如何识别的? 其实这些JNI都给我们做好了,在JNI的头文件