1 // Copyright 2015-present 650 Industries. All rights reserved. 2 3 import Foundation 4 import EXManifests 5 6 let RECENTLY_OPENED_APPS_REGISTRY_KEY = "expo.devlauncher.recentlyopenedapps" 7 8 let TIME_TO_REMOVE = 1_000 * 60 * 60 * 24 * 3 // 3 days 9 10 @objc(EXDevLauncherRecentlyOpenedAppsRegistry) 11 public class EXDevLauncherRecentlyOpenedAppsRegistry: NSObject { 12 private var appRegistry: [String: Any] { 13 get { 14 return UserDefaults.standard.dictionary(forKey: RECENTLY_OPENED_APPS_REGISTRY_KEY) ?? [String: Any]() 15 } 16 set (newAppRegistry) { 17 UserDefaults.standard.set(newAppRegistry, forKey: RECENTLY_OPENED_APPS_REGISTRY_KEY) 18 } 19 } 20 21 @objc appWasOpenednull22 public func appWasOpened(_ url: String, queryParams: [String: String], manifest: Manifest?) { 23 var appEntry: [String: Any] = [:] 24 25 // reloading the same url - update the old entry w/ any new fields instead of creating a new one 26 if let previousMatchingEntry = appRegistry[url] { 27 appEntry = previousMatchingEntry as! [String : Any] 28 } 29 30 let timestamp = getCurrentTimestamp() 31 32 var isEASUpdate = false 33 34 if let host = URL(string:url)?.host { 35 isEASUpdate = host == "u.expo.dev" || host == "staging-u.expo.dev" 36 } 37 38 appEntry["isEASUpdate"] = isEASUpdate 39 40 if isEASUpdate { 41 if let updateMessage = queryParams["updateMessage"] { 42 appEntry["updateMessage"] = updateMessage 43 } 44 } 45 46 if let manifest = manifest { 47 appEntry["name"] = manifest.name() 48 49 // TODO - expose metadata object in expo-manifests 50 let json = manifest.rawManifestJSON() 51 52 if (isEASUpdate) { 53 if let metadata: [String: Any] = json["metadata"] as? [String : Any], let branchName = metadata["branchName"] { 54 appEntry["branchName"] = branchName; 55 } 56 } 57 } 58 59 appEntry["timestamp"] = timestamp 60 appEntry["url"] = url 61 62 var registry = appRegistry 63 registry[url] = appEntry 64 appRegistry = registry 65 } 66 67 @objc recentlyOpenedAppsnull68 public func recentlyOpenedApps() -> [[String: Any]] { 69 guard let registry = appRegistry as? [String: [String: Any]] else { 70 return [] 71 } 72 73 var apps: [[String: Any]] = [] 74 75 appRegistry = registry.filter { (url: String, appEntry: [String: Any]) in 76 if getCurrentTimestamp() - (appEntry["timestamp"] as! Int64) > TIME_TO_REMOVE { 77 return false 78 } 79 80 apps.append(appEntry) 81 return true 82 } 83 84 return apps 85 } 86 87 @objc mostRecentAppnull88 public func mostRecentApp() -> [String: Any]? { 89 let recentlyOpenedApps = self.recentlyOpenedApps() 90 91 if let mostRecentApp = recentlyOpenedApps.max(by: { ($0["timestamp"] as? Int64) ?? 0 < ($1["timestamp"] as? Int64) ?? 0 }) { 92 return mostRecentApp 93 } 94 95 return nil 96 } 97 98 @objc clearRegistrynull99 public func clearRegistry() { 100 resetStorage() 101 } 102 getCurrentTimestampnull103 func getCurrentTimestamp() -> Int64 { 104 return Int64(Date().timeIntervalSince1970 * 1_000) 105 } 106 resetStoragenull107 func resetStorage() { 108 UserDefaults.standard.removeObject(forKey: RECENTLY_OPENED_APPS_REGISTRY_KEY) 109 } 110 } 111