// // 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 "XSCollector.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://app.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) { complete([XSNetwork errorWithCode:-1 message:@"参数错误"]); // 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]; 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:@"请先初始化"]); // 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) { complete(nil, [XSNetwork errorWithCode:-1 message:@"请先登录"]); // 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]; [XSNetwork showHudSuccess:@"支付成功"]; 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]; } ///自动登录 - (void)hAutoWithComplete:(void (^)(id user, NSError* error))complete { [XSNetwork showHudLoading]; //获取上次保存的登录信息. XSUser* user1 = [XSDataCenter valueForKey:@"User.current"]; //未注册, if (user1.uid.length == 0) { __weak __typeof(self) ws = self; [XSNetwork loginWithComplete:^(id object, NSError *error) { if (error != nil) { [XSNetwork showHudFailure:error]; complete(nil, error); return; } [ws setUser:object]; //XenonSDK.sharedSDK.user = object; [XSNetwork showHudSuccess:@"登录成功!"]; complete(object,nil); }]; }else{ // XenonSDK.sharedSDK.token = user1.token; __weak __typeof(self) ws = self; [XSNetwork authWithUser:user1.uid complete:^(XSUser* object, NSError *error) { if (error != nil && ![error.domain isEqual:@"XSNetwork"]) { [XSNetwork showHudFailure:error]; complete(nil,[XSNetwork errorWithCode:-1 message:error.domain]); return; } [XSNetwork showHudSuccess:@"登录成功!"]; if (user1.token.length != 0 && error == nil) { // Update user info. user1.token = object.token; user1.isRegister = NO; XenonSDK.sharedSDK.user = user1; [ws setUser:user1]; complete(user1,nil); } }]; } } // 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"; } ///TalkingData 游戏运营统计 - (void)TDGameOperationsinitWithAppID:(NSString *)appid ChannelId:(NSString *)channelId { if (appid.length == 0) { NSLog(@"TalkingData 游戏运营统计: appid为空!"); return; } if (channelId) { NSLog(@"TalkingData 游戏运营统计: channelId为空!"); } [TalkingDataGA onStart:appid withChannelId:channelId]; } -(void)TDregisterWithAccount:(NSString *)account name:(NSString *)name { [[XSCollector sharedManager] registerWithAccount:account name:name]; } -(void)TDloginWithAccount:(NSString *)account name:(NSString *)name { [[XSCollector sharedManager] loginWithAccount:account name:name]; } -(void)TDreportWithAccount:(NSString*)account Name:(NSString *)name Age:(int)age Gender:(NSInteger)gender { [[XSCollector sharedManager] reportWithAccount:account name:name age:age gender:gender]; } -(void)TDreportWithAccount:(NSString*)account name:(NSString*)name level:(NSInteger)level server:(NSString*)server { [[XSCollector sharedManager] reportWithAccount:account name:name level:level server:server]; } -(void)TDonChargeRequst:(NSString *)orderId iapId:(NSString *)iapId currencyAmount:(double)currencyAmount currencyType:(NSString *)currencyType virtualCurrencyAmount:(double)virtualCurrencyAmount paymentType:(NSString *)paymentType { [[XSCollector sharedManager] onChargeRequst:orderId iapId:iapId currencyAmount:currencyAmount currencyType:currencyType virtualCurrencyAmount:virtualCurrencyAmount paymentType:paymentType]; } - (void)TDonChargeSuccess:(NSString *)orderId { [[XSCollector sharedManager] onChargeSuccess:orderId]; } //TD 自定义事件 -(void)TDonEvent:(NSString *)eventId eventData:(id)parm { [[XSCollector sharedManager] onEvent:eventId eventData:parm]; } - (void)TDAnalyticsinitWithAppID:(NSString *)appid ChannelId:(NSString *)channelId backgroundSession:(BOOL)flag { if (appid.length == 0 ) { NSLog(@"【TalkingData】,error=App ID参数为nil"); return; } if (channelId.length == 0) { NSLog(@"【TalkingData】,error=渠道 ID参数为nil"); } if (flag) { [TalkingData backgroundSessionEnabled]; //获取后台使用时长 } [TalkingData sessionStarted:appid withChannelId:channelId]; //init [TalkingData setExceptionReportEnabled:YES]; //自动获取异常信息 [TalkingData setSignalReportEnabled:YES]; //自动获取异常信号 } -(void)TDAnalyticsTrackPageBegin:(NSString *)pageName { [TalkingData trackPageBegin:pageName]; } -(void)TDAnalyticsTrackPageEnd:(NSString *)pageName { [TalkingData trackPageEnd:pageName]; } //自定义事件1 - (void)TDAnalyticsTrackEvent:(NSString *)eventID { [TalkingData trackEvent:eventID]; } //自定义事件2 - (void)TDAnalyticsTrackEvent:(NSString *)eventID label:(NSString *)event_label { [TalkingData trackEvent:eventID label:event_label]; } //自定义事件3,eventID:自定义事件名称, event_label:自定义事件Label,用来区分具体场景. dict:自定义事件的参数及参数取值. - (void)TDAnalyticsTrackEvent:(NSString *)eventID label:(NSString *)event_label parameters:(NSDictionary *)dict { [TalkingData trackEvent:eventID label:event_label parameters:dict]; } //orderId:订单ID total:订单总金额,货币单位为分 currencyType:货币种类,eg:人民币 CNY;美元 USD;欧元 EUR -(TalkingDataOrder *)TDAnalyticsCreateOrder:(NSString *)orderId total:(int)total currencyType:(NSString *)currencyType { TalkingDataOrder *order = [TalkingDataOrder createOrder:orderId total:total currencyType:currencyType]; return order; } //应用内支付-添加订单详情.order为创建的订单 - (void)TDAnalyticsWith:(TalkingDataOrder *)order AddItem:(NSString *)itemId category:(NSString *)category name:(NSString *)name unitPrice:(int)unitPrice amount:(int)amount { [order addItem:itemId category:category name:name unitPrice:unitPrice amount:amount]; } //应用内支付-成功支付订单 - (void)TDAnalyticsOnPlaceOrder:(NSString *)profileID order:(TalkingDataOrder *)order { [TalkingData onPlaceOrder:profileID order:order]; } ///穿山甲广告Ad //1.init - (void)CSJAdSDKinit { [MLAdManager sharedInstance]; } //优量汇广告Ad-init -(void)YLHAdSDKinit { [YLHAdManager sharedInstance]; } //TopOn广告Ad-init -(void)TopOnAdSDKinit { [TOPONAdManager sharedInstance]; } //2.打开全屏广告 -(void)openBUDFullScreenVideoAd:(NSString *)adName callback:(void (^)(BOOL))callback { [[MLAdManager sharedInstance] openFullScreenVideoAd:adName callback:callback]; } //打开新插屏广告(新增) -(void)openBUDNewInterstitialAd:(NSString *)adName callback:(void (^)(BOOL))callback { [[MLAdManager sharedInstance] openNewInterstitialAd:adName callback:callback]; } //2.打开开屏广告 -(void)openBUDSplashAd:(NSString *)adName callback:(void (^)(BOOL))callback { [[MLAdManager sharedInstance] openSplashAd:adName callback:callback]; } //3. 打开插屏广告 -(void)openBUDInterstitialAd:(NSString *)adName width:(CGFloat)w Height:(CGFloat)h callback:(void (^)(BOOL))callback { [[MLAdManager sharedInstance] openExpressInterstitialAd:adName Width:w Height:h callback:callback]; } //4. 打开视频激励广告 -(void)openBUDExpressRewardedVideoAd:(NSString *)adName callback:(void (^)(BOOL,BOOL))callback { [[MLAdManager sharedInstance] openExpressRewardedVideoAd:adName callback:callback]; } //5. 打开原生Banner广告 -(void)openBUDNativeBannerAd:(NSString *)adName WithX:(CGFloat)x Y:(CGFloat)y Width:(CGFloat)w Height:(CGFloat)h callback:(void (^)(BOOL))callback { [[MLAdManager sharedInstance] openNativeExpressBannerAd:adName WithX:x Y:y Width:w Height:h callback:callback]; } //6. 打开原生广告 -(void)openBUDNativeAd:(NSString *)adName WidthCGRect:(CGRect)rect BUSize:(NSInteger)size callback:(void (^)(BOOL))callback { [[MLAdManager sharedInstance] openNativeAd:adName WidthCGRect:rect BUSize:size callback:callback]; } //5.2 关闭Banner广告 -(void)closeBUDBannerAd:(NSString *)adName { [[MLAdManager sharedInstance] closeBannerAd:adName]; } //优量汇广告 //init -(void)openYLHSplashAd:(NSString *)adName supportZoomoutView:(BOOL)flag callback:(void (^)(BOOL))callback { [[YLHAdManager sharedInstance] openSplashAd:adName supportZoomoutView:flag callback:callback]; } -(void)openYLHInterstitialAd:(NSString *)adName callback:(void (^)(BOOL))callback { [[YLHAdManager sharedInstance] openExpressInterstitialAd:adName callback:callback]; } -(void)openYLHFullScreenAd:(NSString *)adName callback:(void (^)(BOOL))callback { [[YLHAdManager sharedInstance] openFullScreenVideoAd:adName callback:callback]; } -(void)openYLHExpressRewardedVideoAd:(NSString *)adName callback:(void (^)(BOOL, BOOL))callback { [[YLHAdManager sharedInstance] openExpressRewardedVideoAd:adName callback:callback]; } //4.5 打开横幅广告 -(void)openYLHExpressBannerAd:(NSString *)adName callback:(void (^)(BOOL))callback { [[YLHAdManager sharedInstance] openExpressBannerVideoAd:adName callback:callback]; } //4.6 打开原生广告 -(void)openYLHExpressNativeAdWithPlacementId:(NSString *)placementId AdName:(NSString *)adName Frame:(CGRect)rect callback:(void (^)(BOOL))callback { [[YLHAdManager sharedInstance] openExpressNativeAdWithPlacementId:placementId AdName:adName Frame:rect callback:callback]; } -(void)openTOPONSplashAd:(NSString *)adName callback:(void (^)(BOOL))callback { [[TOPONAdManager sharedInstance] opensplashAd:adName callback:callback]; } -(void)openTOPONInterstitialAd:(NSString *)adName callback:(void (^)(BOOL))callback { [[TOPONAdManager sharedInstance] openInterstitialAd:adName callback:callback]; } -(void)openTOPONRewardedVideoAd:(NSString *)adName callback:(void (^)(BOOL,BOOL))callback { [[TOPONAdManager sharedInstance] openRewardedVideoAd:adName callback:callback]; } -(void)openTOPONExpressBannerAd:(NSString *)adName callback:(void (^)(BOOL))callback { [[TOPONAdManager sharedInstance] openExpressBannerAd:adName callback:callback]; } -(void)openTOPONNativeAdWithX:(int)x Y:(int)y width:(int)w height:(int)h adId:(NSString *)adName callback:(void (^)(BOOL))callback { [[TOPONAdManager sharedInstance] openNativeAdWithX:x Y:y width:w height:h adId:adName callback:callback]; } -(void)showHudWith:(NSString *)name { [XSNetwork showHudSuccess:name]; } @end