Skip to content

Commit

Permalink
[feature/flat-mdm-settings] Support for MDM setting hierarchies with …
Browse files Browse the repository at this point in the history
…flat keys (#904)

* - automatic termination + relaunch by notification on MDM changes push
- fix indentation

* - react to setting changes pushed via MDM differently, in a two-step process
	- first notify the user about the changes
	- if the user taps the notification, schedule a relaunch notification and then quit
	- if the user taps the relaunch notification, the app is launched
- request authorization to post notifications if needed
  • Loading branch information
felix-schwarz authored Mar 1, 2021
1 parent a30dfd5 commit 43eaa9c
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 20 deletions.
49 changes: 41 additions & 8 deletions ownCloud/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return true
}

// If the app was re-installed, make sure to wipe keychain data. Since iOS 10.3 keychain entries are not deleted if the app is deleted, but since everything else is lost,
// it might lead to some inconsistency in the app state. Nevertheless we shall be careful here and consider that prior versions of the app didn't have the flag created upon
// very first app launch in UserDefaults. Thus we will check few more factors: no bookmarks configured and no passcode is set
if OCBookmarkManager.shared.bookmarks.count == 0 && AppLockManager.shared.lockEnabled == false {
VendorServices.shared.onFirstLaunch {
OCAppIdentity.shared.keychain?.wipe()
}
}
// If the app was re-installed, make sure to wipe keychain data. Since iOS 10.3 keychain entries are not deleted if the app is deleted, but since everything else is lost,
// it might lead to some inconsistency in the app state. Nevertheless we shall be careful here and consider that prior versions of the app didn't have the flag created upon
// very first app launch in UserDefaults. Thus we will check few more factors: no bookmarks configured and no passcode is set
if OCBookmarkManager.shared.bookmarks.count == 0 && AppLockManager.shared.lockEnabled == false {
VendorServices.shared.onFirstLaunch {
OCAppIdentity.shared.keychain?.wipe()
}
}

setupAndHandleCrashReports()

setupMDMPushRelaunch()

return true
}

Expand Down Expand Up @@ -271,3 +273,34 @@ extension AppDelegate {
crashReporter.enable()
}
}

extension AppDelegate : NotificationResponseHandler {
func setupMDMPushRelaunch() {
NotificationCenter.default.addObserver(self, selector: #selector(offerRelaunchAfterMDMPush), name: .OCClassSettingsManagedSettingsChanged, object: nil)
}

@objc func offerRelaunchAfterMDMPush() {
NotificationManager.shared.requestAuthorization(options: [.alert, .sound], completionHandler: { (granted, _) in
if granted {
let content = UNMutableNotificationContent()

content.title = "New settings received from MDM".localized
content.body = "Tap to quit the app.".localized

let request = UNNotificationRequest(identifier: NotificationManagerComposeIdentifier(AppDelegate.self, "terminate-app"), content: content, trigger: nil)

NotificationManager.shared.add(request, withCompletionHandler: { (_) in })
}
})
}

static func handle(_ center: UNUserNotificationCenter, response: UNNotificationResponse, identifier: String, completionHandler: @escaping () -> Void) {
if identifier == "terminate-app", response.actionIdentifier == UNNotificationDefaultActionIdentifier {
UNUserNotificationCenter.postLocalNotification(with: "mdm-relaunch", title: "Tap to launch the app.".localized, body: nil, after: 0.1) { (error) in
if error == nil {
exit(0)
}
}
}
}
}
5 changes: 5 additions & 0 deletions ownCloud/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -846,3 +846,8 @@
"Limited Photo Access" = "Limited Photo Access";
"Access for the media selected for upload is limited" = "Access for the media selected for upload is limited";
"No Access to the media selected for upload" = "No Access to the media selected for upload";

/* MDM settings push */
"New settings received from MDM" = "New settings received from MDM";
"Tap to quit the app." = "Tap to quit the app.";
"Tap to launch the app." = "Tap to launch the app.";
23 changes: 13 additions & 10 deletions ownCloud/Tasks/UNUserNotificationCenter+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,29 @@
//

/*
* Copyright (C) 2020, ownCloud GmbH.
*
* This code is covered by the GNU Public License Version 3.
*
* For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/
* You should have received a copy of this license along with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.en.html>.
*
*/
* Copyright (C) 2020, ownCloud GmbH.
*
* This code is covered by the GNU Public License Version 3.
*
* For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/
* You should have received a copy of this license along with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.en.html>.
*
*/

import UserNotifications
import ownCloudApp

extension UNUserNotificationCenter {
class func postLocalNotification(with identifier:String, title:String, body:String, after:TimeInterval = 0.5, completion:((Error?) -> Void)? = nil) {
class func postLocalNotification(with identifier:String, title:String, body:String?, after:TimeInterval = 0.5, completion:((Error?) -> Void)? = nil) {
NotificationManager.shared.getNotificationSettings(completionHandler: { (settings) in
if settings.authorizationStatus == .authorized {
let content = UNMutableNotificationContent()

content.title = title
content.body = body

if let body = body {
content.body = body
}

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: after, repeats: false)

Expand Down
3 changes: 2 additions & 1 deletion ownCloudAppFramework/Notifications/NotificationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)requestAuthorizationWithOptions:(UNAuthorizationOptions)options completionHandler:(void (^)(BOOL granted, NSError *__nullable error))completionHandler;
@end

#define ComposeNotificationIdentifier(aClass,identifier) [NSStringFromClass(aClass.class) stringByAppendingFormat:@":%@", identifier]
NSString *NotificationManagerComposeIdentifier(Class aClass, NSString *identifier);
#define ComposeNotificationIdentifier(aClass,identifier) NotificationManagerComposeIdentifier(aClass.class, identifier)

@protocol NotificationResponseHandler <NSObject>
+ (void)handleNotificationCenter:(UNUserNotificationCenter *)center response:(UNNotificationResponse *)response identifier:(NSString *)identifier completionHandler:(dispatch_block_t)completionHandler;
Expand Down
5 changes: 5 additions & 0 deletions ownCloudAppFramework/Notifications/NotificationManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,8 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNoti
}

@end

NSString *NotificationManagerComposeIdentifier(Class aClass, NSString *identifier)
{
return ([NSStringFromClass(aClass) stringByAppendingFormat:@":%@", identifier]);
}

0 comments on commit 43eaa9c

Please sign in to comment.