react-native-navigation的迁移库

RCCManagerModule.m 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. #import "RCCManagerModule.h"
  2. #import "RCCManager.h"
  3. #import <UIKit/UIKit.h>
  4. #import "RCCNavigationController.h"
  5. #import "RCCViewController.h"
  6. #import "RCCDrawerController.h"
  7. #import "RCCLightBox.h"
  8. #import <React/RCTConvert.h>
  9. #import "RCCTabBarController.h"
  10. #import "RCCTheSideBarManagerViewController.h"
  11. #import "RCCNotification.h"
  12. #import "RCTHelpers.h"
  13. #import "RNNSwizzles.h"
  14. #define kSlideDownAnimationDuration 0.35
  15. typedef NS_ENUM(NSInteger, RCCManagerModuleErrorCode)
  16. {
  17. RCCManagerModuleCantCreateControllerErrorCode = -100,
  18. RCCManagerModuleCantFindTabControllerErrorCode = -200,
  19. RCCManagerModuleMissingParamsErrorCode = -300
  20. };
  21. @implementation RCTConvert (RCCManagerModuleErrorCode)
  22. RCT_ENUM_CONVERTER(RCCManagerModuleErrorCode,
  23. (@{@"RCCManagerModuleCantCreateControllerErrorCode": @(RCCManagerModuleCantCreateControllerErrorCode),
  24. @"RCCManagerModuleCantFindTabControllerErrorCode": @(RCCManagerModuleCantFindTabControllerErrorCode),
  25. }), RCCManagerModuleCantCreateControllerErrorCode, integerValue)
  26. @end
  27. @implementation RCTConvert (UIModalPresentationStyle)
  28. RCT_ENUM_CONVERTER(UIModalPresentationStyle,
  29. (@{@"fullScreen": @(UIModalPresentationFullScreen),
  30. @"pageSheet": @(UIModalPresentationPageSheet),
  31. @"formSheet": @(UIModalPresentationFormSheet),
  32. @"currentContext": @(UIModalPresentationCurrentContext),
  33. @"custom": @(UIModalPresentationCustom),
  34. @"overFullScreen": @(UIModalPresentationOverFullScreen),
  35. @"overCurrentContext": @(UIModalPresentationOverCurrentContext),
  36. @"popover": @(UIModalPresentationPopover),
  37. @"none": @(UIModalPresentationNone)
  38. }), UIModalPresentationFullScreen, integerValue)
  39. @end
  40. @implementation RCCManagerModule
  41. RCT_EXPORT_MODULE(RCCManager);
  42. #pragma mark - constatnts export
  43. - (NSDictionary *)constantsToExport
  44. {
  45. return @{
  46. //Error codes
  47. @"RCCManagerModuleCantCreateControllerErrorCode" : @(RCCManagerModuleCantCreateControllerErrorCode),
  48. @"RCCManagerModuleCantFindTabControllerErrorCode" : @(RCCManagerModuleCantFindTabControllerErrorCode),
  49. @"PresentFullScreen": @"fullScreen",
  50. @"PresentPageSheet": @"pageSheet",
  51. @"PresentFormSheet": @"formSheet",
  52. @"PresentCurrentContext": @"currentContext",
  53. @"PresentCustom": @"custom",
  54. @"PresentOverFullScreen": @"overFullScreen",
  55. @"PresentOverCurrentContext": @"overCurrentContext",
  56. @"PresentPopover": @"popover",
  57. @"PresentNone": @"none"
  58. };
  59. }
  60. - (dispatch_queue_t)methodQueue
  61. {
  62. return dispatch_get_main_queue();
  63. }
  64. + (BOOL)requiresMainQueueSetup
  65. {
  66. return YES;
  67. }
  68. #pragma mark - helper methods
  69. +(UIViewController*)modalPresenterViewControllers:(NSMutableArray*)returnAllPresenters
  70. {
  71. UIViewController *modalPresenterViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
  72. if ((returnAllPresenters != nil) && (modalPresenterViewController != nil))
  73. {
  74. [returnAllPresenters addObject:modalPresenterViewController];
  75. }
  76. while (modalPresenterViewController.presentedViewController != nil)
  77. {
  78. modalPresenterViewController = modalPresenterViewController.presentedViewController;
  79. if (returnAllPresenters != nil)
  80. {
  81. [returnAllPresenters addObject:modalPresenterViewController];
  82. }
  83. }
  84. return modalPresenterViewController;
  85. }
  86. +(UIViewController*)lastModalPresenterViewController
  87. {
  88. return [self modalPresenterViewControllers:nil];
  89. }
  90. +(NSError*)rccErrorWithCode:(NSInteger)code description:(NSString*)description
  91. {
  92. NSString *safeDescription = (description == nil) ? @"" : description;
  93. return [NSError errorWithDomain:@"RCCControllers" code:code userInfo:@{NSLocalizedDescriptionKey: safeDescription}];
  94. }
  95. +(void)handleRCTPromiseRejectBlock:(RCTPromiseRejectBlock)reject error:(NSError*)error
  96. {
  97. reject([NSString stringWithFormat: @"%lu", (long)error.code], error.localizedDescription, error);
  98. }
  99. +(void)cancelAllRCCViewControllerReactTouches
  100. {
  101. [[NSNotificationCenter defaultCenter] postNotificationName:RCCViewControllerCancelReactTouchesNotification object:nil];
  102. }
  103. -(void)animateSnapshot:(UIView*)snapshot animationType:(NSString*)animationType resolver:(RCTPromiseResolveBlock)resolve
  104. {
  105. [UIView animateWithDuration:kSlideDownAnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^()
  106. {
  107. if (animationType == nil || [animationType isEqualToString:@"slide-down"])
  108. {
  109. snapshot.transform = CGAffineTransformMakeTranslation(0, snapshot.frame.size.height);
  110. }
  111. else if ([animationType isEqualToString:@"fade"])
  112. {
  113. snapshot.alpha = 0;
  114. }
  115. }
  116. completion:^(BOOL finished)
  117. {
  118. [snapshot removeFromSuperview];
  119. if (resolve != nil)
  120. {
  121. resolve(nil);
  122. }
  123. }];
  124. }
  125. -(void)dismissAllModalPresenters:(NSMutableArray*)allPresentedViewControllers resolver:(RCTPromiseResolveBlock)resolve
  126. {
  127. UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
  128. if (allPresentedViewControllers.count > 0)
  129. {
  130. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^
  131. {
  132. __block NSUInteger counter = 0;
  133. for (UIViewController *viewController in allPresentedViewControllers)
  134. {
  135. counter++;
  136. if (viewController.presentedViewController != nil)
  137. {
  138. dispatch_semaphore_t dismiss_sema = dispatch_semaphore_create(0);
  139. dispatch_async(dispatch_get_main_queue(), ^
  140. {
  141. [viewController dismissViewControllerAnimated:NO completion:^()
  142. {
  143. if (rootViewController != viewController) {
  144. [[RCCManager sharedIntance] unregisterController:viewController];
  145. }
  146. if (counter == allPresentedViewControllers.count && allPresentedViewControllers.count > 0)
  147. {
  148. [allPresentedViewControllers removeAllObjects];
  149. if (resolve != nil)
  150. {
  151. resolve(nil);
  152. }
  153. }
  154. dispatch_semaphore_signal(dismiss_sema);
  155. }];
  156. });
  157. dispatch_semaphore_wait(dismiss_sema, DISPATCH_TIME_FOREVER);
  158. }
  159. else if (counter == allPresentedViewControllers.count && allPresentedViewControllers.count > 0)
  160. {
  161. [allPresentedViewControllers removeAllObjects];
  162. if (resolve != nil)
  163. {
  164. dispatch_async(dispatch_get_main_queue(), ^
  165. {
  166. resolve(nil);
  167. });
  168. }
  169. }
  170. }
  171. });
  172. }
  173. else if (resolve != nil)
  174. {
  175. resolve(nil);
  176. }
  177. }
  178. #pragma mark - RCT exported methods
  179. RCT_EXPORT_METHOD(
  180. setRootController:(NSDictionary*)layout animationType:(NSString*)animationType globalProps:(NSDictionary*)globalProps resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  181. {
  182. if ([[RCCManager sharedInstance] getBridge].loading) {
  183. [self deferSetRootControllerWhileBridgeLoading:layout animationType:animationType globalProps:globalProps resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject];
  184. return;
  185. }
  186. dispatch_async(dispatch_get_main_queue(), ^{
  187. [self performSetRootController:layout animationType:animationType globalProps:globalProps];
  188. resolve(nil);
  189. });
  190. }
  191. /**
  192. * on RN31 there's a timing issue, we must wait for the bridge to finish loading
  193. */
  194. -(void)deferSetRootControllerWhileBridgeLoading:(NSDictionary*)layout animationType:(NSString*)animationType globalProps:(NSDictionary*)globalProps resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject
  195. {
  196. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.0001 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  197. [self setRootController:layout animationType:animationType globalProps:globalProps resolver:resolve rejecter:reject];
  198. });
  199. }
  200. -(void)performSetRootController:(NSDictionary*)layout animationType:(NSString*)animationType globalProps:(NSDictionary*)globalProps
  201. {
  202. NSMutableDictionary *modifiedGloablProps = [globalProps mutableCopy];
  203. modifiedGloablProps[GLOBAL_SCREEN_ACTION_COMMAND_TYPE] = COMMAND_TYPE_INITIAL_SCREEN;
  204. // first clear the registry to remove any refernece to the previous controllers
  205. [[RCCManager sharedInstance] clearModuleRegistry];
  206. [[RCCManager sharedInstance] setAppStyle:nil];
  207. NSDictionary *appStyle = layout[@"props"][@"appStyle"];
  208. if (appStyle) {
  209. [[RCCManager sharedIntance] setAppStyle:appStyle];
  210. if([appStyle[@"autoAdjustScrollViewInsets"] boolValue] == YES)
  211. {
  212. [RNNSwizzles applySwizzles];
  213. }
  214. }
  215. // create the new controller
  216. UIViewController *controller = [RCCViewController controllerWithLayout:layout globalProps:modifiedGloablProps bridge:[[RCCManager sharedInstance] getBridge]];
  217. if (controller == nil) return;
  218. id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
  219. BOOL animated = !((appDelegate.window.rootViewController == nil) || ([animationType isEqualToString:@"none"]));
  220. // if we're animating - add a snapshot now
  221. UIViewController *presentedViewController = nil;
  222. UIView *snapshot = nil;
  223. if (animated)
  224. {
  225. if(appDelegate.window.rootViewController.presentedViewController != nil)
  226. presentedViewController = appDelegate.window.rootViewController.presentedViewController;
  227. else
  228. presentedViewController = appDelegate.window.rootViewController;
  229. snapshot = [presentedViewController.view snapshotViewAfterScreenUpdates:NO];
  230. [appDelegate.window.rootViewController.view addSubview:snapshot];
  231. }
  232. // dismiss the modal controllers without animation just so they can be released
  233. [self dismissAllControllers:@"none" resolver:^(id result)
  234. {
  235. // set the new controller as the root
  236. appDelegate.window.rootViewController = controller;
  237. [appDelegate.window makeKeyAndVisible];
  238. [presentedViewController dismissViewControllerAnimated:NO completion:nil];
  239. if (animated)
  240. {
  241. // move the snaphot to the new root and animate it
  242. [appDelegate.window.rootViewController.view addSubview:snapshot];
  243. [self animateSnapshot:snapshot animationType:animationType resolver:nil];
  244. }
  245. } rejecter:nil];
  246. }
  247. RCT_EXPORT_METHOD(
  248. NavigationControllerIOS:(NSString*)controllerId performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams)
  249. {
  250. if (!controllerId || !performAction) return;
  251. RCCNavigationController* controller = [[RCCManager sharedInstance] getControllerWithId:controllerId componentType:@"NavigationControllerIOS"];
  252. if (!controller || ![controller isKindOfClass:[RCCNavigationController class]]) return;
  253. return [controller performAction:performAction actionParams:actionParams bridge:[[RCCManager sharedInstance] getBridge]];
  254. }
  255. RCT_EXPORT_METHOD(
  256. DrawerControllerIOS:(NSString*)controllerId performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams)
  257. {
  258. if (!controllerId || !performAction) return;
  259. id<RCCDrawerDelegate> controller = [[RCCManager sharedIntance] getControllerWithId:controllerId componentType:@"DrawerControllerIOS"];
  260. if (!controller || (![controller isKindOfClass:[RCCDrawerController class]] && ![controller isKindOfClass:[RCCTheSideBarManagerViewController class]])) return;
  261. return [controller performAction:performAction actionParams:actionParams bridge:[[RCCManager sharedIntance] getBridge]];
  262. }
  263. RCT_EXPORT_METHOD(
  264. TabBarControllerIOS:(NSString*)controllerId performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  265. {
  266. if (!controllerId || !performAction)
  267. {
  268. [RCCManagerModule handleRCTPromiseRejectBlock:reject
  269. error:[RCCManagerModule rccErrorWithCode:RCCManagerModuleMissingParamsErrorCode description:@"missing params"]];
  270. return;
  271. }
  272. RCCTabBarController* controller = [[RCCManager sharedInstance] getControllerWithId:controllerId componentType:@"TabBarControllerIOS"];
  273. if (!controller || ![controller isKindOfClass:[RCCTabBarController class]])
  274. {
  275. [RCCManagerModule handleRCTPromiseRejectBlock:reject
  276. error:[RCCManagerModule rccErrorWithCode:RCCManagerModuleCantFindTabControllerErrorCode description:@"could not find UITabBarController"]];
  277. return;
  278. }
  279. [controller performAction:performAction actionParams:actionParams bridge:[[RCCManager sharedInstance] getBridge] completion:^(){ resolve(nil); }];
  280. }
  281. RCT_EXPORT_METHOD(
  282. modalShowLightBox:(NSDictionary*)params)
  283. {
  284. [RCCLightBox showWithParams:params];
  285. }
  286. RCT_EXPORT_METHOD(
  287. modalDismissLightBox)
  288. {
  289. [RCCLightBox dismiss];
  290. }
  291. RCT_EXPORT_METHOD(
  292. showController:(NSDictionary*)layout animationType:(NSString*)animationType globalProps:(NSDictionary*)globalProps resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  293. {
  294. NSMutableDictionary *modifiedGlobalProps = [globalProps mutableCopy];
  295. modifiedGlobalProps[GLOBAL_SCREEN_ACTION_COMMAND_TYPE] = COMMAND_TYPE_SHOW_MODAL;
  296. UIViewController *controller = [RCCViewController controllerWithLayout:layout globalProps:modifiedGlobalProps bridge:[[RCCManager sharedInstance] getBridge]];
  297. if (controller == nil)
  298. {
  299. [RCCManagerModule handleRCTPromiseRejectBlock:reject
  300. error:[RCCManagerModule rccErrorWithCode:RCCManagerModuleCantCreateControllerErrorCode description:@"could not create controller"]];
  301. return;
  302. }
  303. if (layout[@"props"] && [layout[@"props"] isKindOfClass:[NSDictionary class]] && layout[@"props"][@"style"] && [layout[@"props"][@"style"] isKindOfClass: [NSDictionary class]]) {
  304. NSDictionary *style = layout[@"props"][@"style"];
  305. if (style[@"modalPresentationStyle"] && [style[@"modalPresentationStyle"] isKindOfClass:[NSString class]]) {
  306. NSString *presentationStyle = style[@"modalPresentationStyle"];
  307. UIModalPresentationStyle modalPresentationStyle = [RCTConvert UIModalPresentationStyle:presentationStyle];
  308. controller.modalPresentationStyle = modalPresentationStyle;
  309. }
  310. }
  311. [[RCCManagerModule lastModalPresenterViewController] presentViewController:controller
  312. animated:![animationType isEqualToString:@"none"]
  313. completion:^(){ resolve(nil); }];
  314. }
  315. - (UIViewController *) getVisibleViewControllerFor:(UIViewController *)vc
  316. {
  317. if ([vc isKindOfClass:[UINavigationController class]])
  318. {
  319. return [self getVisibleViewControllerFor:[((UINavigationController*)vc) visibleViewController]];
  320. }
  321. else if ([vc isKindOfClass:[UITabBarController class]])
  322. {
  323. return [self getVisibleViewControllerFor:[((UITabBarController*)vc) selectedViewController]];
  324. }
  325. else if (vc.presentedViewController)
  326. {
  327. return [self getVisibleViewControllerFor:vc.presentedViewController];
  328. }
  329. else if ([vc isKindOfClass:[TheSidebarController class]]) {
  330. TheSidebarController *drawerController = (TheSidebarController*) vc;
  331. return [self getVisibleViewControllerFor:drawerController.contentViewController];
  332. }
  333. else if ([vc isKindOfClass:[MMDrawerController class]]) {
  334. MMDrawerController *drawerController = (MMDrawerController*) vc;
  335. return [self getVisibleViewControllerFor:drawerController.centerViewController];
  336. }
  337. else
  338. {
  339. return vc;
  340. }
  341. }
  342. RCT_EXPORT_METHOD(getCurrentlyVisibleScreenId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  343. {
  344. UIViewController *rootVC = [UIApplication sharedApplication].delegate.window.rootViewController;
  345. UIViewController *visibleVC = [self getVisibleViewControllerFor:rootVC];
  346. NSString *controllerId = [[RCCManager sharedIntance] getIdForController:visibleVC];
  347. id result = (controllerId != nil) ? @{@"screenId": controllerId} : nil;
  348. resolve(result);
  349. }
  350. -(BOOL)viewControllerIsModal:(UIViewController*)viewController
  351. {
  352. BOOL viewControllerIsModal = (viewController.presentingViewController.presentedViewController == viewController)
  353. || ((viewController.navigationController != nil) && (viewController.navigationController.presentingViewController.presentedViewController == viewController.navigationController) && (viewController == viewController.navigationController.viewControllers[0]))
  354. || ([viewController.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]]);
  355. return viewControllerIsModal;
  356. }
  357. RCT_EXPORT_METHOD(
  358. dismissController:(NSString*)animationType resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  359. {
  360. UIViewController* vc = [RCCManagerModule lastModalPresenterViewController];
  361. if ([self viewControllerIsModal:vc])
  362. {
  363. [[RCCManager sharedIntance] unregisterController:vc];
  364. [vc dismissViewControllerAnimated:![animationType isEqualToString:@"none"]
  365. completion:^(){ resolve(nil); }];
  366. }
  367. else
  368. {
  369. resolve(nil);
  370. }
  371. }
  372. RCT_EXPORT_METHOD(
  373. dismissAllControllers:(NSString*)animationType resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  374. {
  375. if([UIApplication sharedApplication].delegate.window.rootViewController.presentedViewController == nil)
  376. {//if there are no modal - do nothing
  377. resolve(nil);
  378. return;
  379. }
  380. NSMutableArray *allPresentedViewControllers = [NSMutableArray array];
  381. [RCCManagerModule modalPresenterViewControllers:allPresentedViewControllers];
  382. BOOL animated = ![animationType isEqualToString:@"none"];
  383. if (animated)
  384. {
  385. id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
  386. UIView *snapshot = [appDelegate.window snapshotViewAfterScreenUpdates:NO];
  387. [appDelegate.window addSubview:snapshot];
  388. [self dismissAllModalPresenters:allPresentedViewControllers resolver:^(id result)
  389. {
  390. [self animateSnapshot:snapshot animationType:animationType resolver:resolve];
  391. }];
  392. }
  393. else
  394. {
  395. [self dismissAllModalPresenters:allPresentedViewControllers resolver:resolve];
  396. }
  397. }
  398. RCT_EXPORT_METHOD(
  399. showNotification:(NSDictionary*)params resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  400. {
  401. [RCCNotification showWithParams:params resolver:resolve rejecter:reject];
  402. }
  403. RCT_EXPORT_METHOD(
  404. dismissNotification:(NSDictionary*)params resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  405. {
  406. [RCCNotification dismissWithParams:params resolver:resolve rejecter:reject];
  407. }
  408. RCT_EXPORT_METHOD(
  409. cancelAllReactTouches)
  410. {
  411. [RCCManagerModule cancelAllRCCViewControllerReactTouches];
  412. }
  413. RCT_EXPORT_METHOD(getLaunchArgs:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  414. {
  415. resolve([[RCCManager sharedInstance] getLaunchArgs]);
  416. }
  417. @end