iOS UILocalNotification 的操作按钮崩溃并损坏了应用程序数据
iOS UILocalNotification's action button crashes and corrupts app data
我们的应用程序已发布小更新,此版本还通过 Apple 支持将其应用程序 ID 从唯一 ID 更改为我们的团队 ID。
According to Apple,更改为使用团队 ID 应该只会重置钥匙串访问权限,我们不使用钥匙串,因此它不会对我们的应用产生任何影响。
但是自更新发布以来,一些 生产用户的应用程序数据遭到损坏。只有当他们使用通知中心或锁定屏幕中的操作按钮响应本地通知时,才会发生这种情况。它可能发生在所有支持的 iOS 版本上。
遇到这种情况的用户有另一种症状,他们收到两个本地通知而不是一个,但应用程序只看到一个通知。此外,在使用 [[UIApplication sharedApplication] cancelAllLocalNotifications]
禁用通知和取消后,这些通知仍然不会消失。
这些重复的通知是在从 App Store 更新应用程序之前安排的,但更新后应用程序对某些用户失去了对它们的控制。详细描述了此问题 in this question。
最大的线索可能在于从 Apple 收到的崩溃报告 -
Incident Identifier: ED0E9C.............74B38C
CrashReporter Key: ae05b............dbc46
Hardware Model: iPhone4,1
Process: MY_APP [444]
Path: /private/var/mobile/Containers/Bundle/Application/65324..................8616/MY_APP.app/MY_APP
Identifier: com.mycompany.myapp
Version: X.X
Code Type: ARM (Native)
Parent Process: launchd [1]
Date/Time: 2015-10-27 21:45:24.24 -0500
Launch Time: 2015-10-27 21:45:20.20 -0500
OS Version: iOS 9.1 (13B143)
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x244b3676 __exceptionPreprocess + 122 (NSException.m:162)
1 libobjc.A.dylib 0x3582ee12 objc_exception_throw + 34 (objc-exception.mm:531)
2 CoreFoundation 0x244b354c +[NSException raise:format:arguments:] + 100 (NSException.m:131)
3 Foundation 0x25240bc4 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 88 (NSException.m:152)
4 UIKit 0x28840754 -[UIApplication _runWithMainScene:transitionContext:completion:] + 2928 (UIApplication.m:3299)
5 UIKit 0x28853a48 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke3218 + 32 (UIApplication.m:11920)
6 UIKit 0x2883d71e -[UIApplication workspaceDidEndTransaction:] + 130 (UIApplication.m:2648)
7 FrontBoardServices 0x2c52dca2 -[FBSSerialQueue _performNext] + 226 (FBSSerialQueue.m:157)
8 FrontBoardServices 0x2c52df94 -[FBSSerialQueue _performNextFromRunLoopSource] + 44 (FBSSerialQueue.m:204)
9 CoreFoundation 0x24476bfa __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 10 (CFRunLoop.c:1761)
10 CoreFoundation 0x244767e8 __CFRunLoopDoSources0 + 448 (CFRunLoop.c:1807)
11 CoreFoundation 0x24474b56 __CFRunLoopRun + 790 (CFRunLoop.c:2536)
12 CoreFoundation 0x243c8114 CFRunLoopRunSpecific + 516 (CFRunLoop.c:2814)
13 CoreFoundation 0x243c7f00 CFRunLoopRunInMode + 104 (CFRunLoop.c:2844)
14 UIKit 0x28610208 -[UIApplication _run] + 520 (UIApplication.m:2489)
15 UIKit 0x2860af10 UIApplicationMain + 140 (UIApplication.m:3665)
16 MY_APP 0xc4972 main + 22 (main.m:14)
17 libdyld.dylib 0x35f9d86e tlv_get_addr + 42 (threadLocalHelpers.s:310)
它有一个与 this question 中完全相同的堆栈跟踪,当用户响应推送通知时会发生这种情况。应用程序加载期间崩溃可能解释了应用程序数据损坏。
正如在堆栈跟踪中看到的,这次崩溃不是由我们的代码引起的,我们没有更改代码中的任何内容,它在 App ID 更改之前一直运行良好,并且发生在我们约 2% 的用户身上。
这是处理通知操作按钮的代码 -
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler {
@try {
if (notification) {
NSDate *alarmTime = notification.userInfo ? [notification.userInfo objectForKey:@"time"] : nil;
[logic saveAlarmTime:alarmTime takenAt:[NSDate date]];
}
}
@catch (NSException *exception) {
NSLog(@"Exception: %@", [exception description]);
}
@finally {
completionHandler();
}
}
导致此崩溃的原因是什么?
(我知道它被扔进了 -[UIApplication _runWithMainScene:transitionContext:completion:] + 2928 (UIApplication.m:3299)
,问题是里面有什么导致它崩溃。)
此行导致崩溃:
[UIApplication _runWithMainScene:transitionContext:completion:] + 2928 (UIApplication.m:3299)
如果团队更改应用程序,则该应用程序的唯一应用程序标识符也会更改,因为它是应用程序的一部分。本地通知使用唯一的应用标识符。所以它基本上确实是 Apple 的一个错误,因为 iOS 应该识别一个没有更多相应应用程序的通知。这也是您启动后的崩溃,但您没有获得通常使用的对象。
盲猜,因为我不知道你的代码。响应本地通知时,在继续之前检查对象和所有关联数据是否存在。你知道,比如:
if (object) {
//do the stuff
} else {
// do nothing
}
(恕我直言,比例外情况要好得多...)
至于不再属于您的通知-用户可以自行删除。只要确保你不会崩溃 - 什么都不做就可以了。通常人们会在某个时候自己删除它们,然后他们清理他们的通知中心。
此异常可能与最初通过操作按钮响应通知无关。此堆栈跟踪指示加载应用程序时出现问题,但有多种可能的原因,任何在加载时使应用程序崩溃的情况都会导致此问题。
例如,当应用程序加载且其 window 未分配根视图控制器时,可能会发生这种情况。如果它是使用 addSubview
而不是 setRootViewController
添加的,也可能会发生,如 .
您必须向遇到此崩溃的用户验证他们在做什么,如果他们确实只响应了本地通知操作按钮,或者他们在打开应用程序时遇到了崩溃。
数据损坏的原因是 "Data protection" 选项。它可以从 Xcode 或 iOS 开发人员门户的标识符 -> 应用程序 ID 下启用。
它有三种状态:"Complete Protection"、"Protected Unless Open"和"Protected Until First User Authentication"。只要数据受到保护,即使是应用程序也无法访问数据。
例如,如果在我们的案例中选择了 "Complete Protection",并且像通知的操作按钮这样的后台进程是 运行,由于权限错误,Core Data 将无法访问数据库。
我仍然不确定为什么它会损坏数据,有时不会显示 "Permission defined" 错误,但它仍然无法读取 SQLite 文件。也许它也写在文件上,但由于加密已打开,它损坏了文件。
解决方案是选择 "Protected Until First User Authentication" 或禁用数据保护。
相关的 SO 问题:CoreData errors/exceptions when app work in background mode
我们的应用程序已发布小更新,此版本还通过 Apple 支持将其应用程序 ID 从唯一 ID 更改为我们的团队 ID。
According to Apple,更改为使用团队 ID 应该只会重置钥匙串访问权限,我们不使用钥匙串,因此它不会对我们的应用产生任何影响。
但是自更新发布以来,一些 生产用户的应用程序数据遭到损坏。只有当他们使用通知中心或锁定屏幕中的操作按钮响应本地通知时,才会发生这种情况。它可能发生在所有支持的 iOS 版本上。
遇到这种情况的用户有另一种症状,他们收到两个本地通知而不是一个,但应用程序只看到一个通知。此外,在使用 [[UIApplication sharedApplication] cancelAllLocalNotifications]
禁用通知和取消后,这些通知仍然不会消失。
这些重复的通知是在从 App Store 更新应用程序之前安排的,但更新后应用程序对某些用户失去了对它们的控制。详细描述了此问题 in this question。
最大的线索可能在于从 Apple 收到的崩溃报告 -
Incident Identifier: ED0E9C.............74B38C
CrashReporter Key: ae05b............dbc46
Hardware Model: iPhone4,1
Process: MY_APP [444]
Path: /private/var/mobile/Containers/Bundle/Application/65324..................8616/MY_APP.app/MY_APP
Identifier: com.mycompany.myapp
Version: X.X
Code Type: ARM (Native)
Parent Process: launchd [1]
Date/Time: 2015-10-27 21:45:24.24 -0500
Launch Time: 2015-10-27 21:45:20.20 -0500
OS Version: iOS 9.1 (13B143)
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x244b3676 __exceptionPreprocess + 122 (NSException.m:162)
1 libobjc.A.dylib 0x3582ee12 objc_exception_throw + 34 (objc-exception.mm:531)
2 CoreFoundation 0x244b354c +[NSException raise:format:arguments:] + 100 (NSException.m:131)
3 Foundation 0x25240bc4 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 88 (NSException.m:152)
4 UIKit 0x28840754 -[UIApplication _runWithMainScene:transitionContext:completion:] + 2928 (UIApplication.m:3299)
5 UIKit 0x28853a48 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke3218 + 32 (UIApplication.m:11920)
6 UIKit 0x2883d71e -[UIApplication workspaceDidEndTransaction:] + 130 (UIApplication.m:2648)
7 FrontBoardServices 0x2c52dca2 -[FBSSerialQueue _performNext] + 226 (FBSSerialQueue.m:157)
8 FrontBoardServices 0x2c52df94 -[FBSSerialQueue _performNextFromRunLoopSource] + 44 (FBSSerialQueue.m:204)
9 CoreFoundation 0x24476bfa __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 10 (CFRunLoop.c:1761)
10 CoreFoundation 0x244767e8 __CFRunLoopDoSources0 + 448 (CFRunLoop.c:1807)
11 CoreFoundation 0x24474b56 __CFRunLoopRun + 790 (CFRunLoop.c:2536)
12 CoreFoundation 0x243c8114 CFRunLoopRunSpecific + 516 (CFRunLoop.c:2814)
13 CoreFoundation 0x243c7f00 CFRunLoopRunInMode + 104 (CFRunLoop.c:2844)
14 UIKit 0x28610208 -[UIApplication _run] + 520 (UIApplication.m:2489)
15 UIKit 0x2860af10 UIApplicationMain + 140 (UIApplication.m:3665)
16 MY_APP 0xc4972 main + 22 (main.m:14)
17 libdyld.dylib 0x35f9d86e tlv_get_addr + 42 (threadLocalHelpers.s:310)
它有一个与 this question 中完全相同的堆栈跟踪,当用户响应推送通知时会发生这种情况。应用程序加载期间崩溃可能解释了应用程序数据损坏。
正如在堆栈跟踪中看到的,这次崩溃不是由我们的代码引起的,我们没有更改代码中的任何内容,它在 App ID 更改之前一直运行良好,并且发生在我们约 2% 的用户身上。
这是处理通知操作按钮的代码 -
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler {
@try {
if (notification) {
NSDate *alarmTime = notification.userInfo ? [notification.userInfo objectForKey:@"time"] : nil;
[logic saveAlarmTime:alarmTime takenAt:[NSDate date]];
}
}
@catch (NSException *exception) {
NSLog(@"Exception: %@", [exception description]);
}
@finally {
completionHandler();
}
}
导致此崩溃的原因是什么?
(我知道它被扔进了 -[UIApplication _runWithMainScene:transitionContext:completion:] + 2928 (UIApplication.m:3299)
,问题是里面有什么导致它崩溃。)
此行导致崩溃:
[UIApplication _runWithMainScene:transitionContext:completion:] + 2928 (UIApplication.m:3299)
如果团队更改应用程序,则该应用程序的唯一应用程序标识符也会更改,因为它是应用程序的一部分。本地通知使用唯一的应用标识符。所以它基本上确实是 Apple 的一个错误,因为 iOS 应该识别一个没有更多相应应用程序的通知。这也是您启动后的崩溃,但您没有获得通常使用的对象。
盲猜,因为我不知道你的代码。响应本地通知时,在继续之前检查对象和所有关联数据是否存在。你知道,比如:
if (object) {
//do the stuff
} else {
// do nothing
}
(恕我直言,比例外情况要好得多...)
至于不再属于您的通知-用户可以自行删除。只要确保你不会崩溃 - 什么都不做就可以了。通常人们会在某个时候自己删除它们,然后他们清理他们的通知中心。
此异常可能与最初通过操作按钮响应通知无关。此堆栈跟踪指示加载应用程序时出现问题,但有多种可能的原因,任何在加载时使应用程序崩溃的情况都会导致此问题。
例如,当应用程序加载且其 window 未分配根视图控制器时,可能会发生这种情况。如果它是使用 addSubview
而不是 setRootViewController
添加的,也可能会发生,如
您必须向遇到此崩溃的用户验证他们在做什么,如果他们确实只响应了本地通知操作按钮,或者他们在打开应用程序时遇到了崩溃。
数据损坏的原因是 "Data protection" 选项。它可以从 Xcode 或 iOS 开发人员门户的标识符 -> 应用程序 ID 下启用。
它有三种状态:"Complete Protection"、"Protected Unless Open"和"Protected Until First User Authentication"。只要数据受到保护,即使是应用程序也无法访问数据。
例如,如果在我们的案例中选择了 "Complete Protection",并且像通知的操作按钮这样的后台进程是 运行,由于权限错误,Core Data 将无法访问数据库。
我仍然不确定为什么它会损坏数据,有时不会显示 "Permission defined" 错误,但它仍然无法读取 SQLite 文件。也许它也写在文件上,但由于加密已打开,它损坏了文件。
解决方案是选择 "Protected Until First User Authentication" 或禁用数据保护。
相关的 SO 问题:CoreData errors/exceptions when app work in background mode