随着技术的发展,越来越多的APP期望拥有3D,AR的能力。要达到这个目标可以选择使用原生开发,也可以使用Unity成熟的3D开发技术链,通过嵌入的方式将Unity容器嵌入到APP中。这里介绍的是通过嵌入Unity容器的方式来实现APP的3D,AR能力的。
 
Unity集成到iOS应用的本质是将Unity中所有用到的资源,模型,代码打包成一个framework动态库,然后嵌入到APP的内部。APP启动后加载Unity页面时,会加载这个framework动态库和里面的所有资源。然后在APP中展示这个Unity页面。
 
Unity集成到iOS应用的官方提供的方案是以Workspace的方式集成,具体步骤如下:
1.Unity项目通过Unity Editer 导出一个iOS项目,这个iOS项目里包含了整个Unity项目的所有代码和资源,可以直接运行在iOS系统上。
2.用Xcode创建一个原生的iOS项目
3.用Xcode创建一个Workspace, 然后通过add file 的形式将这2个项目添加到一个Workspace下面。
4.修改Unity-iPhone项目打包设置,使其打包出适合嵌入的UnityFramework动态库,
5.修改NativeiOSApp项目配置,添加UnityFramework动态库。
对Workspace下面的2个项目进行配置
Unity-iPhone创建
在生成UnityFramework动态库前,需要将Unity项目导出一个iOS项目,导出的过程如下:
1.点击File->Building Settings进入到选择导出页面

2.选择要导出的平台,这里选择iOS,然后点击右下角的"Switch Plateform"按钮,然后点击上面的“Add Open Scenes”添加场景

3.点击“Build”,导出iOS项目

Unity-iPhone设置
关闭以Workspace方式打开的Xcode,单独打开Unity-iPhone项目
1.在Unity-iPhone项目中,设置Data 这个Group的 Target Memebership, 将里面的UnitFramework项打勾,表示这个Data在生成Framework静态库时也要作为其中的一员,放置进去。
2.将NativeCallProxy.h头文件从Framework的 protect组移动到public组,将头文件开放出来。路径为: Unity-iPhone / Libraries / Plugins / iOS / NativeCallProxy.h
3.手机连接电脑,运行,生成静态库。
NativeiOSApp原生项目设置
以Workspace方式打开项目
1.在NativeiOSApp Target - General - Frameworks, Libraries, and Embedded Content 通过点击+ 将UnityFramework设置嵌入到项目中
2.在NativeiOSApp Target - Build Phases - Link Binary With Libraries中,点击-,将UnityFramework移除,表示禁止在项目链接时将UnityFramework链接到可执行文件中,它只作为内嵌在APP中的静态库在运行时加载使用。
3.手机连接电脑,运行,看到Demo运行的效果。
 
 
Unity与原生通信
Unity调用原生
1.首先在原生中实现代理协议NativeCallProxy中的方法(注册由谁来处理unity的调用)和添加暴露给unity的方法。
NativeCallProxy.h文件中方法的声明
__attribute__ ((visibility("default")))
@interface FrameworkLibAPI : NSObject
// call it any time after UnityFrameworkLoad to set object implementing NativeCallsProtocol methods
+(void) registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi; @end
NativeCallProxy.cpp文件中方法的实现
@implementation FrameworkLibAPI

