iOS使用Unity容器动态加载3D模型

using UnityEditor;
using System.IO; /// <summary>
///
/// </summary> public class AssetBundleEditor
{
//1.编译阶段插件声明
[MenuItem("Assets/Build AssetBundles")]
static void BuildAssetBundles() {
string dir = "AssetBundles";
if (!Directory.Exists(dir)) {
//2.在工程根目录下创建dir目录
Directory.CreateDirectory(dir);
}
//3.构建AssetBundle资源,AB资源包是一个压缩文件,可以把它看成是一个压缩的文件夹,里面
//可能包含多个文件,预制件,材质,贴图,声音。
BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.iOS);
}
}
设置需要打包的资源



/// <summary>
///读取原生沙盒Documents/AssetsBundle目录下的文件,Documents/AssetsBundle下的文件通过Native原生下载的资源
/// </summary>
/// <param name="abName">Documents/AssetsBundle下的ab文件</param>
/// <returns>读取到的字符串</returns>
public static AssetBundle GetNativeAssetFromDocumentsOnProDownLoad(string abName)
{
string localPath = "";
if (Application.platform == RuntimePlatform.Android)
{
localPath = "jar:file://" + Application.persistentDataPath + "/AssetsBundle/" + abName;
}
else
{
localPath = "file://" + Application.persistentDataPath + "/AssetsBundle/" + abName;
}
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(localPath);
var operation = request.SendWebRequest();
while (!operation.isDone)
{ }
if (request.result == UnityWebRequest.Result.ConnectionError)
{
Debug.Log(request.error);
return null;
}
else
{
AssetBundle assetBundle = DownloadHandlerAssetBundle.GetContent(request);
return assetBundle;
}
//UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(localPath);
//yield return request.Send();
//AssetBundle assetBundle = DownloadHandlerAssetBundle.GetContent(request);
//return assetBundle; }
注意:当离开Unity容器时需要卸载里面加载的ab包
public void TestUnLoadGameObject()
{
UnLoadGameObjectWithTag("NFT");
} public void UnLoadGameObjectWithTag(string tagName)
{
GameObject go = GameObject.FindWithTag(tagName);
if (go) {
Destroy(go, 0.5f);
} else
{
Debug.Log(go);
} } public void UnLoadAllGameObjectWithTag(string tagName)
{
GameObject[] gos = GameObject.FindGameObjectsWithTag(tagName);
foreach (GameObject go in gos) {
Destroy(go, 0.5f);
} }

public void TestLoadStreamingAssetBundle() {
LoadStreamingAssetBundleWithABName("cube.ab", "Cube", "NFT");
}
public void LoadStreamingAssetBundleWithABName(string abName, string gameObjectName, string tagName)
{
AssetBundle ab = FileUtility.GetNativeAssetFromStreamingAssets(abName);
GameObject profab = ab.LoadAsset<GameObject>(gameObjectName);
profab.tag = tagName;
Instantiate(profab);
GestureController gc = GameObject.FindObjectOfType<GestureController>();
gc.target = profab.transform;
ab.Unload(false);
}
Unity场景切换的脚本实现:
//接收原生事件:切换场景
public void SwitchScene(string parmas)
{
Debug.Log(parmas);
Param param = new Param();
Param res = JsonDataContractJsonSerializer.JsonToObject(parmas, param) as Param;
Debug.Log(res.name); Debug.Log("------------");
for (int i = 0; i < SceneManager.sceneCount; i++) {
Scene scene = SceneManager.GetSceneAt(i);
Debug.Log(scene.name);
} SceneManager.LoadScene(res.name, LoadSceneMode.Single); Debug.Log("------------");
for (int i = 0; i < SceneManager.sceneCount; i++)
{
Scene scene = SceneManager.GetSceneAt(i);
Debug.Log(scene.name);
}
}



#import <Foundation/Foundation.h> @protocol NativeCallsProtocol @required /// Unity调用原生
/// - Parameter params: {"FeatureName":"下载资源", "params": "参数"}
- (void)callNative:(NSString *)params;
@end __attribute__ ((visibility("default"))) @interface NativeCallProxy : NSObject
// call it any time after UnityFrameworkLoad to set object implementing NativeCallsProtocol methods
+ (void)registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi;
@end
NativeCallProxy.mm文件实现如下:
#import "NativeCallProxy.h" @implementation NativeCallProxy
id<NativeCallsProtocol> api = NULL;
+ (void)registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi
{
api = aApi;
} @end extern "C" {
void callNative(const char * value);
} void callNative(const char * value){
return [api callNative:[NSString stringWithUTF8String:value]];
}
原生的Delegate的实现
#pragma mark - NativeCallsProtocol
- (void)callNative:(NSString *)params {
NSLog(@"收到Unity的调用:%@",params);
}
//重要声明,声明在iOS原生中存在下面的方法,然后C#中可以直接进行调用
[DllImport("__Internal")]
static extern void callNative(string value); public void changeLabel(string textString) {
tmpText.text = textString;
} public void btnClick() {
Debug.Log(tmpInput.text);
callNative(tmpInput.text);
}


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; public class Param {
public string packageName { get; set; }
public string name { get; set; }
public string tag { get; set; }
public string type { get; set; }
public string isAll { get; set; }
} public class DispatchGO : MonoBehaviour
{ //接收原生事件
public void DispatchEvent(string parmas) {
Debug.Log(parmas);
//事件分发 ChangeLabel cl = GameObject.FindObjectOfType<ChangeLabel>();
cl.changeLabel(parmas);
} //接收原生事件:加载模型
public void LoadModel(string parmas)
{
Debug.Log(parmas);
Param param = new Param();
Param res = JsonDataContractJsonSerializer.JsonToObject(parmas, param) as Param;
Debug.Log(res.packageName);
Debug.Log(res.name);
Debug.Log(res.tag);
Debug.Log(res.type); if (res.type == "0")
{
LoadAssetUtility laUnity = GameObject.FindObjectOfType<LoadAssetUtility>();
laUnity.LoadStreamingAssetBundleWithABName(res.packageName, res.name, res.tag);
}
else {
LoadAssetUtility laUnity = GameObject.FindObjectOfType<LoadAssetUtility>();
laUnity.LoadNativeAssetBundleWithABName(res.packageName, res.name, res.tag);
}
} //接收原生事件:卸载模型
public void UnLoadModel(string parmas)
{
Debug.Log(parmas);
Param param = new Param();
Param res = JsonDataContractJsonSerializer.JsonToObject(parmas, param) as Param; UnLoadAssetUtility unLAUnity = GameObject.FindObjectOfType<UnLoadAssetUtility>();
if (res.isAll == "1")
{
unLAUnity.UnLoadAllGameObjectWithTag(res.tag);
}
else {
unLAUnity.UnLoadGameObjectWithTag(res.tag);
}
} //接收原生事件:切换场景
public void SwitchScene(string parmas)
{
Debug.Log(parmas);
Param param = new Param();
Param res = JsonDataContractJsonSerializer.JsonToObject(parmas, param) as Param;
Debug.Log(res.name); Debug.Log("------------");
for (int i = 0; i < SceneManager.sceneCount; i++) {
Scene scene = SceneManager.GetSceneAt(i);
Debug.Log(scene.name);
} SceneManager.LoadScene(res.name, LoadSceneMode.Single); Debug.Log("------------");
for (int i = 0; i < SceneManager.sceneCount; i++)
{
Scene scene = SceneManager.GetSceneAt(i);
Debug.Log(scene.name);
}
} // Start is called before the first frame update
void Start()
{ } // Update is called once per frame
void Update()
{ }
}
在iOS原生侧,本地通过使用unityFramework的sendMessageToGOWithName方法从原生想Unity发送消息。
case 103:
{
NSDictionary *params = @{
@"tag":@"NFT",
@"isAll":@"1"
};
[ad.unityFramework sendMessageToGOWithName:"DispatchGO" functionName:"UnLoadModel" message:[self serialJsonToStr:params]];
}
break;
case 104:
{
NSDictionary *params = @{
@"name":@"DemoScene"
};
[ad.unityFramework sendMessageToGOWithName:"DispatchGO" functionName:"SwitchScene" message:[self serialJsonToStr:params]];
}
break;
Unity通过调用iOS中协议声明的方法void callNative(string value); 进行调用。
//重要声明,声明在iOS原生中存在下面的方法,然后C#中可以直接进行调用
[DllImport("__Internal")]
static extern void callNative(string value); public void btnClick() {
Debug.Log(tmpInput.text);
callNative(tmpInput.text);
}
原生端创建Unity容器
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[UnitySceneManager sharedInstance].launchOptions = launchOptions;
[[UnitySceneManager sharedInstance] Init];
return YES;
}
UnitySceneManager的主要实现逻辑如下:#import "UnitySceneManager.h"#import <UnityFramework/NativeCallProxy.h>
extern int argcApp;
extern char ** argvApp; @interface UnitySceneManager()<UnityFrameworkListener, NativeCallsProtocol> @end @implementation UnitySceneManager
#pragma mark - Life Cycle
+ (instancetype)sharedInstance {
static UnitySceneManager *shareObj;
static dispatch_once_t onceKey;
dispatch_once(&onceKey, ^{
shareObj = [[super allocWithZone:nil] init];
});
return shareObj;
} + (instancetype)allocWithZone:(struct _NSZone *)zone {
return [self sharedInstance];
} - (instancetype)copyWithZone:(struct _NSZone *)zone {
return self;
} #pragma mark - Private Method
- (void)Init {
[self initUnityFramework];
[NativeCallProxy registerAPIforNativeCalls:self];
} - (void)unloadUnityInternal {
if (self.unityFramework) {
[self.unityFramework unregisterFrameworkListener:self];
}
self.unityFramework = nil;
} - (BOOL)unityIsInitialized {
return (self.unityFramework && self.unityFramework.appController);
}
// MARK: overwrite #pragma mark - Public Method
- (void)initUnityFramework {
UnityFramework *unityFramework = [self getUnityFramework];
self.unityFramework = unityFramework;
[unityFramework setDataBundleId:"com.zhfei.framework"];
[unityFramework registerFrameworkListener:self];
[unityFramework runEmbeddedWithArgc:argcApp argv:argvApp appLaunchOpts:self.launchOptions];
} - (UnityFramework *)getUnityFramework {
NSString* bundlePath = nil;
bundlePath = [[NSBundle mainBundle] bundlePath];
bundlePath = [bundlePath stringByAppendingString: @"/Frameworks/UnityFramework.framework"]; NSBundle* bundle = [NSBundle bundleWithPath: bundlePath];
if ([bundle isLoaded] == false) [bundle load]; UnityFramework* ufw = [bundle.principalClass getInstance];
if (![ufw appController])
{
// unity is not initialized
[ufw setExecuteHeader: &_mh_execute_header];
}
return ufw;
} #pragma mark - Event #pragma mark - Delegate
#pragma mark - UnityFrameworkListener
- (void)unityDidUnload:(NSNotification*)notification { } - (void)unityDidQuit:(NSNotification*)notification { } #pragma mark - NativeCallsProtocol
- (void)callNative:(NSString *)params {
NSLog(@"收到Unity的调用:%@",params);
} #pragma mark - Getter, Setter #pragma mark - NSCopying #pragma mark - NSObject #pragma mark - AppDelegate生命周期绑定
- (void)applicationWillResignActive {
[[self.unityFramework appController] applicationWillResignActive: [UIApplication sharedApplication]];
} - (void)applicationDidEnterBackground {
[[self.unityFramework appController] applicationDidEnterBackground: [UIApplication sharedApplication]];
} - (void)applicationWillEnterForeground {
[[self.unityFramework appController] applicationWillEnterForeground: [UIApplication sharedApplication]];
} - (void)applicationDidBecomeActive {
[[self.unityFramework appController] applicationDidBecomeActive: [UIApplication sharedApplication]];
} - (void)applicationWillTerminate {
[[self.unityFramework appController] applicationWillTerminate: [UIApplication sharedApplication]];
} @end
Unity容器的原生实现,其实也是在一个普通的ViewController里面包含了Unity视图的View。
#import "UnityContainerViewController.h"
#import "UnitySceneManager.h" @interface UnityContainerViewController () @end @implementation UnityContainerViewController
#pragma mark - Life Cycle
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self setupUI];
} - (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UnitySceneManager *ad = [UnitySceneManager sharedInstance];
ad.unityFramework.appController.rootView.frame = self.view.bounds;
} - (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UnitySceneManager *ad = [UnitySceneManager sharedInstance];
[ad.unityFramework pause:NO];
} - (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
UnitySceneManager *ad = [UnitySceneManager sharedInstance];
[ad.unityFramework pause:YES];
} #pragma mark - Private Method
- (void)setupUI {
self.view.backgroundColor = [UIColor whiteColor];
UnitySceneManager *ad = [UnitySceneManager sharedInstance]; UIView *rootView = ad.unityFramework.appController.rootView;
rootView.frame = [UIScreen mainScreen].bounds;
[self.view addSubview:rootView];
[self.view sendSubviewToBack:rootView];
}
iOS使用Unity容器动态加载3D模型的更多相关文章
- WPF动态加载3D 放大-旋转-平移
原文:WPF动态加载3D 放大-旋转-平移 WavefrontObjLoader.cs 第二步:ModelVisual3DWithName.cs public class ModelVisual3DW ...
- 使用 Assimp 库加载 3D 模型
前言 要想让自己的 3D 之旅多一点乐趣,肯定得想办法找一些有意思一点的 3D 模型.3D 模型有各种各样的格式,obj的,stl的,fbx的等等不一而足.特别是 obj 格式的 3D 模型,完全是纯 ...
- Unity Lightmap动态加载研究
什么情况下需要Lightmap? 移动平台上目前暂时还不能开实时光影效果,会卡成幻灯片.所以就需要将光影烘焙到贴图上. 什么情况下需要动态加载Lightmap? 1.当项目抛弃了Unity的多场景模式 ...
- WPF动态加载3D 放大-旋转-平移
第一步:新建WavefrontObjLoader.cs using System; using System.Collections.Generic; using System.Windows; us ...
- 关于Unity里动态加载图片
Resources.Load 使用该方法可以动态加载资源 过程: 1.首先需要在Project面板里创建一个名为Resources的文件夹(名字必须是这个 不能写错啊) 2.把要加载的游戏对象放到该目 ...
- Unity www动态加载网上图片
一. 1.新建一个UGUI的Button,删掉它的Image组件,添加一个Raw Image组件.如图: 由于删除了Image组件,所以画圈的位置是空的,运行后会自动把Raw Image添加到那里. ...
- Unity中 动态加载 Resources.Load()和Asset Bundle 的区别
版权声明:本文为博主原创文章,未经博主允许不得转载. 初学Unity的过程中,会发现打包发布程序后,unity会自动将场景需要引用到的资源打包到安装包里,没有到的不会跟进去.我们在编辑器里看到的Ass ...
- unity动态加载FBX模型(Http下载到Rescources文件,场景Load直接调用):
using UnityEngine; using System.Collections; using System.IO; using System.Net; using System; using ...
- cesium加载gltf模型点击以及列表点击定位弹窗
前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 之 ...
- Unity动态加载和内存管理(三合一)
原址:http://game.ceeger.com/forum/read.php?tid=4394#info 最近一直在和这些内容纠缠,把心得和大家共享一下: Unity里有两种动态加载机制:一是Re ...
随机推荐
- 【NSSCTF-Round#16】 Web和Crypto详细完整WP
每天都要加油哦! ------2024-01-18 11:16:55 [NSSRound#16 Basic]RCE但是没有完全RCE <?php error_reporting(0); ...
- 设计模式学习-使用go实现组合模式
组合模式 定义 适用范围 优点 缺点 代码实现 参考 组合模式 定义 组合模式(Composite),将对象组合成树形结构以表示'部分-整体'的层次关系.组合模式使得用户对单个对象和组合对象的使用具有 ...
- 【Java】ArrayList线程不安全的坑
问题复现: 使用Java的steam().paralleStream(),foreach()方法向ArrayList添加数据,导致ArrayList中出现空值,代码如下: public static ...
- JavaScript获取浏览器的显示区域大小测试
JavaScript获取浏览器的显示区域大小测试 Now we get the screen size about this browser 网页可见区域宽 document.body.clientW ...
- SpringAOP配置要点
一.基于配置文件 1.关于aop配置文件相关 <!--配置aop--> <aop:config> <!--配置切入点表达式--> <aop:pointcut ...
- 使用Nuget快速集成.Net三维控件
据老一辈的程序员说开发三维程序门槛很高,需要学若干年才能入门,自从遇上AnyCAD三维控件后,开发三维应用变的简单了.当结合nuget后,一切更简单了. 1 准备工作 安装VS201x以后,就可以开始 ...
- Docker从认识到实践再到底层原理(七)|Docker存储卷
前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助. 高质量博客汇总 然后就是博主最近最花时间的一 ...
- 23.2 SEH之异常处理--《Windows核心编程》结构化异常处理
(structured exception handing)SEH 包含终止处理和异常处理.本章讨论异常处理. 当一个硬件或者软件异常被抛出的时候,操作系统会给我们程序一个查看异常类型的机会,并允 ...
- go Printf 语句的占位符 Format
func main() { var a uint8 = 12 var b = "wokao" fmt.Printf("查看类型:%T\n", a) //查看类型 ...
- MySQL架构体系介绍
一.MySQL的完整架构体系 MySQL完整的架构体系: (1)Connectors 指的是不同语言中与SQL的交互. (2)Connection Pool 管理缓冲用户连接,线程处理等需要缓存的需求 ...