react-native-navigation的迁移库

RCCManagerModule.m 21KB

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