// // XenonSDK.m // XenonSDK // // Created by SAGESSE on 2019/3/11. // Copyright © 2019 SAGESSE. All rights reserved. // #import "XenonSDK.h" #import #import #if SDK_HAS_IDFA #import #endif #import "BubbleView.h" #import "RootViewController.h" #import "NoticeViewController.h" #import "UserBindPhoneViewController.h" #import "UserLoginFastViewController.h" #import "UserLoginPhoneViewController.h" #import "UserCenterViewController1.h" #import "UserCenterViewController2.h" #import "XSUtils.h" #import "KDIAPManager.h" #import "NSBundle+KODLocalizable.h" #import "KODCommonConst.h" #import @interface XenonSDK () @end /// /// Game SDK /// @implementation XenonSDK @synthesize user = _user; @synthesize token = _token; /// /// A sington instance of SDK. /// + (instancetype)sharedSDK { static id sharedSDK = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedSDK = XenonSDK.new; if (XSNetwork.baseURL == nil) { XSNetwork.baseURL = @"https://fapp.funcheergame.com"; //测试地址 @"http://47.56.223.128:9099"; //国内正式地址 @"https://app.funcheergame.com"; //国外正式地址 @"https://fapp.funcheergame.com" } }); return sharedSDK; } /// /// Init the sdk with application code. /// \param parameter The parameter provided by the platform. /// /// \param complete This closure called when init complete. /// - (void)initWithParameter:(NSString*)parameter complete:(void (^)(NSError* error))complete { // If init is complete, ignore it this call. if (self.configuration != nil) { if (complete != nil) { complete(nil); // sdk is ready. } return; } // Parse pre-configuration for parameter. NSArray* configs = [parameter componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"|&"]]; if (configs.count != 4) { if (complete != nil) { //参数错误 NSString *str1 = [NSBundle KOD_localizedStringForKey:ParamsError]; complete([XSNetwork errorWithCode:-1 message:str1]); // error -1 } return ; } // Update pre-configuration for parameter. self.appId = configs[0]; self.channelId = configs[1]; self.adId = configs[2]; self.adFlag = configs[3]; // Update system configration for server. [XSNetwork configureWithIdentifier:self.adId flags:self.adFlag complete:^(XSConfiguration* object, NSError *error) { // If an error occurs, directly callback cp. if (error != nil) { if (complete != nil) { complete(error); } return; } // An unknown error. if (object.closeState != 0) { // Display an system notice. id qq = self.configuration.fixLinkQQ ?: @""; id tel = self.configuration.fixLinkTel ?: @""; // Set the update title & contents. //id contents = [NSString stringWithFormat:@"\n亲爱的玩家您好, 由于服务器紧急维护, 目前游戏暂时无法进入, 给您带来的不便我们深表歉意!\n如果您还有其他问题请与我们联系!\n\n客服QQ: %@\n客服电话: %@", qq, tel]; NSString *contents1 = [NSBundle KOD_localizedStringForKey:ServiceErrorPleaseConnnectServicePhone]; NSString *contents = [NSString stringWithFormat:@"%@%@%@",contents1,qq,tel]; UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"系统公告" message:contents preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:nil]]; self.rootViewController = alert; complete([XSNetwork errorWithCode:-8 message:nil]); return; } // Setup sdk with server configuration. self.configuration = object; // Get third-party platform parameters. if (self.configuration.thirdPartyPrams.length != 0) { NSDictionary* thirdPartyPrams = [NSJSONSerialization JSONObjectWithData:[self.configuration.thirdPartyPrams dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; // If the tracker is turned on, create the object. int mask = 0; NSString* dps = thirdPartyPrams[@"dp"]; if (dps.length != 0) { sscanf(dps.UTF8String, "%x", &mask); if (mask != 0) { XSTracker.shared = [XSTracker new]; XSTracker.shared.mask = mask; [XSNetwork trigger:20]; } } // In the initialization. [XSTracker.shared trace:0x010000 parameters:[NSString stringWithFormat:@"%@", NSProcessInfo.processInfo.environment]]; // If an advertisement parameter is specified, try to parse advertising parameter. NSString* adPrams = self.configuration.adPrams; if (adPrams.length != 0) { // Parse advertising parameter. [[adPrams componentsSeparatedByString:@"&"] enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { // Value must be `key=value` NSArray* tmp = [obj componentsSeparatedByString:@"="]; if (tmp.count != 2) { return; } if ([tmp[0] isEqualToString:@"td_app_id"]) { self.configuration.tdAppId = tmp[1]; } if ([tmp[0] isEqualToString:@"td_game_id"]) { self.configuration.tdGameId = tmp[1]; } }]; // If td game id is not provided, the TD sdk is not initialized. if (self.configuration.tdAppId.length != 0 && self.configuration.tdGameId.length != 0) { // Init for data analzer server. XSCollector.shared = [[XSCollector alloc] initWithAppId:self.configuration.tdAppId gameId:self.configuration.tdGameId]; } } } [self sdk_checkVersion:^{ [self sdk_checkNote:^{ // Check workflow ended. [XSTracker.shared trace:0x010001]; // Init sdk complete. if (complete != nil) complete(nil); // init workflow ended. [XSTracker.shared trace:0x010002]; }]; }]; }]; } /// /// Login the sdk. /// \param complete This closure called when login complete. /// - (void)loginWithComplete:(void (^)(id user, NSError* error))complete { // If init is complete, ignore it this call. if (self.configuration == nil) { if (complete != nil) //请先初始化 complete(nil, [XSNetwork errorWithCode:-1 message:[NSBundle KOD_localizedStringForKey:PleaseInitFirst]]); // error -1 //发出登录失败通知. flag=NO NSNotification *notification = [NSNotification notificationWithName:@"LoginSuccessNotificaion" object:nil userInfo:@{@"userInfo":@"",@"flag":@"NO"}]; [[NSNotificationCenter defaultCenter] postNotification:notification]; return; } [XSTracker.shared trace:0x010010]; // Unified operation after successful login. void (^loginedCallback)(void) = ^{ // Build return data. id user = nil; if (self.user != nil) { user = @{ @"uid": self.user.uid, @"token": self.user.token, @"userName": self.user.userName ?: @"", @"phone": self.user.phone ?: @"" }; // According to air bubbles. if (!self.configuration.isFloatDisable) { UIWindow* window = UIApplication.sharedApplication.delegate.window ?: UIApplication.sharedApplication.keyWindow; BubbleView* view = [[BubbleView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)]; [view.contentView addTarget:self action:@selector(center) forControlEvents:UIControlEventTouchUpInside]; UITapGestureRecognizer *tapRecognize = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTap:)]; [view addGestureRecognizer:tapRecognize]; [window addSubview:view]; // It's shown in the first one. UIView* xmp = [window viewWithTag:-1]; if (xmp != nil) { [window bringSubviewToFront:xmp]; } [self.bubbleView removeFromSuperview]; self.bubbleView = view; } [XSTracker.shared trace:0x010013]; } [XSTracker.shared trace:0x010011]; if (complete) { complete(user, nil); } [XSTracker.shared trace:0x010012]; }; // Try automatically login if needed. if (self.user != nil) { [XSNetwork showHudLoading]; [XSNetwork authWithUser:self.user.uid complete:^(XSUser* user, NSError *error) { // If the login fails, clear the user information and login again. if (user.token.length == 0 || error != nil) { [XSNetwork showHudFailure:@"登录时效期已过,请重新登录"]; self.user = nil; [self loginWithComplete:complete]; return; } // Update user info. XSUser* duser = self.user; duser.token = user.token; duser.isRegister = false; self.user = duser; // Login successful, display HUD. [XSNetwork showPrompt:duser.name]; //发出登成功通知.flag=YES NSDictionary *dict = @{@"userInfo":self.user,@"flag":@"YES"}; NSNotification *notification = [NSNotification notificationWithName:@"LoginSuccessNotificaion" object:nil userInfo:dict]; [[NSNotificationCenter defaultCenter] postNotification:notification]; // Check if the user is already connected to the phone. // [self sdk_checkPhone:^{ // loginedCallback(); // }]; //绑定手机 loginedCallback(); }]; [XSTracker.shared trace:0x010014]; return; } // Setup login callback. __weak __typeof(self) ws = self; self.sdk_loginCallback = ^(XSUser* user) { [ws setUser:user]; [ws.rootViewController dismissViewControllerAnimated:YES completion:nil]; // Login successful, display HUD. //发出登录成功通知. NSDictionary *dict = @{@"userInfo":user,@"flag":@"YES"}; NSNotification *notification = [NSNotification notificationWithName:@"LoginSuccessNotificaion" object:nil userInfo:dict]; [[NSNotificationCenter defaultCenter] postNotification:notification]; [XSNetwork showPrompt:user.name]; loginedCallback(); }; // The last time was to log out, so the quick login list is displayed. if (XSUser.history.count != 0) { //self.rootViewController = [[RootViewController alloc] initWithRootViewController:UserLoginFastViewController.new]; self.rootViewController = [[RootViewController alloc] initWithRootViewController:UserLoginPhoneViewController.new]; return; } // To account login self.rootViewController = [[RootViewController alloc] initWithRootViewController:UserLoginPhoneViewController.new]; } /// /// Logout the sdk. /// \param complete This closure called when logout complete. /// - (void)logoutWithComplete:(void (^)(void))complete { // If init is complete, ignore it this call. if (self.configuration == nil) { if (complete != nil) complete(); return; } self.user = nil; [self.bubbleView removeFromSuperview]; self.bubbleView = nil; //发出退出通知. NSNotification *notification = [NSNotification notificationWithName:@"LogoutNotificaion" object:nil userInfo:nil]; [[NSNotificationCenter defaultCenter] postNotification:notification]; if (complete != nil) complete(); [XSTracker.shared trace:0x010020]; } /// /// Logout the game and sdk. /// \param handler This closure called when user logout in web view. /// \note Warning this handler will retain in until next call this method. /// - (void)logoutWhenNotification:(void (^)(void))handler { self.sdk_logoutCallback = ^(id user) { if (handler != nil) handler(); [XSTracker.shared trace:0x010020]; }; } /// /// Buy a product. /// \param parameters Payment request parameters. /// \param complete Payment result of the callback, if the apple payment is completed before the callback, other payments will be the official launch of the callback /// - (void)buy:(NSDictionary*)parameters complete:(void (^)(id order, NSError* error))complete { // Check paramrters. if (self.configuration == nil || self.user == nil) { if (complete != nil) { //请先登录 NSString *str = [NSBundle KOD_localizedStringForKey:PleaseLoginFirst]; complete(nil, [XSNetwork errorWithCode:-1 message:str]); // error -1 return ; } } [XSTracker.shared trace:0x010030]; [XSNetwork showHudLoading]; // // [XSNetwork routeWithComplete:^(id object, NSError *error) { // // if (error != nil) { // [XSNetwork showHudFailure:error]; // if (complete != nil) { // complete(nil, error); // } // return; // } // Get parmeters. XSUser* user = self.user; //NSString* path = object[fqsd(@"PREAACs/NCYsJjQuLRkA")]; //#if SDK_HAS_H5_PAYMENT //Generate h5 payment parameters. // if (path.length != 0) { // // [XSNetwork hideHud]; // [XSTracker.shared trace:0x010031]; // // id payments = @{ // @"cpBillNo": parameters[@"orderId"] ?: @"", // @"orderAmount": parameters[@"amount"] ?: @"", // @"subject": parameters[@"productName"] ?: @"", // // @"roleName": parameters[@"roleName"] ?: @"", // @"serverId": parameters[@"serverId"] ?: @"", // @"extraInfo": parameters[@"extraInfo"] ?: @"", // // @"phone": @"", // @"isTest": @"1", // @"orderPlatform": @"0", // @"orderType": @"1", // @"remark": @"0", // @"isApp": @"0", // // @"uid": user.uid, // @"userName": user.userName ?: @"" // }; // // NSURLComponents* components = [NSURLComponents componentsWithString:path]; // NSDictionary* json = [XSNetwork bodyWithParameters:payments]; // NSString* str = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:json options:0 error:nil] encoding:NSUTF8StringEncoding]; // // components.queryItems = @[[NSURLQueryItem queryItemWithName:@"jsonData" value:str], // [NSURLQueryItem queryItemWithName:@"v" value:@"1"]]; // // if (components.URL == nil) { // if (complete != nil) { // complete(nil, [XSNetwork errorWithCode:-1 message:@"后台参数错误"]); // } // return; // } // // UserCenterViewController* rootViewController = UserCenterViewController.new; // rootViewController.custom = components.URL.absoluteString; // rootViewController.otherView = self.bubbleView; // rootViewController.modalPresentationStyle = UIModalPresentationOverFullScreen; // self.rootViewController = rootViewController; // // // Cannot get the callback state. // rootViewController.callback = ^{ // if (complete != nil) { // complete(nil, nil); // } // }; // return; // } //#endif //#if SDK_HAS_IAP_PAYMENT // Generate iap payment parameters. id payments = @{ @"productCode": parameters[@"productCode"] ?: @"", @"isCoin": @"0", @"orderPlatform": @"0", @"orderType": @"1", @"orderAmount": parameters[@"amount"] ?: @"", @"isTest": @"0", @"subject": parameters[@"productName"] ?: @"", @"roleName": parameters[@"roleName"] ?: @"", @"cpBillNo": parameters[@"orderId"] ?: @"", @"remark": @"0", @"serverId": parameters[@"serverId"] ?: @"", @"extraInfo": parameters[@"extraInfo"] ?: @"", @"uid": user.uid, @"userName": user.userName ?: @"" }; [XSTracker.shared trace:0x010032]; [XSNetwork payWithParameters:payments complete:^(id object, NSError *error) { if (error != nil) { [XSNetwork showHudFailure:error]; if (complete != nil) { complete(nil, error); } return; } [XSTracker.shared trace:0x010034]; //支付成功 NSString *str1 = [NSBundle KOD_localizedStringForKey:PaySuccess]; [XSNetwork showHudSuccess:str1]; if (complete != nil) complete(payments, nil); }]; //#endif //}]; } ///点击悬浮按钮, -(void)handleTap:(UITapGestureRecognizer *)recognizer { if (self.configuration == nil || self.user == nil) { return; } [XSTracker.shared trace:0x010040]; //0:横屏 1:竖屏 #define SCREEN_Direction 0 ///横屏 #if SCREEN_Direction == 0 UserCenterViewController1* rootViewController1 = UserCenterViewController1.new; rootViewController1.otherView = self.bubbleView; rootViewController1.modalPresentationStyle = UIModalPresentationOverFullScreen; self.rootViewController = rootViewController1; #endif ///竖屏 #if SCREEN_Direction == 1 UserCenterViewController2* rootViewController2 = UserCenterViewController2.new; rootViewController2.otherView = self.bubbleView; rootViewController2.modalPresentationStyle = UIModalPresentationOverFullScreen; self.rootViewController = rootViewController2; #endif } /// /// User Center. /// - (void)center { if (self.configuration == nil || self.user == nil) { return; } [XSTracker.shared trace:0x010040]; //0:横屏 1:竖屏 #define SCREEN_Direction 0 ///横屏 #if SCREEN_Direction == 0 UserCenterViewController1* rootViewController1 = UserCenterViewController1.new; rootViewController1.otherView = self.bubbleView; rootViewController1.modalPresentationStyle = UIModalPresentationOverFullScreen; self.rootViewController = rootViewController1; #endif ///竖屏 #if SCREEN_Direction == 1 UserCenterViewController2* rootViewController2 = UserCenterViewController2.new; rootViewController2.otherView = self.bubbleView; rootViewController2.modalPresentationStyle = UIModalPresentationOverFullScreen; self.rootViewController = rootViewController2; #endif } /// Report role info. /// \param roleName This role name. /// /// \param level This role current level. /// /// \param serverId This role current server. /// - (void)reportWithRoleName:(NSString*)roleName level:(NSInteger)level serverId:(NSString*)serverId { if (self.configuration == nil || self.user == nil) { return; } [XSNetwork reportWithUser:self.user.userName Name:roleName level:level server:serverId]; [XSCollector.shared reportWithAccount:self.user.uid name:roleName level:level server:serverId]; } // MARK: -检查版本更新 - (void)sdk_checkVersion:(void(^)(void))complete { // If no configuration file is provided, initialization failed. if (self.configuration == nil) { complete(); return; } // If update cheker is not enabled, ignore it. NSURL* url = [NSURL URLWithString:self.configuration.updateUrl]; if (url == nil || self.configuration.updateState == 0) { complete(); return; } // If the prompt is too frequent, wait. // 1 is normal update. if (self.configuration.updateState == 1 && !([XSDataCenter doubleForKey:@"verion-later"] < NSDate.new.timeIntervalSince1970)) { complete(); return; } NoticeViewController* viewController = NoticeViewController.new; // Set the update title & contents. viewController.title = @"发现新版本"; viewController.contents = [NSString stringWithFormat:@"亲爱的玩家您好,我们发布了新的版本, 更新到新版本可体验更多新奇有趣的玩法!\n\n最新版本: %@\n当前版本: %@\n\n\n", self.configuration.updateVersion, self.shortVersion]; // Set the confirm closure. [viewController addActionWithName:@"立即升级" handler:^{ // -[UIApplication openURL:] ((void(*)(id,SEL,id))objc_msgSend)(UIApplication.sharedApplication, NSSelectorFromString(fqsd(@"p2cAAMrAyrKwq5rIAA==")), url); }]; // Set the cancel closure. if (self.configuration.updateState == 1) { __weak __typeof(self) ws = self; [viewController addActionWithName:@"稍后再说" handler:^{ // Again 24 hours later. [XSDataCenter setDouble:[NSDate dateWithTimeIntervalSinceNow:24*60*60].timeIntervalSince1970 forKey:@"verion-later"]; if (ws.rootViewController == nil) { complete(); return; } // Automatic hidden controller. [ws.rootViewController dismissViewControllerAnimated:YES completion:complete]; }]; } // Show view contorller in key window. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.rootViewController = [[RootViewController alloc] initWithRootViewController:viewController]; }); } - (void)sdk_checkNote:(void(^)(void))complete { // If no configuration file is provided, initialization failed. NSURL* url = [NSURL URLWithString:self.configuration.closeUrl]; if (url == nil || self.configuration.linkQq == 0) { complete(); return ; } // If the announcement is displayed, it is no longer displayed. if (self.configuration.linkQq != 2 && [[XSDataCenter stringForKey:@"notice-later"] isEqualToString:url.absoluteString]) { complete(); return; } NoticeViewController* viewController = NoticeViewController.new; // Set the update title & contents. viewController.title = @"系统公告"; viewController.contents = url; // Set the confirm closure. __weak __typeof(self) ws = self; [viewController addActionWithName:@"我知道了" handler:^{ // Never again. [XSDataCenter setString:url.absoluteString forKey:@"notice-later"]; if (ws.rootViewController == nil) { complete(); return; } // Automatic hidden controller. [ws.rootViewController dismissViewControllerAnimated:YES completion:complete]; }]; // Show view contorller in key window. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.rootViewController = [[RootViewController alloc] initWithRootViewController:viewController]; }); } - (void)sdk_checkPhone:(void(^)(void))complete { // Check if the phone character exists. if (self.user.isRegister || self.user.phone.length != 0 || self.configuration.serverStatus == 1) { complete(); return; } // If the prompt is too frequent, wait. id key = [NSString stringWithFormat:@"%@-bind-later", self.user.uid]; if ([XSDataCenter doubleForKey:key] > NSDate.new.timeIntervalSince1970) { complete(); return; } UserBindPhoneViewController* bindViewController = UserBindPhoneViewController.new; RootViewController* rooViewController = [[RootViewController alloc] initWithRootViewController:bindViewController]; UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:@"您的帐号存在风险, 为了您的帐号安全建议您绑定手机号。" preferredStyle:UIAlertControllerStyleAlert]; // Add confirm action. [alert addAction:[UIAlertAction actionWithTitle:@"绑定手机" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { bindViewController.callback = complete; self.rootViewController = rooViewController; }]]; // Add cancel action. [alert addAction:[UIAlertAction actionWithTitle:@"稍后提醒" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { // Again 24 hours later. [XSDataCenter setDouble:[NSDate dateWithTimeIntervalSinceNow:24*60*60].timeIntervalSince1970 forKey:key]; // Continue. complete(); }]]; (void)rooViewController.view; // preload; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.rootViewController = alert; }); // Hide all hud if needed. [XSNetwork hideHud]; } ///check In-app Purchase lost list. - (void)checkOrderStatus { //检查内购掉单. [KDIAPManager checkOrderStatus]; } // MARK: - - (void)setUser:(XSUser *)user { _user = user; _token = user.token; // Cache. [XSDataCenter setValue:user forKey:@"User.current"]; if (user == nil) { return; } // Make a new login history. NSMutableSet* ids = [NSMutableSet set]; NSMutableArray* history = [NSMutableArray array]; user.lastTime = NSDate.new.timeIntervalSince1970; [ids addObject:user.uid]; [history addObject:user]; for (XSUser* tmp in XSUser.history) { if (![ids containsObject:tmp.uid]) { [ids addObject:tmp.uid]; [history addObject:tmp]; } } XSUser.history = history; } - (XSUser*)user { if (_user != nil) { return _user; } static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ self->_user = [XSDataCenter valueForKey:@"User.current"]; self->_token = self->_user.token; }); return _user; } - (void)setRootViewController:(UIViewController *)rootViewController { _rootViewController = rootViewController; if (rootViewController == nil) { return; } [UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:rootViewController animated:YES completion:nil]; } /// Permanent preservation of data. - (void)setPermanentValue:(NSString*)value forKey:(NSString*)key { // Set value to user defautls. [XSDataCenter setString:value forKey:key]; // Configure the search setting. id setting = @{ // Configure the keychain key type. CFBridgingRelease(kSecClass): CFBridgingRelease(kSecClassGenericPassword), CFBridgingRelease(kSecAttrAccount): key }.mutableCopy; // Delete old item before add new item SecItemDelete(CFBridgingRetain(setting)); // Add new object to search dictionary. [setting setObject:[value dataUsingEncoding:NSUTF8StringEncoding] forKey:CFBridgingRelease(kSecValueData)]; // Add item to keychain with the search dictionary SecItemAdd(CFBridgingRetain(setting), nil); } /// Read data for permanent preservationed. - (id)permanentValueForKey:(NSString*)key { // Read data from user defatuls. NSString* udid = [XSDataCenter stringForKey:key]; if (udid.length != 0) { return udid; } // Configure the search setting. id setting = @{ // Configure the keychain key type. CFBridgingRelease(kSecClass): CFBridgingRelease(kSecClassGenericPassword), // The class name of the SDK is dynamic. CFBridgingRelease(kSecAttrService): NSStringFromClass(self.class), CFBridgingRelease(kSecAttrAccount): key, // Gets result data of data. CFBridgingRelease(kSecReturnData): CFBridgingRelease(kCFBooleanTrue) }; // Start query the keychain query. CFTypeRef result = nil; if (SecItemCopyMatching(CFBridgingRetain(setting), &result) == noErr) { return nil; } // Convert data to a string NSString* value = [[NSString alloc] initWithData:CFBridgingRelease(result) encoding:NSUTF8StringEncoding]; if (value.length == 0) { return nil; } // Set value to user defautls, reduce Keychain access count. [XSDataCenter setString:value forKey:key]; return value; } - (NSString*)advertisingIdentifier { // Read the data from keychain. NSString* advertisingIdentifier = [self permanentValueForKey:@"udid"]; if (advertisingIdentifier.length != 0) { return advertisingIdentifier; } #if SDK_HAS_IDFA // Try to obtain idfa. ASIdentifierManager* advertisingManager = ASIdentifierManager.sharedManager; advertisingIdentifier = advertisingManager.advertisingIdentifier.UUIDString; if (!advertisingManager.isAdvertisingTrackingEnabled) { advertisingIdentifier = [NSString stringWithFormat:@"#%@", NSUUID.new.UUIDString]; } #else // Generate an id to replace idfa. advertisingIdentifier = [NSString stringWithFormat:@"#%@", NSUUID.new.UUIDString]; #endif // Save to keychain to prevent updates. [self setPermanentValue:advertisingIdentifier forKey:@"udid"]; return advertisingIdentifier; } - (NSString*)advertisingVendor { // This parameter has been deprecated and must be empty string. return @""; } - (NSBundle*)bundle { return [NSBundle bundleForClass:self.class]; } - (NSString*)model { struct utsname sinfo; uname(&sinfo); return [NSString stringWithUTF8String: sinfo.machine]; } /// The sdk verions. - (NSString*)version { return self.bundle.infoDictionary[@"CFBundleShortVersionString"] ?: @"1.0"; } /// The game verions. - (NSString*)shortVersion { return NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"] ?: @"1.0"; } - (void)GMAdSDKinit { [GMAdManager sharedInstance]; } ///横幅广告 - (void)adBanner:(NSString*)adId { [[GMAdManager sharedInstance] openAd:adId]; } ///关闭广告(banner, nativeAd) - (void)closeAd:(NSString*)adId { [[GMAdManager sharedInstance] closeAd:adId]; } ///打开原生广告 -(void)openNativeAdWithCenterX:(int)x Y:(int)y width:(int)w height:(int)h { [[GMAdManager sharedInstance] openNativeAdWithX:x Y:y width:w height:h]; } ///打开视频激励广告 -(void)openVideoAd:(NSString *)adName callback:(void (^)(BOOL))complete { [[GMAdManager sharedInstance] openVideoAd:adName callback:^(BOOL flag) { complete(flag); }]; } ///打开积分墙广告 -(void)openofferWallAd:(NSString *)adName callback:(void (^)(BOOL))complete { [[GMAdManager sharedInstance] openofferWallAd:adName callback:^(BOOL flag) { complete(flag); }]; } ///打开插屏广告 -(void)openInterstitialAd:(NSString *)adName callback:(void (^)(BOOL))complete { [[GMAdManager sharedInstance] openinterstitialAd:adName callback:^(BOOL flag) { complete(flag); }]; } //广告是否加载好 -(BOOL)isAvailableAd:(NSString *)adName { BOOL flag = NO; if (adName.length == 0) { return flag; } //1.横幅广告 if ([adName hasPrefix:@"banner_"]) { flag = [GMAdManager sharedInstance].admobBannerAd.isReady; return flag; } //2.原生广告 if ([adName hasPrefix:@"nativeAd_"]) { flag = [GMAdManager sharedInstance].admobNativeAd.isReady; return flag; } //3.视频激励广告 if ([adName hasPrefix:@"video_"]) { flag = [[GMAdManager sharedInstance].rewardVideoAd isAdReady]; return flag; } //4.插屏广告 if ([adName hasPrefix:@"offerWall_"]) { flag = [[GMAdManager sharedInstance].offerWallVideoAd isAdReady]; return flag; } return flag; } ///手机震动 -(void)iphoneVibrate { //手机--设置--声音--响铃模式震动(打开),不然无效. AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); } //跳转appstore评论 -(void)skipToAppsotreWithID:(NSString *)appleId { NSString *urlStr = [NSString stringWithFormat:@"https://itunes.apple.com/us/app/itunes-u/id%@?action=write-review&mt=8", appleId]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlStr]]; } ///自动登录 - (void)xautoWithComplete:(void (^)(id user, NSError* error))complete { XSUser* user = [XSDataCenter valueForKey:@"User.current"]; if (user.uid.length == 0) { complete(nil,[XSNetwork errorWithCode:-1 message:@"未登录记录!"]); return; } // Try authorization login. XenonSDK.sharedSDK.token = user.token; [XSNetwork authWithUser:user.uid complete:^(XSUser* object, NSError *error) { // Check for general errors. if (error != nil && ![error.domain isEqual:@"XSNetwork"]) { [XSNetwork showHudFailure:error]; complete(nil,[XSNetwork errorWithCode:-1 message:error.domain]); return; } // Login successful. if (user.token.length != 0 && error == nil) { // Update user info. user.token = object.token; user.isRegister = NO; XenonSDK.sharedSDK.user = user; if (XenonSDK.sharedSDK.sdk_loginCallback) { complete(user,nil); XenonSDK.sharedSDK.sdk_loginCallback(user); } return; } [XSNetwork showHudFailure:@"登录时效期已过,请重新登录"]; complete(nil,[XSNetwork errorWithCode:-1 message:@"登录时效期已过,请重新登录"]); // Login failed to login page. UserLoginPhoneViewController* viewController = UserLoginPhoneViewController.new; [viewController automatic:user.account]; [self.rootViewController.navigationController pushViewController:viewController animated:YES]; }]; } ///手动登录 -(void)manualLogin { //XSUser *user = [XSDataCenter valueForKey:@"User.current"]; if (XSUser.history.count != 0) { self.rootViewController = [[RootViewController alloc] initWithRootViewController:UserLoginFastViewController.new]; return; } // To account login self.rootViewController = [[RootViewController alloc] initWithRootViewController:UserLoginPhoneViewController.new]; } ///Switch Account -(void)switchAccount { [XenonSDK.sharedSDK logoutWithComplete:^{ //PS:封神传说cp平台,收到登出通知后会调用一次登录接口, 这里重复了.注释掉 XSUser.history = nil; [XenonSDK.sharedSDK loginWithComplete:^(id user, NSError *error) { }]; }]; } /// 统计事件1 /// @param eventName 事件名称 -(void)tjEvent:(NSInteger )eventName { [XSTracker.shared trace:eventName]; } /// 统计事件2 /// @param eventName 事件名称 /// @param parameters 事件对应值 -(void)tjEvent:(NSInteger )eventName value:(id)parameters { [XSTracker.shared trace:eventName parameters:parameters]; } @end