XSNetwork.m 25 KB

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