1. 程式人生 > 實用技巧 >UE4 開發之如何建立 iOS 平臺外掛

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 工程中

前期準備做好以後,我們現在進入到正式的敲程式碼階段.

編碼階段

  1. 在 Source 資料夾中外掛為我們建立了以下原始檔

  1. 開啟 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"
                )
            );
        }
	}
}

  1. 開啟 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。

  1. 開啟 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 ...
			}
			);

  1. 回到我們外掛資料夾上層資料夾的 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
	}
}

  1. 在工程中開啟我們在 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
}

注意點
  1. 別忘了在 Hydroger.Build.cs 中配置外掛名稱
  2. include 外掛標頭檔案,例如:#include “JJLoginNail.h”
  3. 邏輯用 PLATFORM_IOS 包裹

最後,插上真機裝置,在工程中設定好相應的簽名證書,CMD+R 將工程跑在真機裝置上:

  • 觸發按鈕事件,呼叫 SDK 裡面的介面

  • 獲取回撥資訊,並列印

結尾

到這裡,UE4 引擎建立 iOS 外掛步驟就結束了,其實並不是很難,就是配置的環節比較多,如果中間某一個環節掉了鏈子,那我們建立的外掛就無法被工程所引用,所以在外掛的使用過程中,需要仔細的去檢查我們的配置。

好了,本篇教程到這裡就結束了,如果遇到問題可通過留言的方式與我交流,希望本篇文章對大家有所幫助,蟹蟹。

原文作者: HelloWord傑少
原文地址:http://002ii.cn/PrTPz