APP联合Unity3D实战

总体流程如下:

一.下载Unity无黑Logo版本和工具,不用工具的有黑logo(各端一定要统一啊)

Unity版本:Unity 2022.1.24 unity.com/releases/ed...

无黑LogoPatch下载地址:github.com/tylearymf/U...

二.代码交互相关:

iOS

1.UnitySendMessage代码是这样的:

// objectName: Unity 对象的名称 // methodName: Unity 对象绑定的脚本方法名 // message: 自定义消息 UnityPlayer.UnitySendMessage(String objectName, String methodName, String message); 该方法有一个弊端,就是发送消息的方法对应的类,必须要挂载在一个 game object 上。 该方法有一点需要注意,就是在原生触发回调接口的时候,可能跟 Unity 的主线程并不是一个线程,此时需要通知 Unity 主线程执行回调。

所以拒绝使用此方法。以下介绍通过 C# 同名方法反射

2.举个例子:

(1)unity工程 .cs代码

// DllImport这个方法相当于是告诉Unity,有一个CallObjCFunc函数在外部会实现。 // 使用这个方法必须要导入System.Runtime.InteropServices; [DllImport("__Internal")] private static extern void takePhotosFromNative(string dictionaryJson); public override void takePhotosFromNative(string dictionaryJson) { #if UNITY_IOS IosNativeAPI.takePhotosFromNative(dictionaryJson); #endif }

每一个方法都要接入[DllImport("__Internal")]

(2)unity工程 .mm代码

对应的takePhotosFromNative在oc层 //拍照之后返回小屋 void takePhotosFromNative(const char*dictionaryJson) { return [api takePhotosFromNative:[NSString stringWithUTF8String:dictionaryJson]]; }

一定要注意这个 stringWithUTF8String

传入string时候如果传入NSString直接崩溃。 //strdup函数需要引入#import <string.h> return strdup([@"abc" UTF8String]) //要调用strdup()函数分配c内存再返回给unity,不然闪退

(3)另一个原生xcode工程的使用:

