Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion demo/GYBootingProtectionDemo/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ @implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

NSLog(@"------------ Root view did load ------------");
_button = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 200, 30)];
[self.button setTitle:@"Make a crash" forState:UIControlStateNormal];
[self.button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[self.button addTarget:self action:@selector(pressedButton) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.button];
// [self pressedButton];
}

- (void)pressedButton {
Expand Down
32 changes: 28 additions & 4 deletions src/AppDelegate+GYBootingProtection.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,25 @@
static NSString *const cancelButtonTitle = @"取消";
static NSString *const createCrashButtonTitle = @"制造Crash!";
static NSString *const mainStoryboardInfoKey = @"UIMainStoryboardFile";
static const char *kOriginalControllerKey = "kOriginalControllerKey";

@interface AppDelegate()
@property (nonatomic, strong) UIViewController *originalRootViewController;
@end

@implementation AppDelegate (GYBootingProtection)

- (UIViewController *)originalRootViewController {
return objc_getAssociatedObject(self, kOriginalControllerKey);
}

- (void)setOriginalRootViewController:(UIViewController *)originalRootViewController {
objc_setAssociatedObject(self,
kOriginalControllerKey,
originalRootViewController,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

/*
* 连续闪退检测前需要执行的逻辑,如上报统计初始化
*/
Expand All @@ -35,8 +51,8 @@ - (void)onBeforeBootingProtection {
}];

// 彩蛋: 弹 Tips 询问是否制造 crash
[GYBootingProtection setStartupCrashForTest:YES];
[self showAlertForCreateCrashIfNeeded];
// [GYBootingProtection setStartupCrashForTest:YES];
// [self showAlertForCreateCrashIfNeeded];
}


Expand All @@ -54,6 +70,7 @@ - (void)onBootingProtection {
- (void)onBootingProtectionWithCompletion:(BoolCompletionBlock)completion {
[self onBootingProtection];
#pragma mark TODO 如果需要异步修复,在完成后调用 completion

// 正常启动流程
if (completion) completion();
}
Expand All @@ -71,7 +88,10 @@ - (BOOL)swizzled_application:(UIApplication *)application didFinishLaunchingWith
/* ------- 启动连续闪退保护 ------- */

[GYBootingProtection setBoolCompletionBlock:^BOOL{

if (self.originalRootViewController) {
NSLog(@"-------- Orininal root controller: %@", self.originalRootViewController);
self.window.rootViewController = self.originalRootViewController;
}
// 原 didFinishLaunch 正常启动流程
return [self swizzled_application:application didFinishLaunchingWithOptions:launchOptions];
}];
Expand Down Expand Up @@ -132,9 +152,13 @@ - (void)showAlertForCreateCrashIfNeeded {
*/
- (void)presentAlertViewController:(UIAlertController *)alertController {
if (![self hasStoryboardInfo]) {
// 不使用 storyboard 时,真正的 rootController 会在原 didFinishLaunch 中初始化,不需要额外处理
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = [[UIViewController alloc] init];
} else {
// 使用 storyboard 时,需要把 rootController 存下来,待修复完成后,重新设置 self.window.rootViewController
self.originalRootViewController = self.window.rootViewController;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这样写有一个前提,rootViewController在初始化的时候不会crash

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你是说在 rootViewController 的 initWithCoder 里有崩溃的逻辑么,这种情况我暂时没找到解决的办法,因为这种情况在 didFinishLaunching 调用前就已经 crash 了……用这个库的思路(Method Swizzling 动态替换 didFinishLaunching 方法)解决不了这种问题。不过我觉得这种情况应该也很少发生,使用 sb 的话很少会去重写 rootViewController 的 initWithCoder 方法吧。可以在 README 中向使用者说明一下这种情况。

}
self.window.rootViewController = [[UIViewController alloc] init];
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
}
Expand Down