美文网首页
Android Studio手动配置Makefile、CMake

Android Studio手动配置Makefile、CMake

作者: CaoMeng | 来源:发表于2018-11-14 12:24 被阅读144次

前言:

在Ubutu上编译出来的.so文件,怎么添加到Android项目中去使用呢?目前:可以通过
Makefile方式和CMake方式引入预编译静动态库(静态库.a 动态库.so)到项目中去使用。就目前而言CMake是Goole推荐使用方式,但是加入接手一个老的NDK项目是MakeFile方式,看不懂就GePi了,所以这里我们还是介绍一下MakeFile方式将静动态库加入到AS中,完成NDK项目的开发。废话不多说,直接撸步骤了:

一、创建一个普通工程

1、在src/main目录下创建一个ndkBuild文件夹
2、在此文件中创建一个Android.mk文件

用于配置相关信息

3、在此文件中创建一个test.c的源文件

备注:创建文件是注意选择源文件类型为.c的文件(本人在这里比较傻逼,选择的c++,但是后缀名改成.c,编译的时候老是失败)

4、将编译好的的.so库复制到src/main目录下
如图所示目录结构:

image.png
二、配置相关Makefile信息

1、编辑Android.mk文件

LOCAL_PATH := $(call my-dir)
#预编译库的引入 (提前编译好的库)
include $(CLEAR_VARS)
LOCAL_MODULE := Main
LOCAL_SRC_FILES := libMainTest.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := test.c
# 编译hello-jni模块 需要链接 Test 模块
# Test模块是一个预编译库模块
LOCAL_STATIC_LIBRARIES := Main
include $(BUILD_SHARED_LIBRARY)

2、编辑grade(app)文件

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "com.cd.empsun.makefile"
        minSdkVersion 18
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        //设置好
        externalNativeBuild{
            ndkBuild{
                abiFilters 'armeabi-v7a'
            }
        }
    }
    //引入Android.mk的路径
    externalNativeBuild{
        ndkBuild{
            path 'src/main/ndkBuild/Android.mk'
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

3、编辑test.c文件

#include <jni.h>
//引入预编译动态库的方法进行调用
extern int main(int a);
JNIEXPORT int JNICALL
Java_com_cd_empsun_makefile_MainActivity_nativeTest(JNIEnv *env, jobject instance) {
    return main(23);
}

4、使用编译好的.so库里面的函数

public class MainActivity extends AppCompatActivity {
    //加载动态库
    static {
        System.loadLibrary("MainTest");
        System.loadLibrary("test");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e("TAG",nativeTest()+"");
    }
    native int nativeTest();
}

本结果运行在Android 5.1 系统上

01-15 01:23:17.506 6650-6650/com.cd.empsun.makefile E/TAG: 26

再次运行在Android 8.0系统上

Process: com.cd.empsun.makefile, PID: 28444 
java.lang.UnsatisfiedLinkError: dlopen failed: library "D:/Demo/Demo_mk/app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libMainTest.so" not found
at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
at java.lang.System.loadLibrary(System.java:1660)
at com.cd.empsun.makefile.MainActivity.<clinit>(MainActivity.java:10)
at java.lang.Class.newInstance(Native Method)
at android.app.Instrumentation.newActivity(Instrumentation.java:1178)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3082)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3302)
at android.app.ActivityThread.-wrap12(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1891)
at android.os.Handler.dispatchMessage(Handler.java:108)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7425)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

报错提示:没有找到libMainTest.so库文件
通过ndk-denpends.exe工具查看test.so依赖情况发现
1、在AS上打开Terminal工具进入NDK所在盘(本人NDK安装目录是在C盘)
输入:c:
输入:cd C:\Users\chen\AppData\Local\Android\Sdk\ndk-bundle
提前将build好的apk包解压出来,将编译好的libtest.so库复制进ndk-depends.cmd所在的目录下
输入:ndk-depends.cmd libtest.so

Terminal输出的信息
C:\Users\chen\AppData\Local\Android\Sdk\ndk-bundle>ndk-depends.cmd libtest.so
WARNING: Could not find library: D:/Demo/Demo_mk/app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libMainTest.so
libtest.so
libstdc++.so
libm.so
libdl.so
libc.so
D:/Demo/Demo_mk/app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libMainTest.so
C:\Users\chen\AppData\Local\Android\Sdk\ndk-bundle>

看以清楚知道,其实我们的APK包里面就没有libMainTest.so库,所以APP在8.0上会出现奔溃的现象。so...

从6.0开始 使用Android.mk 如果来引入一个预编译动态库 存在问题
在4.4上 如果load一个动态库 ,需要先将这个动态库的依赖的其他动态库load进来
在6.0以下 System.loadLibrary 不会自动为我们加载依赖的动态库
在6.0以上 System.loadLibrary 会自动为我们加载依赖的动态库
这个问题不好兼容,怎么办呢?
1、使用静态库
2、使用CMake

三、配置CMake

1、在src/main目录下创建一个cmake文件夹
include:里面包含需要一些头文件
cmakeTest.c:需要编译的源文件
2、在app目录下创建一个文件:CmakeLists.txt

# 指定cmake最小支持版本的方法
cmake_minimum_required(VERSION 3.6)
# -I 引入相关头文件
include_directories(src/main/cmake/include)
#引入 XX 目录的cmakelist #add_subdirectory(XX)

file(GLOB source src/main/cmake/*.c src/main/cmake/*.cpp src/main/cmake/a/*.cpp )
# cmakeTest: 变量名 最终会生成的so名字
# SHARED: 动态库  STATIC:静态库
add_library(cmakeTest SHARED ${source})

# 有问题!!!
#add_library(Test2 SHARED IMPORTED)
#set_target_properties(Test2 PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libTest.so)
#和makefile不同,cmake 有其他办法引入动态库 让他没问题
# c++: CMAKE_CXX_FLAGS
# set 方法 定义一个变量
#CMAKE_C_FLAGS = "${CMAKE_C_FLAGS} XXXX"
# -L: 库的查找路径 libTest.so
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}")

# 链接   (不能换位置)
# 要生成的目标 so
# 编译hello-jni模块 需要链接(依赖) Test 模块
target_link_libraries(cmakeTest MainTest  log)

3、编辑grade(app)

    defaultConfig {
        applicationId "com.cd.empsun.makefile"
        minSdkVersion 18
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        externalNativeBuild{
//            ndkBuild{
//                abiFilters 'armeabi-v7a'
//            }
            cmake{
                abiFilters 'armeabi-v7a'
            }
        }
    }

    externalNativeBuild{
//        ndkBuild{
//            path 'src/main/ndkBuild/Android.mk'
//        }
        cmake{
            path 'CMakeLists.txt'
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

4、编辑cmakeTest.c文件

#include <jni.h>
extern int main();
JNIEXPORT jint JNICALL
Java_com_cd_empsun_makefile_MainActivity_nativeTest(JNIEnv *env, jobject instance) {
    return main(200);
}

4、引用编译好的libcmakeTest.so

public class MainActivity extends AppCompatActivity {
    static {
        //System.loadLibrary("MainTest");
        System.loadLibrary("cmakeTest");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e("TAG",nativeTest()+"");
    }
    native int nativeTest();
}

Android 8.0.0系统:

11-14 14:25:10.587 8103-8103/com.cd.empsun.makefile E/TAG: 202

Android 5.1.1系统:

01-15 05:45:27.817 14814-14814/com.cd.empsun.makefile E/TAG: 202

相关文章

网友评论

      本文标题:Android Studio手动配置Makefile、CMake

      本文链接:https://www.haomeiwen.com/subject/elplfqtx.html