思路

1.在linux环境编译交叉编译so库

2.在Android Studio创建包含C++的工程

3.在Android工程中引用so库,在C++中利用JNI编写java可以调用的API

编译so库

编译之前先了解以下Android系统的运行环境,从CPU分为以下几类:

1.armeabiv-v7a: 第7代及以上的 ARM 处理器

2.arm64-v8a: 第8代、64位ARM处理器

3.armeabi: 第5代、第6代的ARM处理器

4.x86: 平板、模拟器用得比较多(android studio模拟器用的就是x86)

5.x86_64: 64位的平板

将手机与电脑adb连接,输入cat  /proc/cpuinfo查看手机cpu架构,一般arm64-v8a向下兼容armeabiv-v7a、armeabi,现在的手机大多都是arm64-v8a架构。

 

NDK下载:https://developer.android.google.cn/ndk/downloads/

libuv的交叉编译比较方便,下载安装gyp即可,参考https://github.com/libuv/libuv/blob/master/README.md

NDK里有对应不同CPU架构的编译器, 用build/tools/make-standalone-toolchain.sh安装NDK编译器,也可用绝对路径直接使用NDK包里的工具,下面是脚本参数

安装后将安装的路径添加到PATH里就可以使用了。

编译过程中提示arm-linux-androideabi/bin/ld: fatal error: test: Input/output error,原因:虚拟机共享文件中编译所致。

编译时切换成root权限会少很多问题。

加载so库

使用Android Studio创建包含C++工程(版本3.3.0)

cpp就是java要调用的api文件,CMakeLists.txt是编译cpp的配置文件:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)
set(CURRENT_DIR ${CMAKE_SOURCE_DIR})
message("CURRENT_DIR" ${CMAKE_SOURCE_DIR})
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        ${CURRENT_DIR}/native-lib.cpp )
add_library( uv
        SHARED
        IMPORTED)

set_target_properties( uv
        PROPERTIES IMPORTED_LOCATION
        ${CURRENT_DIR}/../../../libs/armeabi-v7a/libuv.a )

add_library( net
        SHARED
        IMPORTED)

set_target_properties( net
        PROPERTIES IMPORTED_LOCATION
        ${CURRENT_DIR}/../../../libs/armeabi-v7a/libnet.so )



set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

include_directories(${CURRENT_DIR}/../../../libs/include)

target_link_libraries( # Specifies the target library.
        native-lib
        net
        uv
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib} )

cpp文件:

#include <jni.h>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>

#include "CommunicationFunction.h"
#include "CommunicationInterface.h"
#include "uv.h"
extern "C"
{
void *ghander = NULL;

void link_state_cb(void* hander, CmciLinkConfigStruct stCmciLinkConfig, CmciLinkStateEnum enCmciLinkState)
{
    if(enCmciLinkState == CMCI_LINK_STATE_SUCCESS)
    {
        ghander = hander;
        __android_log_print(ANDROID_LOG_DEBUG,"libuv","hander = %d \n",hander);
    }
    else
    {
        hander = NULL;
    }
}

void tcp_read_cb(void* hander, SYS_PBUFFER pBuffer, SYS_U32 u32BufferSize)
{
    for(int i = 0; i < u32BufferSize; i++)
    {
        __android_log_print(ANDROID_LOG_DEBUG,"libuv","%02x \n",pBuffer[i]);
    }

}


JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */)
{
    //std::string hello = "Hello from C++";
    const char *ver = uv_version_string();
    //return env->NewStringUTF(hello.c_str());
    return env->NewStringUTF(ver);
}
void* net_server(void *)
{
    while(1)
    {
        usleep(1000);
        Cmci_PocessMsg();

    }
}
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_netInit(JNIEnv* env, jobject /* this */, jstring ip, jint port)
{
    int flag = 0;
    char buf[5] = "1234";
    const char *tmp_ip = env->GetStringUTFChars(ip,0);
    if (tmp_ip == NULL)
    {
        return;
    }

    int len = strlen(tmp_ip);
    CmciLinkConfigStruct client;
    memset(&client,0, sizeof(client));
    client.enProtocal = CMCI_PRTL_TYPE_TCP;
    client.enLinkType = CMCI_LINK_TYPE_CLIENT;
    client.stTcpConfigClient.enProtocal = CMCI_PRTL_TYPE_IPV4;
    client.stTcpConfigClient.i32Port = port;
    pthread_t net_id;
    pthread_create(&net_id, NULL, net_server, NULL);
    for(int i = 0; i < len; i++)
    {
        client.stTcpConfigClient.ui8ServiceIP[i] = tmp_ip[i];
    }
    Cmci_Init();
    Cmci_RegisterLinkStateCB(link_state_cb);
    Cmci_RegisterReadCB(tcp_read_cb);
    Cmci_StartLink(client);

    sleep(1);
    Cmci_Write(ghander,buf,4);

    return;
}
}



创建tcp连接时失败,调查发现是因为工程中未添加相关权限,AndroidManifest.xml添加:

<uses-permission android:name="android.permission.INTERNET"/>

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