//拍照之后返回小屋

  • (void)takePhotosFromNative:(NSString*)dictionaryJson {

NSDictionary *dic = [NSString dictionaryWithJsonString:dictionaryJson];

self hideUnity\]; JCSUpLoadAvatarViewController \*vc = \[\[JCSUpLoadAvatarViewController alloc\]init\]; vc.pageFromWhere = UploadAvatarPageFromUnityPoster; vc.posterDic = dic; \[\[UIViewController topmostViewController\].navigationController pushViewController:vc animated:YES\]; self.isLogoutFlag = NO; } ### 具体代码: #### 开启unity工具 文件存放位置 Assets/Scripts/NativeBridge/NativeBridge.cs Assets/Plugins/Android Assets/Plugins/iOS 前面是cs代码,后面是android和iOS代码 交互方式:通过 C# 同名方法反射 Assets/Scripts/NativeBridge/NativeBridge.cs中的代码: > using System.Runtime.InteropServices; using UnityEngine; > > public class NativeAPI { static CNativeAPI _nativeAPI = null; static CNativeAPI nativeAPI { get { if (_nativeAPI == null) { #if UNITY_IOS > > _nativeAPI = new CNativeIOS(); #elif UNITY_ANDROID > > _nativeAPI = new CNativeAndroid(); #else _nativeAPI = new CNativeOther(); #endif } return _nativeAPI; } } > > ```csharp > public static string GetAppHeaderFromNative() > { > return nativeAPI.GetAppHeaderFromNative(); > } > > public static void takePhotosFromNative(string dictionaryJson) > { > nativeAPI.takePhotosFromNative(dictionaryJson); > } > > public static void goBackPendingFromNative() > { > nativeAPI.goBackPendingFromNative(); > } > > public static void goBackKillFromNative() > { > nativeAPI.goBackKillFromNative(); > } > > public static void loginFromNative() > { > nativeAPI.loginFromNative(); > } > > public static void hiddenStartUnityLoading() > { > nativeAPI.hiddenStartUnityLoading(); > } > ``` > > } > > public abstract class CNativeAPI { //// 原生方法获取用户信息声明 public abstract string GetAppHeaderFromNative(); > > ```csharp > // 调用相机 > public abstract void takePhotosFromNative(string dictionaryJson); > > // 返回挂起app > public abstract void goBackPendingFromNative(); > > // 返回杀死app > public abstract void goBackKillFromNative(); > > // 登陆 > public abstract void loginFromNative(); > > // 隐藏启动加载 > public abstract void hiddenStartUnityLoading(); > ``` > > } > > public class CNativeIOS : CNativeAPI { public override string GetAppHeaderFromNative() { #if UNITY_IOS return IosNativeAPI.GetAppHeaderFromNative(); #else return null; #endif } > > ```typescript > public override void takePhotosFromNative(string dictionaryJson) > { > ``` > > #if UNITY_IOS IosNativeAPI.takePhotosFromNative(dictionaryJson); #endif } > > ```csharp > public override void goBackPendingFromNative() > { > ``` > > #if UNITY_IOS IosNativeAPI.goBackPendingFromNative(); #endif } > > ```csharp > public override void goBackKillFromNative() > { > ``` > > #if UNITY_IOS IosNativeAPI.goBackKillFromNative(); #endif } > > ```csharp > public override void loginFromNative() > { > ``` > > #if UNITY_IOS IosNativeAPI.loginFromNative(); #endif } > > ```csharp > public override void hiddenStartUnityLoading() > { > // > } > ``` > > } > > public class CNativeAndroid : CNativeAPI { public override string GetAppHeaderFromNative() { return GetAndroidJavaObject().Call("GetAppHeaderFromNative"); } > > ```csharp > public override void takePhotosFromNative(string dictionaryJson) > { > GetAndroidJavaObject().Call("takePhotosFromNative", dictionaryJson); > } > > public override void goBackPendingFromNative() > { > // > } > > public override void goBackKillFromNative() > { > GetAndroidJavaObject().Call("goBackKillFromNative"); > } > > public override void loginFromNative() > { > GetAndroidJavaObject().Call("LoginFromNative"); > } > > public override void hiddenStartUnityLoading() > { > GetAndroidJavaObject().Call("hiddenStartUnityLoading"); > } > > public AndroidJavaObject GetAndroidJavaObject() > { > AndroidJavaClass jc = new AndroidJavaClass("com.company.product.OverrideUnityActivity"); > AndroidJavaObject overrideActivity = jc.GetStatic("instance"); > return overrideActivity; > } > ``` > > } > > public class CNativeOther : CNativeAPI { public override string GetAppHeaderFromNative() { return ""; } > > ```typescript > public override void takePhotosFromNative(string dictionaryJson) > { > // > } > > public override void goBackPendingFromNative() > { > // > } > > public override void goBackKillFromNative() > { > // > } > > public override void hiddenStartUnityLoading() > { > // > } > > public override void loginFromNative() > { > // > } > ``` > > } > > #if UNITY_IOS public static class IosNativeAPI { //// 在Objective-C中实现的原生方法获取用户信息声明 \[DllImport("__Internal")\] public static extern string GetAppHeaderFromNative(); > > ```csharp > // 在Objective-C中实现调用相机 > [DllImport("__Internal")] > public static extern void takePhotosFromNative(string dictionaryJson); > > // 在Objective-C中实现返回挂起app > [DllImport("__Internal")] > public static extern void goBackPendingFromNative(); > > // 在Objective-C中实现返回杀死app > [DllImport("__Internal")] > public static extern void goBackKillFromNative(); > > // 在Objective-C中实现登陆 > [DllImport("__Internal")] > public static extern void loginFromNative(); > ``` > > } #endif Assets/Plugins/iOS中的代码: NativeCallProxy.h > \`#import \ // NativeCallsProtocol defines protocol with methods you want to be called from managed @protocol NativeCallsProtocol //获取token,userid,homeuserid > > * (const char\*)GetAppHeaderFromNative; //拍照之后返回小屋 > * (void)takePhotosFromNative:(NSString\*)dictionaryJson; //返回挂起unity > * (void)goBackPendingFromNative; //返回杀死unity > * (void)goBackKillFromNative; //登陆 > * (void)loginFromNative; @end > > **attribute** ((visibility("default"))) @interface FrameworkLibAPI : NSObject // call it any time after UnityFrameworkLoad to set object implementing NativeCallsProtocol methods +(void) registerAPIforNativeCalls:(id) aApi; > > @end\` NativeCallProxy.mm代码: > \`#import \ #import "NativeCallProxy.h" > > @implementation FrameworkLibAPI > > id api = NULL; +(void) registerAPIforNativeCalls:(id) aApi { api = aApi; } > > @end > > extern "C" { > > //获取token,userid,homeuserid const char\* GetAppHeaderFromNative(void) { return strdup(\[api GetAppHeaderFromNative\]); } > > //拍照之后返回小屋 void takePhotosFromNative(const char\*dictionaryJson) { return \[api takePhotosFromNative:\[NSString stringWithUTF8String:dictionaryJson\]\]; } > > //返回挂起unity void goBackPendingFromNative(void) { return \[api goBackPendingFromNative\]; } > > //返回杀死unity void goBackKillFromNative(void) { return \[api goBackKillFromNative\]; } > > // 登录 void loginFromNative(void) { return \[api loginFromNative\]; } > > } \` ## 三.执行打包:选择file 下的build setting ![image.png](https://file.jishuzhan.net/article/1777229653509935105/562da7ea4331ca4a7e0e92b8ef23f5a9.webp) 然后选择iOS下的build ![image.png](https://file.jishuzhan.net/article/1777229653509935105/1026589187b1ece70bd2743975dbfec0.webp) 如果代码没报错的话,那么恭喜你unity打包出来可以直接运行在xcode上了。 ## 四.打出来的Unity-iPhone.xcodeproj工程集成到另一个工程中。 ### 1.iOS手动修改配置到另一个工程: #### (1)将打出来的包unity所有文件整个移动到另一个工程的unity3d目录下。 ![image.png](https://file.jishuzhan.net/article/1777229653509935105/398f9264dffd476fa70149462f50d778.webp) #### (2)设置data的target为framework ![image.png](https://file.jishuzhan.net/article/1777229653509935105/4b7d221cbc66535594dfd1e7e1d0ff8c.webp) #### (3)修改unity的target为JRDebug_UAT和JRRelease_ProductSever (如果主工程GoHome没有配置多scheme环境的不用设置) ![image.png](https://file.jishuzhan.net/article/1777229653509935105/f765de2fc879907a735fb89acf6e0d44.webp) 以下为主工程设置(与unity无关) ![image.png](https://file.jishuzhan.net/article/1777229653509935105/9b4776191206afea7e60a7bfa0357590.webp) #### (4)unity framework的navtiveCallProxy.h设置为public ![image.png](https://file.jishuzhan.net/article/1777229653509935105/451c062fac4403fc754954b7db1d95f0.webp) 如果这个中间头文件在project中私有的话,要提到public中,framework要公开头文件 #### (5)运行下unity工程 sucess #### (6)运行下ios工程(如果改动不成功,就把iOS的unityframework删除,重新添加下) ![image.png](https://file.jishuzhan.net/article/1777229653509935105/23998af14c0777b200eaac8c9fb5c8a1.webp) ### 2.iOS通过脚本修改配置到另一个工程: ![image.png](https://file.jishuzhan.net/article/1777229653509935105/24e4bf22e55fcad4a11ed49608a9f099.webp) #### (1)build_move_file.sh文件 > #第一步:修改unity导出来后的配置 > > ruby change_target_membership.rb > > #第二步:编译framework > > xcodebuild -project unity3d/Unity-iPhone.xcodeproj -target UnityFramework -configuration Release > > echo "\\n ---- 第二步,编译framework成功 ---- \\n" > > #第三步:添加framework到主工程中 > > ruby add_unityframework_native.rb ​ ####(2)设置data的target为framework + 修改NativeCallProxy类为公开类 change_target_membership.rb文件 > require 'xcodeproj' > > # 打开Xcode项目 > > project_path = 'unity3d/Unity-iPhone.xcodeproj' > > project = Xcodeproj::Project.open(project_path) > > ### 第一步:修改Data文件的targets > > # 找到对应的targets > > unity_iphone_target = project.targets.find { \|target\| target.name == 'Unity-iPhone' } > > unity_framework_target = project.targets.find { \|target\| target.name == 'UnityFramework' } > > # 查找 Data 文件夹的引用 > > data_group = project.main_group.find_subpath('Data', false) > > # 这是 rough check,确保 data_group 确实指向你想要改变 target membership 的目录 > > raise 'Data directory not found' unless data_group > > # 将 Data 文件夹添加到 unity_framework_target > > unity_framework_target.add_resources(\[data_group\]) > > ### 第一步结束 > > ### 第二步:修改NativeCallProxy类为公开类 > > # 找到NativeCallProxy.h文件 > > native_call_proxy_h_ref = project.files.find { \|file\| file.name == 'NativeCallProxy.h' } > > raise 'NativeCallProxy.h file not found' unless native_call_proxy_h_ref > > # 获取 headers build phase > > headers_build_phase = unity_framework_target.build_phases.find { \|bp\| bp.class == Xcodeproj::Project::Object::PBXHeadersBuildPhase } > > # 查找或创建一个 headers group > > headers_group = project.main_group.find_subpath('Headers', true) > > # 设置NativeCallProxy.h为Public > > native_call_proxy_h_ref.build_files.each do \|build_file\| > > build_file.settings = { 'ATTRIBUTES' =\> \['Public'\] } if build_file.file_ref.real_path == native_call_proxy_h_ref.real_path > > end > > ### 第二步结束 > > ### 保存项目 > > project.save ####(3) 添加framework到主工程中 add_unityframework_native.rb文件 > > ```javascript > require 'xcodeproj' > ``` > > # 打开现有的Xcode项目 > > project_path = 'GoHome.xcodeproj' > > project = Xcodeproj::Project.open(project_path) > > # 找到你要添加框架的目标 > > target = project.targets.find { \|t\| t.name == 'GoHome' } > > # 指定要添加的新Framework路径 > > new_framework_path = 'unity3d/build/Release-iphoneos/UnityFramework.framework' > > # 定位到Frameworks引用组,这取决于你项目的实际结构 > > framework_group = project.frameworks_group > > # 查找并删除现有的UnityFramework.framework引用 > > exist_framework_ref = framework_group.files.find { \|file\| file.path =\~ /UnityFramework.framework/ } > > if exist_framework_ref > > # 从构建阶段中移除 > > target.frameworks_build_phases.remove_file_reference(exist_framework_ref) > > # 从项目引用中移除 > > framework_group.children.delete(exist_framework_ref) > > # 实际删除文件引用 > > exist_framework_ref.remove_from_project > > end > > # 添加新的UnityFramework.framework引用 > > framework_reference = framework_group.new_file(new_framework_path) > > # 将framework添加到目标的'Frameworks'构建阶段中 > > target.frameworks_build_phases.add_file_reference(framework_reference, true) > > # 确保新添加的Framework被设置为"Embed \& Sign" > > attributes = \['CodeSignOnCopy', 'RemoveHeadersOnCopy'

