react-native-navigation的迁移库

RCCManagerModule.m 18KB

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