react-native-navigation的迁移库

RCCManagerModule.m 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  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. UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
  123. if (allPresentedViewControllers.count > 0)
  124. {
  125. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^
  126. {
  127. __block NSUInteger counter = 0;
  128. for (UIViewController *viewController in allPresentedViewControllers)
  129. {
  130. counter++;
  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 (rootViewController != viewController) {
  139. [[RCCManager sharedIntance] unregisterController:viewController];
  140. }
  141. if (counter == allPresentedViewControllers.count && allPresentedViewControllers.count > 0)
  142. {
  143. [allPresentedViewControllers removeAllObjects];
  144. if (resolve != nil)
  145. {
  146. resolve(nil);
  147. }
  148. }
  149. dispatch_semaphore_signal(dismiss_sema);
  150. }];
  151. });
  152. dispatch_semaphore_wait(dismiss_sema, DISPATCH_TIME_FOREVER);
  153. }
  154. else if (counter == allPresentedViewControllers.count && allPresentedViewControllers.count > 0)
  155. {
  156. [allPresentedViewControllers removeAllObjects];
  157. if (resolve != nil)
  158. {
  159. dispatch_async(dispatch_get_main_queue(), ^
  160. {
  161. resolve(nil);
  162. });
  163. }
  164. }
  165. }
  166. });
  167. }
  168. else if (resolve != nil)
  169. {
  170. resolve(nil);
  171. }
  172. }
  173. #pragma mark - RCT exported methods
  174. RCT_EXPORT_METHOD(
  175. setRootController:(NSDictionary*)layout animationType:(NSString*)animationType globalProps:(NSDictionary*)globalProps)
  176. {
  177. if ([[RCCManager sharedInstance] getBridge].loading) {
  178. [self deferSetRootControllerWhileBridgeLoading:layout animationType:animationType globalProps:globalProps];
  179. return;
  180. }
  181. dispatch_async(dispatch_get_main_queue(), ^{
  182. [self performSetRootController:layout animationType:animationType globalProps:globalProps];
  183. });
  184. }
  185. /**
  186. * on RN31 there's a timing issue, we must wait for the bridge to finish loading
  187. */
  188. -(void)deferSetRootControllerWhileBridgeLoading:(NSDictionary*)layout animationType:(NSString*)animationType globalProps:(NSDictionary*)globalProps
  189. {
  190. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.0001 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  191. [self setRootController:layout animationType:animationType globalProps:globalProps];
  192. });
  193. }
  194. -(void)performSetRootController:(NSDictionary*)layout animationType:(NSString*)animationType globalProps:(NSDictionary*)globalProps
  195. {
  196. NSMutableDictionary *modifiedGloablProps = [globalProps mutableCopy];
  197. modifiedGloablProps[GLOBAL_SCREEN_ACTION_COMMAND_TYPE] = COMMAND_TYPE_INITIAL_SCREEN;
  198. // first clear the registry to remove any refernece to the previous controllers
  199. [[RCCManager sharedInstance] clearModuleRegistry];
  200. [[RCCManager sharedInstance] setAppStyle:nil];
  201. NSDictionary *appStyle = layout[@"props"][@"appStyle"];
  202. if (appStyle) {
  203. [[RCCManager sharedIntance] setAppStyle:appStyle];
  204. }
  205. // create the new controller
  206. UIViewController *controller = [RCCViewController controllerWithLayout:layout globalProps:modifiedGloablProps bridge:[[RCCManager sharedInstance] getBridge]];
  207. if (controller == nil) return;
  208. id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
  209. BOOL animated = !((appDelegate.window.rootViewController == nil) || ([animationType isEqualToString:@"none"]));
  210. // if we're animating - add a snapshot now
  211. UIViewController *presentedViewController = nil;
  212. UIView *snapshot = nil;
  213. if (animated)
  214. {
  215. if(appDelegate.window.rootViewController.presentedViewController != nil)
  216. presentedViewController = appDelegate.window.rootViewController.presentedViewController;
  217. else
  218. presentedViewController = appDelegate.window.rootViewController;
  219. snapshot = [presentedViewController.view snapshotViewAfterScreenUpdates:NO];
  220. [appDelegate.window.rootViewController.view addSubview:snapshot];
  221. }
  222. // dismiss the modal controllers without animation just so they can be released
  223. [self dismissAllControllers:@"none" resolver:^(id result)
  224. {
  225. // set the new controller as the root
  226. appDelegate.window.rootViewController = controller;
  227. [appDelegate.window makeKeyAndVisible];
  228. [presentedViewController dismissViewControllerAnimated:NO completion:nil];
  229. if (animated)
  230. {
  231. // move the snaphot to the new root and animate it
  232. [appDelegate.window.rootViewController.view addSubview:snapshot];
  233. [self animateSnapshot:snapshot animationType:animationType resolver:nil];
  234. }
  235. } rejecter:nil];
  236. }
  237. RCT_EXPORT_METHOD(
  238. NavigationControllerIOS:(NSString*)controllerId performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams)
  239. {
  240. if (!controllerId || !performAction) return;
  241. RCCNavigationController* controller = [[RCCManager sharedInstance] getControllerWithId:controllerId componentType:@"NavigationControllerIOS"];
  242. if (!controller || ![controller isKindOfClass:[RCCNavigationController class]]) return;
  243. return [controller performAction:performAction actionParams:actionParams bridge:[[RCCManager sharedInstance] getBridge]];
  244. }
  245. RCT_EXPORT_METHOD(
  246. DrawerControllerIOS:(NSString*)controllerId performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams)
  247. {
  248. if (!controllerId || !performAction) return;
  249. id<RCCDrawerDelegate> controller = [[RCCManager sharedIntance] getControllerWithId:controllerId componentType:@"DrawerControllerIOS"];
  250. if (!controller || (![controller isKindOfClass:[RCCDrawerController class]] && ![controller isKindOfClass:[RCCTheSideBarManagerViewController class]])) return;
  251. return [controller performAction:performAction actionParams:actionParams bridge:[[RCCManager sharedIntance] getBridge]];
  252. }
  253. RCT_EXPORT_METHOD(
  254. TabBarControllerIOS:(NSString*)controllerId performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  255. {
  256. if (!controllerId || !performAction)
  257. {
  258. [RCCManagerModule handleRCTPromiseRejectBlock:reject
  259. error:[RCCManagerModule rccErrorWithCode:RCCManagerModuleMissingParamsErrorCode description:@"missing params"]];
  260. return;
  261. }
  262. RCCTabBarController* controller = [[RCCManager sharedInstance] getControllerWithId:controllerId componentType:@"TabBarControllerIOS"];
  263. if (!controller || ![controller isKindOfClass:[RCCTabBarController class]])
  264. {
  265. [RCCManagerModule handleRCTPromiseRejectBlock:reject
  266. error:[RCCManagerModule rccErrorWithCode:RCCManagerModuleCantFindTabControllerErrorCode description:@"could not find UITabBarController"]];
  267. return;
  268. }
  269. [controller performAction:performAction actionParams:actionParams bridge:[[RCCManager sharedInstance] getBridge] completion:^(){ resolve(nil); }];
  270. }
  271. RCT_EXPORT_METHOD(
  272. modalShowLightBox:(NSDictionary*)params)
  273. {
  274. [RCCLightBox showWithParams:params];
  275. }
  276. RCT_EXPORT_METHOD(
  277. modalDismissLightBox)
  278. {
  279. [RCCLightBox dismiss];
  280. }
  281. RCT_EXPORT_METHOD(
  282. showController:(NSDictionary*)layout animationType:(NSString*)animationType globalProps:(NSDictionary*)globalProps resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  283. {
  284. NSMutableDictionary *modifiedGlobalProps = [globalProps mutableCopy];
  285. modifiedGlobalProps[GLOBAL_SCREEN_ACTION_COMMAND_TYPE] = COMMAND_TYPE_SHOW_MODAL;
  286. UIViewController *controller = [RCCViewController controllerWithLayout:layout globalProps:modifiedGlobalProps bridge:[[RCCManager sharedInstance] getBridge]];
  287. if (controller == nil)
  288. {
  289. [RCCManagerModule handleRCTPromiseRejectBlock:reject
  290. error:[RCCManagerModule rccErrorWithCode:RCCManagerModuleCantCreateControllerErrorCode description:@"could not create controller"]];
  291. return;
  292. }
  293. if (layout[@"props"] && [layout[@"props"] isKindOfClass:[NSDictionary class]] && layout[@"props"][@"style"] && [layout[@"props"][@"style"] isKindOfClass: [NSDictionary class]]) {
  294. NSDictionary *style = layout[@"props"][@"style"];
  295. if (style[@"modalPresentationStyle"] && [style[@"modalPresentationStyle"] isKindOfClass:[NSString class]]) {
  296. NSString *presentationStyle = style[@"modalPresentationStyle"];
  297. UIModalPresentationStyle modalPresentationStyle = [RCTConvert UIModalPresentationStyle:presentationStyle];
  298. controller.modalPresentationStyle = modalPresentationStyle;
  299. }
  300. }
  301. [[RCCManagerModule lastModalPresenterViewController] presentViewController:controller
  302. animated:![animationType isEqualToString:@"none"]
  303. completion:^(){ resolve(nil); }];
  304. }
  305. - (UIViewController *) getVisibleViewControllerFor:(UIViewController *)vc
  306. {
  307. if ([vc isKindOfClass:[UINavigationController class]])
  308. {
  309. return [self getVisibleViewControllerFor:[((UINavigationController*)vc) visibleViewController]];
  310. }
  311. else if ([vc isKindOfClass:[UITabBarController class]])
  312. {
  313. return [self getVisibleViewControllerFor:[((UITabBarController*)vc) selectedViewController]];
  314. }
  315. else if (vc.presentedViewController)
  316. {
  317. return [self getVisibleViewControllerFor:vc.presentedViewController];
  318. }
  319. else if ([vc isKindOfClass:[TheSidebarController class]]) {
  320. TheSidebarController *drawerController = (TheSidebarController*) vc;
  321. return [self getVisibleViewControllerFor:drawerController.contentViewController];
  322. }
  323. else if ([vc isKindOfClass:[MMDrawerController class]]) {
  324. MMDrawerController *drawerController = (MMDrawerController*) vc;
  325. return [self getVisibleViewControllerFor:drawerController.centerViewController];
  326. }
  327. else
  328. {
  329. return vc;
  330. }
  331. }
  332. RCT_EXPORT_METHOD(getCurrentlyVisibleScreenId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  333. {
  334. UIViewController *rootVC = [UIApplication sharedApplication].delegate.window.rootViewController;
  335. UIViewController *visibleVC = [self getVisibleViewControllerFor:rootVC];
  336. NSString *controllerId = [[RCCManager sharedIntance] getIdForController:visibleVC];
  337. id result = (controllerId != nil) ? @{@"screenId": controllerId} : nil;
  338. resolve(result);
  339. }
  340. -(BOOL)viewControllerIsModal:(UIViewController*)viewController
  341. {
  342. BOOL viewControllerIsModal = (viewController.presentingViewController.presentedViewController == viewController)
  343. || ((viewController.navigationController != nil) && (viewController.navigationController.presentingViewController.presentedViewController == viewController.navigationController) && (viewController == viewController.navigationController.viewControllers[0]))
  344. || ([viewController.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]]);
  345. return viewControllerIsModal;
  346. }
  347. RCT_EXPORT_METHOD(
  348. dismissController:(NSString*)animationType resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  349. {
  350. UIViewController* vc = [RCCManagerModule lastModalPresenterViewController];
  351. if ([self viewControllerIsModal:vc])
  352. {
  353. [[RCCManager sharedIntance] unregisterController:vc];
  354. [vc dismissViewControllerAnimated:![animationType isEqualToString:@"none"]
  355. completion:^(){ resolve(nil); }];
  356. }
  357. else
  358. {
  359. resolve(nil);
  360. }
  361. }
  362. RCT_EXPORT_METHOD(
  363. dismissAllControllers:(NSString*)animationType resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  364. {
  365. if([UIApplication sharedApplication].delegate.window.rootViewController.presentedViewController == nil)
  366. {//if there are no modal - do nothing
  367. resolve(nil);
  368. return;
  369. }
  370. NSMutableArray *allPresentedViewControllers = [NSMutableArray array];
  371. [RCCManagerModule modalPresenterViewControllers:allPresentedViewControllers];
  372. BOOL animated = ![animationType isEqualToString:@"none"];
  373. if (animated)
  374. {
  375. id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
  376. UIView *snapshot = [appDelegate.window snapshotViewAfterScreenUpdates:NO];
  377. [appDelegate.window addSubview:snapshot];
  378. [self dismissAllModalPresenters:allPresentedViewControllers resolver:^(id result)
  379. {
  380. [self animateSnapshot:snapshot animationType:animationType resolver:resolve];
  381. }];
  382. }
  383. else
  384. {
  385. [self dismissAllModalPresenters:allPresentedViewControllers resolver:resolve];
  386. }
  387. }
  388. RCT_EXPORT_METHOD(
  389. showNotification:(NSDictionary*)params resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  390. {
  391. [RCCNotification showWithParams:params resolver:resolve rejecter:reject];
  392. }
  393. RCT_EXPORT_METHOD(
  394. dismissNotification:(NSDictionary*)params resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  395. {
  396. [RCCNotification dismissWithParams:params resolver:resolve rejecter:reject];
  397. }
  398. RCT_EXPORT_METHOD(
  399. cancelAllReactTouches)
  400. {
  401. [RCCManagerModule cancelAllRCCViewControllerReactTouches];
  402. }
  403. @end