react-native-navigation的迁移库

RCCManagerModule.m 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  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. [[RCCManager sharedInstance] setAppStyle:nil];
  198. NSDictionary *appStyle = layout[@"props"][@"appStyle"];
  199. if (appStyle) {
  200. [[RCCManager sharedIntance] setAppStyle:appStyle];
  201. }
  202. // create the new controller
  203. UIViewController *controller = [RCCViewController controllerWithLayout:layout globalProps:modifiedGloablProps bridge:[[RCCManager sharedInstance] getBridge]];
  204. if (controller == nil) return;
  205. id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
  206. BOOL animated = !((appDelegate.window.rootViewController == nil) || ([animationType isEqualToString:@"none"]));
  207. // if we're animating - add a snapshot now
  208. UIViewController *presentedViewController = nil;
  209. UIView *snapshot = nil;
  210. if (animated)
  211. {
  212. if(appDelegate.window.rootViewController.presentedViewController != nil)
  213. presentedViewController = appDelegate.window.rootViewController.presentedViewController;
  214. else
  215. presentedViewController = appDelegate.window.rootViewController;
  216. snapshot = [presentedViewController.view snapshotViewAfterScreenUpdates:NO];
  217. [appDelegate.window.rootViewController.view addSubview:snapshot];
  218. }
  219. // dismiss the modal controllers without animation just so they can be released
  220. [self dismissAllControllers:@"none" resolver:^(id result)
  221. {
  222. // set the new controller as the root
  223. appDelegate.window.rootViewController = controller;
  224. [appDelegate.window makeKeyAndVisible];
  225. [presentedViewController dismissViewControllerAnimated:NO completion:nil];
  226. if (animated)
  227. {
  228. // move the snaphot to the new root and animate it
  229. [appDelegate.window.rootViewController.view addSubview:snapshot];
  230. [self animateSnapshot:snapshot animationType:animationType resolver:nil];
  231. }
  232. } rejecter:nil];
  233. }
  234. RCT_EXPORT_METHOD(
  235. NavigationControllerIOS:(NSString*)controllerId performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams)
  236. {
  237. if (!controllerId || !performAction) return;
  238. RCCNavigationController* controller = [[RCCManager sharedInstance] getControllerWithId:controllerId componentType:@"NavigationControllerIOS"];
  239. if (!controller || ![controller isKindOfClass:[RCCNavigationController class]]) return;
  240. return [controller performAction:performAction actionParams:actionParams bridge:[[RCCManager sharedInstance] getBridge]];
  241. }
  242. RCT_EXPORT_METHOD(
  243. DrawerControllerIOS:(NSString*)controllerId performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams)
  244. {
  245. if (!controllerId || !performAction) return;
  246. id<RCCDrawerDelegate> controller = [[RCCManager sharedIntance] getControllerWithId:controllerId componentType:@"DrawerControllerIOS"];
  247. if (!controller || (![controller isKindOfClass:[RCCDrawerController class]] && ![controller isKindOfClass:[RCCTheSideBarManagerViewController class]])) return;
  248. return [controller performAction:performAction actionParams:actionParams bridge:[[RCCManager sharedIntance] getBridge]];
  249. }
  250. RCT_EXPORT_METHOD(
  251. TabBarControllerIOS:(NSString*)controllerId performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  252. {
  253. if (!controllerId || !performAction)
  254. {
  255. [RCCManagerModule handleRCTPromiseRejectBlock:reject
  256. error:[RCCManagerModule rccErrorWithCode:RCCManagerModuleMissingParamsErrorCode description:@"missing params"]];
  257. return;
  258. }
  259. RCCTabBarController* controller = [[RCCManager sharedInstance] getControllerWithId:controllerId componentType:@"TabBarControllerIOS"];
  260. if (!controller || ![controller isKindOfClass:[RCCTabBarController class]])
  261. {
  262. [RCCManagerModule handleRCTPromiseRejectBlock:reject
  263. error:[RCCManagerModule rccErrorWithCode:RCCManagerModuleCantFindTabControllerErrorCode description:@"could not find UITabBarController"]];
  264. return;
  265. }
  266. [controller performAction:performAction actionParams:actionParams bridge:[[RCCManager sharedInstance] getBridge] completion:^(){ resolve(nil); }];
  267. }
  268. RCT_EXPORT_METHOD(
  269. modalShowLightBox:(NSDictionary*)params)
  270. {
  271. [RCCLightBox showWithParams:params];
  272. }
  273. RCT_EXPORT_METHOD(
  274. modalDismissLightBox)
  275. {
  276. [RCCLightBox dismiss];
  277. }
  278. RCT_EXPORT_METHOD(
  279. showController:(NSDictionary*)layout animationType:(NSString*)animationType globalProps:(NSDictionary*)globalProps resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  280. {
  281. NSMutableDictionary *modifiedGlobalProps = [globalProps mutableCopy];
  282. modifiedGlobalProps[GLOBAL_SCREEN_ACTION_COMMAND_TYPE] = COMMAND_TYPE_SHOW_MODAL;
  283. UIViewController *controller = [RCCViewController controllerWithLayout:layout globalProps:modifiedGlobalProps bridge:[[RCCManager sharedInstance] getBridge]];
  284. if (controller == nil)
  285. {
  286. [RCCManagerModule handleRCTPromiseRejectBlock:reject
  287. error:[RCCManagerModule rccErrorWithCode:RCCManagerModuleCantCreateControllerErrorCode description:@"could not create controller"]];
  288. return;
  289. }
  290. if (layout[@"props"] && [layout[@"props"] isKindOfClass:[NSDictionary class]] && layout[@"props"][@"style"] && [layout[@"props"][@"style"] isKindOfClass: [NSDictionary class]]) {
  291. NSDictionary *style = layout[@"props"][@"style"];
  292. if (style[@"modalPresentationStyle"] && [style[@"modalPresentationStyle"] isKindOfClass:[NSString class]]) {
  293. NSString *presentationStyle = style[@"modalPresentationStyle"];
  294. UIModalPresentationStyle modalPresentationStyle = [RCTConvert UIModalPresentationStyle:presentationStyle];
  295. controller.modalPresentationStyle = modalPresentationStyle;
  296. }
  297. }
  298. [[RCCManagerModule lastModalPresenterViewController] presentViewController:controller
  299. animated:![animationType isEqualToString:@"none"]
  300. completion:^(){ resolve(nil); }];
  301. }
  302. - (UIViewController *) getVisibleViewControllerFor:(UIViewController *)vc
  303. {
  304. if ([vc isKindOfClass:[UINavigationController class]])
  305. {
  306. return [self getVisibleViewControllerFor:[((UINavigationController*)vc) visibleViewController]];
  307. }
  308. else if ([vc isKindOfClass:[UITabBarController class]])
  309. {
  310. return [self getVisibleViewControllerFor:[((UITabBarController*)vc) selectedViewController]];
  311. }
  312. else if (vc.presentedViewController)
  313. {
  314. return [self getVisibleViewControllerFor:vc.presentedViewController];
  315. }
  316. else
  317. {
  318. return vc;
  319. }
  320. }
  321. RCT_EXPORT_METHOD(getCurrentlyVisibleScreenId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  322. {
  323. UIViewController *rootVC = [UIApplication sharedApplication].delegate.window.rootViewController;
  324. UIViewController *visibleVC = [self getVisibleViewControllerFor:rootVC];
  325. NSString *controllerId = [[RCCManager sharedIntance] getIdForController:visibleVC];
  326. id result = (controllerId != nil) ? @{@"screenId": controllerId} : nil;
  327. resolve(result);
  328. }
  329. -(BOOL)viewControllerIsModal:(UIViewController*)viewController
  330. {
  331. BOOL viewControllerIsModal = (viewController.presentingViewController.presentedViewController == viewController)
  332. || ((viewController.navigationController != nil) && (viewController.navigationController.presentingViewController.presentedViewController == viewController.navigationController) && (viewController == viewController.navigationController.viewControllers[0]))
  333. || ([viewController.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]]);
  334. return viewControllerIsModal;
  335. }
  336. RCT_EXPORT_METHOD(
  337. dismissController:(NSString*)animationType resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  338. {
  339. UIViewController* vc = [RCCManagerModule lastModalPresenterViewController];
  340. if ([self viewControllerIsModal:vc])
  341. {
  342. [[RCCManager sharedIntance] unregisterController:vc];
  343. [vc dismissViewControllerAnimated:![animationType isEqualToString:@"none"]
  344. completion:^(){ resolve(nil); }];
  345. }
  346. else
  347. {
  348. resolve(nil);
  349. }
  350. }
  351. RCT_EXPORT_METHOD(
  352. dismissAllControllers:(NSString*)animationType resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  353. {
  354. if([UIApplication sharedApplication].delegate.window.rootViewController.presentedViewController == nil)
  355. {//if there are no modal - do nothing
  356. resolve(nil);
  357. return;
  358. }
  359. NSMutableArray *allPresentedViewControllers = [NSMutableArray array];
  360. [RCCManagerModule modalPresenterViewControllers:allPresentedViewControllers];
  361. BOOL animated = ![animationType isEqualToString:@"none"];
  362. if (animated)
  363. {
  364. id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
  365. UIView *snapshot = [appDelegate.window snapshotViewAfterScreenUpdates:NO];
  366. [appDelegate.window addSubview:snapshot];
  367. [self dismissAllModalPresenters:allPresentedViewControllers resolver:^(id result)
  368. {
  369. [self animateSnapshot:snapshot animationType:animationType resolver:resolve];
  370. }];
  371. }
  372. else
  373. {
  374. [self dismissAllModalPresenters:allPresentedViewControllers resolver:resolve];
  375. }
  376. }
  377. RCT_EXPORT_METHOD(
  378. showNotification:(NSDictionary*)params resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  379. {
  380. [RCCNotification showWithParams:params resolver:resolve rejecter:reject];
  381. }
  382. RCT_EXPORT_METHOD(
  383. dismissNotification:(NSDictionary*)params resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
  384. {
  385. [RCCNotification dismissWithParams:params resolver:resolve rejecter:reject];
  386. }
  387. RCT_EXPORT_METHOD(
  388. cancelAllReactTouches)
  389. {
  390. [RCCManagerModule cancelAllRCCViewControllerReactTouches];
  391. }
  392. @end