Skip to content

Commit 111796b

Browse files
committed
fix(ios): stop pretending to resave files after initial save
After the initial save of a file, the save button would continue to work and would claim that files were being saved, even though they weren't. This now forces the Save File picker to pop up, since I can't figure out a way to get iOS to match the behavior of other platforms. Opening a file will still keep a file handle as expected.
1 parent 47879a7 commit 111796b

File tree

6 files changed

+90
-37
lines changed

6 files changed

+90
-37
lines changed

apps/mobile/ios/App/.idea/modules.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/mobile/ios/App/.idea/workspace.xml

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/mobile/ios/App/App.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/* Begin PBXBuildFile section */
1010
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
11+
47150DD42D2A212E0001EA7C /* LyricistantViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47150DD32D2A212E0001EA7C /* LyricistantViewController.swift */; };
1112
47905CC32617F5240080728B /* FilesPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47905CC22617F5240080728B /* FilesPlugin.swift */; };
1213
47905CC72617F5B60080728B /* FilesPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 47905CC62617F5B60080728B /* FilesPlugin.m */; };
1314
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
@@ -21,6 +22,7 @@
2122

2223
/* Begin PBXFileReference section */
2324
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
25+
47150DD32D2A212E0001EA7C /* LyricistantViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LyricistantViewController.swift; sourceTree = "<group>"; };
2426
47905CC22617F5240080728B /* FilesPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesPlugin.swift; sourceTree = "<group>"; };
2527
47905CC52617F5B50080728B /* App-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "App-Bridging-Header.h"; sourceTree = "<group>"; };
2628
47905CC62617F5B60080728B /* FilesPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FilesPlugin.m; sourceTree = "<group>"; };
@@ -89,6 +91,7 @@
8991
47905CC22617F5240080728B /* FilesPlugin.swift */,
9092
47905CC62617F5B60080728B /* FilesPlugin.m */,
9193
47905CC52617F5B50080728B /* App-Bridging-Header.h */,
94+
47150DD32D2A212E0001EA7C /* LyricistantViewController.swift */,
9295
);
9396
path = App;
9497
sourceTree = "<group>";
@@ -218,6 +221,7 @@
218221
47905CC72617F5B60080728B /* FilesPlugin.m in Sources */,
219222
47905CC32617F5240080728B /* FilesPlugin.swift in Sources */,
220223
504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
224+
47150DD42D2A212E0001EA7C /* LyricistantViewController.swift in Sources */,
221225
);
222226
runOnlyForDeploymentPostprocessing = 0;
223227
};

apps/mobile/ios/App/App/Base.lproj/Main.storyboard

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14111" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
3-
<device id="retina4_7" orientation="portrait">
4-
<adaptation id="fullscreen"/>
5-
</device>
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
3+
<device id="retina4_7" orientation="portrait" appearance="light"/>
64
<dependencies>
75
<deployment identifier="iOS"/>
8-
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
6+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
97
</dependencies>
108
<scenes>
11-
<!--Bridge View Controller-->
9+
<!--Lyricistant View Controller-->
1210
<scene sceneID="tne-QT-ifu">
1311
<objects>
14-
<viewController id="BYZ-38-t0r" customClass="CAPBridgeViewController" customModule="Capacitor" sceneMemberID="viewController"/>
12+
<viewController id="BYZ-38-t0r" customClass="LyricistantViewController" customModule="App" customModuleProvider="target" sceneMemberID="viewController"/>
1513
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
1614
</objects>
1715
</scene>

apps/mobile/ios/App/App/FilesPlugin.swift

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,41 @@ import Foundation
66
import JavaScriptCore
77

