记录一次使用NDK不使用Android Studio交叉编译C++代码

android里面有mk文件去使用原生代码,但还没试过,

如果要复制代码,务必删掉注释。代码里的注释格式都是c风格的 “//注释”,但下面基本没有c代码,因为是随手写的,所以并不正确,会导致错误。

 

概述就是如下三步

1.编写jni,提供java可调用的原生方法

2.编译c++代码为安卓可用的so库

3.使用原生方法

 

1:使用swig,是c++自动生成jni文件以及接口,省去大量人力。

----下载swigwin,给swig.exe配置path环境变量

----编写脚本:只写了一点点自己用到的,更详细的去swig官网看文档吧。3.0版本链接http://www.swig.org/Doc3.0/SWIGDocumentation.html#CONTENTS

swig是脚本语言,务必注意顺序,举个顺序错误的例子:

%include "VTManager.h"

%include <std_string.i>

因为先处理VTManager.h,再添加std_string的操作,所以VTManager.h里的string就不会被识别,会变成SWIGTYPE_p_std_string这个错误类型。

%module(directors="1") ChcVtCore_swig //“ChcVtCore_swig”是生成文件名,可修改,其他不改
//%{   %}  里面是引用的头文件,注意是#开头
%{
#include "ParseDef.h"
#include "ObjectPool.h"
#include "ParseDataList.h"
#include "VTManager.h"
%}

//%include 注意是%开头  外面是要暴露给java的头文件,而*.i是swig自己脚本头文件,仅仅是添加一些操作
//添加<std_string.i> 可以转换string,不然string会变成SWIGTYPE_p_std_string类型
%include <std_vector.i>
%include <stdint.i>
%include <windows.i>
%include <std_string.i>

//重命名命令。%(firstuppercase)s 是首字母大写。%$isclass是仅修改类名,""是默认参数。
%rename("%(firstuppercase)s", %$isclass) "";

//要暴露给java的头文件
%include "ParseDef.h"
%include "ObjectPool.h"
%include "ParseDataList.h"
%include "VTManager.h"

//使用vector必须使用 %include <std_vector.i> 
//在搭配%template(类名)std::vector<列表对象名>;
%template(ObjectDataVector) std::vector<chcVT::SubObject>;
%template(CharDataVector) std::vector<uint8_t>;
%template(LanguagesDataVector) std::vector<uint16_t>;
%template(SubPointVector) std::vector<chcVT::SubPoint>;
%template(ActGraphicDataVector) std::vector<chcVT::ActGraphic>;
%template(ObjectIndexVector) std::vector<chcVT::ObjectIndex>;

得到一堆java文件,和一个cxx,这个cxx就是java中使用的c接口,也就是编写好的jni文件,

 

2.使用cmake + 交叉工具链 编译,这些ndk都提供了。CmakeLists要自己写。

CmakeLists.txt是组织和编译cpp和h的文件,名字不要错,cmake是要找这个文件的

cmake是跨平台编译器,如果目标是vs,会生成sln。我们的目标是android。

切记放入上面生成的cxx,jni是通道,不然java到不到c函数入口。

project(CGALhellworld) //项目名称,如果目标是vs,会是sln的名称
cmake_minimum_required(VERSION 3.1) //版本申明
 
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_compile_options(-fPIC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fpic") //cmake.exe的环境变量。具体百度cmake配置
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpic")


include_directories(./3rdParty/windows/include)//include路径
aux_source_directory(./AreaCaculate  Allcpp )//添加AreaCaculate这个文件夹下的所有cpp,并命名为allcpp
link_directories(./3rdParty/android/lib/32) //添加静态库路径

//add_library是生成库的意思,生成exe是add_execute
add_library(
AreaCaculate //库名/程序名
SHARED //共享库
${Allcpp})//放入cpp,可以使用绝对路径一个一个写
set_property(TARGET AreaCaculate PROPERTY POSITION_INDEPENDENT_CODE ON)


target_link_libraries(AreaCaculate liblog.so)//添加所需静态库(目标名  库名),这个是log库。可以在c++里直接写loge打印日志

bat脚本:camke编译 省得每次都输入了。

//ndk路径储存为一个变量
SET ANDROID_NDK=D:\mysdk\android-ndk-r14b


//新建一个文件夹,作为编译的场所,可以删掉
rmdir /S /Q build_android
mkdir build_android && cd build_android

//使用cmake编译,具体参数如下
//DCMAKE_TOOLCHAIN_FILE 是交叉工具链,使用相对路径指向ndk
//DANDROID_ABI :目标abi ,armeabi-v7a就是32位arm
//DANDROID_NATIVE_API_LEVEL :安卓版本
//DANDROID_TOOLCHAIN_NAME
//DCMAKE_MAKE_PROGRAM:编译器路径,使用相对路径指向ndk

D:\mysdk\cmake-3.12.0-rc1-win64-x64\bin\cmake.exe -G"MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=%ANDROID_NDK%\build\cmake\android.toolchain.cmake -DANDROID_STL=gnustl_static -DANDROID_ABI="armeabi-v7a" -DANDROID_NDK=%ANDROID_NDK% -DANDROID_NATIVE_API_LEVEL=android-21 -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows-x86_64\bin\make.exe" ..
D:\mysdk\cmake-3.12.0-rc1-win64-x64\bin\cmake.exe --build .

在bat脚本所在文件夹,按住shift然后右键,打开shell,输入./bat文件名.bat。即可开始编译,可以看是否有报错。

 

3.java项目里可以放入java,开始使用c的方法。

 

 

PS:使用log调试:

在c中添加jni和log头文件,arm处理器的在  ndk\platforms\android-14\arch-arm\usr\include

然后添加一个方便的宏

#ifndef __CLOG_H__
#define __CLOG_H__

#ifdef ANDROID
#ifndef _NO_LOG
#include <android/log.h>
#include <jni.h>

#define LOGI(tag, fmt, args...) __android_log_print(ANDROID_LOG_INFO,  tag, fmt, ##args)
#define LOGD(tag, fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, tag, fmt, ##args)
#define LOGE(tag, fmt, args...) __android_log_print(ANDROID_LOG_ERROR, tag, fmt, ##args)
#else
#define LOGI(tag, fmt, args...)
#define LOGD(tag, fmt, args...)
#define LOGE(tag, fmt, args...)
#endif



#else
#define LOGI(tag,fmt,args,...)
#define LOGD(tag,fmt,args,...)
#define LOGE(tag,fmt,args,...)
#endif

#endif//__CLOG_H__

还有cmake里面,链接上log库,这个只是头文件。完成之后就可以c里面直接写 日志了

LOGE("this is tag","this is log cintext");

 

 


版权声明:本文为qq_29377179原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。