UE4 開發之如何建立 iOS 平臺外掛
前言
在前倆篇文章中,我與大家分享了 UE4 開發如何配置 Xcode 的除錯環境以及如何實現 UE4 引擎的按鈕事件的響應,其實寫這倆篇文章的目的就是為接下來的文章做一個引子,就好比是高階餐廳的前菜一樣,接下來我們就要進入到正餐部分了.
既然 UE4 引擎具有跨平臺的特性,那是否真的能像很多跨平臺的開發工具所說的一樣:Write once, run everywhere 呢!我調研過市面上主流的幾個跨平臺開發工具,也自己動手搭建過環境並寫了幾個 Demo,我只想跟大家說:誰用誰知道(捂臉笑)。
每個平臺都有自己的特性,要想做到一份程式碼適配所有平臺的難度是非常大的,因為我們不能保證每個功能都做到完美適配,所以怎麼去解決當前面臨的窘境呢!那就是我們要儘量減少跨平臺功能的數量,只保證我們的核心功能在各個平臺上能完美的適配,把一些輔助功能模組例如:登入,分享,資料採集等模組做成外掛的方式整合到我們的專案中,這些外掛都是用各個平臺的原生程式碼開發的,iOS 平臺就用 OC 或者 swift 開發,Android就用 java 或者 kotlin 開發,所以完全就不用去考慮它的平臺相容性問題了。
那接下來我們就開始今天的教程吧!
作為一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是一個我的iOS交流群:812157648,不管你是小白還是大牛歡迎入駐 ,分享BAT,阿里面試題、面試經驗,討論技術, 大家一起交流學習成長!
UE4 開發之如何建立 iOS 平臺外掛
UE4 為我們廣大開發者提供了眾多的外掛供我們使用,正是有了這些外掛的存在,才讓遊戲開發變得更快更簡單,今天我跟大家分享一下如何編寫 UE4 外掛。
建立 UE4 外掛
- 在 UE 編輯器中,開啟選單欄中的編輯下拉選單,選擇外掛選項
- 選擇右下角的新外掛
- 選擇截圖上的 “第三方庫”, 並填寫外掛名稱,例如我起的為 “JJLoginNail”,以及填寫作者以及描述
- 建立完成後,會在你的 Xcode 工程中自動引用一個 Plugins 資料夾
處理第三方的 Framework
用於測試,我自建了一個 iOS 靜態庫: TestLoginSDK.framework, 裡面包含一個顯示使用者登入介面的介面,以及回撥賬戶名的回撥,參考程式碼如下:
@protocol TestLoginDelegate <NSObject> - (void)OnLoginResult:(NSString *)result; @end @interface JJLoginController : NSObject + (void)showLoginView:(UIViewController *)baseView JJCallBack:(id<TestLoginDelegate>) delegate; @end
- 在 ThirdParty 資料夾下建立 iosframeworks 資料夾,隨後再該資料夾下建立 iosextend.embeddedframework 資料夾,並將第三方的 framework 放入其中
- 將 iosextend.embeddedframework 新增到 .zip 壓縮檔案
- 將 iosframeworks 引入到 Xcode 工程中
前期準備做好以後,我們現在進入到正式的敲程式碼階段.
編碼階段
- 在 Source 資料夾中外掛為我們建立了以下原始檔
- 開啟 JJLoginNail.Build.cs,配置我們的第三方 framework 路徑,配置資訊如下:
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class JJLoginNail : ModuleRules
{
public JJLoginNail(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"JJLoginNailLibrary",
"Projects",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
if (Target.Platform == UnrealTargetPlatform.IOS){
PublicAdditionalFrameworks.Add(
new Framework(
"TestLoginSDK",
"../ThirdParty/iosframeworks/iosextend.embeddedframework.zip"
)
);
}
}
}
- 開啟 JJLoginNail.h 標頭檔案,加入我們呼叫 API 的邏輯,以及處理回撥的邏輯:
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Modules/ModuleManager.h"
#if PLATFORM_IOS
#import <TestLoginSDK/TestLoginSDK.h>
//用於處理 sdk 返回的回撥
@interface FTestLoginResultModule : NSObject<TestLoginDelegate>
@end
#endif
class FJJLoginNailModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
/// 顯示登入介面
void showLogin();
private:
/** Handle to the test dll we will load */
void* ExampleLibraryHandle;
};
注意點:
其中我們的 OC 類別需要用 PLATFORM_IOS 巨集包起來,並 import 我們所需要的第三方framework。
- 開啟 JJLoginNail.cpp 檔案,實現上一步標頭檔案中定義的介面以及在 OC 類中實現回撥函式
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "JJLoginNail.h"
#include "Core.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/IPluginManager.h"
#include "JJLoginNailLibrary/ExampleLibrary.h"
#define LOCTEXT_NAMESPACE "FJJLoginNailModule"
#if PLATFORM_IOS
#include "IOSAppDelegate.h"
@implementation FTestLoginResultModule
- (void)OnLoginResult:(NSString *)result{
NSLog(@"登入賬號為: %@", result);
}
@end
#endif
#if PLATFORM_IOS
static FTestLoginResultModule *loginResult = nil;
#endif
void FJJLoginNailModule::showLogin(){
#if PLATFORM_IOS
dispatch_async(dispatch_get_main_queue(), ^{
[JJLoginController showLoginView:(UIViewController*)[IOSAppDelegate GetDelegate].IOSController JJCallBack:[FTestLoginResultModule new]];
});
#endif
}
void FJJLoginNailModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
// Get the base directory of this plugin
FString BaseDir = IPluginManager::Get().FindPlugin("JJLoginNail")->GetBaseDir();
// Add on the relative location of the third party dll and load it
FString LibraryPath;
#if PLATFORM_WINDOWS
LibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/ThirdParty/JJLoginNailLibrary/Win64/ExampleLibrary.dll"));
#elif PLATFORM_MAC
LibraryPath = FPaths::Combine(*BaseDir, TEXT("Source/ThirdParty/JJLoginNailLibrary/Mac/Release/libExampleLibrary.dylib"));
#endif // PLATFORM_WINDOWS
ExampleLibraryHandle = !LibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*LibraryPath) : nullptr;
if (ExampleLibraryHandle)
{
// Call the test function in the third party library that opens a message box
ExampleLibraryFunction();
}
else
{
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ThirdPartyLibraryError", "Failed to load example third party library"));
}
}
void FJJLoginNailModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
// Free the dll handle
FPlatformProcess::FreeDllHandle(ExampleLibraryHandle);
ExampleLibraryHandle = nullptr;
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FJJLoginNailModule, JJLoginNail)
注意點:
其中需要注意的是:
- 在呼叫 SDK 介面的時候需要切換到主執行緒上,不然 App 會 Crash;
- 在使用 OC 程式碼的時候需要用 PLATFORM_IOS 進行包裹;
- 因為我們在實現邏輯中用到了 IOSAppDelegate 獲取 RootView,所以我們需要在 JJLoginNail.Build.cs 加入一個配置 “ApplicationCore”,不然會提示 IOSAppDelegate.h 標頭檔案找不到,配置如下:
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"JJLoginNailLibrary",
"Projects",
"ApplicationCore"
// ... add other public dependencies that you statically link with here ...
}
);
- 回到我們外掛資料夾上層資料夾的 Source 下,開啟 UE 為我們自動建立的 Hydroger.Build.cs 檔案,並在裡面配置我們的外掛名稱 “JJLoginNail”, 程式碼如下:
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class Hydroger : ModuleRules
{
public Hydroger(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "JJLoginNail"});
PrivateDependencyModuleNames.AddRange(new string[] { });
// Uncomment if you are using Slate UI
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
// Uncomment if you are using online features
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
}
}
- 在工程中開啟我們在 UE 中建立的藍圖類 MyUserWidget.cpp,並在點選事件中加入呼叫外掛介面的邏輯:
#include "MyUserWidget.h"
#include "JJLoginNail.h"
void UMyUserWidget::callStartFunction()
{
// FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, TEXT("start"), TEXT("callStartFunction"));
#if PLATFORM_IOS
FJJLoginNailModule *module = new FJJLoginNailModule();
module->showLogin();
#endif
}
注意點
- 別忘了在 Hydroger.Build.cs 中配置外掛名稱
- include 外掛標頭檔案,例如:#include “JJLoginNail.h”
- 邏輯用 PLATFORM_IOS 包裹
最後,插上真機裝置,在工程中設定好相應的簽名證書,CMD+R 將工程跑在真機裝置上:
- 觸發按鈕事件,呼叫 SDK 裡面的介面
- 獲取回撥資訊,並列印
結尾
到這裡,UE4 引擎建立 iOS 外掛步驟就結束了,其實並不是很難,就是配置的環節比較多,如果中間某一個環節掉了鏈子,那我們建立的外掛就無法被工程所引用,所以在外掛的使用過程中,需要仔細的去檢查我們的配置。
好了,本篇教程到這裡就結束了,如果遇到問題可通過留言的方式與我交流,希望本篇文章對大家有所幫助,蟹蟹。
原文作者: HelloWord傑少
原文地址:http://002ii.cn/PrTPz