id<NativeCallsProtocol> api = NULL;
+(void) registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi
{
api = aApi;
} @end
给Unity暴露的原生调用方法
extern "C" {
void showHostMainWindow(const char* color) { return [api showHostMainWindow:[NSString stringWithUTF8String:color]]; }
}
2.然后在原生的Unity启动时,注册这个处理的对象
- (void)initUnity
{
[self setUfw: UnityFrameworkLoad()];
// Set UnityFramework target for Unity-iPhone/Data folder to make Data part of a UnityFramework.framework and uncomment call to setDataBundleId
// ODR is not supported in this case, ( if you need embedded and ODR you need to copy data )
[[self ufw] setDataBundleId: "com.unity3d.framework"];
[[self ufw] registerFrameworkListener: self];
[NSClassFromString(@"FrameworkLibAPI") registerAPIforNativeCalls:self];
}
3.在Unity中,调用iOS的原生方法
Cube.cs脚本中声明在APP中存在方法showHostMainWindow
#if UNITY_IOS || UNITY_TVOS
public class NativeAPI {
[DllImport("__Internal")]
public static extern void showHostMainWindow(string lastStringColor);
}
#endif
Cube.cs脚本中添加Unity 2d按钮点击事件,调用iOS原生方法
void OnGUI()
{
GUIStyle style = new GUIStyle("button");
style.fontSize = 45;
if (GUI.Button(new Rect(10, 300, 600, 100), "Show Main With Color", style)) showHostMainWindow();
} void showHostMainWindow()
{
#if UNITY_ANDROID
try
{
AndroidJavaClass jc = new AndroidJavaClass("com.unity.mynativeapp.SharedClass");
jc.CallStatic("showMainActivity", lastStringColor);
} catch(Exception e)
{
appendToText("Exception during showHostMainWindow");
appendToText(e.Message);
}
#elif UNITY_IOS || UNITY_TVOS
NativeAPI.showHostMainWindow(lastStringColor);
#endif
}
原生调用Unity
点击原生发送消息按钮,发消息给Unity。
self.btnSendMsg = [UIButton buttonWithType: UIButtonTypeSystem];
[self.btnSendMsg setTitle: @"Send Msg" forState: UIControlStateNormal];
[self.btnSendMsg addTarget: self action: @selector(sendMsgToUnity) forControlEvents: UIControlEventPrimaryActionTriggered]; - (void)sendMsgToUnity
{
[[self ufw] sendMessageToGOWithName: "Cube" functionName: "ChangeColor" message: "yellow"];
} /*
goName: 场景中的游戏物体GameObject
name: 这个游戏物体挂载的脚本中的一个方法
msg: 参数
*/
- (void)sendMessageToGOWithName:(const char*)goName functionName:(const char*)name message:(const char*)msg
{
UnitySendMessage(goName, name, msg);
} void UnitySendMessage(const char* obj, const char* method, const char* msg);
Cube.cs脚本中的方法实现
string lastStringColor = "";
void ChangeColor(string newColor)
{
appendToText( "Changing Color to " + newColor ); lastStringColor = newColor; if (newColor == "red") GetComponent<Renderer>().material.color = Color.red;
else if (newColor == "blue") GetComponent<Renderer>().material.color = Color.blue;
else if (newColor == "yellow") GetComponent<Renderer>().material.color = Color.yellow;
else GetComponent<Renderer>().material.color = Color.black;
}
 
Unity热更新
在Unity项目中使用纯C#构建的渐渐不能适应移动端的需求,移动端通常通过添加热更新插件来实现热更新功能。这个过程起关键作用的是Lua和起对应的解释器。
lua是解释型语言,并不需要事先编译成块,而是运行时动态解释执行的。
这样LUA就和普通的游戏资源如图片,文本没有区别,因此可以在运行时直接从WEB服务器上下载到持久化目录并被其它LUA文件调用。
Lua热更新解决方案是通过一个Lua热更新插件(如ulua、slua、tolua、xlua等)来提供一个Lua的运行环境以及和C#进行交互。
所以lua热更新的流程可以简单理解为:将逻辑代码使用脚本实现,再将脚本转化为文本资源,最后以更新资源的形式来更新程序,以此来实现热更新。
注意:
在iOS应用内的Unity容器中,Untiy的C#资源和Lua资源都是在Unity容器内部进行加载的。如果Unity采用的Lua热更新,则需要原生侧在Lua脚本和资源下载完成后通知Unity进行加载展示。
Demo地址
NativeiOSApp项目地址:https://github.com/zhfei/uaal-example
将 Unity 集成到原生 iOS 应用程序中官方文档:https://docs.unity3d.com/cn/2020.2/Manual/UnityasaLibrary-iOS.html
 
 
 
 
 

