Unity 6.3
0 онлайн 53 гостей 3 в системе
Вход

Введение в нативные плагины в Unity

A нативный плагин предоставляет интерфейс на C, к которому можно обращаться из управляемых скриптов (C#).

Поддержка собственных плагинов Unity использует стандартную функцию .NET Вызов платформенного кода. Эта функция позволяет коду C# вызывать неуправляемые функции, экспортированные библиотеками собственного кода. Для передачи данных между управляемым и неуправляемым кодом используется процесс под названием marshalling.

Для примера нативного плагина, ознакомьтесь с Простейший пример плагина на Github.

Импорт собственных плагинов

Вы можете импортировать нативные плагины в проект Unity в двух основных формах:

  • Двоичные файлы, предварительно скомпилированные для конкретных платформ и архитектур CPU.
  • Файлы исходного кода, которые компилируются как часть процесса сборки вашего проекта Unity. (Чтобы использовать файлы исходного кода в качестве собственного плагина, ваш проект должен использовать IL2CPP scripting backend.)

Чтобы работать в Unity, нативный плагин должен экспортировать свои внешние функции с помощью связывания на C. Этот тип связывания позволяет избежать манипуляции именами C++ и других проблем с Application Binary Interface (ABI).

Чтобы получить доступ к неуправляемой функции из управляемого кода C#, объявляете функцию C# static extern с тем же именем и совместимыми типами возврата и параметров, а затем вызываете ее как любой другой метод. Полные правила объявления и примеры см. в Вызов функций.

Unity поддерживает предварительно скомпилированные статические библиотеки на мобильных платформах Apple (iOS, tvOS и visionOS) и на Android. Плагины, импортированные в проект Unity в виде файлов исходного кода, тоже связываются статически. Такие плагины поддерживаются в проектах с бэкендом скриптинга IL2CPP. Для скриптов редактора и для кода, выполняющегося в режиме Play, плагины из исходного кода не поддерживаются.

После импорта файлов плагина в проект Unity необходимо установить свойства, определяющие, когда библиотека должна загружаться. Для этого выберите импортированные файлы в панели Unity Project и установите соответствующие свойства в панели Inspector. Подробнее см. в Изменение параметров плагина.

Примечание: Когда вы загружаете основной плагин во время сессии Unity Editor – либо через скрипт Редактора, либо в режиме воспроизведения, Редактор не может выгрузить его. Чтобы обновить основной плагин после того, как он был загружен процессом Редактора – либо в качестве предкомпилированного двоичного файла, либо в качестве файла исходного кода, вы должны перезапустить приложение Редактора. В противном случае Редактор продолжает использовать загруженную версию плагина вместо обновленной версии.

Взаимодействие с собственным плагином

Код C#, который вы пишете в Unity, управляется временем выполнения скрипта. Время выполнения скрипта управляет тем, где данные хранятся в памяти, и регулярно перемещает данные во избежание фрагментации памяти. Неуправляемый код в собственном плагине, с другой стороны, управляет своей собственной памятью напрямую и может использовать указатели для адресации конкретных мест в памяти. Когда вы пишете управляемый код, который взаимодействует с неуправляемым кодом, вы должны внимательно относиться к тому, где хранятся данные, когда данные доступны, и какая сторона отвечает за высвобождение памяти, которая больше не требуется.

Некоторые типы данных могут быть представлены иначе в управляемом коде по сравнению с собственным кодом. .NET предоставляет марширующий интероп, который обеспечивает представление и преобразование по умолчанию для большинства типов. В ситуациях, когда поведение по умолчанию является неправильным или неоптимальным, .NET Interop Services API предоставляет следующие атрибуты, которые можно использовать для явного определения желаемого представления и преобразования для конкретных типов данных:

  • StructLayoutAttribute
  • MarshallAsAttribute
  • FieldOffsetAttribute

Дополнительные сведения см. в разделе Передача данных между управляемым и неуправляемым кодом.

Пример базового плагина

Простая библиотека на языке Си с одной функцией может иметь код, который выглядит следующим образом:

float ExamplePluginFunction ()
{
    return 5.0F;
}

Примечание: В этом минимальном примере аннотация экспорта для краткости опущена. Предкомпилированная динамическая библиотека (например, та, которая импортирована ниже с помощью [DllImport("PluginName")]) должна экспортировать свои функции. См. Вызов неуправляемых функций из управляемого кода для аннотации EXPORT_API, которая экспортирует функцию на каждой платформе.

Если вы скомпилировали этот код отдельно и импортировали скомпилированную библиотеку в ваш проект Unity, вы можете использовать следующий скрипт C# для вызова ExamplePluginFunction():

using UnityEngine;
using System.Runtime.InteropServices;

class ExampleScript : MonoBehaviour
{
    // Use the library file name for dynamically linked libraries.
    [DllImport ("PluginName")]
    private static extern float ExamplePluginFunction ();

    void Awake ()
    {
        // Calls the ExamplePluginFunction inside the plugin
        // And prints 5 to the console
        Debug.Log (ExamplePluginFunction ());
    }
}

Если вы импортируете собственный код в качестве исходного кода, то в атрибуте DllImport вместо имени библиотеки вы должны использовать __Internal:

using UnityEngine;
using System.Runtime.InteropServices;

class ExampleScript : MonoBehaviour
{
    // Use __Internal instead of the library name for source-code plug-ins.
    [DllImport ("__Internal")]
    private static extern float ExamplePluginFunction ();

    void Awake ()
    {
        // Calls the ExamplePluginFunction inside the plugin
        // And prints 5 to the console
        Debug.Log (ExamplePluginFunction ());
    }
}

См. DllImport атрибут для получения дополнительных сведений о том, как определить библиотеку основного плагина для загрузки.

Дополнительные ресурсы

Взаимодействие между управляемым и неуправляемым кодом является сложной темой. Данная документация предназначена только для краткого ознакомления с темой. Для более глубокого понимания см. следующую документацию .NET:

  • Маршаллинг интероп
  • Поведение Маршаллирования по Умолчанию
  • Маршрутизация данных с вызовами платформы

Примечание: В данной документации обсуждается модель взаимодействия Platform Invoke. Однако можно также использовать модель взаимодействия COM, обсуждаемую в документации Microsoft .NET.