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 ...
随机推荐
- Gorm实战,轻松掌握数据库增删改查技巧!
Gorm实战,轻松掌握数据库增删改查技巧! CRUD通常指数据库的增删改查操作,本文详细介绍了如何使用GORM实现创建.查询.更新和删除操作. 目录 Gorm实战,轻松掌握数据库增删改查技巧! 一.C ...
- 9.2 Windows驱动开发:内核解析PE结构导出表
在笔者的上一篇文章<内核特征码扫描PE代码段>中LyShark带大家通过封装好的LySharkToolsUtilKernelBase函数实现了动态获取内核模块基址,并通过ntimage.h ...
- 在Spring Cloud 2020中使用Consul配置中心遇到的问题
升级Spring Cloud 2020后发现Consul配置中心失效了,配置中心的配置和bootstrap.yml中的配置都没有生效. 话不多说,先看官方文档:https://docs.spring. ...
- SESSION会话机制解析
Windows Session(会话)的概念 会话 session 是由代表单个用户登录会话的所有进程和系统对象组成的.其中的对象包括所有的窗口,桌面和windows stations.桌面是特定se ...
- Mac 和 windows上 好用的截图 工具 Snipaste
Snipaste 官网:https://zh.snipaste.com/ ========================= 使用方法,比较简单,可以官网查看
- ListView 判断有没有选中的行方法
ListView1.SelCount 返回选中行的行数 应该是 没有测试 但是测试了 如果没有选中行 返回0 如果选中一行了 返回1
- Linux命令-文件、磁盘管理
Linux命令-文件.磁盘管理 1.文件管理 查看文件信息:ls ls是英文单词list的简写,其功能为列出目录的内容,是用户最常用的命令之一,它类似于DOS下的dir命令. Linux文件或者目 ...
- fmt、变量、常量
fmt包 fmt包主要用于打印数据,常用的有Printf.Print.Printf // 文件所属包 package main // 导入fmt包,主要用于打印数据 import "fmt& ...
- Wireguard笔记(三) lan-to-lan子网穿透和多网段并存
目录 Wireguard笔记(一) 节点安装配置和参数说明 Wireguard笔记(二) 命令行操作 Wireguard笔记(三) lan-to-lan子网穿透和多网段并存 多 Wireguard 服 ...
- Swift —— 一、架构解析
一.简介 OpenStack 对象存储 (swift) 用于冗余.可扩展的数据 使用标准化服务器集群存储PB的存储 可访问的数据.它是一种长期存储系统,可存储大量 可以检索和更新的静态数据.对象存储使 ...