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")

相关推荐
杂雾无尘11 天前
不为人知的技巧:Swift 中用特有方法实现"黑魔法"方法交换
ios·swift·客户端
杂雾无尘14 天前
iOS 分享扩展(五):解锁 iOS 分享面板的神秘的联系人推荐功能
ios·swift·客户端
留待舞人归19 天前
【Unity3D优化】优化多语言字体包大小
游戏·unity·游戏引擎·unity3d·优化
程序员老刘21 天前
iOS 26 beta1 真机无法执行hot reload
flutter·ios·客户端
留待舞人归22 天前
【Unity优化】提高热更新和打包速度
游戏·unity·游戏引擎·unity3d·优化
万少22 天前
我们又来啦 又又上架了一个鸿蒙项目-萤火故事屋
前端·harmonyos·客户端
万少23 天前
HarmonyOS Next 弹窗系列教程(3)
前端·harmonyos·客户端
Thomas游戏开发24 天前
Unity3D 自动化游戏框架设计
前端框架·unity3d·游戏开发
一名用户1 个月前
unity实现自定义粒子系统
c#·unity3d·游戏开发
程序员老刘1 个月前
20%的选择决定80%的成败
flutter·架构·客户端