Post

Replies

Boosts

Views

Activity

PDFKit deletes certificates on document load
Why does PDFKit delete signature widgets that have already been digitally signed? This should not happen. Is there an undocumented flag that needs to be set so that PDFKit doesn't remove them when loading or saving the PDF? It's difficult to tell if it is happening at PDFDocument(url: fileURL) or document.write(to: outputURL) If a document is signed and still allows annotations, form filling, comments, etc. we should be able to load the PDF into a PDFDocument and save it without losing the certs. Instead the certs are gone and only the signature annotation widgets are present. Here is a simple example of loading and then saving the PDF with out any changes and it shows that the data is actually being changed... ... import UIKit import PDFKit class ViewController: UIViewController { var pdfView: PDFView! @IBOutlet weak var myButton: UIButton! override func viewDidLoad() { super.viewDidLoad() pdfView = PDFView(frame: self.view.bounds) pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.view.addSubview(pdfView) self.view.bringSubviewToFront(myButton) // Load and compare the PDF data if let originalData = loadPDF() { if let loadedData = getRawDataFromLoadedPDF() { let isDataEqual = comparePDFData(originalData, loadedData) print("Is original data equal to loaded data? \(isDataEqual)") } } } @IBAction func onSave(_ sender: Any) { if let savedData = savePDF() { if let originalData = loadPDF() { let isDataEqual = comparePDFData(originalData, savedData) print("Is original data equal to saved data? \(isDataEqual)") } } } func loadPDF() -> Data? { guard let fileURL = Bundle.main.url(forResource: "document", withExtension: "pdf") else { print("Error: document.pdf not found in bundle.") return nil } do { let originalData = try Data(contentsOf: fileURL) if let document = PDFDocument(url: fileURL) { pdfView.document = document print("PDF loaded successfully.") return originalData } else { print("Error: Unable to load PDF document.") return nil } } catch { print("Error reading PDF data: \(error)") return nil } } func getRawDataFromLoadedPDF() -> Data? { guard let document = pdfView.document else { print("Error: No document is currently loaded in pdfView.") return nil } if let data = document.dataRepresentation() { return data } else { print("Error: Unable to get raw data from loaded PDF document.") return nil } } func comparePDFData(_ data1: Data, _ data2: Data) -> Bool { return data1 == data2 } func savePDF() -> Data? { guard let document = pdfView.document else { print("Error: No document is currently loaded in pdfView.") return nil } let fileManager = FileManager.default let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask) guard let documentsURL = urls.first else { print("Error: Could not find the documents directory.") return nil } let outputURL = documentsURL.appendingPathComponent("document_out.pdf") if document.write(to: outputURL) { print("PDF saved successfully to \(outputURL.path)") do { let savedData = try Data(contentsOf: outputURL) return savedData } catch { print("Error reading saved PDF data: \(error)") return nil } } else { print("Error: Unable to save PDF document.") return nil } } }
1
1
335
Jul ’24
Files App Share Context with Security scoped resource fails
I'm creating an App that can accepted PDFs from a shared context. I am using iOS, Swift, and UIKit with IOS 17.1+ The logic is: get the context see who is sending in (this is always unknown) see if I can open in place (in case I want to save later) send the URL off to open the (PDF) document and load it into PDFKit's pdfView.document I have no trouble loading PDF docs with the file picker. And everything works as expected for shares from apps like Messages, email, etc... (in which case URLContexts.first.options.openInPlace == False) The problem is with opening (sharing) a PDF that is sent from the Files App. (openInPlace == True) If the PDF is in the App's Document Folder, I need the Security scoped resource, to access the URL from the File's App so that I can copy the PDF's data to the PDFViewer.document. I get Security scoped resource access granted each time I get the File App's context URL. But, when I call fileCoordinator.coordinate and try to access a file outside of the App's document folder using the newUrl, I get an error. FYI - The newUrl (byAccessor) and context url (readingItemAt) paths are always same for the Files App URL share context. I can, however, copy the file to a new location in my apps directory and then open it from there and load in the data. But I really do not want to do that. . . . . . Questions: Am I missing something in my pList or are there other parameters specific to sharing a file from the Files App? I'd appreciate if someone shed some light on this? . . . . . Here are the parts of my code related to this with some print statements... . . . . . SceneDelegate func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { // nothing to see here, move along guard let urlContext = URLContexts.first else { print("No URLContext found") return } // let's get the URL (it will be a PDF) let url = urlContext.url let openInPlace = urlContext.options.openInPlace let bundleID = urlContext.options.sourceApplication print("Triggered with URL: \(url)") print("Can Open In Place?: \(openInPlace)") print("For Bundle ID: \(bundleID ?? "None")") // get my Root ViewController from window if let rootViewController = self.window?.rootViewController { // currently using just the view if let targetViewController = rootViewController as? ViewController { targetViewController.prepareToLoadSharedPDFDocument(at: url) } // I might use a UINavigationController in the future else if let navigationController = rootViewController as? UINavigationController, let targetViewController = navigationController.viewControllers.first as? ViewController { targetViewController.prepareToLoadSharedPDFDocument(at: url) } } } . . . . ViewController function I broke out the if statement for accessingScope just to make it easier for me the debug and play around with the code in accessingScope == True func loadPDF(fromUrl url: URL) { // If using the File Picker / don't use this // If going through a Share.... we pass the URL and have three outcomes (1, 2a, 2b) // 1. Security scoped resource access NOT needed if from a Share Like Messages or EMail // 2. Security scoped resource access granted/needed from 'Files' App // a. success if in the App's doc directory // b. fail if NOT in the App's doc directory // Set the securty scope variable var accessingScope = false // Log the URLs for debugging print("URL String: \(url.absoluteString)") print("URL Path: \(url.path())") // Check if the URL requires security scoped resource access if url.startAccessingSecurityScopedResource() { accessingScope = true print("Security scoped resource access granted.") } else { print("Security scoped resource access denied or not needed.") } // Stop accessing the scope once everything is compeleted defer { if accessingScope { url.stopAccessingSecurityScopedResource() print("Security scoped resource access stopped.") } } // Make sure the file is still there (it should be in this case) guard FileManager.default.fileExists(atPath: url.path) else { print("File does not exist at URL: \(url)") return } // Let's see if we can open it in place if accessingScope { let fileCoordinator = NSFileCoordinator() var error: NSError? fileCoordinator.coordinate(readingItemAt: url, options: [], error: &error) { (newUrl) in DispatchQueue.main.async { print(url.path()) print(newUrl.path()) if let document = PDFDocument(url: newUrl) { self.pdfView.document = document self.documentFileName = newUrl.deletingPathExtension().lastPathComponent self.fileLoadLocation = newUrl.path() self.updateGUI(pdfLoaded: true) self.setPDFScale(to: self.VM.pdfPageScale, asNewPDF: true) } else { print("Could not load PDF directly from url: \(newUrl)") } } } if let error = error { PRINT("File coordination error: \(error)") } } else { DispatchQueue.main.async { if let document = PDFDocument(url: url) { self.pdfView.document = document self.documentFileName = url.deletingPathExtension().lastPathComponent self.fileLoadLocation = url.path() self.updateGUI(pdfLoaded: true) self.setPDFScale(to: self.VM.pdfPageScale, asNewPDF: true) } else { PRINT("Could not load PDF from url: \(url)") } } } } . . . . Other relevant pList settings I've added are: Supports opening documents in place - YES Document types - PDFs (com.adobe.pdf) UIDocumentBrowserRecentDocumentContentTypes - com.adobe.pdf Application supports iTunes file sharing - YES And iCloud is one for Entitlements with iCloud Container Identifiers Ubiquity Container Identifiers . . . . Thank you in advance!. B
1
0
495
Jun ’24
IAP Transactions not showing up in App Connect Sales and Trends for new App. Why?
I published a new iPad app 30+ days ago with a few IAP items. Everything works correctly in testing. Now that it's a live app, everything is working as expected as well. You pay for a feature, the feature gets unlocked, and you get billed by Apple. This has been confirmed by myself and a few others who have made AIPs for the app. If the app is removed and added back, the restore purchases works as well. But the problem is that the Trends/Proceeds show $0.00 Why am I not getting paid? And why does App Connect not show any sales when there are confirmed sales since the first week it launched (over 30 days ago)? All documents and banking info are up to date and I can see revenue from my other apps (they don't have AIP).
0
0
483
Jan ’23
Can no longer put modal view on top of another modal view (on iPad)
I have an iPad app that has 3 viewControllers. vcMain, vcMenu, vcInfo vcMenu and vcInfo are custom sized windows vcMain uses a segue to presentModally the vcMenu The vcMenu has an info buttons that uses a segue to presentModally the vcInfo After years, this no longer works as the vcMenu no longer appears to be the topmost window. 'Attempt to present vcInfo on vcMenu (from vcMenu whose view is not in the window hierarchy.' I can bypass this issue when setting isModalInPresentation to true when vcMenu appears, but I do not want to change the behavior of the vcMenu by having to add a 'Close' button Also setting isModalInPresentation to true in the info button function before calling performSegue does not work. It also does not work if I add a delay inside the function (ie perform a #selector). Any suggestions? Is there a new setting somewhere that I am missing? Here is the code... import UIKit class vcMain: UIViewController {     // all functions perfomed in storyboard     // a button uses a segue to open vcMenu with // Kind: presentModally     override func viewDidLoad() { super.viewDidLoad() } } class vcMenu: UIViewController {     let ID_POP_UP = "id1"     @IBAction func btnInfo(_ sender: UIButton) {         isModalInPresentation = true // get error         // performSegue(withIdentifier: ID_POP_UP, sender: nil)         perform(#selector(presentExampleController), with: nil, afterDelay: 2)     }     @objc private func presentExampleController() { // get error even if add a 2s delay         performSegue(withIdentifier: ID_POP_UP, sender: nil)     }     @IBAction func btnBack(_ sender: UIButton) {         isModalInPresentation = false         self.dismiss(animated: true, completion: nil)     }     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {         guard let segueId = segue.identifier else { return }         if segueId == ID_POP_UP { print("ID_POP_UP: \(ID_POP_UP)") }    // Just checking     }     override func viewDidAppear(_ animated: Bool) {         super.viewDidAppear(animated)         //isModalInPresentation = true      // no error     } } class vcInfo: UIViewController {     override func viewDidDisappear(_ animated: Bool) {         if let main = self.parent { main.isModalInPresentation = false } // testing         super.viewDidDisappear(animated)     }     @IBAction func btnCloseAll(_ sender: UIButton) {        self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)  // close all popovers     } }
0
0
562
May ’22
Why do Let Integer constants change values or always equal Zero?
I have about 15 global Integer constants in my app. Half of them display zero. For example... struct Global {     struct lives {         static let free = 3         static let paid = 5     } } let CRATE_LOCATION_ZERO = CGPoint(x: -10000, y: -10000) Then later in code I try to use them... let purchasedApp = true let newLives = purchasedApp ? paid : free let newCrateLocation = CRATE_LOCATION_ZERO When I run the program and get these values, they are always zero. When I add a break point and check the values, they are also zero. The newLives will be 0 The CGPoint will be x:0, y:0 But not all the static (or constant) values end up being 0. Then some others have different values. I've also put up a video to show you what I mean. leckett.net/video/wierd.mov CPU and memory are all okay. I'm running Xcode 12.5.1 Has anybody experienced this?
11
0
739
Sep ’21
Payment queue does not receive a new transaction for Handling Interrupted Purchase - Why?
I've added IAP to an iOS App that includes consumables and non-consumables. I'm going though each criteria for Testing at All Stages of Development with Xcode and Sandbox and Step 10 of Testing an Interrupted Purchase is not happening. For the transaction... I've set everything up I get the transactionState .failed and I call finishTransaction for the queue (as outlined in the docs) After accepting the agreement, the payment queue does not receive a new transaction. Is anyone experiencing the same thing? If yes, how to do get around updating the purchase? If I call restoreCompletedTransactions on the queue, it will pull the transaction (FYI - I am doing a single purchase on a consumable item to start). So does this mean I need to call up the queue on my own each time an interruption appears? (as there is no way to determine if and when the user completed the interrupted transaction). I would appreciate input and how to handle this gracefully so that I can update the UI. Thanks!
2
0
1.3k
Jul ’21
When should I display a message to a user for a failed SKPaymentTransaction?
Hi - I'm implementing IAP and find the documentation a bit limited in error handling descriptions for the SKPaymentTransaction Failed Status and would like to know what others are doing. For example, Apple has some of their own messages that appear during an IAP. Also, when I user cancels somewhere along the way, some Apple messages appear depending on the context. (ie switch to a different store, not accepting T&Cs, change patent on the fly etc...). In other cases, they do not. Displaying the error description to the user seems to be too much detail. Displaying a generic Transaction Failed seems too limited. Plus always displaying a message for a failed transaction may be redundant. Does anyone have a recommend approach for what to display (or not display) for a failed transaction? Greatly appreciate it. Thanks a lot... Blaine
0
0
506
Oct ’20
best practices - when to check condition before updating UI?
I'd lke to hear peoples comments on what the best practices would be for the need to checking a condition before updating a User Interface element in iOS (including watchOS and tvOS).Here are some examples *1. An Undo button keeping track of changesfunc update(_ data: Data) { updateHistory(data: Data) if !btnUndo.isEnabled { btnUndo.isEnabled = true } // use this one or btnUndo.isEnabled = true // use this one? }2. Text in a label that hasn't changedvar timerMonitorHeartRate = Timer() func startMonitoring() { timerMonitorHeartRate.invalidate() timerMonitorHeartRate = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] timer in self?.displayHeartRate() } } func displayHeartRate() { let heartRateValue = BLEHeartRate.value // value comes from some async function let heartRateString = String(format: "Heart Rate %1.2f", heartRateValue) if (lblHearRate.text != heartRateString) { lblHearRate.text = heartRateString } // use this one or lblHearRate.text = heartRateString // use this one? }* these exmples are just off the top of my head, I didn't check them for syntax, only to give you an idea of what I'm talking about.Should we check the conditon before updating an item or does the underlaying code do that for us (i.e., the button will not actually undergo a paint refresh since it will internally check and already know that it is enabled). If this is the case, would the same thing happen when updating a text property with the same text?
3
0
987
Mar ’19
BLE with multiple identical devices - how to choose?
I'm starting to work on BLE and would like some advice on best practices or what to look out for if any one has been down this route.For example, if 3 people are wearing the same Polar Bluetooth HRM (i.e., in a Gym) when the app starts up and scans for perifierials &amp; services how can I choose which device to select?CBCentralManagerScanOptionAllowDuplicatesKey is off by default, to avoid battery drain.Will the closest HRM (strongest signal) appear in the CBPeripheral didDiscoverServiceslist first?Is there a way for the user to 'save' their device? - since there is no pairing option or specific UID available that I am aware of.Thanks...
4
0
4.9k
Nov ’15