沃梦达 / IT编程 / 移动开发 / 正文

UE4 IOS互相调用

目录plist两种调用方式Framework优缺点OC混编优缺点扩展平台代码技巧采坑提示xml is missingIOS截图上篇文章讲了UE4安卓互相调用,这篇来看看IOS原生代码和UE4的关系。plist上篇文章提到了一个概念:UPL,在IOS代码...

目录
  • plist
  • 两种调用方式
    • Framework
      • 优缺点
    • OC混编
      • 优缺点
      • 扩展
  • 平台代码技巧
  • 采坑
    • 提示xml is missing
    • IOS截图

上篇文章讲了UE4安卓互相调用,这篇来看看IOS原生代码和UE4的关系。

plist

上篇文章提到了一个概念:UPL,在IOS代码编写里同样有使用UPL的地方,但对于IOS目前我所见到只是用于更改plist(UE 4.25.1 默认打包会产生下面这样一个 plist 文件info.plist,在一些特殊的需求中,需要往这个 plist 中添加元素或者修改以及删除。)

ios 的 ipa 包中都会有 plist 文件,可以用来配置 app 的一些属性,apple 的开发者文档里对每个支持的 key 有详细的描述:iOS Keys

在 UE 的项目设置中,可以给 plist 添加元素,在 Project Settings-Platform-iOS-Additional Plist data 中可以填入一个字符串,它会被插入到 plist 文件中:

<key>AdditionalElementAAA</key>\n<string>this key is a test element.</string>

中间的 \n 是格式化代码,用于另起一行。

如果想要修改或者删除 plist 的元素,需要通过 UPL 来写逻辑(当然也可以使用 UPL 来添加元素,建议使用这种做法)。

<?xml version="1.0" encoding="utf-8"?>
<root>
    <init>
        <log text="UPL Exalpme adding element to plist..."/>
    </init>
    <trace enable="true"/>
    <iosPListUpdates>
        <addElements tag="dict" once="true">
            <key>AdditionalElementAAA</key>
            <string>this key is a test element.</string>
        </addElements>
    </iosPListUpdates>
</root>

上面是用来添加元素的,上面的内容和直接写到 Additional Plist data 是一样的。

遍历 plist 中的 key:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <init>
        <log text="UPL Exalpme..."/>
    </init>
    <trace enable="true"/>
    <iosPListUpdates>
        <loopElements tag="dict">
            <loopElements tag="$">
                <setStringFromTag result="TagName" tag="$"/>
                <setBoolIsEqual result="bIsKey" arg1="$S(TagName)" arg2="key"/>
                <if condition="bIsKey">
                    <true>
                        <log text="$S(TagName):$S(TagValue)"/>
                    </true>
                </if>
            </loopElements>
        </loopElements>
        
    </iosPListUpdates>
</root>

注意:当前元素以 tag = "$" 方式引用。

两种调用方式

Framework

通过给项目添加ios的framework库来添加ios功能

这块我没有实践过,引用他人的案例来讲解

https://blog.csdn.net/shenjie12345678/article/details/111812429

Build.cs文件

       if (Target.Platform == UnrealTargetPlatform.IOS){
            PublicAdditionalFrameworks.Add(
                new Framework(
                    "TestLoginSDK",
                    "../ThirdParty/iosframeworks/iosextend.embeddedframework.zip"
                )
            );
        }

IOS 上的 Framework 有点类似于静态链接库的意思,相当于把.a+.h+ 资源打包到一块的集合体。更具体的区别描述请看:iOS 库 .a 与.framework 区别

在 UE 中以集成 IOS 上操作 Keycahin 的 SSKeychain 为例,在 Module 的 build.cs 中使用 PublicAdditionalFrameworks 来添加:

PublicAdditionalFrameworks.Add(
    new Framework(
        "SSKeychain",
        "ThirdParty/IOS/SSKeychain.embeddedframework.zip",
        "SSKeychain.framework/SSKeychain.bundle"
        )
);

构造 Framework 的第一个参数是名字,第二个是 framework 的路径(相对于 Module),第三个则是解压之后的 Framework 的 bundle 路径(如果 framework 没有 bundle 则可以忽略这个参数,而且就算有 bundle,但是不写这第三个参数貌似也没什么问题)。

这种方法就是一开始将所有的IOS平台有关的代码封成库,然后在UE中的CPP函数中用一句OC的调用

注意点:

其中需要注意的是:

  • 在调用 SDK 接口的时候需要切换到主线程上,不然 App 会 Crash;

    • dispatch_async(dispatch_get_main_queue(), ^{
      //your code
      });
      
  • 在使用 OC 代码的时候需要用#if PLATFORM_IOS #endif 进行包裹;

优缺点

优点:部分代码可以不开源,成熟的模块可以拿来就用!便于进行分模块管理等等。如果有写ios的同学,直接让他给你整一个你只需要调用一下就好。

缺点:和UE的交互有限,复杂的交互需求写起来比较麻烦。

OC混编

先不提OC的语法各种对CPP程序员反人类,OC混编的优点还是很棒的,其实你可能发现了,上面一种方法里的调用framework库的那一句代码就是oc代码,其实这就是混编了。不过这里的混编更为复杂,指将原先的ios的代码的类Interface、implementation直接写在cpp里。

oc、c、 c++同根同源,他们的基础数据类型天然就能互相调用。

使用OC混编其实可以直接引用ios的库文件,比如

#import <UIKit/UIKit.h>

很多sdk就是这么干的,这样代码可以大部分都放在一起,开发起来很方便,调试一下,想改oc就改oc,想改cpp就改cpp

而且因为身在UE的工程环境下,oc的函数体里可以直接使用UE提供的一些类,当然还是要注意线程问题使用AsyncTask

不过混编的时候执行顺序有时候让人比较困惑,比如我这边先写了NSLog,后写了UE_LOG,在日志中UE_LOG有可能先于NSLog执行,这块还是分开一点比较好,不要太过自由。

优缺点

很多的优点,上面提到了的都是优点,我在oc的函数体里直接excute UE作用域绑定的委托,传递数据,改ue代码和oc代码,xcode build->install->running都很快。

缺点其实也比较明显,写小规模的代码还好,在很大量平台代码的情况下,要在没有代码提示的环境下写逻辑难度还是很大的,况且很多ios平台有一些成熟的代码的解决方案,直接以一个framework库提供更好

扩展

杰少这篇文章讲了UE4的委托和IOS的委托的交互

https://blog.csdn.net/shenjie12345678/article/details/112168356#comments_15713973

平台代码技巧

小技巧:跨平台的代码可以封在不同的同名cpp文件中(分平台名字,编辑器会识别到对应的平台),这样在不同的平台编译的时候只会取对应文件夹下的cpp文件,不会产生重定义

采坑

提示xml is missing

字符串IosPlugin 能找到xml文件,IOSPlugin找不到xml,奇怪的拼写检查。

AdditionalPropertiesForReceipt.Add(new ReceiptProperty("IosPlugin",System.IO.Path.Combine(PluginPath,"IOS/PlatformCommon_APL_IOS.xml")));

IOS截图

截图的传递到ue4的思路很简单,把图片数据转化成字节数组,然后参数传到UE4后,通过这个buffer再解析出图片

使用UIImagePNGRepresentation传到UE4后转换成Texture2D发现显示失败,是一个透明图

定位后发现ios的截图默认为png,64位深,UE4对应处理图片的ImportBufferAsTexture2D接口在处理png64的时候不报错但是无法正确处理。

使用UIImageJPEGRepresentation在IOS层把图片转成jpg解决问题。

本文标题为:UE4 IOS互相调用