88
@objc(FilesPlugin)
9-
public class FilesPlugin: CAPPlugin, UIDocumentPickerDelegate,UINavigationControllerDelegate {
9+
public class FilesPlugin: CAPPlugin, UIDocumentPickerDelegate, UINavigationControllerDelegate {
1010
private var delegate: UIDocumentPickerDelegate? = nil
11-
11+
1212
@objc func openFile(_ call: CAPPluginCall) {
13-
guard let viewController = self.bridge?.viewController else { return }
13+
guard let viewController = self.bridge?.viewController else {
14+
return
15+
}
1416
let types = [UTType.data]
15-
17+
1618
DispatchQueue.main.async {
1719
let documentPickerController = UIDocumentPickerViewController(
1820
forOpeningContentTypes: types
1921
)
20-
22+
2123
self.delegate = OpenFileDelegate(call);
2224
documentPickerController.delegate = self.delegate;
23-
25+
2426
viewController.present(documentPickerController, animated: true, completion: nil)
2527
}
2628
}
27-
29+
2830
@objc func saveFile(_ call: CAPPluginCall) {
29-
guard let array = call.getArray("data")?.map({ value in
31+
guard let dataBytes = call.getArray("data")?.map({ value in
3032
(value as! NSNumber).uint8Value
31-
}) else {
33+
})
34+
else {
3235
call.reject("Couldn't convert data to UTF")
3336
return
3437
}
35-
let data = Data(bytes: array, count: array.count)
38+
let data = Data(bytes: dataBytes, count: dataBytes.count)
3639
guard let path = call.getString("path") else {
3740
showSaveFilePicker(call, data);
3841
return;
3942
}
40-
43+
4144
let url = URL(string: path)!
4245
let error: NSErrorPointer = nil
4346
let coordinator = NSFileCoordinator(filePresenter: nil)
@@ -50,22 +53,40 @@ public class FilesPlugin: CAPPlugin, UIDocumentPickerDelegate,UINavigationContro
5053
}
5154
}
5255
}
53-
56+
57+
private func getPathFromCall(_ call: CAPPluginCall) -> URL? {
58+
guard let encodedBookmarkData = call.getString("path") else {
59+
return nil
60+
}
61+
guard let bookmarkData = Data(base64Encoded: encodedBookmarkData) else {
62+
return nil
63+
}
64+
do {
65+
var bookmarkDataIsStale = false
66+
let url = try URL(resolvingBookmarkData: bookmarkData, bookmarkDataIsStale: &bookmarkDataIsStale)
67+
return url
68+
} catch {
69+
return nil
70+
}
71+
}
72+
5473
private func showSaveFilePicker(_ call: CAPPluginCall, _ data: Data) {
55-
guard let viewController = self.bridge?.viewController else { return }
74+
guard let viewController = self.bridge?.viewController else {
75+
return
76+
}
5677
let fileManager = FileManager.default
57-
78+
5879
do {
5980
let path = fileManager.temporaryDirectory.appendingPathComponent(call.getString("defaultFileName")!)
6081
try data.write(to: path)
61-
82+
6283
DispatchQueue.main.async {
6384
let documentPickerController = UIDocumentPickerViewController(
6485
forExporting: [path])
65-
86+
6687
self.delegate = SaveFileDelegate(call);
6788
documentPickerController.delegate = self.delegate;
68-
89+
6990
viewController.present(documentPickerController, animated: true, completion: nil)
7091
}
7192
} catch {
@@ -76,25 +97,27 @@ public class FilesPlugin: CAPPlugin, UIDocumentPickerDelegate,UINavigationContro
7697
}
7798

7899
private func FileMetadata(_ path: URL) -> [String: Any] {
79-
return ["path": path.absoluteString, "name": path.lastPathComponent];
100+
["path": path.absoluteString, "name": path.lastPathComponent];
80101
}
81102

82103
private func PlatformFile(_ path: URL, _ data: [UInt8]) -> [String: Any] {
83-
return FileMetadata(path).merging(["data": data]) { (current, _) in current }
104+
FileMetadata(path).merging(["data": data]) { (current, _) in
105+
current
106+
}
84107
}
85108

86-
private class OpenFileDelegate : NSObject, UIDocumentPickerDelegate {
109+
private class OpenFileDelegate: NSObject, UIDocumentPickerDelegate {
87110
private let call: CAPPluginCall;
88-
111+
89112
init(_ call: CAPPluginCall) {
90113
self.call = call;
91114
}
92-
115+
93116
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
94117
guard let filePath = urls.first else {
95118
return
96119
}
97-
if(filePath.startAccessingSecurityScopedResource()) {
120+
if (filePath.startAccessingSecurityScopedResource()) {
98121
let error: NSErrorPointer = nil
99122
let coordinator = NSFileCoordinator(filePresenter: nil)
100123
coordinator.coordinate(readingItemAt: filePath, error: error) { url in
@@ -105,33 +128,38 @@ private class OpenFileDelegate : NSObject, UIDocumentPickerDelegate {
105128
call.reject("Unable to read the selected file", nil, error);
106129
}
107130
}
108-
if(error != nil) {
131+
if (error != nil) {
109132
call.reject("Unable to read the selected file", nil, error?.pointee)
110133
}
111134
} else {
112135
call.reject("Unable to read the selected file")
113136
}
114137
}
115-
138+
116139
public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
117140
self.call.resolve();
118141
}
119142
}
120143

121-
private class SaveFileDelegate : NSObject, UIDocumentPickerDelegate {
144+
private class SaveFileDelegate: NSObject, UIDocumentPickerDelegate {
122145
private let call: CAPPluginCall;
123-
146+
124147
init(_ call: CAPPluginCall) {
125148
self.call = call;
126149
}
127-
150+
128151
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
129152
guard let filePath = urls.first else {
130153
return
131154
}
132-
call.resolve(["path": filePath.absoluteString, "name": filePath.lastPathComponent]);
155+
if (!filePath.startAccessingSecurityScopedResource()) {
156+
self.call.reject("Unable to save the file")
157+
return
158+
}
159+
160+
call.resolve(["name": filePath.lastPathComponent])
133161
}
134-
162+
135163
public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
136164
self.call.resolve();
137165
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import UIKit
2+
import Capacitor
3+
4+
class LyricistantViewController: CAPBridgeViewController {
5+
6+
override func viewDidLoad() {
7+
super.viewDidLoad()
8+
9+
bridge?.registerPluginInstance(FilesPlugin())
10+
}
11+
}

0 commit comments

Comments
 (0)