一 生成一个简单库文件so、a
NDK16_Linux中使用NDK编译安卓可用的.c
NDK16_NDK编译生成so并CMAKE集成
配置环境变量
export CC=android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc
export AAA="--sysroot=/home/bao/android-ndk-r17c/platforms/android-21/arch-arm -isystem /home/bao/android-ndk-r17c/sysroot/usr/include -isystem /home/bao/android-ndk-r17c/sysroot/usr/include/arm-linux-androideabi"
生成动态库
$CC $AAA -fPIC -shared main.c -o libTest.so
生成静态库
$CC $AAA -fpic -c test.c -o libTest.o
/home/bao/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc-ar r libTest.a libTest.o
二 Android.mk集成so库问题
- AS新建一个项目,support C++不勾选
- 配置build.gradle
android {
compileSdkVersion 29
defaultConfig {
applicationId "com.example.ray.demo17_mk"
minSdkVersion 17
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// 指导我们的 源文件 编译
externalNativeBuild{
ndkBuild{
// armeabi-v7a
abiFilters 'armeabi-v7a'
}
}
// externalNativeBuild.ndkBuild(new Action<CoreExternalNativeCmakeOptions>() {
// @Override
// void execute(CoreExternalNativeCmakeOptions ndkBuildOptions) {
// // 你希望编译你的 c/c++ 源文件 编译几种cpu(arm、x86 )
// ndkBuildOptions.abiFilters.add("armeabi-v7a")
// ndkBuildOptions.abiFilters.add("x86")
// }
// })
// 应该打包几种cpu
//比如: 集成了第三方库 ,第三方库中提供了 arm的 提供了 x86的
// 可以在此处 指导 只打包 arm
// 生成出来的apk 就只会包含 arm的
ndk{
abiFilters 'armeabi-v7a'
}
}
//配置 native 的编译脚本路径
// externalNativeBuild.ndkBuild(new Action<NdkBuildOptions>() {
// @Override
// void execute(NdkBuildOptions ndkBuildOptions) {
// ndkBuildOptions.path = "src/main/cpp/Android.mk"
// }
// })
externalNativeBuild{
ndkBuild{
path "src/main/cpp/Android.mk"
}
}
- 创建并配置Android.mk+ 预编译库的引入(拷贝so并配置)
#源文件在的位置。宏函数 my-dir 返回当前目录(包含 Android.mk 文件本身的目录)的路径。
LOCAL_PATH := $(call my-dir)
# $(info "LOCAL_PATH:======== ${LOCAL_PATH}");
# 预编译库的引入
include $(CLEAR_VARS)
LOCAL_MODULE := Test
LOCAL_SRC_FILES :=libTest.so
include $(PREBUILT_SHARED_LIBRARY)
#引入其他makefile文件。CLEAR_VARS 变量指向特殊 GNU Makefile,可为您清除许多 LOCAL_XXX 变量
#不会清理 LOCAL_PATH 变量
include $(CLEAR_VARS)
#存储您要构建的模块的名称 每个模块名称必须唯一,且不含任何空格
#如果模块名称的开头已是 lib,则构建系统不会附加额外的前缀 lib;而是按原样采用模块名称,并添加 .so 扩展名。
LOCAL_MODULE := native-lib
#包含要构建到模块中的 C 和/或 C++ 源文件列表 以空格分开
LOCAL_SRC_FILES := native-lib.c \
c.c
#编译native-lib模块需要链接 Test模块
# Test模块是一个预编译库模块
LOCAL_SHARED_LIBRARIES :=Test
#LOCAL_LDLIBS += -llog
#构建动态库
include $(BUILD_SHARED_LIBRARY)
- c中声明并调用so中的方法
#include <jni.h>
extern int test();
//#include <android/log.h>
//如果包名中有_,为避免误解,用_1表示_
void Java_com_example_ray_demo17_1mk_MainActivity_nativeTest(JNIEnv * env, jobject instance) {
// __android_log_print(ANDROID_LOG_ERROR,"jni","libTest.so 里面的test方法:%d",test());
test();
}
- java层调用(生成的apk有两个so)
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("Test");
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nativeTest();
}
native void nativeTest();
}
- Android 6.0 以下需要引入
static {
System.loadLibrary("Test");
System.loadLibrary("native-lib");
}
- Android 6.0以上报错,指向了电脑本地地址,动态库用不了
java.lang.UnsatisfiedLinkError: dlopen failed: library "D:/workspace/Demo17_MK/app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libTest.so" not found
注意:
- 从6.0开始 使用Android.mk 如果来引入一个预编译动态库 有问题
- 在4.4上 如果load一个动态库 ,需要先将这个动态库的依赖的其他动态库load进来
- 在6.0以下 System.loadLibrary 不会自动为我们加载依赖的动态库
- 6.0以上 System.loadLibrary 会自动为我们加载依赖的动态库
三 集成静态库
使用二中的项目及配置,修改相应配置
- Android.mk中 .so改成.a,SHARED改成STATIC
#源文件在的位置。宏函数 my-dir 返回当前目录(包含 Android.mk 文件本身的目录)的路径。
LOCAL_PATH := $(call my-dir)
# $(info "LOCAL_PATH:======== ${LOCAL_PATH}");
# 预编译库的引入
include $(CLEAR_VARS)
LOCAL_MODULE := Test
LOCAL_SRC_FILES :=libTest.a
include $(PREBUILT_STATIC_LIBRARY)
#引入其他makefile文件。CLEAR_VARS 变量指向特殊 GNU Makefile,可为您清除许多 LOCAL_XXX 变量
#不会清理 LOCAL_PATH 变量
include $(CLEAR_VARS)
#存储您要构建的模块的名称 每个模块名称必须唯一,且不含任何空格
#如果模块名称的开头已是 lib,则构建系统不会附加额外的前缀 lib;而是按原样采用模块名称,并添加 .so 扩展名。
LOCAL_MODULE := native-lib
#包含要构建到模块中的 C 和/或 C++ 源文件列表 以空格分开
LOCAL_SRC_FILES := native-lib.c \
c.c
#编译native-lib模块需要链接 Test模块
# Test模块是一个预编译库模块
LOCAL_STATIC_LIBRARIES :=Test
LOCAL_LDLIBS += -llog
#构建动态库
include $(BUILD_SHARED_LIBRARY)
- 调用处进行修改
#include <jni.h>
extern int test();
#include <android/log.h>
//如果包名中有_,为避免误解,用_1表示_
void Java_com_example_ray_demo17_1mk_MainActivity_nativeTest(JNIEnv * env, jobject instance) {
__android_log_print(ANDROID_LOG_ERROR,"jni","libTest.so 里面的test方法:%d",test());
// test();
}
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nativeTest();
}
native void nativeTest();
}
- 运行正常,apk中只有一个so库,这也是动态库和静态库的区别
静态库只有使用到的,才会打包进来,打包好的库文件比较小
四 Application.mk
与Android.mk在同一目录下
# 指定运行时库 (libc )
APP_STL := c++_static
#会交给编译器的参数
APP_CPPFLAGS := -frtti -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -std=c++11 -fsigned-char -Wno-extern-c-compat
# 交给链接器的参数 (so依赖另一个so,这就需要链接 )
APP_LDFLAGS := -latomic
# 要生成的cpu架构
APP_ABI := armeabi-v7a
#解决windows命令行不支持太长的字符输入的问题
APP_SHORT_COMMANDS := true
ifeq ($(NDK_DEBUG),1)
APP_CPPFLAGS += -DCOCOS2D_DEBUG=1
APP_OPTIM := debug
else
APP_CPPFLAGS += -DNDEBUG
APP_OPTIM := release
endif