ReactNative iOS多个Modal冲突问题
2021-12-06 本文已影响0人
li_礼光
RN的modal在iOS的系统中多次调用, 会导致RCTModalHostView不能正确的移除.
Modal冲突系统报错
2021-12-06 15:51:35.013675+0800 AqaraHome[1499:355873] [Presentation] Attempt to present <RCTModalHostViewController: 0x111013d50> on <LHTabbarViewController: 0x10c844600> (from <LHRNRootViewController: 0x10c9d4c00>) which is already presenting <RCTModalHostViewController: 0x149b35a50>.
利用Hook方式解决
简单的思路, 创建一个modal专用队列, 循序执行.
LHRNModalHookManager.h
//
// LHRNModalHookManager.h
// AqaraHome
//
// Created by 礼光 on 2021/12/6.
// Copyright © 2021 Lumi United Technology Co., Ltd. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LHRNModalHookManager : NSObject
@end
NS_ASSUME_NONNULL_END
LHRNModalHookManager.m
//
// LHRNModalHookManager.m
// AqaraHome
//
// Created by 礼光 on 2021/12/6.
// Copyright © 2021 Lumi United Technology Co., Ltd. All rights reserved.
//
#import "LHRNModalHookManager.h"
#import <objc/message.h>
@interface LHRNModalHookManager()
@property (nonatomic, strong) NSOperationQueue *modelQueue;
@property (nonatomic, strong) NSMutableArray <UIViewController *> *presentVCs;
@property (nonatomic, assign) bool isModal;
@end
@implementation LHRNModalHookManager
+ (void)load {
Method presentOldMethod = class_getInstanceMethod(NSClassFromString(@"RCTModalHostViewManager"), @selector(presentModalHostView:withViewController:animated:));
Method presentNewMethod = class_getInstanceMethod(NSClassFromString(@"LHRNModalHookManager"), @selector(presentHookModalHostView:withViewController:animated:));
method_exchangeImplementations(presentOldMethod, presentNewMethod);
Method dismissOldMethod = class_getInstanceMethod(NSClassFromString(@"RCTModalHostViewManager"), @selector(dismissModalHostView:withViewController:animated:));
Method dismissNewMethod = class_getInstanceMethod(NSClassFromString(@"LHRNModalHookManager"), @selector(dismissHookModalHostView:withViewController:animated:));
method_exchangeImplementations(dismissOldMethod, dismissNewMethod);
}
- (void)presentHookModalHostView:(id)modalHostView
withViewController:(id)viewController
animated:(BOOL)animated {
dispatch_block_t completionBlock = ^{ };
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:[LHRNModalHookManager shareInstance]
selector:@selector(operationPresentViewController:)
object:@[viewController, completionBlock]];
[[LHRNModalHookManager shareInstance].presentVCs addObject:viewController];
[[LHRNModalHookManager shareInstance].modelQueue addOperation:op];
}
- (void)dismissHookModalHostView:(id)modalHostView
withViewController:(id)viewController
animated:(BOOL)animated
{
UIViewController *vc = (UIViewController *)[LHRNModalHookManager shareInstance].presentVCs.firstObject;
[vc dismissViewControllerAnimated:NO completion:nil];
[[LHRNModalHookManager shareInstance].presentVCs removeObject:vc];
[[LHRNModalHookManager shareInstance].modelQueue setSuspended:NO];
if ([LHRNModalHookManager shareInstance].presentVCs.count == 0) {
[LHRNModalHookManager shareInstance].isModal = NO;
}
}
+ (instancetype)shareInstance {
static LHRNModalHookManager * manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[LHRNModalHookManager alloc] init];
manager.modelQueue = [[NSOperationQueue alloc] init];
manager.presentVCs = [NSMutableArray array];
});
return manager;
}
- (void)presentViewController:(UIViewController *)viewControllerToPresent
completion:(void (^ )(void))completion {
id comp = completion;
if (comp == nil) {
comp = ^(){};
}
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:[LHRNModalHookManager shareInstance]
selector:@selector(operationPresentViewController:)
object:@[viewControllerToPresent, comp]];
[[LHRNModalHookManager shareInstance].modelQueue addOperation:op];
}
- (void)operationPresentViewController:(id)args {
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *params = (NSArray *)args;
UIViewController *presentVC = params[0];
id completion = params[1];
UIWindow *keyWin = (UIWindow *)[[[UIApplication sharedApplication] windows] objectAtIndex:0];
presentVC.view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.2];
presentVC.modalPresentationStyle = UIModalPresentationFullScreen | UIModalPresentationOverCurrentContext;
presentVC.hidesBottomBarWhenPushed = false;
[keyWin.rootViewController presentViewController:presentVC animated:NO completion:completion];
[[LHRNModalHookManager shareInstance].modelQueue setSuspended:YES];
[LHRNModalHookManager shareInstance].isModal = YES;
});
}
@end
需要考虑的是, 兼容性的问题.