Benutzer Datei speichern lassen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Benutzer Datei speichern lassen

    Ich vermute einmal, dass mit dem Quelltext unten das PDF erstellt und gespeichert wird innerhalb der APP

    Ich möchte aber die Datei so speichern, dass der Benutzer entscheiden kann, ob er die Datei ausserhalb der App speichern will.



    Ich frage mich aber auch noch, ob ich in markupText irgendetwas reinschreiben kann, und dann später erst alles zu zeichnen, oder ob nur das gezeichnet wird, was in diesem String ist in denen ich jetzt die ???? habe.

    let formatter = UIMarkupTextPrintFormatter(markupText: "?????????")
    // IST DAS EGAL WAS HIER STEHT?



    Ich glaube sonst sollte alles stimmen.

    Quellcode

    1. //
    2. // PdfErstellen.swift
    3. // Vitalstoffcontroller
    4. //
    5. // Created by Lukas Hedinger on 20.09.18.
    6. // Copyright © 2018 Afac AG. All rights reserved.
    7. //
    8. import UIKit
    9. import Foundation
    10. class PdfErstellung {
    11. static func PdfErstellen(_ auswahlZeilen : [LebensmittelDataTV], _ vitalstoffWerteListe : [LebensmittelDataTV], _ heuteString : String) {
    12. // 1. Create Print Formatter with input text.
    13. let formatter = UIMarkupTextPrintFormatter(markupText: "?????????") // What ist here?
    14. // 2. Add formatter with pageRender
    15. let render = UIPrintPageRenderer()
    16. render.addPrintFormatter(formatter, startingAtPageAt: 0)
    17. // 3. Assign paperRect and printableRect
    18. let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4, 72 dpi
    19. let printable = page.insetBy(dx: 0, dy: 0)
    20. let rect = CGRect.zero
    21. render.setValue(NSValue(cgRect: page), forKey: "paperRect")
    22. render.setValue(NSValue(cgRect: printable), forKey: "printableRect")
    23. // 4. Create PDF context and draw
    24. let fileName = "Vitalstoffwerte " + heuteString
    25. let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
    26. let documentsDirectory = paths[0]
    27. let pathForPDF = documentsDirectory.appendingFormat("/" + fileName)
    28. UIGraphicsBeginPDFContextToFile(pathForPDF, rect, nil)
    29. // Start Draw of page
    30. var y = 0
    31. var stringRechteckX50 = CGRect(x: 50, y: y, width: 100, height: 20)
    32. var stringRechteckX160 = CGRect(x: 160, y: y, width: 30, height: 20)
    33. var stringRechteckX170 = CGRect(x: 170, y: y, width: 10, height: 20)
    34. var stringRechteckX220 = CGRect(x: 220, y: y, width: 100, height: 20)
    35. var stringRechteckX330 = CGRect(x: 330, y: y, width: 30, height: 20)
    36. var stringRechteckX340 = CGRect(x: 340, y: y, width: 10, height: 20)
    37. var paragraphStyle = NSMutableParagraphStyle()
    38. var font = UIFont(name: "Helvetica Bold", size: 20.0)
    39. var text = ""
    40. let attributes = [
    41. NSAttributedString.Key.paragraphStyle: paragraphStyle,
    42. NSAttributedString.Key.font: font,
    43. NSAttributedString.Key.foregroundColor: UIColor.black
    44. ]
    45. var attributedString = NSAttributedString(string: text, attributes: attributes)
    46. // ÜBERSCHRIFT
    47. font = UIFont(name: "Helvetica Bold", size: 20.0)
    48. text = "Tagesbedarf in % vom " + heuteString
    49. paragraphStyle.alignment = .left
    50. var stringRechteck = CGRect(x: 50, y: 50, width: 300, height: 40)
    51. attributedString.draw(in: stringRechteck)
    52. // Vitalstoffwerte Liste
    53. y = 80
    54. for zeile in 0..<vitalstoffWerteListe.count {
    55. let druckenVitalstoffWerte = vitalstoffWerteListe[zeile]
    56. if druckenVitalstoffWerte.zeilenInfoID == 0 { // Überschrift
    57. y = y + 10
    58. font = UIFont(name: "Helvetica Bold", size: 14.0)
    59. text = druckenVitalstoffWerte.name
    60. attributedString.draw(in: stringRechteckX50)
    61. } else { // Detail
    62. font = UIFont(name: "Helvetica", size: 12.0)
    63. text = druckenVitalstoffWerte.name
    64. attributedString.draw(in: stringRechteckX50)
    65. text = druckenVitalstoffWerte.anzahl
    66. paragraphStyle.alignment = .right
    67. attributedString.draw(in: stringRechteckX160)
    68. text = druckenVitalstoffWerte.masse
    69. paragraphStyle.alignment = .left
    70. attributedString.draw(in: stringRechteckX170)
    71. }
    72. y = y + 30
    73. }
    74. y = 80
    75. text = "Lebensmittel"
    76. font = UIFont(name: "Helvetica Bold", size: 14.0)
    77. paragraphStyle.alignment = .left
    78. attributedString.draw(in: stringRechteckX220)
    79. // Lebensmittelliste
    80. y = 120
    81. for zeile in 0..<auswahlZeilen.count {
    82. let auswahlZeilenObjekt = auswahlZeilen[zeile]
    83. font = UIFont(name: "Helvetica", size: 12.0)
    84. text = auswahlZeilenObjekt.name
    85. attributedString.draw(in: stringRechteckX220)
    86. text = auswahlZeilenObjekt.anzahl
    87. paragraphStyle.alignment = .right
    88. attributedString.draw(in: stringRechteckX330)
    89. text = auswahlZeilenObjekt.masse
    90. paragraphStyle.alignment = .left
    91. attributedString.draw(in: stringRechteckX340)
    92. }
    93. y = y + 30
    94. // End Draw of page
    95. UIGraphicsEndPDFContext()
    96. }
    97. }
    Alles anzeigen
  • Dann brauchst Du doch nur einen Datei-Pfad bzw. eine URL vom Benutzer erfragen ... per Eingabe, Dialog für Ordner-Navigation oder sonstwie. Allerdings wird die Datei immer in der Sandbox Deiner App gespeichert werden.

    Diese Angabe nutzt Du dann in UIGraphicsBeginPDFContextToFile, fertig.

    Alternativ kannst Du auch mit dem UIDocumentPickerViewController arbeiten, um außerhalb Deiner App zu speichern. Da bewege ich mich aber auf dünnem Eis :)

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von MyMattes () aus folgendem Grund: Typo... UIPickerViewDocumentController -> UIDocumentPickerViewController

  • I habe noch den einen und anderen Code gefunden und bin jetzt weiter, habe aber ein neues Problem.

    Vitalstoffcontroller[6161:165020] [default] [ERROR] Failed to determine whether URL/Users/lukashedinger/Library/Developer/CoreSimulator/Devices/4DE0F1A6-67B7-4909-8C46-78278D403E63/data/Containers/Data/Application/D72F4EE0-D330-4B2D-924E-E17FC805EF55/tmp/Vitalstoffwerte 21092018-21092018.pdf (n) is managed by a file provider

    Woanders habe ich etwas dazu gefunden, aber nicht verstanden was mein Fehler sein könnte.
    UIActivityViewController Error: Failed to determine whether URL is managed by a file provider
    How to save file in the documents folder?
    (Vielleicht auch ein bug von IOS 12 habe ich gelesen: forums.developer.apple.com/thread/103198 - ich werde noch weitere Versionen ausprobieren)

    Das Ziel ist es den User das pdf speichern zu lassen, wohin er will, aber wenn er auf save file Folder klickt, kommt oben genannter Fehler.

    Mein neuer Code. Alles was ich vermutlich nicht brauche habe ich aaskommentiert, aber drin gelassen.

    Interessant wäre auch die Frage, ob ich ihn auch drucken lassen kann. Müsste ich ihm dann die PdfData übergeben, Staat das file?

    also hier statt die Dateien (directoryURL) zu übergeben, könnte ich dem auch irgendwie meine (pdfdata) übergeben?

    let contents = try fm.contentsOfDirectory(at: directoryUrl, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
    let activityViewController = UIActivityViewController(activityItems: [contents[0]], applicationActivities: nil)


    Letze Frage: Welche Hervorhebung für den Quellcode ist bei SWIFT am sinnvollsten?

    C-Quellcode

    1. // 5. Save PDF file
    2. let dateiName = "Vitalstoffwerte " + heuteString
    3. let path = "\(NSTemporaryDirectory())\(dateiName).pdf"
    4. pdfData.write( toFile: path, atomically: true)
    5. print("open \(path)")
    6. // var fileUrl: URL = URL(fileURLWithPath: NSTemporaryDirectory())
    7. // fileUrl.appendPathComponent("foo")
    8. // fileUrl.appendPathExtension("bar")
    9. let fileUrl: URL = URL(fileURLWithPath: path)
    10. let directory = "\(NSTemporaryDirectory())"
    11. let directoryUrl : URL = URL(fileURLWithPath: directory)
    12. print("open \(fileUrl)")
    13. print("open \(directoryUrl)")
    14. let fm = FileManager.default
    15. //let fileName = String((fileUrl.lastPathComponent)) as NSString
    16. //let documentsUrl:URL = fm.urls(for: .documentDirectory, in: .userDomainMask).first!
    17. //let destinationFileUrl = documentsUrl.appendingPathComponent("\(fileName)")
    18. //print("open \(documentsUrl)")
    19. //do {
    20. // try fm.removeItem(at: destinationFileUrl)
    21. //} catch (let deleteError) {
    22. // print("Error deleting a file \(destinationFileUrl) : \(deleteError)")
    23. //}
    24. //do {
    25. // try FileManager.default.copyItem(at: fileUrl, to: destinationFileUrl)
    26. //} catch (let writeError) {
    27. // print("Error creating a file \(destinationFileUrl) : \(writeError)")
    28. //}
    29. do {
    30. //Show UIActivityViewController to save the downloaded file
    31. let contents = try fm.contentsOfDirectory(at: directoryUrl, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
    32. print("open \(contents)")
    33. //for i in 0..<contents.count {
    34. let activityViewController = UIActivityViewController(activityItems: [contents[0]], applicationActivities: nil)
    35. self.present(activityViewController, animated: true, completion: nil)
    36. // for IPAD
    37. if let popOver = activityViewController.popoverPresentationController {
    38. popOver.sourceView = self.view
    39. //popOver.sourceRect =
    40. //popOver.barButtonItem
    41. }
    42. //}
    43. // return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]lastObject];
    44. } catch {
    45. print("Fehler")
    46. }
    47. }
    Alles anzeigen

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Lukas Hedinger ()

  • Ich mag gerade auf‘m Schlauch stehen (war ein wahnsinniger Tag), aber was genau willst Du mit dem UIActivityController erreichen? Ich wüsste nicht, dass man mit diesem eine Dateiselektion realisieren kann ... Eher die normalen Aktionen wie „Copy to Pasteboard“.

    Oder willst Du das „Save to files“ von dort verwenden? Dann musst Du doch die Datei als URL liefern, oder? Irgendwie verstehe ich noch nicht, was Du konkret machen willst. Oder kopierst Du gerade nur Code zusammen?

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • Ja ich will "Saves to files" verwenden, so dass der User das Dokument z. B. in die Cloud speichern kann und ich gebe UIActivityController auch die URL. Im Simulator kann ich auch Save to Files auswählen, aber dann kommt der oben genannte Fehler.

    Die Datei ist vorhanden und ich übergebe die URL, aber irgendwie geht es trotzdem nicht.

    Es ist doch richtig, dass ich das (NSTemporaryDirectory()) Directory dem UIActivityViewController übergebe.
    (Testweise habe ich auch versucht die Datei in Dokumenten Ordner zu kopieren und dann dem UIActivityViewController zu übergeben, mit dem gleichen Resultat).


    let path = "\(NSTemporaryDirectory())\(dateiName).pdf"
    let fileUrl: URL = URL(fileURLWithPath: path)

    let directory = "\(NSTemporaryDirectory())"
    let directoryUrl : URL = URL(fileURLWithPath: directory)

    let contents = try fm.contentsOfDirectory(at: directoryUrl, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)

    for i in 0..<contents.count
    let activityViewController = UIActivityViewController(activityItems: [contents[0]], applicationActivities: nil)
    self.present(activityViewController, animated: true, completion: nil)


    Mein Plan ist es das gleiche zu machen, wie bei der Androidversion. Dort mache ich ein PDF Dokument und öffne es mit dem Printmanager und der Benutzer kann dann entscheiden ob er es drucken will oder irgendwo als PDF speichern. Schade, dass es so etwas bei IOS nicht gibt :(. Deshalb versuche ich es eben so, bekomme aber diesen Fehler.

    Vitalstoffcontroller[6161:165020] [default] [ERROR] Failed to determine whether URL/Users/lukashedinger/Library/Developer/CoreSimulator/Devices/4DE0F1A6-67B7-4909-8C46-78278D403E63/data/Containers/Data/Application/D72F4EE0-D330-4B2D-924E-E17FC805EF55/tmp/Vitalstoffwerte 21092018-21092018.pdf (n) is managed by a file provider

    Hast du vielleicht eine Idee, wo ich weiter suchen könnte. In einem der Link steht etwas mit NSURL, statt URL, aber dass soll nach meinem Fachbuch veraltet sein. Bin gerade wieder einmal Ratlos. Na ja das mit der SQL Datenbank habe ich auch irgendwie geschafft, die letzte Hürde werde ich auch noch schaffen :)

    Auf jeden Fall danke für all deine Hilfe und ein möglichst schönen entspannten Tag. :)
  • Ich verstehe Deine Schleife über den Inhalt eines Verzeichnissses, in der Du dann scheinbar den ViewController präsentieren willst, nicht. Aber so ohne Code-Tags ist Dein Programm auch mühsam zu lesen.

    Hangle Dich doch schrittweise an das Thema heran: Nimm die Apple-Dokumentation des Controllers und eine fixe Datei, deren Pfad Du kennst, und versuche dann - ohne PDF-Erstellung oder ähnlichem - einfach mal den UIActivityViewController an‘s Fliegen zu bekommen...

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • Entschuldige die Schlaufe hat sich reingeschlichen, ich habe jetzt den code noch weiter vereinfacht:

    // pdf Daten speichern
    let dateiName = "Vitalstoffwerte " + heuteString
    let path = "\(NSTemporaryDirectory())\(dateiName).pdf"
    pdfData.write( toFile: path, atomically: true)

    // URL aus dem Pfad erstellen
    let fileUrl: URL = URL(fileURLWithPath: path)

    // activityViewController definieren
    let activityViewController = UIActivityViewController(activityItems: [fileUrl], applicationActivities: nil) // muss vielleicht hier statt nil, was anderes stehen, ich denke nicht?

    // Popup erstellen, damit IPAD nicht abstürzt
    activityViewController.popoverPresentationController?.sourceView = self.view

    // activityViewController präsentieren
    self.present(activityViewController, animated: true, completion: nil)

    Nun öffnet das Programm einen View Controller, und gibt dem Benutzer die Möglichkeit die Datei zu speichern, aber dann kommt:

    Vitalstoffcontroller[6161:165020] [default] [ERROR] Failed to determine whether URL/Users/lukashedinger/Library/Developer/CoreSimulator/Devices/4DE0F1A6-67B7-4909-8C46-78278D403E63/data/Containers/Data/Application/D72F4EE0-D330-4B2D-924E-E17FC805EF55/tmp/Vitalstoffwerte 21092018-21092018.pdf (n) is managed by a file provider

    Ich habe auch andere Möglichkeiten versucht, mit dem documentInteractionController und share, aber das gab das gleiche Resultat.
  • Ich meine, dass man UIActivityViewController keine URLs als activityItems übergeben kann.

    Evtl. ist es möglich, anstelle der URL direkt die PDF Daten zu übergeben. Sollte dies nicht funktionieren, dann musst Du ein Wrapper Objekt vom Typ UIActivityItemProvider verwenden. Alternativ kannst Du auch eine eigene Klasse verwenden, welche das UIActivityItemSource Protokoll verwendet.
  • ok danke für deine Antwort. Zufällig habe ich selber herausgefunden, dass ich PDF Daten übergeben kann und das geht. Jetzt habe ich aber herausgefunden, dass mein PDF leer ist und muss jetzt herausfinden wo ich draw benutzen muss, damit es das pdf füllt.

    Falls es jemand interessiert. Hier ist der Code:

    Quellcode

    1. // Save pdf DATA through user
    2. let activityViewController = UIActivityViewController(activityItems: [pdfData], applicationActivities: nil)
    3. activityViewController.popoverPresentationController?.sourceView = self.view // für IPAD nötig
    4. self.present(activityViewController, animated: true, completion: nil)
    und mehr dazu ist hier zu finden:

    PDF zeichnen und speichern

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Lukas Hedinger ()