开发 Unity3d 手机游戏的时候,不免要和第三方 SDK 打交道。于是总是需要实现自己的 AppController 来维护 SDK 的生命周期。
Unity3d 提供了一套插件机制,可以很方便地在项目中使用自己的 CustomAppController 继承并重写默认的 UnityAppController 的方法。
CustomAppController
在 Unity 插件目录下创建以下文件:
/path/to/unity/project/Assets/Plugins/iOS/CustomAppController.mm
注意:
文件名必须是 ___AppController,前缀可自选,但不能省略;否则在 Build 项目的时候,会被移动到错误的目录中去。
下面是集成BBase的入口,也是程序的入口
`//`
`// CustomAppController.m`
`// `
`#import "UnityAppController.h"`
`#import `
`@interface CustomAppController : UnityAppController`
`@end`
`IMPL_APP_CONTROLLER_SUBCLASS (CustomAppController)`
`@implementation CustomAppController`
`- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions`
`{`
` [super application:application didFinishLaunchingWithOptions:launchOptions];`
` [BBaseManager.sharedManager loadConfigureWithApplication:application registerPushNotificationLater:YES itunesConnectSharedSecret:@"" needReceiptVerification:YES gdprAppName:@"" gdprAgreementLink:@"" gdprPolicyLink:@"" ezalterDiversions:nil defaultEzalterParams:nil activateSuccessHandler:^(NSDictionary * _Nonnull json, NSString * _Nullable token) {`
` } activateFailureHandler:^(NSError * _Nonnull error) {`
` } activeSuccessHandler:^(NSDictionary * _Nonnull json) {`
` } activeFailureHandler:^(NSError * _Nonnull error) { `
` }];`
`return YES;`
`}`
`@end`
在 Build iOS Project 的时候,Unity 会自动把 CustomAppController.mm 复制到 /path/to/project/Libraries/CustomAppController.mm
而原来的 UnityAppController.mm 则在 /path/to/project/Classes/UnityAppController.mm
Unity 通过 ** IMPL_APP_CONTROLLER_SUBCLASS **知道要使用我们定制的 CustomAppController 而不是使用默认的 UnityAppController
IMPL_APP_CONTROLLER_SUBCLASS
UnityAppController.h 里面有这样一个宏:
`#define IMPL_APP_CONTROLLER_SUBCLASS(ClassName) \`
`@interface ClassName(OverrideAppDelegate) \`
`{ \`
`} \`
`+(void)load; \`
`@end \`
`@implementation ClassName(OverrideAppDelegate) \`
`+(void)load \`
`{ \`
` extern const char* AppControllerClassName; \`
`AppControllerClassName = #ClassName; \`
`} \`
`@end`
将这个宏加到 CustomAppController.mm 中,即可实现自动设置 AppControllerClassName :
`IMPL_APP_CONTROLLER_SUBCLASS (CustomAppController)`
IMPL_APP_CONTROLLER_SUBCLASS 使用了两个 Objective-C 的特性,一是 category ,用来给已有的类扩展新的方法;二是 +(void)load 静态方法,它会在运行时 CustomAppController 类被加载到内存中时触发,这个时间点比 int main() 函数还要早,所以能够提前“篡改” AppControllerClassName,达到我们的目的。
- 程序入口
程序的入口为main.mm文件,通过IMPL_APP_CONTROLLER_SUBCLASS 调用了自定义继承UnityAppController的 CustomAppController文件,在该文件的 下面这个方法- (BOOL)application:(UIApplication)application didFinishLaunchingWithOptions:(NSDictionary)launchOptions; 中注册了BBase,调用父类UnityAppController中的方法,实现UI的创建
iOS平台Unity引擎的IL2CPP机制
实现原理
Unity引擎作为目前最为主流的3D游戏开发引擎,游戏平台移植性非常好,Unity引擎4.6.2之后的版本采用了IL2CPP机制支持IOS平台64位游戏编译,针对IL2CPP机制进行深入分析之后有利于评估IOS平台的Unity游戏安全性。
Unity引擎采用IL2CPP机制在Mac平台成功编译之后,会生成一个完整的XCode工程,Unity游戏逻辑代码采用C#编写,游戏开发方的C#代码最终会生成在/Classes/Native目录中,对应文件结构如下图所示:
UI显示机制
Unity导出的iOS工程里面的结构大致是这样的,有一个Window,Window上有一个UnityView,但是并没有控制器,也没有根控制器,虽然在导出的iOS工程中Classes文件夹下的UnityAppController中有rootController的属性,但是上面也标注为空~ 直接在window上显示Unity界面的
导出xcode项目后,会产生DisplayManager 这样的一个显示管理器文件, 该文件中会辅助UnityView,Keyboard等等Unity转成iOS的View的显示,在DisplayManager 这个类中,引入了EAGLContext,通过OpenGL 去实现UI 的绘制
注释:
1. CAEAGLLayer 支持在iOS和tvOS应用程序中绘制OpenGL内容的图层。
2.EAGLContext对象管理一个OpenGL ES 渲染上下文 状态信息,命令和使用OpenGL ES绘制所需要的资源。要执行OpenGL ES命令,您需要当前的渲染上下文。
补充:
Unity中的ViewController
Unity中没有viewcontroller的概念,页面之间的切换其实就是在同一个viewcontroller上重绘不同的view,一个叫做UnityView的UIView来显示绘制的页面。
但既然要在iOS上显示界面,就必须要有一个viewcontroller的载体。Unity中没有,所以Unity中有一个_viewControllerForOrientation[5]的数组来维持屏幕4个方向的viewcontroller+autorotate的viewcontroller,也就是说Unity中从始至终最多只有5个viewcontroller。
viewcontroller如何切换
如果现在要显示竖屏页面,就从数组中取出竖屏的viewcontroller,如果没有就创建一个,然后将_unityView赋值给竖屏的viewcontroller.view,如果现在要进入横屏页面,就从数据中取出横屏的viewcontroller,然后将_unityView赋值给横屏的viewcontroller.view。
createDisplayLink
那么手机从竖屏变成横屏后什么时候重绘呢,什么时候显示呢?这个时候就需要createDisplayLink函数,它会创建一个60Hz的timer,为什么是60,因为iPhone的屏幕刷新率就是60Hz,每次的timer执行函数中会去检查当前要显示哪个viewcontroller,以及是否需要重绘,然后显示