ReactNative集成Unity3D

ReactNative集成Unity3D

首先版本号

React Native 版本 0.59.0

Unity3D 版本 2019.3.4f1

这里我们先看Unity3D导出工程的设置

首先我们先建立一个项目,这里我随便建立一个Unity3D项目,如下图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eAOpAFj0-1597387382192)(http://loveit.cool:10088/unity86.png)]

然后我们选择File — Build Settings — iOS — Player Settings,这里我们可以设置打包是release还是debug版本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WpxRYCvu-1597387382197)(http://loveit.cool:10088/unity87.png)]

点击Player Settings后会弹出一下面板,这里有几个需要注意的地方

1.首先 Auto Graphics API 去掉勾选,下面Graphics API去掉metal选择OpenGLES2
2.Bundle ID 和版本号要写成和你集成app一样的ID和版本号
3.Target SDK 选择设备的SDK,否则无法打包发布以及最低版本号支持
4.Strip Engine Code 去掉勾选,此处不对代码打包优化,否则有的静态库会缺失

image.png

image.png

以上操作完毕之后直接点击build打包即可(这里根据项目大小,等待时间不一)

完成打包后会生成以下文件

image.png

接下来我们回到IOS工程

首先我们用rn新建一个ios项目

react-native init r nunity --verbose --version 0.59.0

新建好项目后,这是我的目录结构,我们找到ios目录

image.png

点击打开上图中的ios文件夹,把unity3d工程生成的几个文件复制过来,下午红色框为复制过来的文件

image.png

然后我们用xcode打开新建的rn项目,导入一下包,注意要用两种方式导入

image.png

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7yl7dVW5-1597387382205)(http://106.13.63.7:10088/unity94.png)]

导入完成后为这个样子

image.png

这里我们要删除Libraries里面的ibil2cpp文件夹下的所有引用,注意这里是删除引用 不是删除文件,如下

image.png

然后我们就要引入.framework文件,如下图,注意有三个需要调成Option的,不调整会报错

image.png

然后切换到Build Setting设置以下属性

Enable Bitcode :  NO

Other C Flags
Other C++ Flags
设置以下属性
-DINIT_SCRIPTING_BACKEND=1
-DRUNTIME_IL2CPP=1
-DNET_4_0
-fexceptions

image.png

prefix的设置,参考下图

image.png

设置unity版本号等信息,一共四项根据你的项目版本设置
GCC_THUMB_SUPPORT    NO
GCC_USE_INDIRECT_FUNCTION_CALLS   NO
UNITY_RUNTIME_VERSION   2019.3.4f1
UNITY_SCRIPTING_BACKEND il2cpp

image.png

添加Run Script
"$PROJECT_DIR/MapFileParser.sh"

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7jLxn2k0-1597387382211)(http://106.13.63.7:10088/unity101.png)]

main.mm文件的处理
首先复制Classes里面的main.mm文件内容
然后删除Classes里main.mm文件的引用
同时修改app文件的maim.m 把复制的黏贴过来
然后删除app中的main.m文件的引用
将app中的main.m文件改名为main.mm
然后加入到引用中即可,以下为代码

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#include "RegisterFeatures.h"
#include <csignal>
#include "UnityInterface.h"
#include "../UnityFramework/UnityFramework.h"

void UnityInitTrampoline();

// WARNING: this MUST be c decl (NSString ctor will be called after +load, so we cant really change its value)
const char* AppControllerClassName = "AppDelegate";

int main(int argc, char * argv[]) {
  @autoreleasepool {
    
    UnityInitTrampoline();
    UnityInitRuntime(argc,argv);
    RegisterFeatures();
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}

#if UNITY_USES_DYNAMIC_PLAYER_LIB
extern "C" void SetAllUnityFunctionsForDynamicPlayerLib();
#endif

extern "C" void UnitySetExecuteMachHeader(const MachHeader* header);

extern "C" __attribute__((visibility("default"))) NSString* const kUnityDidUnload;
extern "C" __attribute__((visibility("default"))) NSString* const kUnityDidQuit;

@implementation UnityFramework
{
    int runCount;
}

UnityFramework* _gUnityFramework = nil;
+ (UnityFramework*)getInstance
{
    if (_gUnityFramework == nil)
    {
        _gUnityFramework = [[UnityFramework alloc] init];
    }
    return _gUnityFramework;
}

- (UnityAppController*)appController
{
    return GetAppController();
}

- (void)setExecuteHeader:(const MachHeader*)header
{
    UnitySetExecuteMachHeader(header);
}

- (void)sendMessageToGOWithName:(const char*)goName functionName:(const char*)name message:(const char*)msg
{
    UnitySendMessage(goName, name, msg);
}

- (void)registerFrameworkListener:(id<UnityFrameworkListener>)obj
{
#define REGISTER_SELECTOR(sel, notif_name)                  \
if([obj respondsToSelector:sel])                        \
[[NSNotificationCenter defaultCenter]   addObserver:obj selector:sel name:notif_name object:nil];

    REGISTER_SELECTOR(@selector(unityDidUnload:), kUnityDidUnload);
    REGISTER_SELECTOR(@selector(unityDidQuit:), kUnityDidQuit);

#undef REGISTER_SELECTOR
}

- (void)unregisterFrameworkListener:(id<UnityFrameworkListener>)obj
{
    [[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityDidUnload object: nil];
    [[NSNotificationCenter defaultCenter] removeObserver: obj name: kUnityDidQuit object: nil];
}

- (void)frameworkWarmup:(int)argc argv:(char*[])argv
{
#if UNITY_USES_DYNAMIC_PLAYER_LIB
    SetAllUnityFunctionsForDynamicPlayerLib();
#endif


    UnityInitTrampoline();
    UnityInitRuntime(argc, argv);

    RegisterFeatures();

    // iOS terminates open sockets when an application enters background mode.
    // The next write to any of such socket causes SIGPIPE signal being raised,
    // even if the request has been done from scripting side. This disables the
    // signal and allows Mono to throw a proper C# exception.
    std::signal(SIGPIPE, SIG_IGN);
}

- (void)setDataBundleId:(const char*)bundleId
{
    UnitySetDataBundleDirWithBundleId(bundleId);
}

- (void)runUIApplicationMainWithArgc:(int)argc argv:(char*[])argv
{
    self->runCount += 1;
    [self frameworkWarmup: argc argv: argv];
    UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String: AppControllerClassName]);
}

- (void)runEmbeddedWithArgc:(int)argc argv:(char*[])argv appLaunchOpts:(NSDictionary*)appLaunchOpts
{
    if (self->runCount)
    {
        // initialize from partial unload ( sceneLessMode & onPause )
        UnityLoadApplicationFromSceneLessState();
        [self pause: false];
        [self showUnityWindow];
    }
    else
    {
        // full initialization from ground up
        [self frameworkWarmup: argc argv: argv];

        id app = [UIApplication sharedApplication];

        id appCtrl = [[NSClassFromString([NSString stringWithUTF8String: AppControllerClassName]) alloc] init];
        [appCtrl application: app didFinishLaunchingWithOptions: appLaunchOpts];

        [appCtrl applicationWillEnterForeground: app];
        [appCtrl applicationDidBecomeActive: app];
    }

    self->runCount += 1;
}

- (void)unloadApplication
{
    UnityUnloadApplication();
}

- (void)quitApplication:(int)exitCode
{
    UnityQuitApplication(exitCode);
}

- (void)showUnityWindow
{
    [[[self appController] window] makeKeyAndVisible];
}

- (void)pause:(bool)pause
{
    UnityPause(pause);
}

@end


#if TARGET_IPHONE_SIMULATOR && TARGET_TVOS_SIMULATOR
#include <pthread.h>

extern "C" int pthread_cond_init$UNIX2003(pthread_cond_t *cond, const pthread_condattr_t *attr)
{ return pthread_cond_init(cond, attr); }
extern "C" int pthread_cond_destroy$UNIX2003(pthread_cond_t *cond)
{ return pthread_cond_destroy(cond); }
extern "C" int pthread_cond_wait$UNIX2003(pthread_cond_t *cond, pthread_mutex_t *mutex)
{ return pthread_cond_wait(cond, mutex); }
extern "C" int pthread_cond_timedwait$UNIX2003(pthread_cond_t *cond, pthread_mutex_t *mutex,
    const struct timespec *abstime)
{ return pthread_cond_timedwait(cond, mutex, abstime); }

#endif // TARGET_IPHONE_SIMULATOR && TARGET_TVOS_SIMULATOR

image.png

然后Prefix.pch加上如下引用
#import "UnityAppController.h"

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rxQaJ5JB-1597387382213)(http://106.13.63.7:10088/unity103.png)]

Appdelegate.h如下修改

#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>

@class UnityAppController;
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>

@property (nonatomic, strong) UIWindow *window;

@property (nonatomic, strong) UIWindow *unityWindow;

@property (nonatomic, strong) UIWindow *unityController;

@end

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZasyV2GZ-1597387382214)(http://106.13.63.7:10088/unity104.png)]

Appdelegate.m如下修改

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import "AppDelegate.h"
#import "UnityAppController.h"

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

@implementation AppDelegate

- (UIWindow *)unityWindow
{
  return UnityGetMainWindow();
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:@"rnunity"
                                            initialProperties:nil];

  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  
  _UnityAppController = [[UnityAppController alloc]init];//这里初始化unity
  [_UnityAppController application:application didFinishLaunchingWithOptions:launchOptions];
  self.window = _UnityAppController.window;
//  [self.window makeKeyAndVisible];
  return YES;
}

-(void)applicationWillResignActive:(UIApplication *)application{
  [_UnityAppController applicationWillResignActive:application];
}
 
-(void)applicationDidEnterBackground:(UIApplication *)application{
  [_UnityAppController applicationDidEnterBackground:application];
}
 
-(void)applicationWillEnterForeground:(UIApplication *)application{
  [_UnityAppController applicationWillEnterForeground:application];
}
 
-(void)applicationDidBecomeActive:(UIApplication *)application{
  [_UnityAppController applicationDidBecomeActive:application];
}
 
-(void)applicationWillTerminate:(UIApplication *)application{
  [_UnityAppController applicationWillTerminate:application];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

@end

image.png

运行的时候设置为release版本即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZKcWMswK-1597387382216)(http://106.13.63.7:10088/unity106.png)]

运行效果

image.png

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值