我将PDF保存为我的应用程序,但我希望让用户将PDF文档保存在应用程序之外的目录中。 (对不起,英语不好,我来自瑞士。)
格式化程序中的markupText是否有一些重要的内容,我必须将其用于某些内容?
我认为-UIGraphicsBeginPDFContextToFile(pathForPDF,rect,nil)-将文件保存在我的应用程序的文档目录中,是否正确?
其他问题。我的代码中有任何错误。我从这里的答案中提取了很多代码,希望即时通讯正确无误。
import UIKit
import Foundation
class PdfErstellung {
static func PdfErstellen(_ auswahlZeilen : [LebensmittelDataTV], _ vitalstoffWerteListe : [LebensmittelDataTV], _ heuteString : String) {
var html = "<html><head><meta charset='UTF-8'></head><body>Erstelle Vitalstoffwerte PDF</body></html"
// 1. Create Print Formatter with input text.
let formatter = UIMarkupTextPrintFormatter(markupText: html)
// 2. Add formatter with pageRender
let render = UIPrintPageRenderer()
render.addPrintFormatter(formatter, startingAtPageAt: 0)
// 3. Assign paperRect and printableRect
let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4, 72 dpi
let printable = page.insetBy(dx: 0, dy: 0)
let rect = CGRect.zero
render.setValue(NSValue(cgRect: page), forKey: "paperRect")
render.setValue(NSValue(cgRect: printable), forKey: "printableRect")
// 4. Create PDF context and draw
let fileName = "Vitalstoffwerte " + heuteString
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
let pathForPDF = documentsDirectory.appendingFormat("/" + fileName)
UIGraphicsBeginPDFContextToFile(pathForPDF, rect, nil)
// Start Draw of page
var y = 0
var stringRechteckX50 = CGRect(x: 50, y: y, width: 100, height: 20)
var stringRechteckX160 = CGRect(x: 160, y: y, width: 30, height: 20)
var stringRechteckX170 = CGRect(x: 170, y: y, width: 10, height: 20)
var stringRechteckX220 = CGRect(x: 220, y: y, width: 100, height: 20)
var stringRechteckX330 = CGRect(x: 330, y: y, width: 30, height: 20)
var stringRechteckX340 = CGRect(x: 340, y: y, width: 10, height: 20)
var paragraphStyle = NSMutableParagraphStyle()
var font = UIFont(name: "Helvetica Bold", size: 20.0)
var text = ""
let attributes = [
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: font,
NSAttributedString.Key.foregroundColor: UIColor.black
]
var attributedString = NSAttributedString(string: text, attributes: attributes)
// ÜBERSCHRIFT
font = UIFont(name: "Helvetica Bold", size: 20.0)
text = "Tagesbedarf in % vom " + heuteString
paragraphStyle.alignment = .left
var stringRechteck = CGRect(x: 50, y: 50, width: 300, height: 40)
attributedString.draw(in: stringRechteck)
// Vitalstoffwerte Liste
y = 80
for zeile in 0..<vitalstoffWerteListe.count {
let druckenVitalstoffWerte = vitalstoffWerteListe[zeile]
if druckenVitalstoffWerte.zeilenInfoID == 0 { // Überschrift
y = y + 10
font = UIFont(name: "Helvetica Bold", size: 14.0)
text = druckenVitalstoffWerte.name
attributedString.draw(in: stringRechteckX50)
} else { // Detail
font = UIFont(name: "Helvetica", size: 12.0)
text = druckenVitalstoffWerte.name
attributedString.draw(in: stringRechteckX50)
text = druckenVitalstoffWerte.anzahl
paragraphStyle.alignment = .right
attributedString.draw(in: stringRechteckX160)
text = druckenVitalstoffWerte.masse
paragraphStyle.alignment = .left
attributedString.draw(in: stringRechteckX170)
}
y = y + 30
}
y = 80
text = "Lebensmittel"
font = UIFont(name: "Helvetica Bold", size: 14.0)
paragraphStyle.alignment = .left
attributedString.draw(in: stringRechteckX220)
// Lebensmittelliste
y = 120
for zeile in 0..<auswahlZeilen.count {
let auswahlZeilenObjekt = auswahlZeilen[zeile]
font = UIFont(name: "Helvetica", size: 12.0)
text = auswahlZeilenObjekt.name
attributedString.draw(in: stringRechteckX220)
text = auswahlZeilenObjekt.anzahl
paragraphStyle.alignment = .right
attributedString.draw(in: stringRechteckX330)
text = auswahlZeilenObjekt.masse
paragraphStyle.alignment = .left
attributedString.draw(in: stringRechteckX340)
}
y = y + 30
// End Draw of page
UIGraphicsEndPDFContext()
}
// I think the Pdf was saved before, but i do not know exactly
static func savePdf(_ urlString: String, _ fileName: String) {
DispatchQueue.main.async {
let url = URL(string: urlString)
let pdfData = try? Data.init(contentsOf: url!)
let resourceDocPath = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last! as URL
let pdfNameFromUrl = "YourAppName-\(fileName).pdf"
let actualPath = resourceDocPath.appendingPathComponent(pdfNameFromUrl)
do {
try pdfData?.write(to: actualPath, options: .atomic)
print("pdf successfully saved!")
} catch {
print("Pdf could not be saved")
}
}
}
}
----编辑-----
我有很多改变。感谢您提供的链接,我找到了其他链接并有了新的想法。
我的下一个问题是:
Vitalstoffcontroller [6161:165020] [默认] [错误]无法确定URL / Users / lukashedinger / Library / Developer / CoreSimulator / Devices / 4DE0F1A6-67B7-4909-8C46-78278D403E63 /数据/容器/数据/应用程序/ D72F4EE0-D330-4B2D-924E-E17FC805EF55 / tmp / Vitalstoffwerte 21092018-21092018.pdf(n)由文件提供商管理
我发现了这个,但不明白我的错误是什么。
UIActivityViewController Error: Failed to determine whether URL is managed by a file provider
How to save file in the documents folder?
(也许是IOS 12的错误,我读过:https://forums.developer.apple.com/thread/103198)
我的新密码
// 5. Save PDF file
let dateiName = "Vitalstoffwerte " + heuteString
let path = "\(NSTemporaryDirectory())\(dateiName).pdf"
pdfData.write( toFile: path, atomically: true)
print("open \(path)")
// var fileUrl: URL = URL(fileURLWithPath: NSTemporaryDirectory())
// fileUrl.appendPathComponent("foo")
// fileUrl.appendPathExtension("bar")
let fileUrl: URL = URL(fileURLWithPath: path)
let directory = "\(NSTemporaryDirectory())"
let directoryUrl : URL = URL(fileURLWithPath: directory)
print("open \(fileUrl)")
print("open \(directoryUrl)")
let fm = FileManager.default
//let fileName = String((fileUrl.lastPathComponent)) as NSString
//let documentsUrl:URL = fm.urls(for: .documentDirectory, in: .userDomainMask).first!
//let destinationFileUrl = documentsUrl.appendingPathComponent("\(fileName)")
//print("open \(documentsUrl)")
//do {
// try fm.removeItem(at: destinationFileUrl)
//} catch (let deleteError) {
// print("Error deleting a file \(destinationFileUrl) : \(deleteError)")
//}
//do {
// try FileManager.default.copyItem(at: fileUrl, to: destinationFileUrl)
//} catch (let writeError) {
// print("Error creating a file \(destinationFileUrl) : \(writeError)")
//}
do {
//Show UIActivityViewController to save the downloaded file
let contents = try fm.contentsOfDirectory(at: directoryUrl, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
print("open \(contents)")
//for i in 0..<contents.count {
let activityViewController = UIActivityViewController(activityItems: [contents[0]], applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil)
// for IPAD
if let popOver = activityViewController.popoverPresentationController {
popOver.sourceView = self.view
//popOver.sourceRect =
//popOver.barButtonItem
}
//}
// return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]lastObject];
} catch {
print("Fehler")
}
}
-------更新:找到了解决我的问题的方法,但是没有解决文件-----
我将pdfData直接提供给ViewController,并且不将其保存到文件中。
UIActivityViewController(activityItems:[pdfData],applicationActivities:nil)
我不使用文件,这样对我来说已经足够
答案 0 :(得分:-1)
我完成了,那就是我的代码
func SavePdfUser(){
// Create page rect
let pageRect = CGRect(x: 0, y: 0, width: 595.28, height: 841.89) // A4, 72 dpi
// Create PDF context and draw
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, pageRect, nil)
UIGraphicsBeginPDFPage()
// From here you can draw page, best make it in a function
PdfErstellung.PdfErstellen(auswahlZeilen, vitalstoffWerteListe, heuteString)
UIGraphicsEndPDFContext()
// Save pdf DATA through user
let activityViewController = UIActivityViewController(activityItems: [pdfData], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view // für IPAD nötig
self.present(activityViewController, animated: true, completion: nil)
// save temporary for preview
let dateiName = "Vitalstoffwerte " + heuteString
let fileUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(dateiName).pdf")
do {
try pdfData.write(to: fileUrl, options: .atomic)
} catch {
print(error,"file not save")
}
// Preview
let webview = WKWebView(frame: UIScreen.main.bounds)
view.addSubview(webview)
webview.load(URLRequest(url: fileUrl))
}
导入UIKit 导入基金会
PdfErstellung类{
static func PdfErstellen(_ auswahlZeilen : [LebensmittelDataTV], _ vitalstoffWerteListe : [LebensmittelDataTV], _ heuteString : String) {
var y = 0 // Points from above - von oben
var x = 0 // Points form left - von links
var width = 0 // length of rect - länge vom rechteck
var height = 0 // height of rect - höhe vom rechteck
var stringRechteck = CGRect(x: x, y: y, width: width, height: height) // make rect for text - rechteck für Text
var paragraphStyle = NSMutableParagraphStyle() // text alignment - text ausrichtung
var font = UIFont(name: "HelveticaNeue-Bold", size: 10.0) // Important: the font name must be written correct - Wichtig: Textname muss korrekt geschrieben werden
var text = ""
let attributes = [
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: font,
NSAttributedString.Key.foregroundColor: UIColor.black
]
// Title - ÜBERSCHRIFT
font = UIFont(name: "HelveticaNeue-Bold", size: 20.0)
text = "Tagesbedarf in % vom " + heuteString // heuteString = date/datum
paragraphStyle.alignment = .left
x = 50; y = 30; width = 300; height = 40
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text.draw(in: stringRechteck, withAttributes: attributes)
// List - Vitalstoffwerte Liste
y = 45
for zeile in 0..<vitalstoffWerteListe.count {
let druckenVitalstoffWerte = vitalstoffWerteListe[zeile]
if druckenVitalstoffWerte.zeilenInfoID == 0 { // Title - Überschrift
y = y + 5 // distance to above becaus is title - Abstand nach oben, weil Überschrift
x = 50; width = 80; height = 20
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
font = UIFont(name: "HelveticaNeue-Bold", size: 10.0) // change font - verändere schrift
text = druckenVitalstoffWerte.name
text.draw(in: stringRechteck, withAttributes: attributes)
font = UIFont(name: "HelveticaNeue", size: 8.0) // change font back - schrift zurück ändern
} else { // or detail
x = 50; width = 90; height = 20
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text = druckenVitalstoffWerte.name
text.draw(in: stringRechteck, withAttributes: attributes)
x = 150; width = 40
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text = druckenVitalstoffWerte.anzahl
paragraphStyle.alignment = .right
text.draw(in: stringRechteck, withAttributes: attributes)
paragraphStyle.alignment = .left
x = 195; width = 20
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text = druckenVitalstoffWerte.masse
text.draw(in: stringRechteck, withAttributes: attributes)
}
y = y + 10 // 10 down for next line - 10 nach unten für nächste Zeile
}
// Title - Überschrift
x = 220; y = 50; width = 100; height = 20
text = "Lebensmittel"
font = UIFont(name: "HelveticaNeue-Bold", size: 8.0)
paragraphStyle.alignment = .left
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text.draw(in: stringRechteck, withAttributes: attributes)
font = UIFont(name: "HelveticaNeue", size: 8.0)
// List - Lebensmittelliste
y = 60
for zeile in 0..<auswahlZeilen.count {
let auswahlZeilenObjekt = auswahlZeilen[zeile]
x = 220; width = 90; height = 20
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text = auswahlZeilenObjekt.name
text.draw(in: stringRechteck, withAttributes: attributes)
x = 320; width = 40
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text = auswahlZeilenObjekt.anzahl
paragraphStyle.alignment = .right
text.draw(in: stringRechteck, withAttributes: attributes)
paragraphStyle.alignment = .left
x = 365; width = 20
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text = auswahlZeilenObjekt.masse
text.draw(in: stringRechteck, withAttributes: attributes)
y = y + 10
if zeile == 75 { // 76 items - Zeilen
break
}
}
y = 60
if auswahlZeilen.count > 75 { // new
for zeile in 76..<auswahlZeilen.count {
let auswahlZeilenObjekt = auswahlZeilen[zeile]
x = 390; width = 90; height = 20
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text = auswahlZeilenObjekt.name
text.draw(in: stringRechteck, withAttributes: attributes)
x = 490; width = 40
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text = auswahlZeilenObjekt.anzahl
paragraphStyle.alignment = .right
text.draw(in: stringRechteck, withAttributes: attributes)
paragraphStyle.alignment = .left
x = 535; width = 20
stringRechteck = CGRect(x: x, y: y, width: width, height: height)
text = auswahlZeilenObjekt.masse
text.draw(in: stringRechteck, withAttributes: attributes)
y = y + 10
if zeile == 151 { // 76 items - Zeilen
break
}
}
}
}
}
-编辑-仅在iOS 12中才是问题专家。
我不知道为什么,但是在某些模拟器中:我可以制作文件,并将URL赋予UIActivityViewController,并且我拥有自己的文件名,而其他URL则失败,我必须直接给pdfData。
我的想法:我先尝试使用URL,如果失败,则提供pdfData
do {
let dateiName = "Vitalstoffwerte " + heuteString
let fileUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(dateiName).pdf")
do {
try pdfData.write(to: fileUrl, options: .atomic)
} catch {
print(error,"file not save")
}
let activityViewController = UIActivityViewController(activityItems: [fileUrl], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view // für IPAD nötig
self.present(activityViewController, animated: true, completion: nil)
} catch {
let activityViewController = UIActivityViewController(activityItems: [pdfData], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view // für IPAD nötig
self.present(activityViewController, animated: true, completion: nil)
}
我的问题专家,如何找出用户是否可以保存文件(如果尝试过),是否可以在日志中询问错误代码?该做,抓不走。
2018-09-25 15:36:55.787894 + 0200 Vitalstoffcontroller [8656:186334] [默认] [错误]无法确定URL / Users / lukashedinger / Library / Developer / CoreSimulator / Devices / 45A185C5-6DEA-4A52 -B415-939758FB7F7E / data / Containers / Data / Application / 2469BE4A-53B2-4545-B5D7-E64FBCDB383E / tmp / Vitalstoffwerte 25092018-25092018.pdf(n)由文件提供商管理 2018-09-25 15:36:56.312499 + 0200 Vitalstoffcontroller [8656:186334] [ShareSheet]已取消请求-错误:操作无法完成。参数无效
-编辑-
一个临时解决方案是,在ios12中,我将数据提供给UIActivityViewController,否则我将数据另存为文件,并将URL提供给UIActivityViewController。
if #available(iOS 12.0, *) {
let activityViewController = UIActivityViewController(activityItems: [pdfData], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view // für IPAD nötig
self.present(activityViewController, animated: true, completion: nil)
} else {
let dateiName = "Vitalstoffwerte " + heuteString
let fileUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(dateiName).pdf")
do {
try pdfData.write(to: fileUrl, options: .atomic)
} catch {
print(error,"file not save")
}
let activityViewController = UIActivityViewController(activityItems: [fileUrl], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view // für IPAD nötig
self.present(activityViewController, animated: true, completion: nil)
}