@thelacanians/vue-native-cli 0.4.15 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +329 -15
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +118 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +178 -1
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeneratedModuleRegistry.kt +28 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +3 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ComponentFactoryTest.kt +674 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ErrorOverlayViewTest.kt +183 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/EventThrottleTest.kt +203 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/HotReloadManagerTest.kt +162 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/JSPolyfillsTest.kt +153 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeBridgeTest.kt +6 -3
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeModuleTest.kt +475 -0
- package/native/android/gradle.properties +1 -0
- package/native/android/gradlew +1 -1
- package/native/ios/VueNativeCore/Package.swift +1 -1
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/EventThrottle.swift +1 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +143 -5
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +43 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +116 -4
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +100 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeneratedModuleRegistry.swift +28 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +3 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/CertificatePinningTests.swift +190 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/ComponentFactoryTests.swift +585 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/EventThrottleTests.swift +161 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/HotReloadManagerTests.swift +88 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSPolyfillsTests.swift +319 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/NativeModuleTests.swift +400 -0
- package/native/macos/VueNativeMacOS/Package.swift +34 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/ErrorOverlayView.swift +112 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/EventThrottle.swift +58 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/HotReloadManager.swift +153 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSPolyfills.swift +696 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSRuntime.swift +347 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/NativeBridge.swift +877 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/VueNativeWindowController.swift +125 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/ComponentRegistry.swift +209 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActionSheetFactory.swift +155 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActivityIndicatorFactory.swift +85 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VAlertDialogFactory.swift +132 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VButtonFactory.swift +83 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VCheckboxFactory.swift +108 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VDropdownFactory.swift +155 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VImageFactory.swift +270 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VInputFactory.swift +257 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VKeyboardAvoidingFactory.swift +22 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VListFactory.swift +324 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VModalFactory.swift +231 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VOutlineViewFactory.swift +276 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPickerFactory.swift +134 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPressableFactory.swift +120 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VProgressBarFactory.swift +71 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRadioFactory.swift +193 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRefreshControlFactory.swift +25 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSafeAreaFactory.swift +46 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VScrollViewFactory.swift +190 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSectionListFactory.swift +374 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSegmentedControlFactory.swift +125 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSliderFactory.swift +131 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSplitViewFactory.swift +215 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VStatusBarFactory.swift +25 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSwitchFactory.swift +92 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VTextFactory.swift +336 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VToolbarFactory.swift +212 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VVideoFactory.swift +245 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VViewFactory.swift +314 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VWebViewFactory.swift +162 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/NativeComponentFactory.swift +54 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/ClickableView.swift +100 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/Extensions.swift +23 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/GestureWrapper.swift +183 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/NSColor+Hex.swift +78 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/FlippedView.swift +19 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/LayoutNode.swift +493 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AnimationModule.swift +354 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AppStateModule.swift +62 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/BiometryModule.swift +60 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/CameraModule.swift +167 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ClipboardModule.swift +34 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DeviceInfoModule.swift +49 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DragDropModule.swift +50 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/FileDialogModule.swift +86 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/HapticsModule.swift +42 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/KeyboardModule.swift +28 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/LinkingModule.swift +49 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/MenuModule.swift +95 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NativeModuleRegistry.swift +63 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NotificationsModule.swift +112 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/PermissionsModule.swift +149 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ShareModule.swift +37 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/WindowModule.swift +71 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Resources/vue-native-placeholder.js +2 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Styling/StyleEngine.swift +885 -0
- package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/ComponentFactoryTests.swift +80 -0
- package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/VueNativeMacOSTests.swift +149 -0
- package/native/shared/VueNativeShared/AGENTS.md +129 -0
- package/native/shared/VueNativeShared/Package.swift +14 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/CertificatePinning.swift +134 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/EventThrottle.swift +78 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/HotReloadManager.swift +162 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/JSRuntime.swift +412 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AsyncStorageModule.swift +68 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AudioModule.swift +359 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/DatabaseModule.swift +259 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/FileSystemModule.swift +233 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/GeolocationModule.swift +156 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/NetworkModule.swift +59 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/PerformanceModule.swift +113 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/SecureStorageModule.swift +119 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/WebSocketModule.swift +212 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeEventDispatcher.swift +6 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModule.swift +26 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModuleRegistry.swift +37 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/SharedJSPolyfills.swift +673 -0
- package/native/shared/VueNativeShared/Tests/VueNativeSharedTests/VueNativeSharedTests.swift +44 -0
- package/package.json +8 -2
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// Native module providing file system access.
|
|
4
|
+
///
|
|
5
|
+
/// Methods:
|
|
6
|
+
/// - readFile(path: String, encoding: String?) -> String
|
|
7
|
+
/// - writeFile(path: String, content: String, encoding: String?)
|
|
8
|
+
/// - deleteFile(path: String)
|
|
9
|
+
/// - exists(path: String) -> Bool
|
|
10
|
+
/// - listDirectory(path: String) -> [String]
|
|
11
|
+
/// - downloadFile(url: String, destPath: String) -> String
|
|
12
|
+
/// - getDocumentsPath() -> String
|
|
13
|
+
/// - getCachesPath() -> String
|
|
14
|
+
/// - stat(path: String) -> { size, isDirectory, modified }
|
|
15
|
+
/// - mkdir(path: String)
|
|
16
|
+
/// - copyFile(srcPath: String, destPath: String)
|
|
17
|
+
/// - moveFile(srcPath: String, destPath: String)
|
|
18
|
+
public final class FileSystemModule: NativeModule {
|
|
19
|
+
public let moduleName = "FileSystem"
|
|
20
|
+
|
|
21
|
+
private let fileManager = FileManager.default
|
|
22
|
+
|
|
23
|
+
public init() {}
|
|
24
|
+
|
|
25
|
+
public func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
26
|
+
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
|
27
|
+
guard let self = self else { return }
|
|
28
|
+
switch method {
|
|
29
|
+
case "readFile":
|
|
30
|
+
guard let path = args.first as? String else {
|
|
31
|
+
callback(nil, "readFile: missing path")
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
let encoding = (args.count > 1 ? args[1] as? String : nil) ?? "utf8"
|
|
35
|
+
guard self.fileManager.fileExists(atPath: path) else {
|
|
36
|
+
callback(nil, "readFile: file not found at \(path)")
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
guard let data = self.fileManager.contents(atPath: path) else {
|
|
40
|
+
callback(nil, "readFile: could not read file at \(path)")
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
if encoding == "base64" {
|
|
44
|
+
callback(data.base64EncodedString(), nil)
|
|
45
|
+
} else {
|
|
46
|
+
guard let text = String(data: data, encoding: .utf8) else {
|
|
47
|
+
callback(nil, "readFile: file is not valid UTF-8")
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
callback(text, nil)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
case "writeFile":
|
|
54
|
+
guard args.count >= 2,
|
|
55
|
+
let path = args[0] as? String,
|
|
56
|
+
let content = args[1] as? String else {
|
|
57
|
+
callback(nil, "writeFile: missing path or content")
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
let encoding = (args.count > 2 ? args[2] as? String : nil) ?? "utf8"
|
|
61
|
+
let data: Data?
|
|
62
|
+
if encoding == "base64" {
|
|
63
|
+
data = Data(base64Encoded: content)
|
|
64
|
+
} else {
|
|
65
|
+
data = content.data(using: .utf8)
|
|
66
|
+
}
|
|
67
|
+
guard let fileData = data else {
|
|
68
|
+
callback(nil, "writeFile: could not encode content")
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
// Create parent directory if needed
|
|
72
|
+
let dir = (path as NSString).deletingLastPathComponent
|
|
73
|
+
if !self.fileManager.fileExists(atPath: dir) {
|
|
74
|
+
do {
|
|
75
|
+
try self.fileManager.createDirectory(atPath: dir, withIntermediateDirectories: true)
|
|
76
|
+
} catch {
|
|
77
|
+
callback(nil, "writeFile: could not create directory: \(error.localizedDescription)")
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
self.fileManager.createFile(atPath: path, contents: fileData)
|
|
82
|
+
callback(nil, nil)
|
|
83
|
+
|
|
84
|
+
case "deleteFile":
|
|
85
|
+
guard let path = args.first as? String else {
|
|
86
|
+
callback(nil, "deleteFile: missing path")
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
guard self.fileManager.fileExists(atPath: path) else {
|
|
90
|
+
callback(nil, "deleteFile: file not found at \(path)")
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
do {
|
|
94
|
+
try self.fileManager.removeItem(atPath: path)
|
|
95
|
+
callback(nil, nil)
|
|
96
|
+
} catch {
|
|
97
|
+
callback(nil, "deleteFile: \(error.localizedDescription)")
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
case "exists":
|
|
101
|
+
guard let path = args.first as? String else {
|
|
102
|
+
callback(nil, "exists: missing path")
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
callback(self.fileManager.fileExists(atPath: path), nil)
|
|
106
|
+
|
|
107
|
+
case "listDirectory":
|
|
108
|
+
guard let path = args.first as? String else {
|
|
109
|
+
callback(nil, "listDirectory: missing path")
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
do {
|
|
113
|
+
let contents = try self.fileManager.contentsOfDirectory(atPath: path)
|
|
114
|
+
callback(contents, nil)
|
|
115
|
+
} catch {
|
|
116
|
+
callback(nil, "listDirectory: \(error.localizedDescription)")
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
case "downloadFile":
|
|
120
|
+
guard args.count >= 2,
|
|
121
|
+
let urlString = args[0] as? String,
|
|
122
|
+
let destPath = args[1] as? String else {
|
|
123
|
+
callback(nil, "downloadFile: missing url or destPath")
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
guard let url = URL(string: urlString) else {
|
|
127
|
+
callback(nil, "downloadFile: invalid URL")
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
let task = URLSession.shared.dataTask(with: url) { data, response, error in
|
|
131
|
+
if let error = error {
|
|
132
|
+
callback(nil, "downloadFile: \(error.localizedDescription)")
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
guard let data = data else {
|
|
136
|
+
callback(nil, "downloadFile: no data received")
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
// Create parent directory if needed
|
|
140
|
+
let dir = (destPath as NSString).deletingLastPathComponent
|
|
141
|
+
if !self.fileManager.fileExists(atPath: dir) {
|
|
142
|
+
do {
|
|
143
|
+
try self.fileManager.createDirectory(atPath: dir, withIntermediateDirectories: true)
|
|
144
|
+
} catch {
|
|
145
|
+
callback(nil, "downloadFile: could not create directory: \(error.localizedDescription)")
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
self.fileManager.createFile(atPath: destPath, contents: data)
|
|
150
|
+
callback(destPath, nil)
|
|
151
|
+
}
|
|
152
|
+
task.resume()
|
|
153
|
+
|
|
154
|
+
case "getDocumentsPath":
|
|
155
|
+
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
|
|
156
|
+
callback(paths.first, nil)
|
|
157
|
+
|
|
158
|
+
case "getCachesPath":
|
|
159
|
+
let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)
|
|
160
|
+
callback(paths.first, nil)
|
|
161
|
+
|
|
162
|
+
case "stat":
|
|
163
|
+
guard let path = args.first as? String else {
|
|
164
|
+
callback(nil, "stat: missing path")
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
do {
|
|
168
|
+
let attrs = try self.fileManager.attributesOfItem(atPath: path)
|
|
169
|
+
let size = (attrs[.size] as? Int) ?? 0
|
|
170
|
+
let isDir = (attrs[.type] as? FileAttributeType) == .typeDirectory
|
|
171
|
+
let modified = (attrs[.modificationDate] as? Date)?.timeIntervalSince1970 ?? 0
|
|
172
|
+
callback([
|
|
173
|
+
"size": size,
|
|
174
|
+
"isDirectory": isDir,
|
|
175
|
+
"modified": modified * 1000 // milliseconds for JS
|
|
176
|
+
] as [String: Any], nil)
|
|
177
|
+
} catch {
|
|
178
|
+
callback(nil, "stat: \(error.localizedDescription)")
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
case "mkdir":
|
|
182
|
+
guard let path = args.first as? String else {
|
|
183
|
+
callback(nil, "mkdir: missing path")
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
do {
|
|
187
|
+
try self.fileManager.createDirectory(atPath: path, withIntermediateDirectories: true)
|
|
188
|
+
callback(nil, nil)
|
|
189
|
+
} catch {
|
|
190
|
+
callback(nil, "mkdir: \(error.localizedDescription)")
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
case "copyFile":
|
|
194
|
+
guard args.count >= 2,
|
|
195
|
+
let srcPath = args[0] as? String,
|
|
196
|
+
let destPath = args[1] as? String else {
|
|
197
|
+
callback(nil, "copyFile: missing srcPath or destPath")
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
do {
|
|
201
|
+
// Remove destination if it exists (copyItem throws if dest exists)
|
|
202
|
+
if self.fileManager.fileExists(atPath: destPath) {
|
|
203
|
+
try self.fileManager.removeItem(atPath: destPath)
|
|
204
|
+
}
|
|
205
|
+
try self.fileManager.copyItem(atPath: srcPath, toPath: destPath)
|
|
206
|
+
callback(nil, nil)
|
|
207
|
+
} catch {
|
|
208
|
+
callback(nil, "copyFile: \(error.localizedDescription)")
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
case "moveFile":
|
|
212
|
+
guard args.count >= 2,
|
|
213
|
+
let srcPath = args[0] as? String,
|
|
214
|
+
let destPath = args[1] as? String else {
|
|
215
|
+
callback(nil, "moveFile: missing srcPath or destPath")
|
|
216
|
+
return
|
|
217
|
+
}
|
|
218
|
+
do {
|
|
219
|
+
if self.fileManager.fileExists(atPath: destPath) {
|
|
220
|
+
try self.fileManager.removeItem(atPath: destPath)
|
|
221
|
+
}
|
|
222
|
+
try self.fileManager.moveItem(atPath: srcPath, toPath: destPath)
|
|
223
|
+
callback(nil, nil)
|
|
224
|
+
} catch {
|
|
225
|
+
callback(nil, "moveFile: \(error.localizedDescription)")
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
default:
|
|
229
|
+
callback(nil, "FileSystemModule: Unknown method '\(method)'")
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import CoreLocation
|
|
3
|
+
|
|
4
|
+
/// Native module for GPS/location access.
|
|
5
|
+
/// Uses CoreLocation which is available on both iOS and macOS.
|
|
6
|
+
///
|
|
7
|
+
/// Methods:
|
|
8
|
+
/// - getCurrentPosition() -> location payload
|
|
9
|
+
/// - watchPosition() -> watchId (Int); fires "location:update" global events
|
|
10
|
+
/// - clearWatch(watchId: Int)
|
|
11
|
+
///
|
|
12
|
+
/// Location payload keys: latitude, longitude, altitude, accuracy,
|
|
13
|
+
/// altitudeAccuracy, heading, speed, timestamp
|
|
14
|
+
public final class GeolocationModule: NativeModule {
|
|
15
|
+
public var moduleName: String { "Geolocation" }
|
|
16
|
+
private weak var eventDispatcher: NativeEventDispatcher?
|
|
17
|
+
|
|
18
|
+
public init(eventDispatcher: NativeEventDispatcher) {
|
|
19
|
+
self.eventDispatcher = eventDispatcher
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
23
|
+
switch method {
|
|
24
|
+
case "getCurrentPosition":
|
|
25
|
+
DispatchQueue.main.async {
|
|
26
|
+
GeolocationManager.shared.getCurrentPosition(callback: callback)
|
|
27
|
+
}
|
|
28
|
+
case "watchPosition":
|
|
29
|
+
let weakDispatcher = eventDispatcher
|
|
30
|
+
DispatchQueue.main.async {
|
|
31
|
+
let watchId = GeolocationManager.shared.watchPosition(eventDispatcher: weakDispatcher)
|
|
32
|
+
callback(watchId, nil)
|
|
33
|
+
}
|
|
34
|
+
case "clearWatch":
|
|
35
|
+
guard let watchId = args.first.flatMap({ $0 as? Int }) else {
|
|
36
|
+
callback(nil, nil); return
|
|
37
|
+
}
|
|
38
|
+
DispatchQueue.main.async {
|
|
39
|
+
GeolocationManager.shared.clearWatch(watchId)
|
|
40
|
+
callback(nil, nil)
|
|
41
|
+
}
|
|
42
|
+
default:
|
|
43
|
+
callback(nil, "GeolocationModule: Unknown method '\(method)'")
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public func invokeSync(method: String, args: [Any]) -> Any? { nil }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// MARK: - Internal location manager
|
|
51
|
+
|
|
52
|
+
/// All CLLocationManager interactions happen on @MainActor (main thread),
|
|
53
|
+
/// matching the CoreLocation threading requirement.
|
|
54
|
+
@MainActor
|
|
55
|
+
private final class GeolocationManager: NSObject, CLLocationManagerDelegate {
|
|
56
|
+
static let shared = GeolocationManager()
|
|
57
|
+
|
|
58
|
+
private var manager: CLLocationManager?
|
|
59
|
+
private var pendingCallbacks: [(Any?, String?) -> Void] = []
|
|
60
|
+
|
|
61
|
+
// Map watchId -> weak event dispatcher reference
|
|
62
|
+
private struct WeakDispatcher { weak var dispatcher: NativeEventDispatcher? }
|
|
63
|
+
private var watchCallbacks: [Int: WeakDispatcher] = [:]
|
|
64
|
+
private var nextWatchId = 1
|
|
65
|
+
|
|
66
|
+
// MARK: Setup
|
|
67
|
+
|
|
68
|
+
private func ensureManager() {
|
|
69
|
+
guard manager == nil else { return }
|
|
70
|
+
let mgr = CLLocationManager()
|
|
71
|
+
mgr.delegate = self
|
|
72
|
+
mgr.desiredAccuracy = kCLLocationAccuracyBest
|
|
73
|
+
manager = mgr
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// MARK: Public interface (called on main thread)
|
|
77
|
+
|
|
78
|
+
private func isAuthorized(_ status: CLAuthorizationStatus) -> Bool {
|
|
79
|
+
if status == .authorizedAlways { return true }
|
|
80
|
+
#if os(iOS)
|
|
81
|
+
if status == .authorizedWhenInUse { return true }
|
|
82
|
+
#endif
|
|
83
|
+
// On macOS, .authorized maps to .authorizedAlways — already covered above
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
func getCurrentPosition(callback: @escaping (Any?, String?) -> Void) {
|
|
88
|
+
ensureManager()
|
|
89
|
+
guard let manager = manager else {
|
|
90
|
+
callback(nil, "Failed to initialize location manager"); return
|
|
91
|
+
}
|
|
92
|
+
let status = manager.authorizationStatus
|
|
93
|
+
guard isAuthorized(status) else {
|
|
94
|
+
callback(nil, "Location permission not granted"); return
|
|
95
|
+
}
|
|
96
|
+
pendingCallbacks.append(callback)
|
|
97
|
+
manager.requestLocation()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
func watchPosition(eventDispatcher: NativeEventDispatcher?) -> Int {
|
|
101
|
+
ensureManager()
|
|
102
|
+
guard let manager = manager else {
|
|
103
|
+
return -1
|
|
104
|
+
}
|
|
105
|
+
let status = manager.authorizationStatus
|
|
106
|
+
guard isAuthorized(status) else {
|
|
107
|
+
return -1
|
|
108
|
+
}
|
|
109
|
+
let watchId = nextWatchId; nextWatchId += 1
|
|
110
|
+
watchCallbacks[watchId] = WeakDispatcher(dispatcher: eventDispatcher)
|
|
111
|
+
manager.startUpdatingLocation()
|
|
112
|
+
return watchId
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
func clearWatch(_ watchId: Int) {
|
|
116
|
+
watchCallbacks.removeValue(forKey: watchId)
|
|
117
|
+
if watchCallbacks.isEmpty {
|
|
118
|
+
manager?.stopUpdatingLocation()
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// MARK: CLLocationManagerDelegate
|
|
123
|
+
// nonisolated required by protocol; we hop to @MainActor via Task.
|
|
124
|
+
|
|
125
|
+
nonisolated func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
|
|
126
|
+
guard let loc = locations.last else { return }
|
|
127
|
+
let payload: [String: Any] = [
|
|
128
|
+
"latitude": loc.coordinate.latitude,
|
|
129
|
+
"longitude": loc.coordinate.longitude,
|
|
130
|
+
"altitude": loc.altitude,
|
|
131
|
+
"accuracy": loc.horizontalAccuracy,
|
|
132
|
+
"altitudeAccuracy": loc.verticalAccuracy,
|
|
133
|
+
"heading": loc.course,
|
|
134
|
+
"speed": loc.speed,
|
|
135
|
+
"timestamp": loc.timestamp.timeIntervalSince1970 * 1000
|
|
136
|
+
]
|
|
137
|
+
Task { @MainActor in
|
|
138
|
+
// Fire one-shot callbacks
|
|
139
|
+
let cbs = self.pendingCallbacks
|
|
140
|
+
self.pendingCallbacks.removeAll()
|
|
141
|
+
for cb in cbs { cb(payload, nil) }
|
|
142
|
+
// Fire watch callbacks
|
|
143
|
+
for (_, wd) in self.watchCallbacks {
|
|
144
|
+
wd.dispatcher?.dispatchGlobalEvent("location:update", payload: payload)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
nonisolated func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
|
|
150
|
+
Task { @MainActor in
|
|
151
|
+
let cbs = self.pendingCallbacks
|
|
152
|
+
self.pendingCallbacks.removeAll()
|
|
153
|
+
for cb in cbs { cb(nil, error.localizedDescription) }
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Network
|
|
2
|
+
import Foundation
|
|
3
|
+
|
|
4
|
+
/// Monitors network connectivity and pushes changes to JS via global events.
|
|
5
|
+
/// Uses NativeEventDispatcher protocol instead of a concrete bridge type.
|
|
6
|
+
public final class NetworkModule: NativeModule {
|
|
7
|
+
public var moduleName: String { "Network" }
|
|
8
|
+
|
|
9
|
+
private let monitor = NWPathMonitor()
|
|
10
|
+
private let monitorQueue = DispatchQueue(label: "vue-native.network")
|
|
11
|
+
private weak var eventDispatcher: NativeEventDispatcher?
|
|
12
|
+
|
|
13
|
+
public init(eventDispatcher: NativeEventDispatcher) {
|
|
14
|
+
self.eventDispatcher = eventDispatcher
|
|
15
|
+
startMonitoring()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private func startMonitoring() {
|
|
19
|
+
monitor.pathUpdateHandler = { [weak self] path in
|
|
20
|
+
let isConnected = path.status == .satisfied
|
|
21
|
+
let connectionType: String
|
|
22
|
+
if path.usesInterfaceType(.wifi) {
|
|
23
|
+
connectionType = "wifi"
|
|
24
|
+
} else if path.usesInterfaceType(.cellular) {
|
|
25
|
+
connectionType = "cellular"
|
|
26
|
+
} else if path.usesInterfaceType(.wiredEthernet) {
|
|
27
|
+
connectionType = "ethernet"
|
|
28
|
+
} else {
|
|
29
|
+
connectionType = "none"
|
|
30
|
+
}
|
|
31
|
+
let dispatcher = self?.eventDispatcher
|
|
32
|
+
DispatchQueue.main.async {
|
|
33
|
+
dispatcher?.dispatchGlobalEvent("network:change", payload: [
|
|
34
|
+
"isConnected": isConnected,
|
|
35
|
+
"connectionType": connectionType
|
|
36
|
+
])
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
monitor.start(queue: monitorQueue)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
43
|
+
switch method {
|
|
44
|
+
case "getStatus":
|
|
45
|
+
let path = monitor.currentPath
|
|
46
|
+
let isConnected = path.status == .satisfied
|
|
47
|
+
let connectionType: String
|
|
48
|
+
if path.usesInterfaceType(.wifi) { connectionType = "wifi" }
|
|
49
|
+
else if path.usesInterfaceType(.cellular) { connectionType = "cellular" }
|
|
50
|
+
else if path.usesInterfaceType(.wiredEthernet) { connectionType = "ethernet" }
|
|
51
|
+
else { connectionType = "none" }
|
|
52
|
+
callback(["isConnected": isConnected, "connectionType": connectionType], nil)
|
|
53
|
+
default:
|
|
54
|
+
callback(nil, "Unknown method: \(method)")
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public func invokeSync(method: String, args: [Any]) -> Any? { nil }
|
|
59
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// Native module for performance profiling.
|
|
4
|
+
/// Tracks memory usage via task_info and bridge operation counts.
|
|
5
|
+
/// Dispatches `perf:metrics` global events every 1 second while profiling is active.
|
|
6
|
+
///
|
|
7
|
+
/// NOTE: FPS tracking is platform-specific (requires CADisplayLink on iOS,
|
|
8
|
+
/// CVDisplayLink or CADisplayLink on macOS). This shared module reports FPS as 0
|
|
9
|
+
/// unless a platform-specific subclass or wrapper provides it.
|
|
10
|
+
/// Platforms can set `fpsProvider` to supply real-time FPS data.
|
|
11
|
+
public final class PerformanceModule: NSObject, NativeModule {
|
|
12
|
+
|
|
13
|
+
public let moduleName = "Performance"
|
|
14
|
+
|
|
15
|
+
private weak var eventDispatcher: NativeEventDispatcher?
|
|
16
|
+
private var isProfiling = false
|
|
17
|
+
|
|
18
|
+
// Metrics timer
|
|
19
|
+
private var metricsTimer: Timer?
|
|
20
|
+
|
|
21
|
+
// Bridge operation count
|
|
22
|
+
private var bridgeOpsCount: Int = 0
|
|
23
|
+
|
|
24
|
+
/// Optional FPS provider. Platform-specific code sets this to a closure
|
|
25
|
+
/// that returns the current FPS reading (e.g., from CADisplayLink).
|
|
26
|
+
public var fpsProvider: (() -> Double)?
|
|
27
|
+
|
|
28
|
+
public init(eventDispatcher: NativeEventDispatcher) {
|
|
29
|
+
self.eventDispatcher = eventDispatcher
|
|
30
|
+
super.init()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
34
|
+
switch method {
|
|
35
|
+
case "startProfiling":
|
|
36
|
+
startProfiling(callback: callback)
|
|
37
|
+
case "stopProfiling":
|
|
38
|
+
stopProfiling(callback: callback)
|
|
39
|
+
case "getMetrics":
|
|
40
|
+
let metrics = collectMetrics()
|
|
41
|
+
callback(metrics, nil)
|
|
42
|
+
default:
|
|
43
|
+
callback(nil, "PerformanceModule: unknown method '\(method)'")
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// MARK: - Start / Stop
|
|
48
|
+
|
|
49
|
+
private func startProfiling(callback: @escaping (Any?, String?) -> Void) {
|
|
50
|
+
guard !isProfiling else { callback(true, nil); return }
|
|
51
|
+
isProfiling = true
|
|
52
|
+
bridgeOpsCount = 0
|
|
53
|
+
|
|
54
|
+
DispatchQueue.main.async { [weak self] in
|
|
55
|
+
guard let self = self else { return }
|
|
56
|
+
|
|
57
|
+
// Timer for periodic metrics dispatch (every 1 second)
|
|
58
|
+
self.metricsTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
|
59
|
+
self?.dispatchMetrics()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
callback(true, nil)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private func stopProfiling(callback: @escaping (Any?, String?) -> Void) {
|
|
67
|
+
guard isProfiling else { callback(true, nil); return }
|
|
68
|
+
isProfiling = false
|
|
69
|
+
|
|
70
|
+
DispatchQueue.main.async { [weak self] in
|
|
71
|
+
self?.metricsTimer?.invalidate()
|
|
72
|
+
self?.metricsTimer = nil
|
|
73
|
+
callback(true, nil)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// MARK: - Metrics collection
|
|
78
|
+
|
|
79
|
+
private func collectMetrics() -> [String: Any] {
|
|
80
|
+
let fps = fpsProvider?() ?? 0
|
|
81
|
+
return [
|
|
82
|
+
"fps": round(fps * 10) / 10,
|
|
83
|
+
"memoryMB": getMemoryUsageMB(),
|
|
84
|
+
"bridgeOps": bridgeOpsCount,
|
|
85
|
+
"timestamp": Date().timeIntervalSince1970 * 1000,
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private func dispatchMetrics() {
|
|
90
|
+
guard isProfiling else { return }
|
|
91
|
+
bridgeOpsCount += 1 // Count the metrics dispatch itself
|
|
92
|
+
let metrics = collectMetrics()
|
|
93
|
+
DispatchQueue.main.async { [weak self] in
|
|
94
|
+
self?.eventDispatcher?.dispatchGlobalEvent("perf:metrics", payload: metrics)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// MARK: - Memory measurement
|
|
99
|
+
|
|
100
|
+
private func getMemoryUsageMB() -> Double {
|
|
101
|
+
var info = mach_task_basic_info()
|
|
102
|
+
var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size) / 4
|
|
103
|
+
let result = withUnsafeMutablePointer(to: &info) {
|
|
104
|
+
$0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
|
|
105
|
+
task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if result == KERN_SUCCESS {
|
|
109
|
+
return Double(info.resident_size) / (1024 * 1024)
|
|
110
|
+
}
|
|
111
|
+
return 0
|
|
112
|
+
}
|
|
113
|
+
}
|
package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/SecureStorageModule.swift
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Security
|
|
3
|
+
|
|
4
|
+
/// Native module providing secure key-value storage backed by the Keychain.
|
|
5
|
+
/// Works on both iOS and macOS via the Security framework.
|
|
6
|
+
///
|
|
7
|
+
/// Methods:
|
|
8
|
+
/// - get(key: String) -> String?
|
|
9
|
+
/// - set(key: String, value: String)
|
|
10
|
+
/// - remove(key: String)
|
|
11
|
+
/// - clear()
|
|
12
|
+
public final class SecureStorageModule: NativeModule {
|
|
13
|
+
public let moduleName = "SecureStorage"
|
|
14
|
+
|
|
15
|
+
private let service = "com.vuenative.securestorage"
|
|
16
|
+
|
|
17
|
+
public init() {}
|
|
18
|
+
|
|
19
|
+
public func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
20
|
+
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
|
21
|
+
guard let self = self else { return }
|
|
22
|
+
switch method {
|
|
23
|
+
case "get":
|
|
24
|
+
guard let key = args.first as? String else {
|
|
25
|
+
callback(nil, "get: missing key")
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
let query: [String: Any] = [
|
|
29
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
30
|
+
kSecAttrService as String: self.service,
|
|
31
|
+
kSecAttrAccount as String: key,
|
|
32
|
+
kSecReturnData as String: true,
|
|
33
|
+
kSecMatchLimit as String: kSecMatchLimitOne,
|
|
34
|
+
]
|
|
35
|
+
var result: AnyObject?
|
|
36
|
+
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
37
|
+
if status == errSecSuccess, let data = result as? Data,
|
|
38
|
+
let value = String(data: data, encoding: .utf8) {
|
|
39
|
+
callback(value, nil)
|
|
40
|
+
} else if status == errSecItemNotFound {
|
|
41
|
+
callback(nil, nil)
|
|
42
|
+
} else {
|
|
43
|
+
callback(nil, "get: Keychain error \(status)")
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
case "set":
|
|
47
|
+
guard args.count >= 2,
|
|
48
|
+
let key = args[0] as? String,
|
|
49
|
+
let value = args[1] as? String else {
|
|
50
|
+
callback(nil, "set: missing key or value")
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
guard let data = value.data(using: .utf8) else {
|
|
54
|
+
callback(nil, "set: failed to encode value")
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Try to update first
|
|
59
|
+
let searchQuery: [String: Any] = [
|
|
60
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
61
|
+
kSecAttrService as String: self.service,
|
|
62
|
+
kSecAttrAccount as String: key,
|
|
63
|
+
]
|
|
64
|
+
let updateAttributes: [String: Any] = [
|
|
65
|
+
kSecValueData as String: data,
|
|
66
|
+
]
|
|
67
|
+
let updateStatus = SecItemUpdate(searchQuery as CFDictionary, updateAttributes as CFDictionary)
|
|
68
|
+
|
|
69
|
+
if updateStatus == errSecItemNotFound {
|
|
70
|
+
// Item doesn't exist yet, add it
|
|
71
|
+
var addQuery = searchQuery
|
|
72
|
+
addQuery[kSecValueData as String] = data
|
|
73
|
+
let addStatus = SecItemAdd(addQuery as CFDictionary, nil)
|
|
74
|
+
if addStatus == errSecSuccess {
|
|
75
|
+
callback(nil, nil)
|
|
76
|
+
} else {
|
|
77
|
+
callback(nil, "set: Keychain add error \(addStatus)")
|
|
78
|
+
}
|
|
79
|
+
} else if updateStatus == errSecSuccess {
|
|
80
|
+
callback(nil, nil)
|
|
81
|
+
} else {
|
|
82
|
+
callback(nil, "set: Keychain update error \(updateStatus)")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
case "remove":
|
|
86
|
+
guard let key = args.first as? String else {
|
|
87
|
+
callback(nil, "remove: missing key")
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
let query: [String: Any] = [
|
|
91
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
92
|
+
kSecAttrService as String: self.service,
|
|
93
|
+
kSecAttrAccount as String: key,
|
|
94
|
+
]
|
|
95
|
+
let status = SecItemDelete(query as CFDictionary)
|
|
96
|
+
if status == errSecSuccess || status == errSecItemNotFound {
|
|
97
|
+
callback(nil, nil)
|
|
98
|
+
} else {
|
|
99
|
+
callback(nil, "remove: Keychain error \(status)")
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
case "clear":
|
|
103
|
+
let query: [String: Any] = [
|
|
104
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
105
|
+
kSecAttrService as String: self.service,
|
|
106
|
+
]
|
|
107
|
+
let status = SecItemDelete(query as CFDictionary)
|
|
108
|
+
if status == errSecSuccess || status == errSecItemNotFound {
|
|
109
|
+
callback(nil, nil)
|
|
110
|
+
} else {
|
|
111
|
+
callback(nil, "clear: Keychain error \(status)")
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
default:
|
|
115
|
+
callback(nil, "SecureStorageModule: Unknown method '\(method)'")
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|