XSNetwork.m 27 KB

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