APP联合Unity3D实战 总体流程如下: 打开Xcode

总体流程如下:

未命名文件 (3).png

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

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

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

二.代码交互相关:

iOS

1.UnitySendMessage代码是这样的:

1
2
3
4
arduino复制代码// objectName: Unity 对象的名称
// methodName: Unity 对象绑定的脚本方法名
// message: 自定义消息
UnityPlayer.UnitySendMessage(String objectName, String methodName, String message);

该方法有一个弊端,就是发送消息的方法对应的类,必须要挂载在一个 game object 上。
该方法有一点需要注意,就是在原生触发回调接口的时候,可能跟 Unity 的主线程并不是一个线程,此时需要通知 Unity 主线程执行回调。

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

2.举个例子:

(1)unity工程 .cs代码

1
2
3
4
5
6
7
8
9
10
csharp复制代码// 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层

1
2
3
4
arduino复制代码//拍照之后返回小屋
void takePhotosFromNative(const char*dictionaryJson) {
return [api takePhotosFromNative:[NSString stringWithUTF8String:dictionaryJson]];
}

一定要注意这个 stringWithUTF8String

传入string时候如果传入NSString直接崩溃。

1
2
kotlin复制代码//strdup函数需要引入#import <string.h>
return strdup([@"abc" UTF8String]) //要调用strdup()函数分配c内存再返回给unity,不然闪退

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ini复制代码//拍照之后返回小屋

- (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中的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
Java复制代码 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;
}
}

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();

// 调用相机
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
}

public override void takePhotosFromNative(string dictionaryJson)
{
#if UNITY_IOS
IosNativeAPI.takePhotosFromNative(dictionaryJson);
#endif
}

public override void goBackPendingFromNative()
{
#if UNITY_IOS
IosNativeAPI.goBackPendingFromNative();
#endif
}

public override void goBackKillFromNative()
{
#if UNITY_IOS
IosNativeAPI.goBackKillFromNative();
#endif
}

public override void loginFromNative()
{
#if UNITY_IOS
IosNativeAPI.loginFromNative();
#endif
}

public override void hiddenStartUnityLoading()
{
//
}
}

public class CNativeAndroid : CNativeAPI
{
public override string GetAppHeaderFromNative()
{
return GetAndroidJavaObject().Call<string>("GetAppHeaderFromNative");
}

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<AndroidJavaObject>("instance");
return overrideActivity;
}
}

public class CNativeOther : CNativeAPI
{
public override string GetAppHeaderFromNative()
{
return "";
}

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();

// 在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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
objectivec复制代码#import <Foundation/Foundation.h>
// 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<NativeCallsProtocol>) aApi;

@end`

NativeCallProxy.mm代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
arduino复制代码 #import <Foundation/Foundation.h>
#import "NativeCallProxy.h"

@implementation FrameworkLibAPI

id<NativeCallsProtocol> api = NULL;
+(void) registerAPIforNativeCalls:(id<NativeCallsProtocol>) 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

然后选择iOS下的build

image.png

如果代码没报错的话,那么恭喜你unity打包出来可以直接运行在xcode上了。

四.打出来的Unity-iPhone.xcodeproj工程集成到另一个工程中。

1.iOS手动修改配置到另一个工程:

(1)将打出来的包unity所有文件整个移动到另一个工程的unity3d目录下。

image.png

(2)设置data的target为framework

image.png

(3)修改unity的target为JRDebug_UAT和JRRelease_ProductSever (如果主工程GoHome没有配置多scheme环境的不用设置)

image.png

以下为主工程设置(与unity无关)

image.png

(4)unity framework的navtiveCallProxy.h设置为public

image.png
如果这个中间头文件在project中私有的话,要提到public中,framework要公开头文件

(5)运行下unity工程

sucess

(6)运行下ios工程(如果改动不成功,就把iOS的unityframework删除,重新添加下)

image.png

2.iOS通过脚本修改配置到另一个工程:

image.png

(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文件

1
2
3
> 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代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
objectivec复制代码 #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代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
scss复制代码 #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);
}


-(UIViewController *) getUnityRootViewController {
return [[self.unityFwk appController] rootViewController];
}

-(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 {

[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退出时销毁干净场景的全局资源)

image.png

1
2
3
4
ini复制代码   [[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。

  1. 把Unity项目和原生Android项目解压到同一个文件夹里使得后续操作更简单。

image

2、生成Android平台的Gradle项目

在Unity中打开这个项目,导航到“Build Settings”,切换到安卓平台并且勾选“Export Project”来导出项目。

image

当Unity项目导出之后,你会得到包含了unityLibrary模块的androidBuild文件夹。。

image

3、把Unity Library模块添加到NativeAndroidApp

现在你要做的是,将unityLibrary模块添加到你的原生Android项目中去。你可以通过修改Android Studio项目的settings.gradle文件来实现,只需在文件最后添加上一行代码来包含unityLibrary

1
2
php复制代码include ':unityLibrary'
project(':unityLibrary').projectDir=new File('..\UnityProject\androidBuild\unityLibrary')

image

之后,更新app模块的build.gradle文件来声明对unityLibrary模块的依赖。

1
java复制代码implementation project(':unityLibrary')

image

打开build.gradle文件,把下面代码添加到allprojects{repositories{代码块。

1
2
3
bash复制代码flatDir {
dirs "${project(':unityLibrary').projectDir}/libs"
}

image

Gradle文件已经修改,单击Sync Now。

image

修改完后,同步Gradle,这样unityLibrary就被加入到项目中了。

image

  1. 你现在可以尝试构建并运行应用了。如果一切顺利,应用应当能够正常启动和运行。

image

如果一切顺利,我们应该可以运行NativeAndroidApp。

image

请注意:在应用程序安装到设备后,会出现二个启动应用程序的图标,请把…从unityLibrary的AndroidManifest.xml去掉,仅保留集成版本。

当你完成集成并安装应用到你的设备之后,你可能会注意到有两个启动图标出现。这通常是因为unityLibrary模块的AndroidManifest.xml文件中定义了一个额外的启动器入口。你需要做的是,去掉这个多余的入口,只保留你的原生Android应用需要的那部分。这样做你的应用就只会有一个启动图标了。

另外,如果你在将Unity项目集成到原生Android应用的过程中遇到了任何难题,一个解决的办法是使用一个全面配置好的完整项目。你可以下载这个完整的项目文件包,解压后,在Android Studio中打开NativeAndroidApp。这个完整的项目已经设置好了所需的所有配置,并且可以直接构建和部署。这样就可以省去你手动整合的麻烦,特别是如果你是第一次尝试这样做或是对整个流程不是很熟悉的话。使用完整项目作为起点,可以帮助你更容易地理解整合过程,并且保证你有一个稳定的基础来进行后续的开发和调试。

参考Unity完整项目地址:

请访问云盘下载示例项目

下载链接: pan.baidu.com/s/1JFWjbrh2…

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%