XSNetwork.m 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. //
  2. // XSNetwork.m
  3. // XenonSDK
  4. //
  5. // Created by SAGESSE on 2019/5/28.
  6. // Copyright © 2019 SAGESSE. All rights reserved.
  7. //
  8. #import "XenonSDK.h"
  9. #import "JSONModel.h"
  10. #import "XSTracker.h"
  11. #import "XSUtils.h"
  12. #import "MBProgressHUD.h"
  13. #import <StoreKit/StoreKit.h>
  14. //#if SDK_HAS_IAP_PAYMENT
  15. #import "KDIAPManager.h"
  16. //#endif
  17. @interface XSNetwork ()
  18. @end
  19. @implementation XSNetwork
  20. dispatch_semaphore_t sdk_net_semaphore;
  21. dispatch_queue_t sdk_net_waiting;
  22. NSInteger sdk_net_count;
  23. NSString* sdk_net_baseURL;
  24. MBProgressHUD* sdk_net_hud;
  25. + (NSString*)baseURL {
  26. return sdk_net_baseURL;
  27. }
  28. + (void)setBaseURL:(NSString *)baseURL {
  29. sdk_net_baseURL = baseURL;
  30. }
  31. + (NSError*)errorWithCode:(NSInteger)code message:(NSString*)message {
  32. return [NSError errorWithDomain:@"XSNetwork"
  33. code:code
  34. userInfo:@{NSLocalizedDescriptionKey:message}];
  35. }
  36. + (void)showHudLoading {
  37. [sdk_net_hud removeFromSuperview];
  38. sdk_net_hud = [MBProgressHUD showHUDAddedTo:UIApplication.sharedApplication.keyWindow animated:YES];
  39. sdk_net_hud.labelText = nil;
  40. sdk_net_hud.removeFromSuperViewOnHide = YES;
  41. [sdk_net_hud layoutIfNeeded];
  42. [sdk_net_hud show:YES];
  43. }
  44. + (void)showHudSuccess:(id)error {
  45. [sdk_net_hud removeFromSuperview];
  46. sdk_net_hud = [MBProgressHUD showHUDAddedTo:UIApplication.sharedApplication.keyWindow animated:YES];
  47. sdk_net_hud.detailsLabelText = error;
  48. sdk_net_hud.userInteractionEnabled = NO;
  49. sdk_net_hud.mode = MBProgressHUDModeText;
  50. //hud?.customView = UIImageView(image: UIImage(named: "success", in: nil, compatibleWith: nil))
  51. sdk_net_hud.removeFromSuperViewOnHide = YES;
  52. [sdk_net_hud hide:YES afterDelay:1.8];
  53. }
  54. + (void)showHudFailure:(id)error {
  55. NSString* message = error;
  56. if ([error isKindOfClass:NSError.class]) {
  57. message = [error localizedDescription];
  58. }
  59. [sdk_net_hud removeFromSuperview];
  60. sdk_net_hud = [MBProgressHUD showHUDAddedTo:UIApplication.sharedApplication.keyWindow animated:YES];
  61. sdk_net_hud.detailsLabelText = message;
  62. sdk_net_hud.userInteractionEnabled = NO;
  63. sdk_net_hud.mode = MBProgressHUDModeText;
  64. //hud?.customView = UIImageView(image: UIImage(named: "error", in: nil, compatibleWith: nil))
  65. sdk_net_hud.removeFromSuperViewOnHide = YES;
  66. [sdk_net_hud layoutIfNeeded];
  67. [sdk_net_hud hide:YES afterDelay:2];
  68. }
  69. + (void)hideHud {
  70. [sdk_net_hud removeFromSuperview];
  71. }
  72. + (void)showPrompt:(NSString*)user {
  73. // If no user information is provided, it is turned off by default.
  74. if (user.length == 0) {
  75. [self showHudSuccess:@"登录成功"];
  76. return;
  77. }
  78. // Hide the hud first to prevent errors.
  79. [self hideHud];
  80. UIWindow* window = UIApplication.sharedApplication.keyWindow;
  81. UIView* view = [[UIView alloc] initWithFrame:window.bounds];
  82. UIToolbar* prompt = [[UIToolbar alloc] init];
  83. UILabel* label = [[UILabel alloc] init];
  84. // A tag must be set and the view hierarchy needs to be reset when adding a hover window.
  85. view.tag = -1;
  86. view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  87. // Additional actions are allowed during the hud pop-up.
  88. view.userInteractionEnabled = NO;
  89. NSMutableAttributedString* value = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"欢迎 %@ 加入游戏", user]];
  90. [value addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:0 green:0.48 blue:1 alpha:1] range:NSMakeRange(2, user.length + 2)];
  91. label.attributedText = value;
  92. label.textAlignment = NSTextAlignmentCenter;
  93. label.numberOfLines = 0;
  94. label.font = [UIFont systemFontOfSize:14];
  95. CGSize size = [label sizeThatFits:CGSizeMake(window.frame.size.width - 80, 0)];
  96. CGFloat width = fmax(size.width + 32, 120);
  97. CGFloat height = fmax(size.height + 16, 32);
  98. CGFloat sp = 8;
  99. if (UIApplication.sharedApplication.statusBarFrame.size.height < 20) {
  100. sp += 16;
  101. }
  102. CGFloat top = UIApplication.sharedApplication.statusBarFrame.size.height + sp;
  103. if (@available(iOS 11.0, *)) {
  104. top = window.safeAreaInsets.top + sp;
  105. }
  106. prompt.layer.cornerRadius = 8;
  107. prompt.layer.masksToBounds = YES;
  108. prompt.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
  109. prompt.frame = CGRectMake((window.frame.size.width - width) / 2, top, width, height);
  110. label.frame = prompt.bounds;
  111. // [prompt addSubview:label];
  112. // [view addSubview:prompt];
  113. // [window addSubview:view];
  114. prompt.transform = CGAffineTransformMakeTranslation(0, -CGRectGetMaxY(prompt.frame));
  115. [UIView animateWithDuration:0.25 animations:^{
  116. prompt.transform = CGAffineTransformIdentity;
  117. } completion:^(BOOL t) {
  118. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  119. [UIView animateWithDuration:0.25 animations:^{
  120. prompt.transform = CGAffineTransformMakeTranslation(0, -CGRectGetMaxY(prompt.frame));
  121. } completion:^(BOOL x) {
  122. [view removeFromSuperview];
  123. }];
  124. });
  125. }];
  126. }
  127. + (NSData*)encryptWithParameters:(NSData*)data forKey:(NSString*)key {
  128. #if SDK_HAS_PROTECT_NETWORK_ENCRYPT
  129. if (data != nil) {
  130. NSString* dkey = sdk_md5(key);
  131. NSData* ddata = sdk_encrypt(data, [dkey substringFromIndex:dkey.length - 8]);
  132. return [ddata base64EncodedDataWithOptions:0];
  133. }
  134. #endif
  135. return data;
  136. }
  137. + (NSData*)decryptWithParameters:(NSData*)data forKey:(NSString*)key {
  138. #if SDK_HAS_PROTECT_NETWORK_ENCRYPT
  139. if (data != nil) {
  140. NSString* dkey = sdk_md5(key);
  141. NSData* ddata = [[NSData alloc] initWithBase64EncodedData:data options:0];
  142. return sdk_decrypt(ddata, [dkey substringFromIndex:dkey.length - 8]);
  143. }
  144. #endif
  145. return data;
  146. }
  147. + (NSDictionary*)bodyWithParameters:(id)parameters {
  148. // Generate request header parameters.
  149. NSString* timestamp = @((NSInteger)(NSDate.new.timeIntervalSince1970 * 1000)).stringValue;
  150. NSDictionary* header = @{
  151. @"appId": XenonSDK.sharedSDK.appId ?: @"",
  152. @"channelId": XenonSDK.sharedSDK.channelId ?: @"",
  153. @"adId": XenonSDK.sharedSDK.adId ?: @"",
  154. @"adFlag": XenonSDK.sharedSDK.adFlag ?: @"",
  155. @"sdkVersion": XenonSDK.sharedSDK.version,
  156. @"gameVersion": XenonSDK.sharedSDK.shortVersion,
  157. @"timestamp": timestamp,
  158. @"token": XenonSDK.sharedSDK.token ?: @"",
  159. @"osInfo": [NSString stringWithFormat:@"iOS%@", UIDevice.currentDevice.systemVersion],
  160. @"osType": @"2",
  161. @"idfa": XenonSDK.sharedSDK.advertisingIdentifier,
  162. @"idfv": XenonSDK.sharedSDK.advertisingVendor,
  163. @"model": XenonSDK.sharedSDK.model,
  164. @"wifi": @"Not Found", /*Network.state.SSID ?? */
  165. @"networkType": @"2", // 1 is wifi, 2 is other. /*Network.state.isWifi ? "1" : */
  166. @"tdid": XSCollector.shared.identifer ?: @"",
  167. @"trackData": @"",
  168. //
  169. @"requestIp": @"",
  170. @"imei": @"",
  171. @"mac": @"",
  172. @"androidid": @"",
  173. @"verificationCode": sdk_signature(parameters, timestamp)
  174. };
  175. // Generate results, or add parameters dynamically.
  176. id result = @{
  177. @"head": header,
  178. @"body": parameters
  179. }.mutableCopy;
  180. // When the network needs encryption, 1-12 parameters are generated randomly in order to scramble the ciphertext length.
  181. #if SDK_HAS_PROTECT_NETWORK_ENCRYPT
  182. NSMutableArray* arr = [NSMutableArray new];
  183. for (int i = arc4random() % 12; i > 0; --i) {
  184. [arr addObject: sdk_md5([NSString stringWithFormat:@"%zu", (NSUInteger)arc4random()])];
  185. }
  186. [result setObject:arr forKey:@"other"];
  187. #endif
  188. return result;
  189. }
  190. + (void)busy {
  191. dispatch_async(dispatch_get_main_queue(), ^{
  192. sdk_net_count += 1;
  193. if (sdk_net_count == 1) {
  194. UIApplication.sharedApplication.networkActivityIndicatorVisible = YES;
  195. }
  196. });
  197. }
  198. + (void)idle {
  199. dispatch_async(dispatch_get_main_queue(), ^{
  200. if (sdk_net_count == 0) {
  201. return;
  202. }
  203. sdk_net_count = sdk_net_count - 1;
  204. if (sdk_net_count == 0) {
  205. UIApplication.sharedApplication.networkActivityIndicatorVisible = NO;
  206. }
  207. });
  208. }
  209. /// Suspended all network requests.
  210. + (void)suspend {
  211. if (sdk_net_waiting != nil) {
  212. return;
  213. }
  214. sdk_net_waiting = dispatch_queue_create("XSNetwork", 0);
  215. sdk_net_semaphore = dispatch_semaphore_create(0);
  216. dispatch_async(sdk_net_waiting, ^{
  217. // Lock the thread.
  218. dispatch_semaphore_wait(sdk_net_semaphore, DISPATCH_TIME_FOREVER);
  219. });
  220. }
  221. /// Resume all network requests.
  222. + (void)resume {
  223. if (sdk_net_waiting == nil) {
  224. return;
  225. }
  226. sdk_net_waiting = nil;
  227. dispatch_semaphore_signal(sdk_net_semaphore);
  228. sdk_net_semaphore = nil;
  229. }
  230. /// Send a request(maybe suspend).
  231. + (void)requestWithURL:(id)url parameters:(id)parameters model:(Class)model complete:(void(^)(id obj, NSError* error))complete {
  232. // Need wait from queue?
  233. if (sdk_net_waiting == nil) {
  234. [self requestWithoutSuspend:url parameters:parameters model:model complete:complete];
  235. return;
  236. }
  237. // Enter waiting status.
  238. dispatch_async(sdk_net_waiting, ^{
  239. dispatch_async(dispatch_get_main_queue(), ^{
  240. [self requestWithoutSuspend:url parameters:parameters model:model complete:complete];
  241. });
  242. });
  243. }
  244. /// Send a request.
  245. + (void)requestWithoutSuspend:(id)url parameters:(id)parameters model:(Class)model complete:(void(^)(id obj, NSError* error))complete {
  246. // Generate encryption options.
  247. #if SDK_HAS_PROTECT_NETWORK_ENCRYPT
  248. NSUInteger options = arc4random() | 1;
  249. #else
  250. NSUInteger options = arc4random() & ~1;
  251. #endif
  252. // Convert to URL
  253. NSString* path = [NSString stringWithFormat:@"/data/%@-%@-%@-%zd", XenonSDK.sharedSDK.appId, XenonSDK.sharedSDK.adId, url, options];
  254. NSURL* req = [NSURL URLWithString:path relativeToURL:[NSURL URLWithString: self.baseURL]];
  255. if (req == nil) {
  256. complete(nil, nil);
  257. return;
  258. }
  259. // Generate request & parameters.
  260. NSDictionary* body = [self bodyWithParameters:parameters];
  261. NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:req cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60];
  262. NSError* serror = nil;
  263. NSData* sdata = [NSJSONSerialization dataWithJSONObject:body options:0 error:&serror];
  264. if (sdata == nil || serror != nil) {
  265. complete(nil, serror);
  266. }
  267. request.HTTPBody = [self encryptWithParameters:sdata forKey:path];
  268. request.HTTPMethod = @"POST";
  269. [request addValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
  270. //#if DEBUG
  271. // NSLog(@"%@ << %@", path, [[NSString alloc] initWithData:sdata encoding:NSUTF8StringEncoding]);
  272. //#endif
  273. // Network start request.
  274. [self busy];
  275. // Send a request to server.
  276. NSURLSessionDataTask* task = [NSURLSession.sharedSession dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  277. // Must be calleback in the main thread.
  278. dispatch_async(dispatch_get_main_queue(), ^{
  279. // Network request completed.
  280. [self idle];
  281. // decode data;
  282. NSData* ddata = [self decryptWithParameters:data forKey:path];
  283. NSError* derror = nil;
  284. NSDictionary* djson = nil;
  285. if (ddata) {
  286. djson = [NSJSONSerialization JSONObjectWithData:ddata options:0 error:&derror];
  287. }
  288. // #if DEBUG
  289. // NSLog(@"%@ >> %@", path, error.description ?: [[NSString alloc] initWithData:ddata encoding:NSUTF8StringEncoding]);
  290. // #endif
  291. // If data is nil, the request is failure.
  292. if (data == nil || error != nil || derror != nil) {
  293. // Request failure for system error.
  294. complete(nil, error ?: derror);
  295. return;
  296. }
  297. id header = djson[@"head"];
  298. if ([header[@"responseCode"] integerValue] != 0) {
  299. // Request failure for system error.
  300. NSInteger code = [header[@"responseCode"] integerValue];
  301. NSString* message = header[@"responseMsg"];
  302. complete(nil, [self errorWithCode:code message:message]);
  303. return;
  304. }
  305. // In request success case.
  306. id dbody = djson[@"body"];
  307. id obj = [[model alloc] initWithDictionary:dbody error:&derror];
  308. if (obj == nil && derror == nil) {
  309. obj = dbody;
  310. }
  311. complete(obj , derror);
  312. });
  313. }];
  314. // Start.
  315. [task resume];
  316. }
  317. /// Request systme configure.
  318. + (void)configureWithIdentifier:(NSString*)identifier flags:(NSString*)flags complete:(void(^)(id object, NSError* error))complete {
  319. // Prepare request parameters.
  320. id url = @"0";//"/api/game/v1/active"
  321. id ps = @{
  322. @"adId": identifier,
  323. @"adFlag": flags
  324. };
  325. // Suspend requests for other.
  326. [self suspend];
  327. // Send a request to server.
  328. [self requestWithoutSuspend:url parameters:ps model:XSConfiguration.self complete:^(id obj, NSError *error) {
  329. // Resume requests for other.
  330. [self resume];
  331. // Next.
  332. complete(obj, error);
  333. }];
  334. }
  335. /// Send SMS security code.
  336. + (void)sendSMSWithPhone:(NSString*)phone type:(NSInteger)type complete:(void(^)(id object, NSError* error))complete {
  337. // Prepare request parameters.
  338. id url = @"7";//"/api/sms/v1/send"
  339. id ps = @{
  340. @"phone": phone,
  341. @"sendType": @(type).stringValue // 1 bind, 2 forget, 3 login
  342. };
  343. // Send a request to server.
  344. [self requestWithURL:url parameters:ps model:nil complete:^(id obj, NSError *error) {
  345. complete(nil, error);
  346. }];
  347. }
  348. /// Auth login.
  349. + (void)authWithUser:(NSString*)uid complete:(void(^)(id object, NSError* error))complete {
  350. // Prepare request parameters.
  351. id url = @"1";//"/api/user/v1/checkToken"
  352. id ps = @{
  353. @"uid": uid
  354. };
  355. // Send a request to server.
  356. [self requestWithURL:url parameters:ps model:XSUser.self complete:complete];
  357. }
  358. /// Check user with phone
  359. + (void)checkWithPhone:(NSString*)phone complete:(void(^)(id object, NSError* error))complete {
  360. // Prepare request parameters.
  361. id url = @"5";//"/api/user/v1/checkUserPhone"
  362. id ps = @{
  363. @"phone": phone
  364. };
  365. // Send a request to server.
  366. [self requestWithURL:url parameters:ps model:nil complete:complete];
  367. }
  368. /// Bind user with phone.
  369. + (void)bindWithPhone:(NSString*)phone code:(NSString*)code username:(NSString*)username complete:(void(^)(id object, NSError* error))complete {
  370. // Prepare request parameters.
  371. id url = @"6";//"/api/user/v1/bindPhone"
  372. id ps = @{
  373. @"userName": username,
  374. @"phone": phone,
  375. @"code": code
  376. };
  377. // Send a request to server.
  378. [self requestWithURL:url parameters:ps model:nil complete:complete];
  379. }
  380. /// Reset password.
  381. + (void)resetWithPhone:(NSString*)phone code:(NSString*)code password:(NSString*)password complete:(void(^)(id object, NSError* error))complete {
  382. // Prepare request parameters.
  383. id url = @"4";//"/api/user/v1/forget"
  384. id ps = @{
  385. @"phone": phone,
  386. @"pwd": [sdk_md5(password) uppercaseString],
  387. @"code": code
  388. };
  389. // Send a request to server.
  390. [self requestWithURL:url parameters:ps model:nil complete:complete];
  391. }
  392. /// Fast login a user.
  393. + (void)loginWithComplete:(void(^)(id object, NSError* error))complete {
  394. // Prepare request parameters.
  395. id url = @"2";//"/api/user/v1/register"
  396. id ps = @{
  397. @"userName": @"",
  398. @"pwd": @"",
  399. @"loginType": @"0" // falst login
  400. };
  401. // Send a request to server.
  402. [self requestWithURL:url parameters:ps model:XSUser.self complete:^(XSUser* user, NSError *error) {
  403. if (user != nil) {
  404. if (user.isRegister) {
  405. [XSCollector.shared registerWithAccount:user.uid name:user.userName];
  406. } else {
  407. [XSCollector.shared loginWithAccount:user.uid name:user.userName];
  408. }
  409. }
  410. complete(user, error);
  411. }];
  412. }
  413. //Facebook login a user
  414. +(void)loginFacebookWithToken:(NSString *)token appId:(NSString *)appid playerId:(NSString *)playerid complete:(void (^)(id, NSError *))complete {
  415. // Prepare request parameters.
  416. id url = @"f";//"/api/third/facebook/v1/login"
  417. id ps = @{
  418. @"idToken": token,
  419. @"appId": appid,
  420. @"playerid": playerid
  421. };
  422. // Send a request to server.
  423. [self requestWithURL:url parameters:ps model:XSUser.self complete:^(XSUser* user, NSError *error) {
  424. if (user != nil) {
  425. if (user.isRegister) {
  426. [XSCollector.shared registerWithAccount:user.uid name:user.userName];
  427. } else {
  428. [XSCollector.shared loginWithAccount:user.uid name:user.userName];
  429. }
  430. }
  431. complete(user, error);
  432. }];
  433. }
  434. //Facebook bind a user
  435. +(void)bindFacebookWithToken:(NSString *)token appId:(NSString *)appid playerId:(NSString *)playerid complete:(void (^)(id, NSError *))complete {
  436. XSUser* user1 = [XSDataCenter valueForKey:@"User.current"];
  437. // Prepare request parameters.
  438. id url = @"g";//"/api/third/facebook/v1/bind"
  439. id ps = @{
  440. @"idToken": token,
  441. @"appId": appid,
  442. @"playerid": playerid,
  443. @"uid":user1.uid?:@""
  444. };
  445. // Send a request to server.
  446. [self requestWithURL:url parameters:ps model:XSUser.self complete:^(XSUser* user, NSError *error) {
  447. complete(user, error);
  448. }];
  449. }
  450. /// Apple login a user.
  451. +(void)loginApplekWithToken:(NSString *)token complete:(void (^)(id, NSError *))complete {
  452. // Prepare request parameters.
  453. id url = @"m"; //"/api/third/apple/v1/login"
  454. id ps = @{
  455. @"idToken": token
  456. };
  457. // Send a request to server.
  458. [self requestWithURL:url parameters:ps model:XSUser.self complete:^(XSUser* user, NSError *error) {
  459. if (user != nil) {
  460. if (user.isRegister) {
  461. [XSCollector.shared registerWithAccount:user.uid name:user.userName];
  462. } else {
  463. [XSCollector.shared loginWithAccount:user.uid name:user.userName];
  464. }
  465. }
  466. complete(user, error);
  467. }];
  468. }
  469. /// Phone & Security Code login a user.
  470. + (void)loginWithPhone:(NSString*)phone code:(NSString*)code complete:(void(^)(id object, NSError* error))complete {
  471. // Prepare request parameters.
  472. id url = @"3";//"/api/user/v1/login"
  473. id ps = @{
  474. @"userName": phone,
  475. @"pwd": code,
  476. @"loginType": @"3" // Phone & Security Code login
  477. };
  478. // Send a request to server.
  479. [self requestWithURL:url parameters:ps model:XSUser.self complete:^(XSUser* user, NSError *error) {
  480. user.account = phone;
  481. user.pwd = nil;
  482. if (user != nil) {
  483. if (user.isRegister) {
  484. [XSCollector.shared registerWithAccount:user.uid name:user.userName];
  485. } else {
  486. [XSCollector.shared loginWithAccount:user.uid name:user.userName];
  487. }
  488. }
  489. complete(user, error);
  490. }];
  491. }
  492. /// Account & Password login a user.
  493. + (void)loginWithAccount:(NSString*)account password:(NSString*)password complete:(void(^)(id object, NSError* error))complete {
  494. // Prepare request parameters.
  495. id url = @"3";//"/api/user/v1/login"
  496. id ps = @{
  497. @"userName": account,
  498. @"pwd": [sdk_md5(password) uppercaseString],
  499. @"loginType": @"1" // account login
  500. };
  501. // Send a request to server.
  502. [self requestWithURL:url parameters:ps model:XSUser.self complete:^(XSUser* user, NSError *error) {
  503. user.account = account;
  504. user.pwd = password;
  505. if (user != nil) {
  506. [XSCollector.shared loginWithAccount:user.uid name:user.userName];
  507. }
  508. complete(user, error);
  509. }];
  510. }
  511. /// Account & Password login a user.
  512. + (void)registerWithAccount:(NSString*)account password:(NSString*)password complete:(void(^)(id object, NSError* error))complete {
  513. // Prepare request parameters.
  514. id url = @"2";//"/api/user/v1/register"
  515. id ps = @{
  516. @"userName": account,
  517. @"pwd": [sdk_md5(password) uppercaseString],
  518. @"loginType": @"1" // account login
  519. };
  520. // Send a request to server.
  521. [self requestWithURL:url parameters:ps model:XSUser.self complete:^(XSUser* user, NSError *error) {
  522. user.account = account;
  523. user.pwd = password;
  524. user.isRegister = YES;
  525. if (user != nil) {
  526. [XSCollector.shared registerWithAccount:user.uid name:user.userName];
  527. }
  528. complete(user, error);
  529. }];
  530. }
  531. // MARK - 广告记录
  532. +(void)adRecord:(NSString *)action
  533. spaceId:(NSString *)spaceId
  534. agentName:(NSString *)agentName
  535. medium:(NSString *)medium
  536. adUnitId:(NSString *)adUnitId
  537. type:(NSString *)type
  538. unitAdId:(NSString *)unitAdId
  539. errorMsg:(NSString *)errorMeg{
  540. NSString *uid = [XenonSDK sharedSDK].user.uid;
  541. id url = @"e"; //"/api/game/v1/adAction"
  542. id ps = @{
  543. @"action": action,
  544. @"spaceId": spaceId,
  545. @"uid" : uid? uid:@"",
  546. @"agentName" : agentName? agentName:@"",
  547. @"medium" : medium? medium:@"",
  548. @"adUnitId" : adUnitId? adUnitId:@"",
  549. @"type" : type? type:@"",
  550. @"unitAdId" : unitAdId? unitAdId:@"",
  551. @"errmsg" : errorMeg? errorMeg:@""
  552. };
  553. // Send a request to server.
  554. [self requestWithoutSuspend:url parameters:ps model:XSUser.self complete:^(id obj, NSError *error) {
  555. //complete(obj, error);
  556. }];
  557. }
  558. // MARK - Utils
  559. /// Auto trigger;
  560. + (void)trigger:(NSInteger)count {
  561. #if SDK_HAS_PROTECT_NETWORK_PRETEND
  562. // If tracking is not enabled, turn it off.
  563. if (XSTracker.shared == nil) {
  564. return;
  565. }
  566. // Prepare request parameters.
  567. NSString* url = @"*";
  568. NSMutableDictionary* ps = [NSMutableDictionary new];
  569. for (int i = arc4random() % 12 + 1; i > 0; --i) {
  570. id key = [sdk_md5(@(arc4random()).stringValue) substringToIndex:((arc4random() % 14) + 1)];
  571. id value = [[key dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
  572. ps[key] = value;
  573. }
  574. // Send a request to server.
  575. [self requestWithURL:url parameters:ps model:nil complete:^(id obj, NSError *error) {
  576. if (error == nil || count > 0) {
  577. return;
  578. }
  579. NSInteger ft = arc4random() % 10000;
  580. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC * ft), dispatch_get_main_queue(), ^{
  581. [self trigger:count - 1];
  582. });
  583. }];
  584. #endif
  585. }
  586. + (void)log:(NSInteger)code session:(NSString*)session extra:(NSString*)extra {
  587. // Prepare request parameters.
  588. id url = @"9";//"/api/ardent/v1/add"
  589. id ps = @{
  590. @"digitId": [NSString stringWithFormat:@"0x%06zx", code],
  591. @"sessionId": session,
  592. @"iosStr": extra
  593. };
  594. // Send a request to server.
  595. [self requestWithoutSuspend:url parameters:ps model:nil complete:^(id obj, NSError *error) {
  596. // Nothing.
  597. }];
  598. }
  599. + (void)reportWithUser:(NSString*)uid Name:(NSString*)name level:(NSInteger)level server:(NSString*)server {
  600. // Prepare request parameters.
  601. id url = @"a";//"/api/game/v1/sendServer"
  602. id ps = @{
  603. @"uid": uid ?: @"",
  604. @"gameServerId": server,
  605. @"roleLev": @(level).stringValue,
  606. @"roleName": name
  607. };
  608. // Send a request to server.
  609. [self requestWithURL:url parameters:ps model:nil complete:^(id obj, NSError *error) {
  610. }];
  611. }
  612. /// Get pay route.
  613. + (void)routeWithComplete:(void(^)(id object, NSError* error))complete {
  614. // Prepare request parameters.
  615. id url = @"8";//"/api/p/v1/pCheck"
  616. id ps = @{
  617. @"uid": XenonSDK.sharedSDK.user.uid ?: @""
  618. };
  619. // Send a request to server.
  620. [self requestWithURL:url parameters:ps model:nil complete:complete];
  621. }
  622. //#if SDK_HAS_IAP_PAYMENT
  623. /// Pay a product.
  624. + (void)payWithParameters:(id)parameters complete:(void(^)(id object, NSError* error))complete {
  625. // Prepare request parameters.
  626. id url = @"b";//"/api/p/v1/apple/create"
  627. id ps = parameters;
  628. // Check if in-app purchases are available.
  629. if (!SKPaymentQueue.canMakePayments) {
  630. complete(nil, [XSNetwork errorWithCode:-2 message:@"该设备不支持内购"]);
  631. return;
  632. }
  633. // Send a request to server.
  634. [self requestWithURL:url parameters:ps model:nil complete:^(id obj, NSError *error) {
  635. if (error != nil) {
  636. complete(nil, error);
  637. return;
  638. }
  639. // Get prarmeter
  640. NSString* orderId = [obj valueForKeyPath:@"orderId"];
  641. NSString* productId = [obj valueForKeyPath:@"product.productId"];
  642. if (orderId.length == 0 || productId.length == 0) {
  643. complete(nil, [XSNetwork errorWithCode:-2 message:@"服务器异常"]);
  644. return;
  645. }
  646. [[KDIAPManager shareIAPManager] startIAPWithOrderId:orderId productID:productId completeHandle:^(IAPResultType type, NSData *data) {
  647. //complete(nil, [XSNetwork errorWithCode:-2 message:@"购买成功!"]);
  648. if (type == IAPResultSuccess) {
  649. [XSNetwork showHudSuccess:@"购买成功!"];
  650. complete(ps,nil);
  651. }else if (type == IAPResultVerFailed){
  652. [XSNetwork showHudSuccess:@"订单校验失败!"];
  653. complete(nil, [XSNetwork errorWithCode:-1 message:@"订单校验失败!"]);
  654. }else{
  655. [XSNetwork showHudFailure:@"购买失败!"];
  656. complete(nil, [XSNetwork errorWithCode:-1 message:@"购买失败!"]);
  657. }
  658. }];
  659. }];
  660. }
  661. /// Pay a product with receipt.
  662. + (void)payWithReceipt:(id)receipt orderId:(id)orderId complete:(void(^)(id object, NSError* error))complete {
  663. // Prepare request parameters.
  664. id url = @"c";//"/api/p/v1/apple/p"
  665. id ps = @{
  666. @"data": receipt,
  667. @"orderId": orderId,
  668. @"uid": XenonSDK.sharedSDK.user.uid ?: @""
  669. };
  670. // Send a request to server.
  671. [self requestWithURL:url parameters:ps model:nil complete:complete];
  672. }
  673. //#endif
  674. @end