【安卓】NDK配置与项目集成

Posted by Qfrost on 2021-09-23
Estimated Reading Time 3 Minutes
Words 870 In Total
Viewed Times

折腾了一下Android+SO,用的环境是IDEA+NDK。主要因为IDE和各种环境依赖迭代太快,网上教程很乱,方法基本都是过时的,自己踩了很多坑,这里做个记录。

0x01 下载NDK

先去下载NDK : https://developer.android.google.cn/ndk/downloads?hl=zh-cn

解压,并将该目录配置到环境变量。

0x02 Java接口声明

Java要调用so还需要一个导出定义。需要创建一个类,类名随意

1
2
3
4
5
6
7
package com.test.myapplication;
public class JniTest {
static {
System.loadLibrary("demo"); // libname需要与makefile文件中声明的LOCAL_MODULE相同
}
public native String getString(String str);
}

在里面加载了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),从而无需单独的工具。

1
javac -h . JniTest.java     // JniTest.java为Java声明Native函数的类

这样即可生成一个.h文件,该文件包含导出函数的声明,编写SO文件时,必须对这些声明函数进行实现。

如果嫌每次敲命令太麻烦,可以配一个External Tool。 File->Settings->Tools->External Tools 点“+”新建一个External Tool。

1
2
3
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中的相同。

1
2
3
4
5
6
7
8
#include "demo.h"       // 由javac导出
#include <jni.h>

JNIEXPORT jstring JNICALL Java_com_test_myapplication_JniTest_getString(JNIEnv *env , jobject obj, jstring ssss){ // 与导出.h文件后与其定义的函数名相同
char *str = "hello from c";
jstring jstr = (**env).NewStringUTF(env, str);
return jstr;
}

比较麻烦是java和c的类型转化,可以参考 http://blog.sina.com.cn/s/blog_5e357d2d01012cu3.html

然后还要写makefile,这个也有模板可以抄

1
2
3
4
5
6
7
8
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