AIInfoManager.m 17 KB

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