embed_frameworks_build_phase = target.build_phases.find { |bp| bp.is_a?(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase) && bp.symbol_dst_subfolder_spec == :frameworks }

如果没有找到嵌入的构建阶段,就创建一个

unless embed_frameworks_build_phase

embed_frameworks_build_phase = project.new(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase)

embed_frameworks_build_phase.name = 'Embed Frameworks'

embed_frameworks_build_phase.symbol_dst_subfolder_spec = :frameworks

target.build_phases << embed_frameworks_build_phase

end

添加文件引用到那个构建阶段

build_file = embed_frameworks_build_phase.add_file_reference(framework_reference)

build_file.settings = { 'ATTRIBUTES' => attributes }

将改动保存到Xcode项目文件

project.save

puts ' ---- 最后一步,替换Framework成功 ---- '

以上运行到了原生工程中,接下来是原生代码中具体使用。

1.封装中间类

JCSUnityManager.h代码

`#import <Foundation/Foundation.h> #include <UnityFramework/UnityFramework.h> #include <UnityFramework/NativeCallProxy.h>

NS_ASSUME_NONNULL_BEGIN

@interface JCSUnityManager : UIResponder<UIApplicationDelegate,UnityFrameworkListener,NativeCallsProtocol>

  • (instancetype _Nullable )shareInstance; -(void) setLaunchConfigs:(UIWindow *)utWindow launchOptions:(NSDictionary *)options; -(void)firstTimePrepareUnity:(void(^)(BOOL completed))completion; -(void) prepareUnity:(void(^)(BOOL completed))completion; -(void) pauseUnity:(BOOL)paused; -(void) hideUnity; -(void) quitUnity:(void(^)())completion; -(void) unloadUnity;
  • (bool)unityIsInitialized; -(void) sendMessage:(NSString *)clsName Method:(NSString *)method Message:(NSString *)message; -(UIViewController *) getUnityRootViewController; -(UIView *) getUnityView; @property (nonatomic, strong) UnityFramework *unityFwk; @property(nonatomic, assign) BOOL isLogoutFlag; //获取token,userid,homeuserid
  • (const char*)GetAppHeaderFromNative; //拍照之后返回小屋
  • (void)takePhotosFromNative:(NSString*)dictionaryJson; //返回挂起unity
  • (void)goBackPendingFromNative; //返回杀死unity
  • (void)goBackKillFromNative; //登陆
  • (void)loginFromNative;

@end

NS_ASSUME_NONNULL_END`

