Android-记录第一次尝试jni的踩坑之路

实现

首先保证我们的环境是ok的

  • gcc
  • openjdk
    直接用apt-get install安装即可,百度一查很多教程

首先我们创建下目标java文件

public class HelloNative {
    static {
        System.loadLibrary("HelloNative");
    }

    public static native void sayHello();
    public static void main(String[] args) {
        new HelloNative().sayHello();
    }
}

完成之后,我们需要获取对应的.h文件

# 编译java文件
javac HelloNative.java
# 获取头文件
javah HelloNative

然后我们就会获得一个HelloNative.h文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class HelloNative */

#ifndef _Included_HelloNative
#define _Included_HelloNative
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloNative
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloNative_sayHello
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

不要动,我们需要新建一个对应的HelloNative.c文件来实现定义的native方法sayHello

#include 
#include "HelloNative.h"

JNIEXPORT void JNICALL Java_HelloNative_sayHello(JNIEnv *env, jclass jc) {
    printf("Hello Native!\n");
}

ok,现在里成功已经差半步了
我们需要对c文件进行编译获取.so动态链接库供java文件调用

g++ -fPIC -shared HelloNative.c -o libHelloNative.so

此时就ok了,看看效果

java HelloNative

对应有输出结果,ok的!

踩坑

看起来一帆风顺,实际上踩了不少坑

添加头文件

开始编译c会提示找不到jni.h和jni_md.h,这两个文件是jdk中的,没有加入到搜索include目录下,可以直接ln建立链接或者cp过去

动态链接库路径

因为之前写过cpp,对于linux下c链接.so是有默认路径的,我们生成的.so路径可能不在其中,因此需要将.so所在的路径添加到搜索路径中
通常采用export指令即可(临时)
对于我来说,通常采用这个指令:

export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH}

这里:的作用就是分割不同路径,和环境变量PATH写法是一样的
其中:
$()是获取指令结果
${}是获取变量值

找不到.so

已经指定了路径,但是仍然会抛出异常问题

Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
        at java.lang.Runtime.loadLibrary0(Runtime.java:871)
        at java.lang.System.loadLibrary(System.java:1124)
        at HelloNative.<clinit>(HelloNative.java:3)

很头大,根据exception提示还是说找不到.so
在网上查了半天,发现是和命名机制相关,我们在loadLibrary的时候是有修改的
loadLibrary(“XXX”);
实际上对应的.so为libXXX.so
因此我们在生成.so命名的时候别忘了前缀lib

你可能感兴趣的:(android杂谈,android,java,开发语言)