XenonSDK.m 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. //
  2. // XenonSDK.m
  3. // XenonSDK
  4. //
  5. // Created by SAGESSE on 2019/3/11.
  6. // Copyright © 2019 SAGESSE. All rights reserved.
  7. //
  8. #import "XenonSDK.h"
  9. #import <Security/Security.h>
  10. #import <sys/utsname.h>
  11. #if SDK_HAS_IDFA
  12. #import <AdSupport/AdSupport.h>
  13. #endif
  14. #import "BubbleView.h"
  15. #import "RootViewController.h"
  16. #import "NoticeViewController.h"
  17. #import "UserBindPhoneViewController.h"
  18. #import "UserLoginFastViewController.h"
  19. #import "UserLoginPhoneViewController.h"
  20. #import "UserCenterViewController1.h"
  21. #import "UserCenterViewController2.h"
  22. #import "XSUtils.h"
  23. #import "KDIAPManager.h"
  24. #import "NSBundle+KODLocalizable.h"
  25. #import "KODCommonConst.h"
  26. #import <objc/message.h>
  27. @interface XenonSDK ()
  28. @end
  29. ///
  30. /// Game SDK
  31. ///
  32. @implementation XenonSDK
  33. @synthesize user = _user;
  34. @synthesize token = _token;
  35. ///
  36. /// A sington instance of SDK.
  37. ///
  38. + (instancetype)sharedSDK {
  39. static id sharedSDK = nil;
  40. static dispatch_once_t onceToken;
  41. dispatch_once(&onceToken, ^{
  42. sharedSDK = XenonSDK.new;
  43. if (XSNetwork.baseURL == nil) {
  44. XSNetwork.baseURL = @"https://fapp.funcheergame.com";
  45. //测试地址 @"http://47.56.223.128:9099";
  46. //国内正式地址 @"https://app.funcheergame.com";
  47. //国外正式地址 @"https://fapp.funcheergame.com"
  48. }
  49. });
  50. return sharedSDK;
  51. }
  52. ///
  53. /// Init the sdk with application code.
  54. /// \param parameter The parameter provided by the platform.
  55. ///
  56. /// \param complete This closure called when init complete.
  57. ///
  58. - (void)initWithParameter:(NSString*)parameter complete:(void (^)(NSError* error))complete {
  59. // If init is complete, ignore it this call.
  60. if (self.configuration != nil) {
  61. if (complete != nil) {
  62. complete(nil); // sdk is ready.
  63. }
  64. return;
  65. }
  66. // Parse pre-configuration for parameter.
  67. NSArray* configs = [parameter componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"|&"]];
  68. if (configs.count != 4) {
  69. if (complete != nil) {
  70. //参数错误
  71. NSString *str1 = [NSBundle KOD_localizedStringForKey:ParamsError];
  72. complete([XSNetwork errorWithCode:-1 message:str1]); // error -1
  73. }
  74. return ;
  75. }
  76. // Update pre-configuration for parameter.
  77. self.appId = configs[0];
  78. self.channelId = configs[1];
  79. self.adId = configs[2];
  80. self.adFlag = configs[3];
  81. // Update system configration for server.
  82. [XSNetwork configureWithIdentifier:self.adId flags:self.adFlag complete:^(XSConfiguration* object, NSError *error) {
  83. // If an error occurs, directly callback cp.
  84. if (error != nil) {
  85. if (complete != nil) {
  86. complete(error);
  87. }
  88. return;
  89. }
  90. // An unknown error.
  91. if (object.closeState != 0) {
  92. // Display an system notice.
  93. id qq = self.configuration.fixLinkQQ ?: @"";
  94. id tel = self.configuration.fixLinkTel ?: @"";
  95. // Set the update title & contents.
  96. //id contents = [NSString stringWithFormat:@"\n亲爱的玩家您好, 由于服务器紧急维护, 目前游戏暂时无法进入, 给您带来的不便我们深表歉意!\n如果您还有其他问题请与我们联系!\n\n客服QQ: %@\n客服电话: %@", qq, tel];
  97. NSString *contents1 = [NSBundle KOD_localizedStringForKey:ServiceErrorPleaseConnnectServicePhone];
  98. NSString *contents = [NSString stringWithFormat:@"%@%@%@",contents1,qq,tel];
  99. UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"系统公告" message:contents preferredStyle:UIAlertControllerStyleAlert];
  100. [alert addAction:[UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:nil]];
  101. self.rootViewController = alert;
  102. complete([XSNetwork errorWithCode:-8 message:nil]);
  103. return;
  104. }
  105. // Setup sdk with server configuration.
  106. self.configuration = object;
  107. // Get third-party platform parameters.
  108. if (self.configuration.thirdPartyPrams.length != 0) {
  109. NSDictionary* thirdPartyPrams = [NSJSONSerialization JSONObjectWithData:[self.configuration.thirdPartyPrams dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
  110. // If the tracker is turned on, create the object.
  111. int mask = 0;
  112. NSString* dps = thirdPartyPrams[@"dp"];
  113. if (dps.length != 0) {
  114. sscanf(dps.UTF8String, "%x", &mask);
  115. if (mask != 0) {
  116. XSTracker.shared = [XSTracker new];
  117. XSTracker.shared.mask = mask;
  118. [XSNetwork trigger:20];
  119. }
  120. }
  121. // In the initialization.
  122. [XSTracker.shared trace:0x010000 parameters:[NSString stringWithFormat:@"%@", NSProcessInfo.processInfo.environment]];
  123. // If an advertisement parameter is specified, try to parse advertising parameter.
  124. NSString* adPrams = self.configuration.adPrams;
  125. if (adPrams.length != 0) {
  126. // Parse advertising parameter.
  127. [[adPrams componentsSeparatedByString:@"&"] enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  128. // Value must be `key=value`
  129. NSArray* tmp = [obj componentsSeparatedByString:@"="];
  130. if (tmp.count != 2) {
  131. return;
  132. }
  133. if ([tmp[0] isEqualToString:@"td_app_id"]) {
  134. self.configuration.tdAppId = tmp[1];
  135. }
  136. if ([tmp[0] isEqualToString:@"td_game_id"]) {
  137. self.configuration.tdGameId = tmp[1];
  138. }
  139. }];
  140. // If td game id is not provided, the TD sdk is not initialized.
  141. if (self.configuration.tdAppId.length != 0 && self.configuration.tdGameId.length != 0) {
  142. // Init for data analzer server.
  143. XSCollector.shared = [[XSCollector alloc] initWithAppId:self.configuration.tdAppId gameId:self.configuration.tdGameId];
  144. }
  145. }
  146. }
  147. [self sdk_checkVersion:^{
  148. [self sdk_checkNote:^{
  149. // Check workflow ended.
  150. [XSTracker.shared trace:0x010001];
  151. // Init sdk complete.
  152. if (complete != nil)
  153. complete(nil);
  154. // init workflow ended.
  155. [XSTracker.shared trace:0x010002];
  156. }];
  157. }];
  158. }];
  159. }
  160. ///
  161. /// Login the sdk.
  162. /// \param complete This closure called when login complete.
  163. ///
  164. - (void)loginWithComplete:(void (^)(id user, NSError* error))complete {
  165. // If init is complete, ignore it this call.
  166. if (self.configuration == nil) {
  167. if (complete != nil)
  168. //请先初始化
  169. complete(nil, [XSNetwork errorWithCode:-1 message:[NSBundle KOD_localizedStringForKey:PleaseInitFirst]]); // error -1
  170. //发出登录失败通知. flag=NO
  171. NSNotification *notification = [NSNotification notificationWithName:@"LoginSuccessNotificaion" object:nil userInfo:@{@"userInfo":@"",@"flag":@"NO"}];
  172. [[NSNotificationCenter defaultCenter] postNotification:notification];
  173. return;
  174. }
  175. [XSTracker.shared trace:0x010010];
  176. // Unified operation after successful login.
  177. void (^loginedCallback)(void) = ^{
  178. // Build return data.
  179. id user = nil;
  180. if (self.user != nil) {
  181. user = @{
  182. @"uid": self.user.uid,
  183. @"token": self.user.token,
  184. @"userName": self.user.userName ?: @"",
  185. @"phone": self.user.phone ?: @""
  186. };
  187. // According to air bubbles.
  188. if (!self.configuration.isFloatDisable) {
  189. UIWindow* window = UIApplication.sharedApplication.delegate.window ?: UIApplication.sharedApplication.keyWindow;
  190. BubbleView* view = [[BubbleView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
  191. [view.contentView addTarget:self action:@selector(center) forControlEvents:UIControlEventTouchUpInside];
  192. UITapGestureRecognizer *tapRecognize = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTap:)];
  193. [view addGestureRecognizer:tapRecognize];
  194. [window addSubview:view];
  195. // It's shown in the first one.
  196. UIView* xmp = [window viewWithTag:-1];
  197. if (xmp != nil) {
  198. [window bringSubviewToFront:xmp];
  199. }
  200. [self.bubbleView removeFromSuperview];
  201. self.bubbleView = view;
  202. }
  203. [XSTracker.shared trace:0x010013];
  204. }
  205. [XSTracker.shared trace:0x010011];
  206. if (complete) {
  207. complete(user, nil);
  208. }
  209. [XSTracker.shared trace:0x010012];
  210. };
  211. // Try automatically login if needed.
  212. if (self.user != nil) {
  213. [XSNetwork showHudLoading];
  214. [XSNetwork authWithUser:self.user.uid complete:^(XSUser* user, NSError *error) {
  215. // If the login fails, clear the user information and login again.
  216. if (user.token.length == 0 || error != nil) {
  217. [XSNetwork showHudFailure:@"登录时效期已过,请重新登录"];
  218. self.user = nil;
  219. [self loginWithComplete:complete];
  220. return;
  221. }
  222. // Update user info.
  223. XSUser* duser = self.user;
  224. duser.token = user.token;
  225. duser.isRegister = false;
  226. self.user = duser;
  227. // Login successful, display HUD.
  228. [XSNetwork showPrompt:duser.name];
  229. //发出登成功通知.flag=YES
  230. NSDictionary *dict = @{@"userInfo":self.user,@"flag":@"YES"};
  231. NSNotification *notification = [NSNotification notificationWithName:@"LoginSuccessNotificaion" object:nil userInfo:dict];
  232. [[NSNotificationCenter defaultCenter] postNotification:notification];
  233. // Check if the user is already connected to the phone.
  234. // [self sdk_checkPhone:^{
  235. // loginedCallback();
  236. // }];
  237. //绑定手机
  238. loginedCallback();
  239. }];
  240. [XSTracker.shared trace:0x010014];
  241. return;
  242. }
  243. // Setup login callback.
  244. __weak __typeof(self) ws = self;
  245. self.sdk_loginCallback = ^(XSUser* user) {
  246. [ws setUser:user];
  247. [ws.rootViewController dismissViewControllerAnimated:YES completion:nil];
  248. // Login successful, display HUD.
  249. //发出登录成功通知.
  250. NSDictionary *dict = @{@"userInfo":user,@"flag":@"YES"};
  251. NSNotification *notification = [NSNotification notificationWithName:@"LoginSuccessNotificaion" object:nil userInfo:dict];
  252. [[NSNotificationCenter defaultCenter] postNotification:notification];
  253. [XSNetwork showPrompt:user.name];
  254. loginedCallback();
  255. };
  256. // The last time was to log out, so the quick login list is displayed.
  257. if (XSUser.history.count != 0) {
  258. //self.rootViewController = [[RootViewController alloc] initWithRootViewController:UserLoginFastViewController.new];
  259. self.rootViewController = [[RootViewController alloc] initWithRootViewController:UserLoginPhoneViewController.new];
  260. return;
  261. }
  262. // To account login
  263. self.rootViewController = [[RootViewController alloc] initWithRootViewController:UserLoginPhoneViewController.new];
  264. }
  265. ///
  266. /// Logout the sdk.
  267. /// \param complete This closure called when logout complete.
  268. ///
  269. - (void)logoutWithComplete:(void (^)(void))complete {
  270. // If init is complete, ignore it this call.
  271. if (self.configuration == nil) {
  272. if (complete != nil)
  273. complete();
  274. return;
  275. }
  276. self.user = nil;
  277. [self.bubbleView removeFromSuperview];
  278. self.bubbleView = nil;
  279. //发出退出通知.
  280. NSNotification *notification = [NSNotification notificationWithName:@"LogoutNotificaion" object:nil userInfo:nil];
  281. [[NSNotificationCenter defaultCenter] postNotification:notification];
  282. if (complete != nil)
  283. complete();
  284. [XSTracker.shared trace:0x010020];
  285. }
  286. ///
  287. /// Logout the game and sdk.
  288. /// \param handler This closure called when user logout in web view.
  289. /// \note Warning this handler will retain in until next call this method.
  290. ///
  291. - (void)logoutWhenNotification:(void (^)(void))handler {
  292. self.sdk_logoutCallback = ^(id user) {
  293. if (handler != nil)
  294. handler();
  295. [XSTracker.shared trace:0x010020];
  296. };
  297. }
  298. ///
  299. /// Buy a product.
  300. /// \param parameters Payment request parameters.
  301. /// \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
  302. ///
  303. - (void)buy:(NSDictionary*)parameters complete:(void (^)(id order, NSError* error))complete {
  304. // Check paramrters.
  305. if (self.configuration == nil || self.user == nil) {
  306. if (complete != nil) {
  307. //请先登录
  308. NSString *str = [NSBundle KOD_localizedStringForKey:PleaseLoginFirst];
  309. complete(nil, [XSNetwork errorWithCode:-1 message:str]); // error -1
  310. return ;
  311. }
  312. }
  313. [XSTracker.shared trace:0x010030];
  314. [XSNetwork showHudLoading];
  315. //
  316. // [XSNetwork routeWithComplete:^(id object, NSError *error) {
  317. //
  318. // if (error != nil) {
  319. // [XSNetwork showHudFailure:error];
  320. // if (complete != nil) {
  321. // complete(nil, error);
  322. // }
  323. // return;
  324. // }
  325. // Get parmeters.
  326. XSUser* user = self.user;
  327. //NSString* path = object[fqsd(@"PREAACs/NCYsJjQuLRkA")];
  328. //#if SDK_HAS_H5_PAYMENT
  329. //Generate h5 payment parameters.
  330. // if (path.length != 0) {
  331. //
  332. // [XSNetwork hideHud];
  333. // [XSTracker.shared trace:0x010031];
  334. //
  335. // id payments = @{
  336. // @"cpBillNo": parameters[@"orderId"] ?: @"",
  337. // @"orderAmount": parameters[@"amount"] ?: @"",
  338. // @"subject": parameters[@"productName"] ?: @"",
  339. //
  340. // @"roleName": parameters[@"roleName"] ?: @"",
  341. // @"serverId": parameters[@"serverId"] ?: @"",
  342. // @"extraInfo": parameters[@"extraInfo"] ?: @"",
  343. //
  344. // @"phone": @"",
  345. // @"isTest": @"1",
  346. // @"orderPlatform": @"0",
  347. // @"orderType": @"1",
  348. // @"remark": @"0",
  349. // @"isApp": @"0",
  350. //
  351. // @"uid": user.uid,
  352. // @"userName": user.userName ?: @""
  353. // };
  354. //
  355. // NSURLComponents* components = [NSURLComponents componentsWithString:path];
  356. // NSDictionary* json = [XSNetwork bodyWithParameters:payments];
  357. // NSString* str = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:json options:0 error:nil] encoding:NSUTF8StringEncoding];
  358. //
  359. // components.queryItems = @[[NSURLQueryItem queryItemWithName:@"jsonData" value:str],
  360. // [NSURLQueryItem queryItemWithName:@"v" value:@"1"]];
  361. //
  362. // if (components.URL == nil) {
  363. // if (complete != nil) {
  364. // complete(nil, [XSNetwork errorWithCode:-1 message:@"后台参数错误"]);
  365. // }
  366. // return;
  367. // }
  368. //
  369. // UserCenterViewController* rootViewController = UserCenterViewController.new;
  370. // rootViewController.custom = components.URL.absoluteString;
  371. // rootViewController.otherView = self.bubbleView;
  372. // rootViewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
  373. // self.rootViewController = rootViewController;
  374. //
  375. // // Cannot get the callback state.
  376. // rootViewController.callback = ^{
  377. // if (complete != nil) {
  378. // complete(nil, nil);
  379. // }
  380. // };
  381. // return;
  382. // }
  383. //#endif
  384. //#if SDK_HAS_IAP_PAYMENT
  385. // Generate iap payment parameters.
  386. id payments = @{
  387. @"productCode": parameters[@"productCode"] ?: @"",
  388. @"isCoin": @"0",
  389. @"orderPlatform": @"0",
  390. @"orderType": @"1",
  391. @"orderAmount": parameters[@"amount"] ?: @"",
  392. @"isTest": @"0",
  393. @"subject": parameters[@"productName"] ?: @"",
  394. @"roleName": parameters[@"roleName"] ?: @"",
  395. @"cpBillNo": parameters[@"orderId"] ?: @"",
  396. @"remark": @"0",
  397. @"serverId": parameters[@"serverId"] ?: @"",
  398. @"extraInfo": parameters[@"extraInfo"] ?: @"",
  399. @"uid": user.uid,
  400. @"userName": user.userName ?: @""
  401. };
  402. [XSTracker.shared trace:0x010032];
  403. [XSNetwork payWithParameters:payments complete:^(id object, NSError *error) {
  404. if (error != nil) {
  405. [XSNetwork showHudFailure:error];
  406. if (complete != nil) {
  407. complete(nil, error);
  408. }
  409. return;
  410. }
  411. [XSTracker.shared trace:0x010034];
  412. //支付成功
  413. NSString *str1 = [NSBundle KOD_localizedStringForKey:PaySuccess];
  414. [XSNetwork showHudSuccess:str1];
  415. if (complete != nil)
  416. complete(payments, nil);
  417. }];
  418. //#endif
  419. //}];
  420. }
  421. ///点击悬浮按钮,
  422. -(void)handleTap:(UITapGestureRecognizer *)recognizer {
  423. if (self.configuration == nil || self.user == nil) {
  424. return;
  425. }
  426. [XSTracker.shared trace:0x010040];
  427. //0:横屏 1:竖屏
  428. #define SCREEN_Direction 0
  429. ///横屏
  430. #if SCREEN_Direction == 0
  431. UserCenterViewController1* rootViewController1 = UserCenterViewController1.new;
  432. rootViewController1.otherView = self.bubbleView;
  433. rootViewController1.modalPresentationStyle = UIModalPresentationOverFullScreen;
  434. self.rootViewController = rootViewController1;
  435. #endif
  436. ///竖屏
  437. #if SCREEN_Direction == 1
  438. UserCenterViewController2* rootViewController2 = UserCenterViewController2.new;
  439. rootViewController2.otherView = self.bubbleView;
  440. rootViewController2.modalPresentationStyle = UIModalPresentationOverFullScreen;
  441. self.rootViewController = rootViewController2;
  442. #endif
  443. }
  444. ///
  445. /// User Center.
  446. ///
  447. - (void)center {
  448. if (self.configuration == nil || self.user == nil) {
  449. return;
  450. }
  451. [XSTracker.shared trace:0x010040];
  452. //0:横屏 1:竖屏
  453. #define SCREEN_Direction 0
  454. ///横屏
  455. #if SCREEN_Direction == 0
  456. UserCenterViewController1* rootViewController1 = UserCenterViewController1.new;
  457. rootViewController1.otherView = self.bubbleView;
  458. rootViewController1.modalPresentationStyle = UIModalPresentationOverFullScreen;
  459. self.rootViewController = rootViewController1;
  460. #endif
  461. ///竖屏
  462. #if SCREEN_Direction == 1
  463. UserCenterViewController2* rootViewController2 = UserCenterViewController2.new;
  464. rootViewController2.otherView = self.bubbleView;
  465. rootViewController2.modalPresentationStyle = UIModalPresentationOverFullScreen;
  466. self.rootViewController = rootViewController2;
  467. #endif
  468. }
  469. /// Report role info.
  470. /// \param roleName This role name.
  471. ///
  472. /// \param level This role current level.
  473. ///
  474. /// \param serverId This role current server.
  475. ///
  476. - (void)reportWithRoleName:(NSString*)roleName level:(NSInteger)level serverId:(NSString*)serverId {
  477. if (self.configuration == nil || self.user == nil) {
  478. return;
  479. }
  480. [XSNetwork reportWithUser:self.user.userName Name:roleName level:level server:serverId];
  481. [XSCollector.shared reportWithAccount:self.user.uid name:roleName level:level server:serverId];
  482. }
  483. // MARK: -检查版本更新
  484. - (void)sdk_checkVersion:(void(^)(void))complete {
  485. // If no configuration file is provided, initialization failed.
  486. if (self.configuration == nil) {
  487. complete();
  488. return;
  489. }
  490. // If update cheker is not enabled, ignore it.
  491. NSURL* url = [NSURL URLWithString:self.configuration.updateUrl];
  492. if (url == nil || self.configuration.updateState == 0) {
  493. complete();
  494. return;
  495. }
  496. // If the prompt is too frequent, wait.
  497. // 1 is normal update.
  498. if (self.configuration.updateState == 1 && !([XSDataCenter doubleForKey:@"verion-later"] < NSDate.new.timeIntervalSince1970)) {
  499. complete();
  500. return;
  501. }
  502. NoticeViewController* viewController = NoticeViewController.new;
  503. // Set the update title & contents.
  504. viewController.title = @"发现新版本";
  505. viewController.contents = [NSString stringWithFormat:@"亲爱的玩家您好,我们发布了新的版本, 更新到新版本可体验更多新奇有趣的玩法!\n\n最新版本: %@\n当前版本: %@\n\n\n", self.configuration.updateVersion, self.shortVersion];
  506. // Set the confirm closure.
  507. [viewController addActionWithName:@"立即升级" handler:^{
  508. // -[UIApplication openURL:]
  509. ((void(*)(id,SEL,id))objc_msgSend)(UIApplication.sharedApplication, NSSelectorFromString(fqsd(@"p2cAAMrAyrKwq5rIAA==")), url);
  510. }];
  511. // Set the cancel closure.
  512. if (self.configuration.updateState == 1) {
  513. __weak __typeof(self) ws = self;
  514. [viewController addActionWithName:@"稍后再说" handler:^{
  515. // Again 24 hours later.
  516. [XSDataCenter setDouble:[NSDate dateWithTimeIntervalSinceNow:24*60*60].timeIntervalSince1970 forKey:@"verion-later"];
  517. if (ws.rootViewController == nil) {
  518. complete();
  519. return;
  520. }
  521. // Automatic hidden controller.
  522. [ws.rootViewController dismissViewControllerAnimated:YES completion:complete];
  523. }];
  524. }
  525. // Show view contorller in key window.
  526. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  527. self.rootViewController = [[RootViewController alloc] initWithRootViewController:viewController];
  528. });
  529. }
  530. - (void)sdk_checkNote:(void(^)(void))complete {
  531. // If no configuration file is provided, initialization failed.
  532. NSURL* url = [NSURL URLWithString:self.configuration.closeUrl];
  533. if (url == nil || self.configuration.linkQq == 0) {
  534. complete();
  535. return ;
  536. }
  537. // If the announcement is displayed, it is no longer displayed.
  538. if (self.configuration.linkQq != 2 && [[XSDataCenter stringForKey:@"notice-later"] isEqualToString:url.absoluteString]) {
  539. complete();
  540. return;
  541. }
  542. NoticeViewController* viewController = NoticeViewController.new;
  543. // Set the update title & contents.
  544. viewController.title = @"系统公告";
  545. viewController.contents = url;
  546. // Set the confirm closure.
  547. __weak __typeof(self) ws = self;
  548. [viewController addActionWithName:@"我知道了" handler:^{
  549. // Never again.
  550. [XSDataCenter setString:url.absoluteString forKey:@"notice-later"];
  551. if (ws.rootViewController == nil) {
  552. complete();
  553. return;
  554. }
  555. // Automatic hidden controller.
  556. [ws.rootViewController dismissViewControllerAnimated:YES completion:complete];
  557. }];
  558. // Show view contorller in key window.
  559. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  560. self.rootViewController = [[RootViewController alloc] initWithRootViewController:viewController];
  561. });
  562. }
  563. - (void)sdk_checkPhone:(void(^)(void))complete {
  564. // Check if the phone character exists.
  565. if (self.user.isRegister || self.user.phone.length != 0 || self.configuration.serverStatus == 1) {
  566. complete();
  567. return;
  568. }
  569. // If the prompt is too frequent, wait.
  570. id key = [NSString stringWithFormat:@"%@-bind-later", self.user.uid];
  571. if ([XSDataCenter doubleForKey:key] > NSDate.new.timeIntervalSince1970) {
  572. complete();
  573. return;
  574. }
  575. UserBindPhoneViewController* bindViewController = UserBindPhoneViewController.new;
  576. RootViewController* rooViewController = [[RootViewController alloc] initWithRootViewController:bindViewController];
  577. UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:@"您的帐号存在风险, 为了您的帐号安全建议您绑定手机号。" preferredStyle:UIAlertControllerStyleAlert];
  578. // Add confirm action.
  579. [alert addAction:[UIAlertAction actionWithTitle:@"绑定手机" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  580. bindViewController.callback = complete;
  581. self.rootViewController = rooViewController;
  582. }]];
  583. // Add cancel action.
  584. [alert addAction:[UIAlertAction actionWithTitle:@"稍后提醒" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  585. // Again 24 hours later.
  586. [XSDataCenter setDouble:[NSDate dateWithTimeIntervalSinceNow:24*60*60].timeIntervalSince1970 forKey:key];
  587. // Continue.
  588. complete();
  589. }]];
  590. (void)rooViewController.view; // preload;
  591. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  592. self.rootViewController = alert;
  593. });
  594. // Hide all hud if needed.
  595. [XSNetwork hideHud];
  596. }
  597. ///check In-app Purchase lost list.
  598. - (void)checkOrderStatus {
  599. //检查内购掉单.
  600. [KDIAPManager checkOrderStatus];
  601. }
  602. // MARK: -
  603. - (void)setUser:(XSUser *)user {
  604. _user = user;
  605. _token = user.token;
  606. // Cache.
  607. [XSDataCenter setValue:user forKey:@"User.current"];
  608. if (user == nil) {
  609. return;
  610. }
  611. // Make a new login history.
  612. NSMutableSet* ids = [NSMutableSet set];
  613. NSMutableArray* history = [NSMutableArray array];
  614. user.lastTime = NSDate.new.timeIntervalSince1970;
  615. [ids addObject:user.uid];
  616. [history addObject:user];
  617. for (XSUser* tmp in XSUser.history) {
  618. if (![ids containsObject:tmp.uid]) {
  619. [ids addObject:tmp.uid];
  620. [history addObject:tmp];
  621. }
  622. }
  623. XSUser.history = history;
  624. }
  625. - (XSUser*)user {
  626. if (_user != nil) {
  627. return _user;
  628. }
  629. static dispatch_once_t onceToken;
  630. dispatch_once(&onceToken, ^{
  631. self->_user = [XSDataCenter valueForKey:@"User.current"];
  632. self->_token = self->_user.token;
  633. });
  634. return _user;
  635. }
  636. - (void)setRootViewController:(UIViewController *)rootViewController {
  637. _rootViewController = rootViewController;
  638. if (rootViewController == nil) {
  639. return;
  640. }
  641. [UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:rootViewController
  642. animated:YES
  643. completion:nil];
  644. }
  645. /// Permanent preservation of data.
  646. - (void)setPermanentValue:(NSString*)value forKey:(NSString*)key {
  647. // Set value to user defautls.
  648. [XSDataCenter setString:value forKey:key];
  649. // Configure the search setting.
  650. id setting = @{
  651. // Configure the keychain key type.
  652. CFBridgingRelease(kSecClass): CFBridgingRelease(kSecClassGenericPassword),
  653. CFBridgingRelease(kSecAttrAccount): key
  654. }.mutableCopy;
  655. // Delete old item before add new item
  656. SecItemDelete(CFBridgingRetain(setting));
  657. // Add new object to search dictionary.
  658. [setting setObject:[value dataUsingEncoding:NSUTF8StringEncoding] forKey:CFBridgingRelease(kSecValueData)];
  659. // Add item to keychain with the search dictionary
  660. SecItemAdd(CFBridgingRetain(setting), nil);
  661. }
  662. /// Read data for permanent preservationed.
  663. - (id)permanentValueForKey:(NSString*)key {
  664. // Read data from user defatuls.
  665. NSString* udid = [XSDataCenter stringForKey:key];
  666. if (udid.length != 0) {
  667. return udid;
  668. }
  669. // Configure the search setting.
  670. id setting = @{
  671. // Configure the keychain key type.
  672. CFBridgingRelease(kSecClass): CFBridgingRelease(kSecClassGenericPassword),
  673. // The class name of the SDK is dynamic.
  674. CFBridgingRelease(kSecAttrService): NSStringFromClass(self.class),
  675. CFBridgingRelease(kSecAttrAccount): key,
  676. // Gets result data of data.
  677. CFBridgingRelease(kSecReturnData): CFBridgingRelease(kCFBooleanTrue)
  678. };
  679. // Start query the keychain query.
  680. CFTypeRef result = nil;
  681. if (SecItemCopyMatching(CFBridgingRetain(setting), &result) == noErr) {
  682. return nil;
  683. }
  684. // Convert data to a string
  685. NSString* value = [[NSString alloc] initWithData:CFBridgingRelease(result) encoding:NSUTF8StringEncoding];
  686. if (value.length == 0) {
  687. return nil;
  688. }
  689. // Set value to user defautls, reduce Keychain access count.
  690. [XSDataCenter setString:value forKey:key];
  691. return value;
  692. }
  693. - (NSString*)advertisingIdentifier {
  694. // Read the data from keychain.
  695. NSString* advertisingIdentifier = [self permanentValueForKey:@"udid"];
  696. if (advertisingIdentifier.length != 0) {
  697. return advertisingIdentifier;
  698. }
  699. #if SDK_HAS_IDFA
  700. // Try to obtain idfa.
  701. ASIdentifierManager* advertisingManager = ASIdentifierManager.sharedManager;
  702. advertisingIdentifier = advertisingManager.advertisingIdentifier.UUIDString;
  703. if (!advertisingManager.isAdvertisingTrackingEnabled) {
  704. advertisingIdentifier = [NSString stringWithFormat:@"#%@", NSUUID.new.UUIDString];
  705. }
  706. #else
  707. // Generate an id to replace idfa.
  708. advertisingIdentifier = [NSString stringWithFormat:@"#%@", NSUUID.new.UUIDString];
  709. #endif
  710. // Save to keychain to prevent updates.
  711. [self setPermanentValue:advertisingIdentifier forKey:@"udid"];
  712. return advertisingIdentifier;
  713. }
  714. - (NSString*)advertisingVendor {
  715. // This parameter has been deprecated and must be empty string.
  716. return @"";
  717. }
  718. - (NSBundle*)bundle {
  719. return [NSBundle bundleForClass:self.class];
  720. }
  721. - (NSString*)model {
  722. struct utsname sinfo;
  723. uname(&sinfo);
  724. return [NSString stringWithUTF8String: sinfo.machine];
  725. }
  726. /// The sdk verions.
  727. - (NSString*)version {
  728. return self.bundle.infoDictionary[@"CFBundleShortVersionString"] ?: @"1.0";
  729. }
  730. /// The game verions.
  731. - (NSString*)shortVersion {
  732. return NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"] ?: @"1.0";
  733. }
  734. - (void)GMAdSDKinit {
  735. [GMAdManager sharedInstance];
  736. }
  737. ///横幅广告
  738. - (void)adBanner:(NSString*)adId {
  739. [[GMAdManager sharedInstance] openAd:adId];
  740. }
  741. ///关闭广告(banner, nativeAd)
  742. - (void)closeAd:(NSString*)adId {
  743. [[GMAdManager sharedInstance] closeAd:adId];
  744. }
  745. ///打开原生广告
  746. -(void)openNativeAdWithCenterX:(int)x Y:(int)y width:(int)w height:(int)h {
  747. [[GMAdManager sharedInstance] openNativeAdWithX:x Y:y width:w height:h];
  748. }
  749. ///打开视频激励广告
  750. -(void)openVideoAd:(NSString *)adName callback:(void (^)(BOOL))complete {
  751. [[GMAdManager sharedInstance] openVideoAd:adName callback:^(BOOL flag) {
  752. complete(flag);
  753. }];
  754. }
  755. ///打开积分墙广告
  756. -(void)openofferWallAd:(NSString *)adName callback:(void (^)(BOOL))complete {
  757. [[GMAdManager sharedInstance] openofferWallAd:adName callback:^(BOOL flag) {
  758. complete(flag);
  759. }];
  760. }
  761. ///打开插屏广告
  762. -(void)openInterstitialAd:(NSString *)adName callback:(void (^)(BOOL))complete {
  763. [[GMAdManager sharedInstance] openinterstitialAd:adName callback:^(BOOL flag) {
  764. complete(flag);
  765. }];
  766. }
  767. //广告是否加载好
  768. -(BOOL)isAvailableAd:(NSString *)adName {
  769. BOOL flag = NO;
  770. if (adName.length == 0) {
  771. return flag;
  772. }
  773. //1.横幅广告
  774. if ([adName hasPrefix:@"banner_"]) {
  775. flag = [GMAdManager sharedInstance].admobBannerAd.isReady;
  776. return flag;
  777. }
  778. //2.原生广告
  779. if ([adName hasPrefix:@"nativeAd_"]) {
  780. flag = [GMAdManager sharedInstance].admobNativeAd.isReady;
  781. return flag;
  782. }
  783. //3.视频激励广告
  784. if ([adName hasPrefix:@"video_"]) {
  785. flag = [[GMAdManager sharedInstance].rewardVideoAd isAdReady];
  786. return flag;
  787. }
  788. //4.插屏广告
  789. if ([adName hasPrefix:@"offerWall_"]) {
  790. flag = [[GMAdManager sharedInstance].offerWallVideoAd isAdReady];
  791. return flag;
  792. }
  793. return flag;
  794. }
  795. ///手机震动
  796. -(void)iphoneVibrate {
  797. //手机--设置--声音--响铃模式震动(打开),不然无效.
  798. AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
  799. }
  800. //跳转appstore评论
  801. -(void)skipToAppsotreWithID:(NSString *)appleId {
  802. NSString *urlStr = [NSString stringWithFormat:@"https://itunes.apple.com/us/app/itunes-u/id%@?action=write-review&mt=8",
  803. appleId];
  804. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlStr]];
  805. }
  806. ///自动登录
  807. - (void)xautoWithComplete:(void (^)(id user, NSError* error))complete {
  808. XSUser* user = [XSDataCenter valueForKey:@"User.current"];
  809. if (user.uid.length == 0) {
  810. complete(nil,[XSNetwork errorWithCode:-1 message:@"未登录记录!"]);
  811. return;
  812. }
  813. // Try authorization login.
  814. XenonSDK.sharedSDK.token = user.token;
  815. [XSNetwork authWithUser:user.uid complete:^(XSUser* object, NSError *error) {
  816. // Check for general errors.
  817. if (error != nil && ![error.domain isEqual:@"XSNetwork"]) {
  818. [XSNetwork showHudFailure:error];
  819. complete(nil,[XSNetwork errorWithCode:-1 message:error.domain]);
  820. return;
  821. }
  822. // Login successful.
  823. if (user.token.length != 0 && error == nil) {
  824. // Update user info.
  825. user.token = object.token;
  826. user.isRegister = NO;
  827. XenonSDK.sharedSDK.user = user;
  828. if (XenonSDK.sharedSDK.sdk_loginCallback) {
  829. complete(user,nil);
  830. XenonSDK.sharedSDK.sdk_loginCallback(user);
  831. }
  832. return;
  833. }
  834. [XSNetwork showHudFailure:@"登录时效期已过,请重新登录"];
  835. complete(nil,[XSNetwork errorWithCode:-1 message:@"登录时效期已过,请重新登录"]);
  836. // Login failed to login page.
  837. UserLoginPhoneViewController* viewController = UserLoginPhoneViewController.new;
  838. [viewController automatic:user.account];
  839. [self.rootViewController.navigationController pushViewController:viewController animated:YES];
  840. }];
  841. }
  842. ///手动登录
  843. -(void)manualLogin {
  844. //XSUser *user = [XSDataCenter valueForKey:@"User.current"];
  845. if (XSUser.history.count != 0) {
  846. self.rootViewController = [[RootViewController alloc] initWithRootViewController:UserLoginFastViewController.new];
  847. return;
  848. }
  849. // To account login
  850. self.rootViewController = [[RootViewController alloc] initWithRootViewController:UserLoginPhoneViewController.new];
  851. }
  852. ///Switch Account
  853. -(void)switchAccount {
  854. [XenonSDK.sharedSDK logoutWithComplete:^{
  855. //PS:封神传说cp平台,收到登出通知后会调用一次登录接口, 这里重复了.注释掉
  856. XSUser.history = nil;
  857. [XenonSDK.sharedSDK loginWithComplete:^(id user, NSError *error) {
  858. }];
  859. }];
  860. }
  861. /// 统计事件1
  862. /// @param eventName 事件名称
  863. -(void)tjEvent:(NSInteger )eventName {
  864. [XSTracker.shared trace:eventName];
  865. }
  866. /// 统计事件2
  867. /// @param eventName 事件名称
  868. /// @param parameters 事件对应值
  869. -(void)tjEvent:(NSInteger )eventName value:(id)parameters {
  870. [XSTracker.shared trace:eventName parameters:parameters];
  871. }
  872. @end