折腾了一下Android+SO,用的环境是IDEA+NDK。主要因为IDE和各种环境依赖迭代太快,网上教程很乱,方法基本都是过时的,自己踩了很多坑,这里做个记录。
0x01 下载NDK
先去下载NDK : https://developer.android.google.cn/ndk/downloads?hl=zh-cn
解压,并将该目录配置到环境变量。
0x02 Java接口声明
Java要调用so还需要一个导出定义。需要创建一个类,类名随意
|
|
在里面加载了so文件,并用native关键字声明一个函数,声明该函数为native函数
0x03 导出Native-Header
因为是从Java的函数调用到So的函数,需要对Java里声明的函数导出C的声明,即JNI的Native-Header导出。查了很多资料是用javah工具生成so的Native-Header,但是实测发现我的JDK11上没有这个文件,而JDK8上却有,但是我配置上JDK8的javah用于生成Native-Header也会报错“错误: 无法访问androidx.appcompat.app.AppCompatActivity”。
查了官方资料,发现javah工具已被具有更优越的功能的javac。它已在JDK 10中删除。从JDK 8开始,javac提供了在编译Java源代码时编写本机头文件的功能(javac -h),从而无需单独的工具。
javac -h . JniTest.java // JniTest.java为Java声明Native函数的类
这样即可生成一个.h文件,该文件包含导出函数的声明,编写SO文件时,必须对这些声明函数进行实现。
如果嫌每次敲命令太麻烦,可以配一个External Tool。 File->Settings->Tools->External Tools 点“+”新建一个External Tool。
Program: javac
Arguments: -h $OutputPath$ $FilePath$
Working directory: $ProjectFileDir$
然后对包含Native声明的类右键->External Tools->Generate Native-Header,即可生成JNI的Native-Header文件。
0x04 SO
然后要写so的代码。在main下可以创建一个文件夹,里面放So中要用的所有C代码。这里创建了demo.c
然后将前面生成的.h文件也放在同一目录下(这里重命名为demo.h)。然后在demo.c中实现SO的代码。这个写法和导出方式是标准的JNI SO写法,直接抄就好了,但要注意实现的接口函数名必须与.h中的相同。
|
|
比较麻烦是java和c的类型转化,可以参考 http://blog.sina.com.cn/s/blog_5e357d2d01012cu3.html
然后还要写makefile,这个也有模板可以抄
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := demo
LOCAL_SRC_FILES := demo.c
include $(BUILD_SHARED_LIBRARY)
0x05 Build
新版IDEA支持项目与Native项目相关联,可在项目Build的时候自动对Native的项目做build并集成。右键选中包,有个选项叫“Link C++ Project with Gradle”,选择后选中mk文件,即IDEA会自动的对该SO项目和Android项目做关联,完全不用管so的build与集成之类的问题。
但是在运行的时候很可能会出现这个问题:“NDK not configured.Download it with SDK manager.” 这个问题的解决方案挺多的,个人认为比较方便的方法是在项目的 local.properties 文件中手动指定NDK的Path
- ndk.dir=D:\IDE\java\ndk-r23