react-native-navigation的迁移库

RCCManagerModule.m 21KB

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