1.接入微信無法回調onresp IOS9.0之后廢棄原本的兩個方法
-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url;
-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation;
更改為:(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary*)options;
2.Ios 微信sdk接入
@1下載地址 :https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319164&token=&lang=zh_CN
@2 導入sdk

@3項目配置 設置支持http請求 並且添加白名單weixin 和wechat

@4 關閉bitcode

@5設置URL types(url schemes 就是你申請的appid)

@6build phases 設置

@7 上代碼

實現 .mm文件
#import "WeixinInterface.h"
#import "AFNetworking.h"
#import "UnityAppController.h"
static WeixinInterface * s_shareApp=nil;
static NSString *Urlkey=nil;
static NSString *UrlValue=nil;
#define WeiXinID @"你申請的aapid"
#define WeiXinSecret @"secrest"
#define GameObjectName "在unity'中回調的代碼名字"
#define MethodName "回調方法"
@implementation WeixinInterface
#pragma mark - LifeCycle
+(instancetype)sharedManager {
static dispatch_once_t onceToken;
static WeixinInterface *instance;
dispatch_once(&onceToken, ^{
instance = [[WeixinInterface alloc] init];
});
return instance;
}
-(void)destroy
{
if (s_shareApp)
{
s_shareApp=nil;
}
}
@synthesize filePath;
#pragma mark - View lifecycle
- (void)OnLogin:(NSString *)js
{
NSLog(@"OnLogin");
SendAuthReq *req = [[SendAuthReq alloc] init];
req.scope = @"snsapi_userinfo";
//req.openID = URL_APPID;
req.state = @"1245";
//appdelegate = [UIApplication sharedApplication].delegate;
//appdelegate.wxDelegate = self;
[WXApi sendReq:req];
[WXApi sendAuthReq:req viewController:UnityGetGLViewController() delegate:self];
}
- (bool) isWXAppInstalled { return [WXApi isWXAppInstalled]; }
- (bool) isWXAppSupportApi { return [WXApi isWXAppSupportApi]; }
-(void)loginSuccessByCode:(NSString *)code
{
NSLog(@"code %@",code);
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];//請求
manager.responseSerializer = [AFHTTPResponseSerializer serializer];//響應
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"application/json", @"text/json",@"text/plain", nil];
//通過 appid secret 認證code . 來發送獲取 access_token的請求
[manager GET:[NSString stringWithFormat:@"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%@&secret=%@&code=%@&grant_type=authorization_code",WeiXinID,WeiXinSecret,code] parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { //獲得access_token,然后根據access_token獲取用戶信息請求。
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
NSLog(@"dic %@",dic);
/*
access_token 接口調用憑證
expires_in access_token接口調用憑證超時時間,單位(秒)
refresh_token 用戶刷新access_token
openid 授權用戶唯一標識
scope 用戶授權的作用域,使用逗號(,)分隔
unionid 當且僅當該移動應用已獲得該用戶的userinfo授權時,才會出現該字段
*/
NSString* accessToken=[dic valueForKey:@"access_token"];
NSString* openID=[dic valueForKey:@"openid"];
[self requestUserInfoByToken:accessToken andOpenid:openID];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"error %@",error.localizedFailureReason);
}];
}
- (BOOL)handleOpenURL:(NSURL *) url
{
//url:ruileiqipai://?key=roomid&value=965816&from=singlemessage&isappinstalled=0&reload=1
NSString *urlStr = [url absoluteString];
NSLog(@"url:%@",urlStr);
[self GetURLParameters:urlStr];
return [WXApi handleOpenURL:url delegate:self];
}
/*! 微信回調,不管是登錄還是分享成功與否,都是走這個方法 @brief 發送一個sendReq后,收到微信的回應
*
* 收到一個來自微信的處理結果。調用一次sendReq后會收到onResp。
* 可能收到的處理結果有SendMessageToWXResp、SendAuthResp等。
* @param resp具體的回應內容,是自動釋放的
*/
-(void) onResp:(BaseResp*)resp{
NSLog(@"resp %d",resp.errCode);
/*
enum WXErrCode {
WXSuccess = 0, 成功
WXErrCodeCommon = -1, 普通錯誤類型
WXErrCodeUserCancel = -2, 用戶點擊取消並返回
WXErrCodeSentFail = -3, 發送失敗
WXErrCodeAuthDeny = -4, 授權失敗
WXErrCodeUnsupport = -5, 微信不支持
};
*/
if ([resp isKindOfClass:[SendAuthResp class]]) { //授權登錄的類。
if (resp.errCode == 0) { //成功。
//這里處理回調的方法 。 通過代理吧對應的登錄消息傳送過去。
if([resp isKindOfClass:[SendAuthResp class]]) // 登錄授權
{
SendAuthResp *resp2 = (SendAuthResp *)resp;
//[[WeixinLogin getIntance] loginSuccessByCode:resp2.code];
[self loginSuccessByCode:resp2.code];
}
}else{ //失敗
NSLog(@"error %@",resp.errStr);
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"登錄失敗"
message:[NSString stringWithFormat:@"reason : //%@",resp.errStr]
delegate:nil cancelButtonTitle:NSLocalizedString(@"Close(關閉)",nil) otherButtonTitles:nil];
[alerView show];
}
}
}
-(void)requestUserInfoByToken:(NSString *)token andOpenid:(NSString *)openID{
NSLog(@"requestUserInfoByToken");
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager GET:[NSString stringWithFormat:@"https://api.weixin.qq.com/sns/userinfo?access_token=%@&openid=%@",token,openID] parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSDictionary *dic = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
NSLog(@"dic ==== %@",dic);
//NSError *jsonError;
//NSString *responseData = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:&jsonError];
NSError *error;
NSData *jsStr = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonData= [[NSString alloc] initWithData:jsStr encoding:NSUTF8StringEncoding];
NSLog(@"#####responseData1 = %@",jsonData);
//NSLog(@"#####responseData = %@",responseData);
UnitySendMessage(GameObjectName, MethodName, [jsonData cStringUsingEncoding:NSUTF8StringEncoding]);
if(Urlkey != nil && UrlValue != nil)
{
NSString *keyandValue=[NSString stringWithFormat:@"%@&%@",Urlkey,UrlValue];
NSLog(@"keyandValue:%@",keyandValue);
UnitySendMessage(GameObjectName, GetURLKeyAndValue, [keyandValue cStringUsingEncoding:NSUTF8StringEncoding]);
Urlkey = nil;
UrlValue = nil;
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"error %ld",(long)error.code);
}];
}
- (void)didReceiveMemoryWarning {
//[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
@8在Appcontrl中實現app注冊
#import "UnityAppController.h"
#import "UnityAppController+ViewHandling.h"
#import "UnityAppController+Rendering.h"
#import "iPhone_Sensors.h"
#import <CoreGraphics/CoreGraphics.h>
#import <QuartzCore/QuartzCore.h>
#import <QuartzCore/CADisplayLink.h>
#import <Availability.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/EAGLDrawable.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#include <mach/mach_time.h>
// MSAA_DEFAULT_SAMPLE_COUNT was moved to iPhone_GlesSupport.h
// ENABLE_INTERNAL_PROFILER and related defines were moved to iPhone_Profiler.h
// kFPS define for removed: you can use Application.targetFrameRate (30 fps by default)
// DisplayLink is the only run loop mode now - all others were removed
#include "CrashReporter.h"
#include "UI/OrientationSupport.h"
#include "UI/UnityView.h"
#include "UI/Keyboard.h"
#include "UI/SplashScreen.h"
#include "Unity/InternalProfiler.h"
#include "Unity/DisplayManager.h"
#include "Unity/EAGLContextHelper.h"
#include "Unity/GlesHelper.h"
#include "Unity/ObjCRuntime.h"
#include "PluginBase/AppDelegateListener.h"
#include <assert.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sysctl.h>
#import "Libraries/Plugins/iOS/WXApi.h"
#import "Libraries/Plugins/iOS/Control/WXApiManager.h"
#import "Libraries/Plugins/iOS/SDK/WeixinInterface.h"
// we assume that app delegate is never changed and we can cache it, instead of re-query UIApplication every time
UnityAppController* _UnityAppController = nil;
// Standard Gesture Recognizers enabled on all iOS apps absorb touches close to the top and bottom of the screen.
// This sometimes causes an ~1 second delay before the touch is handled when clicking very close to the edge.
// You should enable this if you want to avoid that delay. Enabling it should not have any effect on default iOS gestures.
#define DISABLE_TOUCH_DELAYS 1
// we keep old bools around to support "old" code that might have used them
bool _ios42orNewer = false, _ios43orNewer = false, _ios50orNewer = false, _ios60orNewer = false, _ios70orNewer = false;
bool _ios80orNewer = false, _ios81orNewer = false, _ios82orNewer = false, _ios83orNewer = false, _ios90orNewer = false, _ios91orNewer = false;
bool _ios100orNewer = false, _ios101orNewer = false, _ios102orNewer = false, _ios103orNewer = false;
bool _ios110orNewer = false, _ios111orNewer = false, _ios112orNewer = false;
// was unity rendering already inited: we should not touch rendering while this is false
bool _renderingInited = false;
// was unity inited: we should not touch unity api while this is false
bool _unityAppReady = false;
// see if there's a need to do internal player pause/resume handling
//
// Typically the trampoline code should manage this internally, but
// there are use cases, videoplayer, plugin code, etc where the player
// is paused before the internal handling comes relevant. Avoid
// overriding externally managed player pause/resume handling by
// caching the state
bool _wasPausedExternal = false;
// should we skip present on next draw: used in corner cases (like rotation) to fill both draw-buffers with some content
bool _skipPresent = false;
// was app "resigned active": some operations do not make sense while app is in background
bool _didResignActive = false;
// was startUnity scheduled: used to make startup robust in case of locking device
static bool _startUnityScheduled = false;
bool _supportsMSAA = false;
#if UNITY_SUPPORT_ROTATION
// Required to enable specific orientation for some presentation controllers: see supportedInterfaceOrientationsForWindow below for details
NSInteger _forceInterfaceOrientationMask = 0;
#endif
@implementation UnityAppController
@synthesize unityView = _unityView;
@synthesize unityDisplayLink = _displayLink;
@synthesize rootView = _rootView;
@synthesize rootViewController = _rootController;
@synthesize mainDisplay = _mainDisplay;
@synthesize renderDelegate = _renderDelegate;
@synthesize quitHandler = _quitHandler;
#if UNITY_SUPPORT_ROTATION
@synthesize interfaceOrientation = _curOrientation;
#endif
- (id)init
{
if ((self = _UnityAppController = [super init]))
{
// due to clang issues with generating warning for overriding deprecated methods
// we will simply assert if deprecated methods are present
// NB: methods table is initied at load (before this call), so it is ok to check for override
NSAssert(![self respondsToSelector: @selector(createUnityViewImpl)],
@"createUnityViewImpl is deprecated and will not be called. Override createUnityView"
);
NSAssert(![self respondsToSelector: @selector(createViewHierarchyImpl)],
@"createViewHierarchyImpl is deprecated and will not be called. Override willStartWithViewController"
);
NSAssert(![self respondsToSelector: @selector(createViewHierarchy)],
@"createViewHierarchy is deprecated and will not be implemented. Use createUI"
);
}
return self;
}
- (void)setWindow:(id)object {}
- (UIWindow*)window { return _window; }
- (void)shouldAttachRenderDelegate {}
- (void)preStartUnity {}
- (void)startUnity:(UIApplication*)application
{
NSAssert(_unityAppReady == NO, @"[UnityAppController startUnity:] called after Unity has been initialized");
UnityInitApplicationGraphics();
// we make sure that first level gets correct display list and orientation
[[DisplayManager Instance] updateDisplayListCacheInUnity];
UnityLoadApplication();
Profiler_InitProfiler();
[self showGameUI];
[self createDisplayLink];
UnitySetPlayerFocus(1);
}
extern "C" void UnityDestroyDisplayLink()
{
[GetAppController() destroyDisplayLink];
}
extern "C" void UnityRequestQuit()
{
_didResignActive = true;
if (GetAppController().quitHandler)
GetAppController().quitHandler();
else
exit(0);
}
#if UNITY_SUPPORT_ROTATION
- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
// No rootViewController is set because we are switching from one view controller to another, all orientations should be enabled
if ([window rootViewController] == nil)
return UIInterfaceOrientationMaskAll;
// Some presentation controllers (e.g. UIImagePickerController) require portrait orientation and will throw exception if it is not supported.
// At the same time enabling all orientations by returning UIInterfaceOrientationMaskAll might cause unwanted orientation change
// (e.g. when using UIActivityViewController to "share to" another application, iOS will use supportedInterfaceOrientations to possibly reorient).
// So to avoid exception we are returning combination of constraints for root view controller and orientation requested by iOS.
// _forceInterfaceOrientationMask is updated in willChangeStatusBarOrientation, which is called if some presentation controller insists on orientation change.
return [[window rootViewController] supportedInterfaceOrientations] | _forceInterfaceOrientationMask;
}
- (void)application:(UIApplication*)application willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientation duration:(NSTimeInterval)duration
{
// Setting orientation mask which is requested by iOS: see supportedInterfaceOrientationsForWindow above for details
_forceInterfaceOrientationMask = 1 << newStatusBarOrientation;
}
#endif
#if !PLATFORM_TVOS
- (void)application:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification*)notification
{
AppController_SendNotificationWithArg(kUnityDidReceiveLocalNotification, notification);
UnitySendLocalNotification(notification);
}
#endif
#if UNITY_USES_REMOTE_NOTIFICATIONS
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
AppController_SendNotificationWithArg(kUnityDidReceiveRemoteNotification, userInfo);
UnitySendRemoteNotification(userInfo);
}
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
AppController_SendNotificationWithArg(kUnityDidRegisterForRemoteNotificationsWithDeviceToken, deviceToken);
UnitySendDeviceToken(deviceToken);
}
#if !PLATFORM_TVOS
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler
{
AppController_SendNotificationWithArg(kUnityDidReceiveRemoteNotification, userInfo);
UnitySendRemoteNotification(userInfo);
if (handler)
{
handler(UIBackgroundFetchResultNoData);
}
}
#endif
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
AppController_SendNotificationWithArg(kUnityDidFailToRegisterForRemoteNotificationsWithError, error);
UnitySendRemoteNotificationError(error);
// alas people do not check remote notification error through api (which is clunky, i agree) so log here to have at least some visibility
::printf("\nFailed to register for remote notifications:\n%s\n\n", [[error localizedDescription] UTF8String]);
}
#endif
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:( NSDictionary *)options
{
return [WXApi handleOpenURL:url delegate:[WeixinInterface sharedManager]];
}
- (BOOL)application:(UIApplication*)application willFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
return YES;
}
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
::printf("-> applicationDidFinishLaunching()\n");
// send notfications
#if !PLATFORM_TVOS
if (UILocalNotification* notification = [launchOptions objectForKey: UIApplicationLaunchOptionsLocalNotificationKey])
UnitySendLocalNotification(notification);
if ([UIDevice currentDevice].generatesDeviceOrientationNotifications == NO)
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
#endif
UnityInitApplicationNoGraphics([[[NSBundle mainBundle] bundlePath] UTF8String]);
[self selectRenderingAPI];
[UnityRenderingView InitializeForAPI: self.renderingAPI];
_window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];
_unityView = [self createUnityView];
[DisplayManager Initialize];
_mainDisplay = [DisplayManager Instance].mainDisplay;
[_mainDisplay createWithWindow: _window andView: _unityView];
[self createUI];
[self preStartUnity];
[WXApi registerApp:@"你申請的appid"];
// if you wont use keyboard you may comment it out at save some memory
[KeyboardDelegate Initialize];
//#if !PLATFORM_TVOS && DISABLE_TOUCH_DELAYS
//for (UIGestureRecognizer *g in _window.gestureRecognizers)
//{
// g.delaysTouchesBegan = false;
//}
//#endif
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication*)application
{
::printf("-> applicationDidEnterBackground()\n");
}
- (void)applicationWillEnterForeground:(UIApplication*)application
{
::printf("-> applicationWillEnterForeground()\n");
// applicationWillEnterForeground: might sometimes arrive *before* actually initing unity (e.g. locking on startup)
if (_unityAppReady)
{
// if we were showing video before going to background - the view size may be changed while we are in background
[GetAppController().unityView recreateRenderingSurfaceIfNeeded];
}
}
- (void)applicationDidBecomeActive:(UIApplication*)application
{
::printf("-> applicationDidBecomeActive()\n");
[self removeSnapshotView];
if (_unityAppReady)
{
if (UnityIsPaused() && _wasPausedExternal == false)
{
UnityWillResume();
UnityPause(0);
}
if (_wasPausedExternal)
{
if (UnityIsFullScreenPlaying())
TryResumeFullScreenVideo();
}
UnitySetPlayerFocus(1);
}
else if (!_startUnityScheduled)
{
_startUnityScheduled = true;
[self performSelector: @selector(startUnity:) withObject: application afterDelay: 0];
}
_didResignActive = false;
}
- (void)removeSnapshotView
{
// do this on the main queue async so that if we try to create one
// and remove in the same frame, this always happens after in the same queue
dispatch_async(dispatch_get_main_queue(), ^{
if (_snapshotView)
{
[_snapshotView removeFromSuperview];
_snapshotView = nil;
}
});
}
- (void)applicationWillResignActive:(UIApplication*)application
{
::printf("-> applicationWillResignActive()\n");
if (_unityAppReady)
{
UnitySetPlayerFocus(0);
_wasPausedExternal = UnityIsPaused();
if (_wasPausedExternal == false)
{
// do pause unity only if we dont need special background processing
// otherwise batched player loop can be called to run user scripts
int bgBehavior = UnityGetAppBackgroundBehavior();
if (bgBehavior == appbgSuspend || bgBehavior == appbgExit)
{
// Force player to do one more frame, so scripts get a chance to render custom screen for minimized app in task manager.
// NB: UnityWillPause will schedule OnApplicationPause message, which will be sent normally inside repaint (unity player loop)
// NB: We will actually pause after the loop (when calling UnityPause).
UnityWillPause();
[self repaint];
UnityPause(1);
// this is done on the next frame so that
// in the case where unity is paused while going
// into the background and an input is deactivated
// we don't mess with the view hierarchy while taking
// a view snapshot (case 760747).
dispatch_async(dispatch_get_main_queue(), ^{
// if we are active again, we don't need to do this anymore
if (!_didResignActive)
{
return;
}
_snapshotView = [self createSnapshotView];
if (_snapshotView)
[_rootView addSubview: _snapshotView];
});
}
}
}
_didResignActive = true;
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application
{
::printf("WARNING -> applicationDidReceiveMemoryWarning()\n");
UnityLowMemory();
}
- (void)applicationWillTerminate:(UIApplication*)application
{
::printf("-> applicationWillTerminate()\n");
Profiler_UninitProfiler();
UnityCleanup();
extern void SensorsCleanup();
SensorsCleanup();
}
@end
void AppController_SendNotification(NSString* name)
{
[[NSNotificationCenter defaultCenter] postNotificationName: name object: GetAppController()];
}
void AppController_SendNotificationWithArg(NSString* name, id arg)
{
[[NSNotificationCenter defaultCenter] postNotificationName: name object: GetAppController() userInfo: arg];
}
void AppController_SendUnityViewControllerNotification(NSString* name)
{
[[NSNotificationCenter defaultCenter] postNotificationName: name object: UnityGetGLViewController()];
}
extern "C" UIWindow* UnityGetMainWindow() {
return GetAppController().mainDisplay.window;
}
extern "C" UIViewController* UnityGetGLViewController() {
return GetAppController().rootViewController;
}
extern "C" UIView* UnityGetGLView() {
return GetAppController().unityView;
}
extern "C" ScreenOrientation UnityCurrentOrientation() { return GetAppController().unityView.contentOrientation; }
bool LogToNSLogHandler(LogType logType, const char* log, va_list list)
{
NSLogv([NSString stringWithUTF8String: log], list);
return true;
}
static void AddNewAPIImplIfNeeded();
// From https://stackoverflow.com/questions/4744826/detecting-if-ios-app-is-run-in-debugger
static bool isDebuggerAttachedToConsole(void)
// Returns true if the current process is being debugged (either
// running under the debugger or has a debugger attached post facto).
{
int junk;
int mib[4];
struct kinfo_proc info;
size_t size;
// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.
info.kp_proc.p_flag = 0;
// Initialize mib, which tells sysctl the info we want, in this case
// we're looking for information about a specific process ID.
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
// Call sysctl.
size = sizeof(info);
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
assert(junk == 0);
// We're being debugged if the P_TRACED flag is set.
return ((info.kp_proc.p_flag & P_TRACED) != 0);
}
void UnityInitTrampoline()
{
#if ENABLE_CRASH_REPORT_SUBMISSION
SubmitCrashReportsAsync();
#endif
InitCrashHandling();
_ios42orNewer = _ios43orNewer = _ios50orNewer = _ios60orNewer = _ios70orNewer = _ios80orNewer = true;
NSString* version = [[UIDevice currentDevice] systemVersion];
#define CHECK_VER(s) [version compare: s options: NSNumericSearch] != NSOrderedAscending
_ios81orNewer = CHECK_VER(@"8.1"), _ios82orNewer = CHECK_VER(@"8.2"), _ios83orNewer = CHECK_VER(@"8.3");
_ios90orNewer = CHECK_VER(@"9.0"), _ios91orNewer = CHECK_VER(@"9.1");
_ios100orNewer = CHECK_VER(@"10.0"), _ios101orNewer = CHECK_VER(@"10.1"), _ios102orNewer = CHECK_VER(@"10.2"), _ios103orNewer = CHECK_VER(@"10.3");
_ios110orNewer = CHECK_VER(@"11.0"), _ios111orNewer = CHECK_VER(@"11.1"), _ios112orNewer = CHECK_VER(@"11.2");
#undef CHECK_VER
AddNewAPIImplIfNeeded();
#if !TARGET_IPHONE_SIMULATOR
// Use NSLog logging if a debugger is not attached, otherwise we write to stdout.
if (!isDebuggerAttachedToConsole())
UnitySetLogEntryHandler(LogToNSLogHandler);
#endif
}
// sometimes apple adds new api with obvious fallback on older ios.
// in that case we simply add these functions ourselves to simplify code
static void AddNewAPIImplIfNeeded()
{
if (![[CADisplayLink class] instancesRespondToSelector: @selector(setPreferredFramesPerSecond:)])
{
IMP CADisplayLink_setPreferredFramesPerSecond_IMP = imp_implementationWithBlock(^void(id _self, NSInteger fps) {
typedef void (*SetFrameIntervalFunc)(id, SEL, NSInteger);
UNITY_OBJC_CALL_ON_SELF(_self, @selector(setFrameInterval:), SetFrameIntervalFunc, (int)(60.0f / fps));
});
class_replaceMethod([CADisplayLink class], @selector(setPreferredFramesPerSecond:), CADisplayLink_setPreferredFramesPerSecond_IMP, CADisplayLink_setPreferredFramesPerSecond_Enc);
}
if (![[UIScreen class] instancesRespondToSelector: @selector(nativeScale)])
{
IMP UIScreen_NativeScale_IMP = imp_implementationWithBlock(^CGFloat(id _self) {
return ((UIScreen*)_self).scale;
});
class_replaceMethod([UIScreen class], @selector(nativeScale), UIScreen_NativeScale_IMP, UIScreen_nativeScale_Enc);
}
if (![[UIScreen class] instancesRespondToSelector: @selector(maximumFramesPerSecond)])
{
IMP UIScreen_MaximumFramesPerSecond_IMP = imp_implementationWithBlock(^NSInteger(id _self) {
return 60;
});
class_replaceMethod([UIScreen class], @selector(maximumFramesPerSecond), UIScreen_MaximumFramesPerSecond_IMP, UIScreen_maximumFramesPerSecond_Enc);
}
if (![[UIView class] instancesRespondToSelector: @selector(safeAreaInsets)])
{
IMP UIView_SafeAreaInsets_IMP = imp_implementationWithBlock(^UIEdgeInsets(id _self) {
return UIEdgeInsetsZero;
});
class_replaceMethod([UIView class], @selector(safeAreaInsets), UIView_SafeAreaInsets_IMP, UIView_safeAreaInsets_Enc);
}
}
