AIInfoManager.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. //
  2. // AIInfoManager.m
  3. // PDF Reader Pro Edition
  4. //
  5. // Created by Niehaoyu on 2024/1/24.
  6. //
  7. #import "AIInfoManager.h"
  8. #import "NSNULL+Filtration.h"
  9. #import "NSObject+DeviceInfo.h"
  10. #import "IAPProductsManager.h"
  11. #import <PDF_Reader_Pro-Swift.h>
  12. #import "ASIFormDataRequest.h"
  13. #import "JSONKit.h"
  14. static AIInfoManager *__Manager = nil;
  15. @interface AIInfoManager ()
  16. @property (nonatomic, readwrite) BOOL aiInfoValid;
  17. @end
  18. @implementation AIInfoManager
  19. + (AIInfoManager *)defaultManager {
  20. if (!__Manager) {
  21. __Manager = [[AIInfoManager alloc] init];
  22. }
  23. return __Manager;
  24. }
  25. - (instancetype)init {
  26. self = [super init];
  27. self.aiInfoValid = NO;
  28. if (![[NSUserDefaults standardUserDefaults] objectForKey:@"kAIIconShowIdentifyKeyTip"]) {
  29. self.showAIIcon = YES;
  30. [[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"kAIIconShowIdentifyKeyTip"];
  31. [[NSUserDefaults standardUserDefaults] synchronize];
  32. }
  33. _showAIIcon = [[NSUserDefaults standardUserDefaults] boolForKey:kAIIconShowIdentifyKey];
  34. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  35. [self fetchAIInfoWithComplention:^(NSDictionary * _Nonnull info, NSError * _Nonnull error) {
  36. }];
  37. });
  38. return self;
  39. }
  40. #pragma mark - Setter
  41. - (NSString *)bundleIdentify {
  42. return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]?:@"";
  43. }
  44. - (NSString *)udid {
  45. // return @"8D397BE0-F478-5269-A8F1-BE1E3B757221";
  46. return GetHardwareUUID()?:@"";
  47. }
  48. - (void)setShowAIIcon:(BOOL)showAIIcon {
  49. _showAIIcon = showAIIcon;
  50. [[NSUserDefaults standardUserDefaults] setBool:_showAIIcon forKey:kAIIconShowIdentifyKey];
  51. [[NSUserDefaults standardUserDefaults] synchronize];
  52. }
  53. #pragma mark - Method
  54. - (void)activateAIWithInfo:(NSDictionary *)info
  55. complention:(AIActivityComplention)complention {
  56. if (![info[@"cdkey"] length] &&
  57. ![info[@"receipt_str"] length]) {
  58. //激活码为空
  59. NSError *error = [NSError errorWithDomain:@""
  60. code:ActivityErrorTypeCDKeyEmpty
  61. userInfo:nil];
  62. if (complention)
  63. complention(nil, error);
  64. return;
  65. }
  66. #if VERSION_DMG
  67. NSString *cdKey = info[@"cdkey"]?:@"";
  68. if (![cdKey hasPrefix:@"AI-"]) {
  69. //激活码为空
  70. NSError *error = [NSError errorWithDomain:@""
  71. code:ActivityErrorTypeFormatError
  72. userInfo:nil];
  73. if (complention)
  74. complention(nil, error);
  75. return;
  76. }
  77. #endif
  78. __block AIActivityComplention tComplention = complention;
  79. __block VerificationManager *weak_self = self;
  80. NSString *platform = @"DMG";
  81. #if VERSION_DMG
  82. platform = @"DMG";
  83. #else
  84. platform = @"AiStore";
  85. #endif
  86. //Process Params
  87. NSString *app_version = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] description];
  88. if (!app_version.length)
  89. app_version = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] description];
  90. NSDictionary *params =
  91. @{
  92. //激活信息
  93. @"subscription":@{
  94. @"app_code":@"com.brother.pdfreaderpro.ai",
  95. #if VERSION_DMG
  96. @"cdkey":info[@"cdkey"]?:@"",
  97. #else
  98. @"receipt_str":info[@"receipt_str"]?:@""
  99. #endif
  100. },
  101. //设备信息
  102. @"device":@{
  103. @"app_name":[self bundleIdentify]?:@"",
  104. @"unique_sn":[self udid]?:@"",
  105. @"model":GetProductName()?:@"",
  106. @"os":GetSystemVersion()?:@"",
  107. @"time_zone":[[NSTimeZone localTimeZone] localizedName:NSTimeZoneNameStyleShortDaylightSaving locale:[NSLocale currentLocale]]?:@"",
  108. @"language":[[NSLocale currentLocale] localeIdentifier]?:@"",
  109. @"app_version":app_version?:@"",
  110. @"platform":platform?:@"DMG"
  111. }
  112. };
  113. NSMutableData *postData = [VerificationManager mutableDataWithDic:params];
  114. //Send Request
  115. NSString *urlString = [kVerificationServer stringByAppendingString:@"api/auth_devices/activate"];
  116. NSURL *url = [NSURL URLWithString:urlString];
  117. ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
  118. request.requestMethod = @"POST";
  119. [request setPostBody:postData];
  120. NSString *postLength = [NSString stringWithFormat:@"%ld", (unsigned long)[postData length]];
  121. NSMutableDictionary *requestHeaders = [NSMutableDictionary dictionaryWithObjectsAndKeys:
  122. postLength, @"Content-Length", nil];
  123. request.defaultResponseEncoding = NSUTF8StringEncoding;
  124. [request setRequestHeaders:requestHeaders];
  125. [request addRequestHeader:@"Content-Type" value:@"application/json"];
  126. [request addRequestHeader:@"Accept" value:@"application/vnd.api+json;version=1"];
  127. __block void(^processRequest)(void) = ^{
  128. dispatch_async(dispatch_get_main_queue(), ^{
  129. NSDictionary *info = [[request.responseString objectFromJSONString] filterNullObject];
  130. NSError *error = request.error;
  131. if (info && [info isKindOfClass:[NSDictionary class]]) {
  132. if ([info valueForKey:@"errors"]) {
  133. error = [NSError errorWithDomain:@"激活失败"
  134. code:ActivityErrorTypeUnknow
  135. userInfo:info];
  136. }else if ([info valueForKey:@"error"]) {
  137. error = [NSError errorWithDomain:@"激活失败"
  138. code:ActivityErrorTypeUnknow
  139. userInfo:info];
  140. }
  141. }else {
  142. if(error) {
  143. error = [NSError errorWithDomain:error.domain code:ActivityErrorTypeNetworkDisable userInfo:error.userInfo];
  144. } else {
  145. error = [NSError errorWithDomain:@"激活失败"
  146. code:ActivityErrorTypeUnknow
  147. userInfo:@{}];
  148. }
  149. }
  150. if (!error) {
  151. NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
  152. AIInfo *aiInfo = [[AIInfo alloc] initWithDict:info[@"data"]];
  153. self.aiInfo = aiInfo;
  154. self.aiInfoValid = YES;
  155. NSString *notificationName = (NSString *)kDeviceAIStatusChangeNotification;
  156. [[NSNotificationCenter defaultCenter] postNotificationName:notificationName
  157. object:self
  158. userInfo:info];
  159. }
  160. if (tComplention)
  161. tComplention(info, error);
  162. });
  163. };
  164. [request setFailedBlock:^{
  165. processRequest();
  166. }];
  167. [request setCompletionBlock:^{
  168. processRequest();
  169. }];
  170. [request startAsynchronous];
  171. }
  172. - (void)fetchAIInfoWithComplention:(AIActivityComplention)complention {
  173. __block AIActivityComplention tComplention = complention;
  174. __block AIInfoManager *weak_self = self;
  175. NSString *platform = @"DMG";
  176. #if VERSION_DMG
  177. platform = @"DMG";
  178. #else
  179. platform = @"AiStore";
  180. #endif
  181. //Process Params
  182. NSString *app_version = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] description];
  183. if (!app_version.length)
  184. app_version = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] description];
  185. NSDictionary *params = @{@"unique_sn":[self udid]?:@"",
  186. @"app_name":[self bundleIdentify]?:@"",
  187. @"platform":platform?:@"DMG",
  188. #if VERSION_DMG
  189. #else
  190. @"receipt_str":[IAPProductsManager defaultManager].temptransactioReceipt?:@""
  191. #endif
  192. };
  193. NSMutableData *postData = [VerificationManager mutableDataWithDic:params];
  194. //Send Request
  195. NSString *urlString = [kVerificationServer stringByAppendingString:@"api/getAiInfo"];
  196. NSURL *url = [NSURL URLWithString:urlString];
  197. ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
  198. request.requestMethod = @"POST";
  199. [request setPostBody:postData];
  200. NSString *postLength = [NSString stringWithFormat:@"%ld", (unsigned long)[postData length]];
  201. NSMutableDictionary *requestHeaders = [NSMutableDictionary dictionaryWithObjectsAndKeys:
  202. postLength, @"Content-Length", nil];
  203. request.defaultResponseEncoding = NSUTF8StringEncoding;
  204. [request setRequestHeaders:requestHeaders];
  205. [request addRequestHeader:@"Content-Type" value:@"application/json"];
  206. [request addRequestHeader:@"Accept" value:@"application/vnd.api+json;version=1"];
  207. __block void(^processRequest)(void) = ^{
  208. dispatch_async(dispatch_get_main_queue(), ^{
  209. NSDictionary *info = [[request.responseString objectFromJSONString] filterNullObject];
  210. BOOL isReceiptNeverUsed = NO;//当前票据未激活设备(针对AppStore版购买过但未激活的情况)
  211. NSError *error = request.error;
  212. if (info && [info isKindOfClass:[NSDictionary class]]) {
  213. if ([info valueForKey:@"errors"]) {
  214. error = [NSError errorWithDomain:@"激活失败"
  215. code:ActivityErrorTypeUnknow
  216. userInfo:info];
  217. NSDictionary *errorsDict = ((NSArray *)[info valueForKey:@"errors"]).firstObject;
  218. if ([errorsDict valueForKey:@"attribute"]) {
  219. if ([[errorsDict valueForKey:@"attribute"] isEqualToString:@"inactivated"]) {
  220. isReceiptNeverUsed = YES;
  221. } else if ([[errorsDict valueForKey:@"attribute"] isEqualToString:@"device_expired"]) {
  222. self.aiInfoValid = NO;
  223. }
  224. }
  225. }else if ([info valueForKey:@"error"]) {
  226. error = [NSError errorWithDomain:@"激活失败"
  227. code:ActivityErrorTypeUnknow
  228. userInfo:info];
  229. }
  230. }else {
  231. if(error) {
  232. error = [NSError errorWithDomain:error.domain code:ActivityErrorTypeNetworkDisable userInfo:error.userInfo];
  233. } else {
  234. error = [NSError errorWithDomain:@"激活失败"
  235. code:ActivityErrorTypeUnknow
  236. userInfo:@{}];
  237. }
  238. }
  239. if (!error) {
  240. AIInfo *aiInfo = [[AIInfo alloc] initWithDict:info[@"data"]];
  241. self.aiInfo = aiInfo;
  242. self.aiInfoValid = YES;
  243. NSString *notificationName = (NSString *)kDeviceAIStatusChangeNotification;
  244. [[NSNotificationCenter defaultCenter] postNotificationName:notificationName
  245. object:self
  246. userInfo:info];
  247. }
  248. #if VERSION_DMG
  249. #else
  250. if (isReceiptNeverUsed && [IAPProductsManager defaultManager].temptransactioReceipt) {
  251. //当前票据未激活设备(针对AppStore版购买过但未激活的情况)
  252. BOOL didPurchase = NO;
  253. #if VERSION_FREE
  254. if ([IAPProductsManager defaultManager].liteAIProduct.isSubscribed) {
  255. didPurchase = YES;
  256. }
  257. #else
  258. if ([IAPProductsManager defaultManager].proAIProduct.isSubscribed) {
  259. didPurchase = YES;
  260. }
  261. #endif
  262. if (didPurchase) {
  263. NSDictionary *infoDic = @{@"receipt_str":[IAPProductsManager defaultManager].temptransactioReceipt};
  264. [self activateAIWithInfo:infoDic
  265. complention:^(NSDictionary * _Nonnull info, NSError * _Nonnull error) {
  266. }];
  267. }
  268. }
  269. #endif
  270. if (tComplention)
  271. tComplention(info, error);
  272. });
  273. };
  274. [request setFailedBlock:^{
  275. processRequest();
  276. }];
  277. [request setCompletionBlock:^{
  278. processRequest();
  279. }];
  280. [request startAsynchronous];
  281. }
  282. - (void)restoreAIWithInfo:(NSDictionary *)info
  283. complention:(AIActivityComplention)complention {
  284. __block AIActivityComplention tComplention = complention;
  285. __block AIInfoManager *weak_self = self;
  286. NSString *platform = @"DMG";
  287. #if VERSION_DMG
  288. platform = @"DMG";
  289. #else
  290. platform = @"AiStore";
  291. #endif
  292. //Process Params
  293. NSString *app_version = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] description];
  294. if (!app_version.length)
  295. app_version = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] description];
  296. NSDictionary *params = @{@"unique_sn":[self udid]?:@"",
  297. @"app_name":[self bundleIdentify]?:@"",
  298. @"receipt_str":info[@"receipt_str"]?:@"",
  299. @"platform":platform?:@"DMG"};
  300. NSMutableData *postData = [VerificationManager mutableDataWithDic:params];
  301. //Send Request
  302. NSString *urlString = [kVerificationServer stringByAppendingString:@"api/changeStoreBind"];
  303. NSURL *url = [NSURL URLWithString:urlString];
  304. ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
  305. request.requestMethod = @"POST";
  306. [request setPostBody:postData];
  307. NSString *postLength = [NSString stringWithFormat:@"%ld", (unsigned long)[postData length]];
  308. NSMutableDictionary *requestHeaders = [NSMutableDictionary dictionaryWithObjectsAndKeys:
  309. postLength, @"Content-Length", nil];
  310. request.defaultResponseEncoding = NSUTF8StringEncoding;
  311. [request setRequestHeaders:requestHeaders];
  312. [request addRequestHeader:@"Content-Type" value:@"application/json"];
  313. [request addRequestHeader:@"Accept" value:@"application/vnd.api+json;version=1"];
  314. __block void(^processRequest)(void) = ^{
  315. dispatch_async(dispatch_get_main_queue(), ^{
  316. NSDictionary *info = [[request.responseString objectFromJSONString] filterNullObject];
  317. NSError *error = request.error;
  318. if (info && [info isKindOfClass:[NSDictionary class]]) {
  319. if ([info valueForKey:@"errors"]) {
  320. error = [NSError errorWithDomain:@"激活失败"
  321. code:ActivityErrorTypeUnknow
  322. userInfo:info];
  323. }else if ([info valueForKey:@"error"]) {
  324. error = [NSError errorWithDomain:@"激活失败"
  325. code:ActivityErrorTypeUnknow
  326. userInfo:info];
  327. }
  328. }else {
  329. if(error) {
  330. error = [NSError errorWithDomain:error.domain code:ActivityErrorTypeNetworkDisable userInfo:error.userInfo];
  331. } else {
  332. error = [NSError errorWithDomain:@"激活失败"
  333. code:ActivityErrorTypeUnknow
  334. userInfo:@{}];
  335. }
  336. }
  337. if (!error) {
  338. AIInfo *aiInfo = [[AIInfo alloc] initWithDict:info[@"data"]];
  339. self.aiInfo = aiInfo;
  340. NSString *notificationName = (NSString *)kDeviceAIStatusChangeNotification;
  341. [[NSNotificationCenter defaultCenter] postNotificationName:notificationName
  342. object:self
  343. userInfo:info];
  344. }
  345. if (tComplention)
  346. tComplention(info, error);
  347. });
  348. };
  349. [request setFailedBlock:^{
  350. processRequest();
  351. }];
  352. [request setCompletionBlock:^{
  353. processRequest();
  354. }];
  355. [request startAsynchronous];
  356. }
  357. @end
  358. @interface AIInfo ()
  359. @property (nonatomic, readwrite) NSDictionary *infoDict;
  360. @property (nonatomic, readwrite) BOOL validAIFunction;
  361. @property (nonatomic, readwrite) NSString *cdKey;
  362. @property (nonatomic, readwrite) int totalToken;
  363. @property (nonatomic, readwrite) int usedTimes;
  364. @property (nonatomic, readwrite) NSDate *startDate;
  365. @property (nonatomic, readwrite) NSDate *endDate;
  366. @property (nonatomic, readwrite) int remainingDays;
  367. @property (nonatomic, readwrite) int pre_creditToken;
  368. @end
  369. @implementation AIInfo
  370. - (id)initWithDict:(NSDictionary *)dict {
  371. self = [super init];
  372. if (self) {
  373. self.infoDict = dict;
  374. [self setUp];
  375. }
  376. return self;
  377. }
  378. - (id)init {
  379. self = [super init];
  380. if (self) {
  381. [self setUp];
  382. }
  383. return self;
  384. }
  385. - (void)setUp {
  386. self.cdKey = self.infoDict[@"cdkey"]?:@"";
  387. self.totalToken = [self.infoDict[@"total"] intValue];
  388. self.usedTimes = [self.infoDict[@"used_times"] intValue];
  389. self.remainingDays = [self.infoDict[@"remaining_days"] intValue];
  390. if (self.infoDict[@"start_date"]) {
  391. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  392. [formatter setLocale:[NSLocale systemLocale]];
  393. [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  394. self.startDate = [formatter dateFromString:self.infoDict[@"start_date"]] ?: [[NSDate alloc] initWithTimeIntervalSince1970:0];
  395. } else {
  396. self.startDate = [[NSDate alloc] initWithTimeIntervalSince1970:0];
  397. }
  398. if (self.infoDict[@"end_date"]) {
  399. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  400. [formatter setLocale:[NSLocale systemLocale]];
  401. [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  402. self.endDate = [formatter dateFromString:self.infoDict[@"end_date"]] ?: [[NSDate alloc] initWithTimeIntervalSince1970:0];
  403. } else {
  404. self.startDate = [[NSDate alloc] initWithTimeIntervalSince1970:0];
  405. }
  406. self.pre_creditToken = [self.infoDict[@"pre_credit"] intValue];
  407. }
  408. - (NSDate *)startDate {
  409. return _startDate ?: [[NSDate alloc] initWithTimeIntervalSince1970:0];
  410. }
  411. - (NSDate *)endDate {
  412. return _endDate ?: [[NSDate alloc] initWithTimeIntervalSince1970:0];
  413. }
  414. - (BOOL)validAIFunction {
  415. CGFloat timeInterval = self.endDate.timeIntervalSinceNow;
  416. if (timeInterval > 0) {
  417. return YES;
  418. } else {
  419. return NO;
  420. }
  421. }
  422. @end
  423. #if DEBUG
  424. @implementation AIInfoManager (KMTest)
  425. //- (AIInfo *)aiInfo {
  426. // return [[AIInfo alloc] initWithDict:@{@"1" : @"1"}];
  427. //}
  428. @end
  429. #endif