JCSUnityManager.m代码

`#import "JCSUnityManager.h" #import "AppDelegate.h" #import "AppDelegate+Event.h" #import "JRLoginViewModel.h" #import "JCSUpLoadAvatarViewController.h" #import "NSString+Help.h"

@interface JCSUnityManager()

@property(nonatomic,strong) UIWindow *hostWindow; @property(nonatomic,strong) NSDictionary *launchOpts;

@property (nonatomic, strong) JRLoginViewModel *viewModel; @end

@implementation JCSUnityManager

/** 单例 */

  • (instancetype)shareInstance{ static JCSUnityManager *instance = nil; static dispatch_once_t onceToken; _dispatch_once(&onceToken, ^{ instance = [[JCSUnityManager alloc] init]; }); return instance; }

-(void)setLaunchConfigs:(UIWindow *)utWindow launchOptions:(NSDictionary *)options { self.hostWindow = utWindow; self.launchOpts = options; }

  • (bool)unityIsInitialized { // 判斷是否已經初始化過Unity執行環境 return self.unityFwk && [self.unityFwk appController]; }

  • (void)initUnity:(void(^)(BOOL completed))completion { // 初始化Unity執行環境 if([self unityIsInitialized]) { completion(true); return; }

    self.unityFwk = [self loadUnityFramework]; [self.unityFwk setDataBundleId:"com.unity3d.framework"]; [self.unityFwk registerFrameworkListener:self]; [NSClassFromString(@"FrameworkLibAPI") registerAPIforNativeCalls:self];

    // 取得APP執行參數 NSArray *arguments = [[NSProcessInfo processInfo] arguments]; int argc = (int)arguments.count;

    self.unityFwk runEmbeddedWithArgc:argc argv:\[self getChar:arguments\] appLaunchOpts: self.launchOpts\]; completion(true); }

-(UIView *)getUnityView { return [self getUnityRootViewController].view; }

-(void)firstTimePrepareUnity:(void(^)(BOOL completed))completion { // 準備Unity執行環境並執行 if (![self unityIsInitialized]) { [self initUnity:^(BOOL completed) { if (completed) { dispatch_async(dispatch_get_main_queue(), ^{ completion(true); }); } }]; } else { dispatch_async(dispatch_get_main_queue(), ^{ completion(true); }); } }

-(void) prepareUnity:(void(^)(BOOL))completion { // 準備Unity執行環境並執行 if (![self unityIsInitialized]) { [self initUnity:^(BOOL completed) { if (completed) { [self.unityFwk showUnityWindow]; dispatch_async(dispatch_get_main_queue(), ^{ completion(true); }); } }]; } else {

scss 复制代码
    [self.unityFwk showUnityWindow];
                
    dispatch_async(dispatch_get_main_queue(), ^{
        completion(true);
    });
}

}

-(void) sendMessage:(NSString *)clsName Method:(NSString *)method Message:(NSString *)message { [self.unityFwk sendMessageToGOWithName:clsName.UTF8String functionName:method.UTF8String message:message.UTF8String]; }

-(void) hideUnity { if (self.hostWindow != nil) { [self.hostWindow makeKeyAndVisible]; } }

-(void) pauseUnity:(BOOL)paused { if (self.unityFwk != nil) { [self.unityFwk pause:paused]; } }

-(void) quitUnity:(void(^)())completion { if ([self unityIsInitialized]) { [self.unityFwk appController].quitHandler = ^{ NSLog(@"AppController.quitHandler called"); dispatch_async(dispatch_get_main_queue(), ^{ completion(); }); }; [self.unityFwk quitApplication:0]; } }

  • (void) unloadUnity { if ([self unityIsInitialized]) { [self.unityFwk unloadApplication]; } }

#pragma mark - 清掉Listener

  • (void)unityDidUnload:(NSNotification*)notification { NSLog(@"unityDidUnloaded called"); if (self.hostWindow != nil) { [self.hostWindow makeKeyAndVisible]; } [self.unityFwk unregisterFrameworkListener:self]; self.unityFwk = nil;

    if(self.isLogoutFlag) { [JCSCommonTool clearLocalData]; self.isLogoutFlag = NO; }

// [self setUnityFwk: nil]; }

  • (void)unityDidQuit:(NSNotification *)notification { NSLog(@"========== %s ============",func);

    if (self.hostWindow != nil) { [self.hostWindow makeKeyAndVisible]; } }

  • (UnityFramework *) loadUnityFramework { // 載入UnityFramework

    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; }

  • (char**)getChar:(NSArray *) a_array{ NSUInteger count = [a_array count]; char **array = (char *)malloc((count + 1) * sizeof(char));

    for (unsigned i = 0; i < count; i++) { array[i] = strdup([[a_array objectAtIndex:i] UTF8String]); } array[count] = NULL; return array; }

  • (void)applicationWillResignActive:(UIApplication *)application { [[[JCSUnityManager shareInstance].unityFwk appController] applicationWillResignActive: application]; }

  • (void)applicationDidEnterBackground:(UIApplication *)application { [[[JCSUnityManager shareInstance].unityFwk appController]applicationDidEnterBackground: application]; }

  • (void)applicationWillEnterForeground:(UIApplication *)application { [[[JCSUnityManager shareInstance].unityFwk appController] applicationWillEnterForeground: application]; }

  • (void)applicationDidBecomeActive:(UIApplication *)application { [[[JCSUnityManager shareInstance].unityFwk appController] applicationDidBecomeActive: application]; }

  • (void)applicationWillTerminate:(UIApplication *)application { [[[JCSUnityManager shareInstance].unityFwk appController] applicationWillTerminate: application]; }

#pragma mark - NativeCallsProtocol //获取token,userid,homeuserid

  • (const char*)GetAppHeaderFromNative { self.isLogoutFlag = NO; NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]init];

    // token NSString *authorization = [JRAccountManager authorization]; [dictionary setValue:authorization forKey:@"Authorization"];

    dictionary setValue:\[JRAccountManager memberId\] forKey:@"userId"\]; NSString \*roomHostId = \[JCSCommonTool getUnityCurrentUserId\]; if(roomHostId \&\& !\[roomHostId isEqualToString:\[JRAccountManager memberId\]\]) { \[dictionary setValue:roomHostId forKey:@"roomHostId"\]; } else { \[dictionary setValue:\[JRAccountManager memberId\] forKey:@"roomHostId"\]; } NSString \*str = \[JRAPIManager hostUrl\]; \[dictionary setValue:str forKey:@"hostUrl"\]; NSLog(@"dictionary==%@",dictionary); NSError \*error; NSData \*jsonData = \[NSJSONSerialization dataWithJSONObject:dictionary options:0 error:\&error\]; NSString \*dicString = \[\[NSString alloc\] initWithData:jsonData encoding:NSUTF8StringEncoding\]; const char \*temp11 = \[dicString UTF8String\]; // \[\[self ufw\] sendMessageToGOWithName: "Cube" functionName: "ReceiveHeaderDictionaryFromiOS" message: temp11\]; return temp11; }

  • (void)takePhotosFromNative:(NSString*)dictionaryJson { // NSLog(@"拍照%@",dictionaryJson); NSDictionary *dic = [NSString dictionaryWithJsonString:dictionaryJson]; // NSMutableDictionary *muDic = [[NSMutableDictionary alloc]initWithDictionary:dic]; // NSLog(@"拍照dic%@",dic); // [self pauseUnity:YES]; [self hideUnity]; JCSUpLoadAvatarViewController *vc = [[JCSUpLoadAvatarViewController alloc]init]; vc.pageFromWhere = UploadAvatarPageFromUnityPoster; vc.posterDic = dic; [[UIViewController topmostViewController].navigationController pushViewController:vc animated:YES]; self.isLogoutFlag = NO;

}

//返回挂起unity

  • (void)goBackPendingFromNative { self.isLogoutFlag = NO;

}

//返回杀死unity

  • (void)goBackKillFromNative { // [self quitUnity:^{ // NSLog(@"%@",self.unityFwk); // }]; [self unloadUnity]; self.isLogoutFlag = NO; // [self hideUnity]; }

//登陆

  • (void)loginFromNative { NSLog(@"登录");

    self unloadUnity\]; self.isLogoutFlag = YES;

2.appdelegate预加载unity:(避免黑屏或者闪屏等待时间过长,需要unity退出时销毁干净场景的全局资源)

\[JCSUnityManager shareInstance\]firstTimePrepareUnity:\^(BOOL completed) { \[\[JCSUnityManager shareInstance\] unloadUnity\]; }\]; \[\[JCSUnityManager shareInstance\]setLaunchConfigs:self.window launchOptions:launchOptions\]; ### Android **1、下载和解压项目** 这个项目里有一个跟安卓原生应用一起工作的UnityPlayerActivity的扩展,叫OverrideUnityActivity。这个Unity项目会被我们嵌入到Android Studio的一个基础的应用模板中,它就像任何一个带用户界面的Android应用那样,通过Intent的方式启动Unity部分。 我们提供的原生Android项目是来自Android Studio模板的Basic Activity应用程序,我们会把前面的Unity项目加入到这里。该项目有UI和MainUnityActivity来扩展OverrideUnityActivity,可以使用Intent启动MainUnityActivity。 2. 把Unity项目和原生Android项目解压到同一个文件夹里使得后续操作更简单。 ![image](https://file.jishuzhan.net/article/1777229653509935105/cc7ccc1108cea8e9ffbf9be44588001b.webp) **2、生成Android平台的Gradle项目** 在Unity中打开这个项目,导航到"Build Settings",切换到安卓平台并且勾选"Export Project"来导出项目。 ![image](https://file.jishuzhan.net/article/1777229653509935105/8029decf96164062ae36464e6b64718b.webp) 当Unity项目导出之后,你会得到包含了unityLibrary模块的androidBuild文件夹。。 ![image](https://file.jishuzhan.net/article/1777229653509935105/f09a1d2a7063a0b956d19a0ae13aacb4.webp) 3、把Unity Library模块添加到NativeAndroidApp 现在你要做的是,将unityLibrary模块添加到你的原生Android项目中去。你可以通过修改Android Studio项目的settings.gradle文件来实现,只需在文件最后添加上一行代码来包含unityLibrary ```php 复制代码 include ':unityLibrary' project(':unityLibrary').projectDir=new File('..\UnityProject\androidBuild\unityLibrary') ``` ![image](https://file.jishuzhan.net/article/1777229653509935105/9d4f40dd2f9aca1c6aa95fa5a47f84a7.webp) 之后,更新app模块的build.gradle文件来声明对unityLibrary模块的依赖。 ```java 复制代码 implementation project(':unityLibrary') ``` ![image](https://file.jishuzhan.net/article/1777229653509935105/c66a1b046d0461b1326a5d60fe0a1591.webp) 打开build.gradle文件,把下面代码添加到allprojects{repositories{代码块。 ```bash 复制代码 flatDir { dirs "${project(':unityLibrary').projectDir}/libs" } ``` ![image](https://file.jishuzhan.net/article/1777229653509935105/2af7e8aac88a62b5e035b8d232fa111e.webp) Gradle文件已经修改,单击Sync Now。 ![image](https://file.jishuzhan.net/article/1777229653509935105/41f1743655b1994961495828a6517212.webp) 修改完后,同步Gradle,这样unityLibrary就被加入到项目中了。 ![image](https://file.jishuzhan.net/article/1777229653509935105/925e1ec74f20053ff9431c6570ab2a1a.webp) 1. 你现在可以尝试构建并运行应用了。如果一切顺利,应用应当能够正常启动和运行。 ![image](https://file.jishuzhan.net/article/1777229653509935105/6a3dc6d6684cdf4cc70ef1e05e4cf562.webp) 如果一切顺利,我们应该可以运行NativeAndroidApp。 ![image](https://file.jishuzhan.net/article/1777229653509935105/bbb6096fcd027ca23c0cb598bb8a03c5.webp) 请注意:在应用程序安装到设备后,会出现二个启动应用程序的图标,请把...从unityLibrary的AndroidManifest.xml去掉,仅保留集成版本。 当你完成集成并安装应用到你的设备之后,你可能会注意到有两个启动图标出现。这通常是因为unityLibrary模块的AndroidManifest.xml文件中定义了一个额外的启动器入口。你需要做的是,去掉这个多余的入口,只保留你的原生Android应用需要的那部分。这样做你的应用就只会有一个启动图标了。 另外,如果你在将Unity项目集成到原生Android应用的过程中遇到了任何难题,一个解决的办法是使用一个全面配置好的完整项目。你可以下载这个完整的项目文件包,解压后,在Android Studio中打开NativeAndroidApp。这个完整的项目已经设置好了所需的所有配置,并且可以直接构建和部署。这样就可以省去你手动整合的麻烦,特别是如果你是第一次尝试这样做或是对整个流程不是很熟悉的话。使用完整项目作为起点,可以帮助你更容易地理解整合过程,并且保证你有一个稳定的基础来进行后续的开发和调试。 ## 参考Unity完整项目地址: 请访问云盘下载示例项目 下载链接: [pan.baidu.com/s/1JFWjbrh2...](https://link.juejin.cn/?target=https%3A%2F%2Fpan.baidu.com%2Fs%2F1JFWjbrh2x-qAsCzMwLywLA "https://link.juejin.cn/?target=https%3A%2F%2Fpan.baidu.com%2Fs%2F1JFWjbrh2x-qAsCzMwLywLA")

相关推荐
北桥苏2 天前
如何在 Unity3D 中实现圆角效果?
unity3d·游戏开发
却尘4 天前
Server Actions 深度剖析(2):缓存管理与重新验证,如何用一行代码干掉整个客户端状态层
前端·客户端·next.js
程序员老刘6 天前
Google突然“变脸“,2026年要给全球开发者上“紧箍咒“?
android·flutter·客户端
Lei活在当下7 天前
【业务场景架构实战】1. 多模块 Hilt 使用原则和环境搭建
性能优化·架构·客户端
万少12 天前
可可图片编辑 HarmonyOS(3)应用间分享图片
前端·harmonyos·客户端
泉城老铁15 天前
VUE2实现加载Unity3d
前端·vue.js·unity3d
程序员老刘16 天前
Dart MCP翻车了!3.9.0版本无法运行,这个坑你踩过吗?
flutter·ai编程·客户端
程序员老刘17 天前
Cursor vs Claude Code vs AS+AI助手:谁才是客户端的编程神器?
flutter·ai编程·客户端
evamango17 天前
《Unity Shader入门精要》十一、让画面动起来
unity3d
Thomas游戏开发17 天前
Unity Android性能优化设置指南
前端框架·unity3d·游戏开发