在原生APP中集成Unity容器的更多相关文章

  1. iOS原生项目中集成React Native

    1.本文的前提条件是,电脑上已经安装了CocoaPods,React Native相关环境. 2.使用Xcode新建一个工程.EmbedRNMeituan [图1] 3.使用CocoaPods安装Re ...

  2. 怎么在我们的App中集成条码扫描功能?

    现在很多App都有条码扫描功能,有的手机比如某米在照相机中集成了条码扫描功能,但是还有一部分手机没有这样的集成,比如韩国某星,需要自己下载一个条码扫描App.今天我们就来看看怎么在自己的App中集成一 ...

  3. APICloud原生APP中ajax需要用api.ajax

    报错截屏: APICloud原生APP中ajax请求需要用api.ajax(api对象的ajax方法来替代),否则会将引起请求失败. APICloud api.ajax

  4. c#中的Unity容器

    DIP是依赖倒置原则:一种软件架构设计的原则(抽象概念).依赖于抽象不依赖于细节 IOC即为控制反转(Inversion of Control):传统开发,上端依赖(调用/指定)下端对象,会有依赖,把 ...

  5. 在APP中集成iAd Banner展示广告盈利

    如果你已经做了一款超牛X的APP.你也许还有一件是需要操心.APP够好了,怎么盈利呢?你可以对下载你的APP的用户收费.也可以完全的免费,然后在APP里放广告来实现盈利.现在来说,除非一款APP真的是 ...

  6. 在Android App中集成Google登录

    技术文章 来源:码农网 发布:2016-09-19 浏览:194 摘要:今天,几乎所有的web和移动app都自带谷歌和Facebook登录,这对app开发者和用户来说是一个非常有用的功能,因为几乎每个 ...

  7. 如何在WCF中集成unity

    第一种是代码方式: 点击打开链接http://blogs.microsoft.co.il/gadib/2010/11/30/wcf-and-unity-20/ 还有一种方式可以扩展成配置文件,有时间再 ...

  8. RN与现有的原生app集成

    https://facebook.github.io/react-native/docs/integration-with-existing-apps.html RN可以很好地支持往一个原生的app上 ...

  9. 转发-UI基础教程 – 原生App切图的那些事儿

    UI基础教程 – 原生App切图的那些事儿 转发:http://www.shejidaren.com/app-ui-cut-and-slice.html 移动APP切图是UI设计必须学会的一项技能,切 ...

  10. 原生App切图的那些事儿

    如何切图? 了解iphone界面的尺寸 最小的分辨率是320x480,我们把这个尺寸定为基准界面尺寸(baseline),基准尺寸所用的图标定为1倍图(1x). 在实际设计过程中,为了降低设计成本,一 ...

随机推荐

  1. 2021-05-22:假设所有字符都是小写字母, 大字符串是str,arr是去重的单词表, 每个单词都不是空字符串且可以使用任意次。使用arr中的单词有多少种拼接str的方式。 返回方法数。

    2021-05-22:假设所有字符都是小写字母, 大字符串是str,arr是去重的单词表, 每个单词都不是空字符串且可以使用任意次.使用arr中的单词有多少种拼接str的方式. 返回方法数. 福大大 ...

  2. docker安装go-fastdfs

    1.docker命令安装 docker run -d --name fastdfs -p 8180:8080 sjqzhang/go-fastdfs 2.浏览器访问 http://192.168.20 ...

  3. Spring Boot 配置文件总结

    前言 Spring Boot 中提供一个全局的配置文件:application.properties,这个配置文件的作用就是,允许我们通过这个配置文件去修改 Spring Boot 自动配置的默认值. ...

  4. ModuleNotFoundError: No module named 'flask_login'

    ModuleNotFoundError: No module named 'flask_login' 解决: pip install  flask_login

  5. SICP:惰性求值、流和尾递归(Python实现)

    求值器完整实现代码我已经上传到了GitHub仓库:TinySCM,感兴趣的童鞋可以前往查看.这里顺便强烈推荐UC Berkeley的同名课程CS 61A. 即使在变化中,它也丝毫未变. --赫拉克利特 ...

  6. Typora使用方法

    Typora使用方法 常见快捷键 无序列表:- + 空格 有序列表:1. + 空格 引用:> + 空格 标题:ctrl + 数字 表格:ctrl + t 选中一整行:ctrl + l 选中单词: ...

  7. js 正则校验非法字符

    今日使用 vue + element 对数据录入进行非法字符校验,到处找了一圈都不是想要的,于是自己按需求写一个 1.内容可以包含 大小写字母,中文和 . ( ) . , : % 2.内容第一位不允许 ...

  8. es笔记六之聚合操作之指标聚合

    本文首发于公众号:Hunter后端 原文链接:es笔记六之聚合操作之指标聚合 聚合操作,在 es 中的聚合可以分为大概四种聚合: bucketing(桶聚合) mertic(指标聚合) matrix( ...

  9. CoFiltering:BestPracticesandTechniquesinTextGeneration

    目录 Co-Filtering: Best Practices and Techniques in Text Generation Introduction: Text generation has ...

  10. C++面试八股文:知道std::unordered_set/std::unordered_map吗?

    某日二师兄参加XXX科技公司的C++工程师开发岗位第27面: 面试官:知道std::unordered_set/std::unordered_map吗? 二师兄:知道.两者都是C++11引入的新容器, ...