Unity通过NDK实现C#与C++之间的相互调用

由于一些历史遗留问题,我们项目还在使用一套C++实现的Box2D定点数的库,由于最近修改了视野算法所以需要重新打包安卓的【.so】文件,特此记录
1、关于NDK
在Android平台,C/C++需通过NDK编译成动态链接库.so文件,然后C#中通过[DllImport(“soname”)]声明后即可调用。(我们项目使用了lua作为胶水层进行调用 原理一样但是需要单独打一个lua的so文件 在安卓平台上)windows 平台运行dll即可

C#是Unity的官方推荐的开发语言。如果某些逻辑需要C++支持以提供高性能特性,或者需要C++去跟底层硬件或者操作系统级别的接口交互,那么就需要用C#去调用C++的接口。
这往往依赖动态链接。即用C++开发动态链接库,然后C#调用动态链接库里暴露的接口。

而在Android上开发动态链接库(.so文件)的方法,就是NDK开发。
NDK,全称Native Development Kit,是Android的一种开发工具包。
目前的Android开发,不再是纯粹的Java层开发,更多的会与C/C++结合,把一些重要的方和行为以及一些私密性质的东西放在C/C++中,通过NDK将其编译成.so动态库文件,放入工程中的libs目录。
2.版本
注意需要下载的版本。如果你的NDK同时也为Unity的IL2cpp服务,那就需要注意Unity对NDK的版本有硬性要求,比如2018的版本要求 NDK r16b的版本
下载地址
在这里插入图片描述
下载下来的压缩包,解压之后会得到如下目录:
在这里插入图片描述
最重要的是那个叫做 ndk-build.cmd 的脚本文件。它是一个基于make的构建脚本。查看它的源码你会发现它实际上执行的是:
在这里插入图片描述
为了能够在全局使用这个脚本,你最好将这个目录加入到环境变量中,也可以在这个目录打开cmd 看个人习惯
3.利用NDK构建.so
现在开始利用NDK构建.so文件,目的是在.so文件中暴露一个函数给C#调用。这个函数是自定义的加法函数,它会将两个整型相加,再返回结果。

class  MyClass
{
	public:
    static float AddFloat(float a, float b)
    {
        return a + b;
    }
 
};


extern "C"
{
	float AddFloat(float a,float b)
	{
		return MyClass::AddFloat(a,b);
	}
}

我们将在这个文件所在的目录下运行ndk-build.cmd,在此之前,我们还需要两个文件:Android.mk 和 Application.mk。这两个文件将包含 ndk-build 所需要的所有配置。两个文件的内容如下:
Android.mk

LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_MODULE    := gh_so
LOCAL_SRC_FILES := \
cs_call_c.c \
cs_call_cpp.cpp \
cpp_call_cs.h \
cpp_call_cs.cpp \
java_call_cpp.cpp \
cpp_call_java.cpp
 
include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_STL := c++_static
APP_CPPFLAGS := -frtti -std=c++11
APP_PLATFORM := android-19
APP_CFLAGS += -Wno-error=format-security
APP_BUILD_SCRIPT := Android.mk
APP_ABI := armeabi-v7a x86

Android.mk 为 ndk-build描述了构建所需的源代码,链接库等信息。

变量 描述
LOCAL_PATH 这个变量描述了构建所需的源代码在当前工程中的相对位置。如果你是使用Android Studio进行开发,那源代码一般位于工程的 app/src/main/cpp 目录下。$(call my-dir) 返回Android.mk所在的目录。
CLEAR_VARS 将一个特殊的Makefile文件包含进来。CLEAR_VARS定义了这个文件的位置。这个Makefile文件会清除所有之前定义过的Android.mk变量,一般都以LOCAL_开头
LOCAL_MODULE ndk-build构建出来的库的名称,如果设定的名称没有以lib开头,则ndk-build会自动为你加这个前缀。例如,上面定义的名称将构建出来一个叫gh.so的库
LOCAL_C_INCLUDES 当你的代码中include一些文件不在默认的搜索路径时,你可以使用这个变量去指定。一般来说,标准c头文件,和一些常见的Android头文件,都是在默认的搜索路径中的,他们都可以在你下载的NDK工具包中找得到
LOCAL_SRC_FILES 需要构建的源文件(不包含头文件)都需要放到这里面
LOCAL_CFLAGS 这个变量定义一些ndk-build的编译选项,一般来说,不需要额外的设置
BUILD_SHARED_LIBRARY 将一个特殊的构建文件包含进来。BUILD_SHARED_LIBRARY定义了这个文件的位置。该文件会收集你在定义的所有上述LOCAL_开头的变量所包含的信息,然后确定如何从源文件中构建动态链接库。这个构建脚本要求你至少定义了LOCAL_MODULE和LOCAL_SRC_FILES两个变量。

