AndroidNDK开发使用Cmake编译生成so文件 您所在的位置:网站首页 安卓反编译工具 AndroidNDK开发使用Cmake编译生成so文件

AndroidNDK开发使用Cmake编译生成so文件

#AndroidNDK开发使用Cmake编译生成so文件| 来源: 网络整理| 查看: 265

AndroidNDK开发使用Cmake编译生成so文件

最近做串口开发需要编译不同的so文件,于是查找了各种资料,学习了一下so编译.

1.添加Cmake文件: cmake_minimum_required(VERSION 3.4.1) //cmake版本 ​ include_directories(src/main/jni/serial_port)   //引入的jni文件路径 aux_source_directory(src/main/jni SRC_FILE) //src文件路径 ​ add_library(serial_port SHARED ${SRC_FILE}) find_library(log-lib log) ​ target_link_libraries(serial_port ${log-lib}) 复制代码

image.png

2.添加Cmake依赖: externalNativeBuild {    cmake {        cppFlags "" ​        abiFilters "arm64-v8a","armeabi-v7a"//生成的so平台类型 ​   } } 复制代码 externalNativeBuild {    cmake {        path 'CMakeLists.txt'//Cmake地址   } } 复制代码

image.png

3.jni文件如下:

image.png

4.Android.mk文件: # # Copyright 2009 Cedric Priscal # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ​ LOCAL_PATH := $(call my-dir) ​ include $(CLEAR_VARS) ​ TARGET_PLATFORM := android-3 LOCAL_MODULE   := serial_port  //模块名称 LOCAL_SRC_FILES := SerialPort.c LOCAL_LDLIBS   := -llog ​ include $(BUILD_SHARED_LIBRARY) 复制代码 5.Application.mk文件 APP_ABI := arm64-v8a,armeabi-v7a//配置abi平台 复制代码 6.SerialPort.c文件: /* * Copyright 2009-2011 Cedric Priscal * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ ​ #include #include #include #include #include #include #include ​ #include "SerialPort.h" ​ #include "android/log.h" static const char *TAG="serial_port"; #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args) #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) ​ static speed_t getBaudrate(jint baudrate) {   switch(baudrate) {   case 0: return B0;   case 50: return B50;   case 75: return B75;   case 110: return B110;   case 134: return B134;   case 150: return B150;   case 200: return B200;   case 300: return B300;   case 600: return B600;   case 1200: return B1200;   case 1800: return B1800;   case 2400: return B2400;   case 4800: return B4800;   case 9600: return B9600;   case 19200: return B19200;   case 38400: return B38400;   case 57600: return B57600;   case 115200: return B115200;   case 230400: return B230400;   case 460800: return B460800;   case 500000: return B500000;   case 576000: return B576000;   case 921600: return B921600;   case 1000000: return B1000000;   case 1152000: return B1152000;   case 1500000: return B1500000;   case 2000000: return B2000000;   case 2500000: return B2500000;   case 3000000: return B3000000;   case 3500000: return B3500000;   case 4000000: return B4000000;   default: return -1;   } } ​ /* * Class:     android_serialport_SerialPort * Method:   open * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; */ JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags) {   int fd;   speed_t speed;   jobject mFileDescriptor; ​   /* Check arguments */   {      speed = getBaudrate(baudrate);      if (speed == -1) {         /* TODO: throw an exception */         LOGE("Invalid baudrate");         return NULL;     }   } ​   /* Opening device */   {      jboolean iscopy;      const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);      LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);      fd = open(path_utf, O_RDWR | flags);      LOGD("open() fd = %d", fd);     (*env)->ReleaseStringUTFChars(env, path, path_utf);      if (fd == -1)     {         /* Throw an exception */         LOGE("Cannot open port");         /* TODO: throw an exception */         return NULL;     }   } ​   /* Configure device */   {      struct termios cfg;      LOGD("Configuring serial port");      if (tcgetattr(fd, &cfg))     {         LOGE("tcgetattr() failed");         close(fd);         /* TODO: throw an exception */         return NULL;     } ​      cfmakeraw(&cfg);      cfsetispeed(&cfg, speed);      cfsetospeed(&cfg, speed); ​      if (tcsetattr(fd, TCSANOW, &cfg))     {         LOGE("tcsetattr() failed");         close(fd);         /* TODO: throw an exception */         return NULL;     }   } ​   /* Create a corresponding file descriptor */   {      jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");      jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V");      jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");      mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);     (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);   } ​   return mFileDescriptor; } ​ /* * Class:     cedric_serial_SerialPort * Method:   close * Signature: ()V */ JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close (JNIEnv *env, jobject thiz) {   jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);   jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); ​   jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");   jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); ​   jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);   jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); ​   LOGD("close(fd = %d)", descriptor);   close(descriptor); } ​ jstring Java_com_example_compilesodemo_MainActivity_sayHello(JNIEnv* env,jobject jobj){   char* text="I am from C";   return (*env)->NewStringUTF(env,text); } 复制代码 7.SerialPort.h文件: /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class android_serialport_api_SerialPort */ ​ #ifndef _Included_android_serialport_api_SerialPort #define _Included_android_serialport_api_SerialPort #ifdef __cplusplus extern "C" { #endif /* * Class:     android_serialport_api_SerialPort * Method:   open * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; */ JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open (JNIEnv *, jclass, jstring, jint, jint); ​ /* * Class:     android_serialport_api_SerialPort * Method:   close * Signature: ()V */ JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close (JNIEnv *, jobject); ​ ​ #ifdef __cplusplus } #endif #endif 复制代码 8.运行项目:

直接跑项目或者使用gradle构建so生成的so文件如下:这里大家根据自己的需求配置生成不同的so文件

image.png

9.项目中引入so文件:

如果不引入so文件初始化和调用时会报错,提示找不到so文件,

image.png

image.png

10.Java调用so的测试代码如下: public class MainActivity extends AppCompatActivity {    private static final String TAG = MainActivity.class.getName(); ​   {        System.loadLibrary("serial_port");//加载so库   } ​    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();   } ​    private void initView() {        TextView textView = ((TextView)findViewById(R.id.tv_test));        textView.setText(sayHello());        Log.d(TAG,"-----传入的数据为:------"+ textView.getText().toString());   } ​    public native String sayHello();//调用jni方法 } 复制代码 11.运行效果如下:

image.png

12.打印日志如下:

image.png

13.总结:

可以看到项目demo成功运行,期前也遇到不少问题,so的加载和调用,jni初始化,数据传递等等,如果有兴趣的同学可以自己去试试,学到手的东西才是自己的。本文是以串口通信的so为例,所以里面的头文件及数据调用的方法都是在加载串口数据,不过我为了测试所以暂时只写了一个简单的,因为测试串口需要设备和串口通信助手,这里先不讲,后面有空会逐一讲解串口通信流程和实战demo.

14.项目源码如下:

gitee.com/jackning_ad…



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有