[Программирование] Интеграция библиотеки на Swift в UE4

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
09-Окт-2020 16:32

Недавно возникла задача интеграции кода, который был написан только на Swift в проект на UE4. При этом вариант "давайте быстренько перепишем все на Objective C" не рассматривался. Готового решения нигде не нашел, пришлось, как это часто бывает, копать и вширь и вглубь. Задача была успешно решена и чтобы помочь кому-то еще, решил написать туториал.
Обычно, если нужно интегрировать какой-либо специфичный для iOS/macOS платформы код, используется сборка библиотеки в виде Framework, который должен быть статический. Сам же код пишется на Objective C. Далее, зависимость прописывается в скрипте сборки проекта MyProject.Build.cs, например, так:
if (Target.Platform == UnrealTargetPlatform.IOS)
{
    string ExtraPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "../ThirdParty"));
    PublicAdditionalFrameworks.Add(
        new Framework(
            "MyFramework",
            ExtraPath + "/" + "MyFramework.framework.zip"
        )
    );
}

Для Swift можно попробовать пойти этим же путем, но возникнет проблема — зависимость от некоторых библиотек языка. Предупреждение при линковке будет выглядеть так:
ld: warning: Could not find auto-linked library 'swiftFoundation'
ld: warning: Could not find auto-linked library 'swiftDarwin'
ld: warning: Could not find auto-linked library 'swiftCoreFoundation'
ld: warning: Could not find auto-linked library 'swiftCore'
ld: warning: Could not find auto-linked library 'swiftCoreGraphics'
ld: warning: Could not find auto-linked library 'swiftObjectiveC'
ld: warning: Could not find auto-linked library 'swiftDispatch'
ld: warning: Could not find auto-linked library 'swiftSwiftOnoneSupport'

После чего последуют стандартные ошибки о том что не найдены некоторые символы в объектных файлах. Можно попробовать найти где находится каждая библиотека, упомянутая выше, и указать путь к ней через ключ L, но я решил перейти на динамический тип Framework, который сам подгрузит эти библиотеки.
Сборка проект пройдет нормально, однако при запуске приложение будет падать со знакомой iOS разработчикам ошибкой:
dyld: Library not loaded: @rpath/MyFramework.framework/MyFramework
  Referenced from: /private/var/mobile/Containers/Bundle/Application/.../MyApp.app/MyApp
  Reason: image not found

Это связано с тем, что UE4 не умеет работать с динамическим типом Framework, и не копирует его при создании пакета приложения. Это можно было бы решить путем изменения кода IOS Toolchain и сборкой своей версии движка, но хотелось всего этого избежать и на помощь пришел IOSPlugin.
Это расширение обычно используется для модификации plist файла приложения, например, добавления описания для прав доступа:
<iosPListUpdates>
    <addElements tag="dict" once="true">
        <key>NSCameraUsageDescription</key>
        <string>The camera is used for live preview.</string>
    </addElements>
</iosPListUpdates>

Нам же пригодится элемент copyDir. Он позволяет задать путь к директории, которую мы хотим скопировать, и место назначения:
<init>
    <log text="Copy MyFramwork..."/>
    <copyDir src="/.../MyFramework.framework" dst="$S(BuildDir)/Frameworks/MyFramework.framework" />
</init>

Важно, чтобы команда копирования располагалась в блоке init. После этого приложение начинает работать.
Итоговый файл MyProject.Build.cs будет выглядеть так:
using UnrealBuildTool;
using System.IO;
public class MyProject : ModuleRules
{
    public MyProject(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
        if (Target.Platform == UnrealTargetPlatform.IOS)
        {
            string ExtraPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "../ThirdParty"));
            PublicAdditionalFrameworks.Add(
                new Framework(
                    "MyFramework",
                    ExtraPath + "/" + "MyFramework.framework.zip"
                )
            );
            string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, Target.RelativeEnginePath);
            AdditionalPropertiesForReceipt.Add("IOSPlugin", Path.Combine(PluginPath, "MyProject_IOS_UPL.xml"));
        }
    }
}

А файл MyProject_IOS_UPL.xml так:
<?xml version="1.0" encoding="utf-8"?>
<root>
    <init>
        <log text="Copy MyFramework..."/>
        <copyDir src="/.../MyFramework.framework" dst="$S(BuildDir)/Frameworks/MyFramework.framework" />
    </init>
</root>

Это решение в некотором роде обходной путь, пока не появится нормальной поддержки динамического Framework в UE4, но меня оно полностью устроило.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_programmirovanie (Программирование), #_swift, #_unreal_engine, #_programmirovanie (
Программирование
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 23:50
Часовой пояс: UTC + 5