react-native-navigation的迁移库

RCCManagerModule.m 20KB

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