Application.mk 为ndk-build描述了项目的构建性质。

|APP_STL | 需要使用哪些C++标准库 |
|APP_CPPFLAGS | 项目中,C++部分使用的编译选项 |
|APP_PLATFORM | 构建的Android API级别,对应于应用程序的min SDK Version |
|APP_CFLAGS | 项目中,C/C++部分使用的编译选项 |
|APP_BUILD_SCRIPT | Android.mk 文件所在的位置 |
|APP_ABI | 需要为哪些abi机器构建共享库 |

然后我们在终端输入以下命令:

ndk-build.cmd NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk

在这里插入图片描述
你会得到一个libs目录和一个obj中间文件暂存目录。libs目录里面就是对应你所设置的abi平台对应的两种架构的so文件
在这里插入图片描述

将so拷贝到Unity工程中的Assets/Plugins/Android/libs目录中
将我们打包出来的.so文件放到上述的目录下。因为不同abi的共享库名称都一样,为避免冲突,我们拷贝它的任意父目录即可。无论.so存放到哪儿,Unity都会识别出这个共享库属于哪个abi平台的。项目目录结构如下
在这里插入图片描述
4.通过DllImport调用

using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;

public class CsCallCCPP_DllImport_SO : MonoBehaviour
{
    public Text txt;
    public Button btn1;
    public Button btn2;

    void Start()
    {
        btn1.onClick.AddListener(() => 
        {
            //C#调用C
            txt.text = "C#调用C接口: AddInt(2, 6) = " + AddInt(2, 6);
        });

        btn2.onClick.AddListener(() => 
        {
            //C#调用C++
            txt.text = "C#调用C++接口: AddFloat(2.7, 4.2) = " + AddFloat(2.7f, 4.2f);
        });


    }

    //C接口
    [DllImport("gh_so")]
    public static extern int AddInt(int a, int b);

    //C++接口
    [DllImport("gh_so")]
    public static extern float AddFloat(float a, float b);
}

5.打包调用
在这里插入图片描述

相关推荐

  1. C++---string字符数组之间相互转换

    2024-07-10 08:48:06       19 阅读
  2. C++ Qt:QString数字之间相互转换

    2024-07-10 08:48:06       13 阅读
  3. nodejs 实现内部之间接口相互调用

    2024-07-10 08:48:06       45 阅读
  4. C++/CLI学习笔记3(快速打通c++c#相互调用桥梁)

    2024-07-10 08:48:06       19 阅读
  5. C++/CLI学习笔记8(快速打通c++c#相互调用桥梁)

    2024-07-10 08:48:06       23 阅读
  6. C++/CLI学习笔记1(快速打通c++c#相互调用桥梁)

    2024-07-10 08:48:06       24 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 08:48:06       4 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 08:48:06       5 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 08:48:06       4 阅读
  4. Python语言-面向对象

    2024-07-10 08:48:06       4 阅读

热门阅读

  1. 技术浅谈:如何入门一门编程语言

    2024-07-10 08:48:06       6 阅读
  2. C#如何进行深度学习对行人进行识别?

    2024-07-10 08:48:06       8 阅读
  3. 金南瓜科技的SECS/GEM解决方案

    2024-07-10 08:48:06       12 阅读
  4. Linux 系统监控工具深度解析:Glances 与 Nmon

    2024-07-10 08:48:06       7 阅读
  5. 使用YOLO5进行模型训练机器学习【教程篇】

    2024-07-10 08:48:06       13 阅读
  6. IT专业入门,高考假期预习指南

    2024-07-10 08:48:06       10 阅读
  7. 强化OT安全英国发布工控网络事件响应实践指南

    2024-07-10 08:48:06       15 阅读
  8. 使用静态图加速

    2024-07-10 08:48:06       7 阅读
  9. 修改ES索引名称

    2024-07-10 08:48:06       8 阅读
  10. asp.netWebForm(.netFramework) CSRF漏洞

    2024-07-10 08:48:06       10 阅读
  11. Redis的使用(三)常见使用场景-session共享

    2024-07-10 08:48:06       8 阅读