总体流程如下:
一.下载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;
}
}
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
#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代码:
#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
然后选择iOS下的build
如果代码没报错的话,那么恭喜你unity打包出来可以直接运行在xcode上了。
四.打出来的Unity-iPhone.xcodeproj工程集成到另一个工程中。
1.iOS手动修改配置到另一个工程:
(1)将打出来的包unity所有文件整个移动到另一个工程的unity3d目录下。
(2)设置data的target为framework
(3)修改unity的target为JRDebug_UAT和JRRelease_ProductSever (如果主工程GoHome没有配置多scheme环境的不用设置)
以下为主工程设置(与unity无关)
(4)unity framework的navtiveCallProxy.h设置为public
如果这个中间头文件在project中私有的话,要提到public中,framework要公开头文件
(5)运行下unity工程
sucess
(6)运行下ios工程(如果改动不成功,就把iOS的unityframework删除,重新添加下)
2.iOS通过脚本修改配置到另一个工程:
(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文件
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);
}
-(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退出时销毁干净场景的全局资源)
[[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。
- 把Unity项目和原生Android项目解压到同一个文件夹里使得后续操作更简单。
2、生成Android平台的Gradle项目
在Unity中打开这个项目,导航到“Build Settings”,切换到安卓平台并且勾选“Export Project”来导出项目。
当Unity项目导出之后,你会得到包含了unityLibrary模块的androidBuild文件夹。。
3、把Unity Library模块添加到NativeAndroidApp
现在你要做的是,将unityLibrary模块添加到你的原生Android项目中去。你可以通过修改Android Studio项目的settings.gradle文件来实现,只需在文件最后添加上一行代码来包含unityLibrary
include ':unityLibrary'
project(':unityLibrary').projectDir=new File('..\UnityProject\androidBuild\unityLibrary')
之后,更新app模块的build.gradle文件来声明对unityLibrary模块的依赖。
implementation project(':unityLibrary')
打开build.gradle文件,把下面代码添加到allprojects{repositories{代码块。
flatDir {
dirs "${project(':unityLibrary').projectDir}/libs"
}
Gradle文件已经修改,单击Sync Now。
修改完后,同步Gradle,这样unityLibrary就被加入到项目中了。
- 你现在可以尝试构建并运行应用了。如果一切顺利,应用应当能够正常启动和运行。
如果一切顺利,我们应该可以运行NativeAndroidApp。
请注意:在应用程序安装到设备后,会出现二个启动应用程序的图标,请把...从unityLibrary的AndroidManifest.xml去掉,仅保留集成版本。
当你完成集成并安装应用到你的设备之后,你可能会注意到有两个启动图标出现。这通常是因为unityLibrary模块的AndroidManifest.xml文件中定义了一个额外的启动器入口。你需要做的是,去掉这个多余的入口,只保留你的原生Android应用需要的那部分。这样做你的应用就只会有一个启动图标了。
另外,如果你在将Unity项目集成到原生Android应用的过程中遇到了任何难题,一个解决的办法是使用一个全面配置好的完整项目。你可以下载这个完整的项目文件包,解压后,在Android Studio中打开NativeAndroidApp。这个完整的项目已经设置好了所需的所有配置,并且可以直接构建和部署。这样就可以省去你手动整合的麻烦,特别是如果你是第一次尝试这样做或是对整个流程不是很熟悉的话。使用完整项目作为起点,可以帮助你更容易地理解整合过程,并且保证你有一个稳定的基础来进行后续的开发和调试。
参考Unity完整项目地址:
请访问云盘下载示例项目
下载链接: pan.baidu.com/s/1zk3tuvLn… 提取码: 6ybx