前言
前段时间需要用Unity3D做AR开发展示嵌入的iOS和android中,在过程中碰到了一些问题,现在分享给大家。
准备工作
Unity版本用的是
版本升高之后,在app调试时会crash,无法进行调试,不知道具体的原因是什么,但app release之后是可以使用的。
导入依赖文件
在Unity文件中导入NativeCallProxy的依赖文件。
// NativeCallProxy.h
#import <Foundation/Foundation.h>
@protocol NativeCallsProtocol
@required
- (void)iOSLog:(NSString *)value;
- (void)backToIOS;
@end
__attribute__ ((visibility("default")))
@interface FrameworkLibAPI: NSObject
+(void)registerAPIforNativeCalls:(id<NativeCallsProtocol>) aApi;
@end
NativeCallProxy.mm
文件
// NativeCallProxy.mm
#import <Foundation/Foundation.h>
#import "NativeCallProxy.h"
@implementation FrameworkLibAPI
id<NativeCallsProtocol> api = NULL;
+(void)registerAPIforNativeCalls: (id<NativeCallsProtocol>) aApi
{
api = aApi;
}
@end
extern "C" {
void iOSLog(const char * value);
}
void iOSLog(const char * value) {
return [api iOSLog:[NSString stringWithUTF8String: value]];
}
extern "C" {
void backToIOS(const char * value);
}
void backToIOS(const char* value) {
return [api backToIOS];
}
这两个文件导入到Unity3D原文件中,如图所示,放入iOS文件夹下。
Unity3D的脚本文件代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
public class Jiaoben : MonoBehaviour {
[DllImport("__Internal")]
private static extern void iOSLog(string name);
[DllImport("__Internal")]
private static extern void backToIOS();
// Unity调用iOS的两个方法,一个是打印log另一个是返回按钮
void Start() {
Debug.Log("脚本开始运行");
}
// Update is called once per frame
void Update()
{
}
// iOS调用Unity的方法。
public void sendArMessage(string msg) {
Debug.Log("从iOS接收到的消息:", msg);
}
}
导入iOS工程
将导出的文件拖入到iOS工程中。
选中Unity-iPhone
中的Data
文件,并选中UnityFramework
如下图
然后选中UnityFramework目标,并点击build按钮进行build。更新UnityFramework文件,如下图。
build完成后,选中你的主项目,找到General中的Frameworks,Libraries,and Embedded Content
。
点击+
,在弹出的搜索框中选中UnityFramework.framework,Embed的状态无需改变
最终状态
iOS端开发
接下来我们对iOS端的AppDelegate文件进行修改
// AppDelegate.h
#import <UIKit/UIKit.h>
#include <UnityFramework/UnityFramework.h>
#import <UnityFramework/NativeCallProxy.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate,UnityFrameworkListener, NativeCallsProtocol>
@property (strong, nonatomic) UIWindow * window;
@property (strong, nonatomic) UnityFramework *ufw;
- (void)showUnityView;
- (void)showNativeView;
- (void)sendMessageWithName:(const char*)goName functionName:(const char*) functionName message:(const char*)msg;
@end
AppDelegate.m
#import "AppDelegate.h"
#import "QHJSBaseWebLoader.h"
/* UnityFrameworkLoad */
UIKIT_STATIC_INLINE UnityFramework* UnityFrameworkLoad()
{
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];
}
[ufw setDataBundleId:"com.unity3d.framework"]; /////////add this code
return ufw;
}
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[self initUnity];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
QHJSBaseWebLoader *rootVc = [[QHJSBaseWebLoader alloc]init];
UINavigationController *rootNav = [[UINavigationController alloc]initWithRootViewController:rootVc];
[rootNav setNavigationBarHidden:YES];
[self.window setRootViewController:rootNav];
[self.window makeKeyAndVisible];
return YES;
}
// 打印方法
-(void)iOSLog:(NSString *)value{
NSLog(@"%@", [NSString stringWithFormat:@"Unity 掉用iOS打印出 :%@",value]);
}
// 返回按钮
-(void)backToIOS {
[self showNativeView];
}
- (UIViewController *) rootViewController {
return [[self ufw] appController].rootViewController;
}
#pragma mark - Unity
- (BOOL)unityIsInitialized
{
return [self ufw] && [[self ufw] appController];
}
- (void)initUnity
{
/* 判断Unity 是否已经初始化 */
if ([self unityIsInitialized]) return;
/* 初始化Unity */
self.ufw = UnityFrameworkLoad();
[self.ufw setDataBundleId:"com.unity3d.framework"];
[self.ufw registerFrameworkListener:self];
[NSClassFromString(@"FrameworkLibAPI") registerAPIforNativeCalls:self];
NSString *argvStr = [[NSUserDefaults standardUserDefaults] valueForKey:@"argv"];
char **argv;
sscanf([argvStr cStringUsingEncoding:NSUTF8StringEncoding], "%p",&argv);
int argc = [[[NSUserDefaults standardUserDefaults] valueForKey:@"argc"] intValue];
NSDictionary *launchOptions = [[NSUserDefaults standardUserDefaults] valueForKey:@"launchOptions"];
[self.ufw runEmbeddedWithArgc:argc argv:argv appLaunchOpts:launchOptions];
}
- (void)showUnityView {
if (![self unityIsInitialized]){
NSLog(@"Unity 还未初始化");
}
[self.ufw showUnityWindow];
}
- (void)showNativeView {
[self.window makeKeyAndVisible];
}
- (void)sendMessageWithName:(const char*)goName functionName:(const char*) functionName message:(const char*)msg{
[self.ufw sendMessageToGOWithName:goName functionName:functionName message:msg];
}
#pragma mark - UnityFrameworkListener
- (void)unityDidUnload:(NSNotification *)notification
{
NSLog(@"========== %s ============",__func__);
[self.window makeKeyAndVisible];
[[self ufw] unregisterFrameworkListener: self];
[self setUfw: nil];
}
- (void)unityDidQuit:(NSNotification *)notification
{
NSLog(@"========== %s ============",__func__);
}
- (void)applicationWillResignActive:(UIApplication *)application {
[[[self ufw] appController] applicationWillResignActive: application];
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[[self ufw] appController] applicationDidEnterBackground: application];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[[[self ufw] appController] applicationWillEnterForeground: application];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[[self ufw] appController] applicationDidBecomeActive: application];
}
- (void)applicationWillTerminate:(UIApplication *)application {
[[[self ufw] appController] applicationWillTerminate: application];
}
@end
调用方法
AppDelegate *appDelegate = (AppDelegate *)([UIApplication sharedApplication].delegate);
[appDelegate showUnityView];
[appDelegate sendMessageWithName:[@"AR Session Origin" UTF8String] functionName:[@"sendArMessage" UTF8String] message:[message.body UTF8String]];
通过这个调用方法就可以打开新的Unity的页面。