「大好きなお弁当屋さんのレシートアプリを作ろう!」
この例では、お客さんの購入した品目を入力し、PDFレシートを生成できるレシートアプリを作ります。PDFレシートはHTMLテンプレートに基づいて生成されます。
この記事で学ぶこと:
- 表を含むウェブページのコーディング(簡単)
- PDFファイルをHTMLの文字列から生成
- PDFのプレビューウィンドウを表示
スタータープロジェクト
ここでスタータープロジェクトをダウンロードする必要があります。これは、顧客のレシートにアイテムを入力できるミニ販売管理ソフトウェアです。
完成したプロジェクトはこちらで見ることができます。
HTML文字列の準備
PDFはWebページから生成されるため、いくつかのHTMLコードを記述する必要があります。
HTMLヘッダー
headerHTMLstring
というヘルパー関数を追加できます。 htmlファイルのヘッダーには、Webページのタイトル、テーブルのスタイル、およびテーブルの最初の行(ヘッダー)があります。
func headerHTMLstring() -> String {
//htmlヘッダーを生成します。
//たとえば、ここに店の名前を入力できます
return """
<!DOCTYPE html>
<html>
<head>
<title>レシート</title>
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
</style>
<body>
<h2>Invoice</h2>
<table style="width:100%">
<tr>
<th>名前</th>
<th>価格</th>
</tr>
"""
}
もちろん、レシートをかっこよく見せるために、そこにあなたの店舗の写真を追加することができます。または、レシートの番号や購入時刻を追加することもできます。
各販売アイテムの個別の行
ここで、表内で1つの行を表すHTMLコードを生成する関数を追加します。その行には、販売アイテムの名前とその価格が含まれています。
func getSingleRow(itemName: String, itemPrice: Int) -> String {
return """
<tr>
<td>\(itemName)</td>
<td>\(String(itemPrice))</td>
</tr>
"""
}
HTMLフッター
ついにHTMLフッターを追加
func footerHTMLstring() -> String {
return """
</table>
</body>
</html>
"""
}
HTML文字列を準備
今や私たちは、ヘッダー、列、フッターを組み合わせてHTML文字列を作成します
私たちは完成したHTML文字列を蓄積する変数からスタートします。
var htmlString = ""
HTMLのヘッダーの内容を変数に追加します。
let htmlHeader = headerHTMLstring()
htmlString.append(htmlHeader)
セール品を追加するために商品配列にループ処理を行ってください
var totalPrice = 0
for item in items {
let name = item.name
let price = item.price
let rowString = getSingleRow(itemName: name, itemPrice: price)
htmlString.append(rowString)
totalPrice += price
}
すると合計金額とHTMLファイルのフッターを追加できます
// 合計金額を追加する
htmlString.append("\n 合計金額: \(totalPrice) yen \n")
// フッターを取得する
let footerString = footerHTMLstring()
htmlString.append(footerString)
これでHTMLのWebページのコードが完成したことになります。PDFファイルの生成作業をしていきましょう。
HTML文字列からPDFファイルを作成しましょう
ここでは UIPrintPageRenderer
, UIMarkupTextPrintFormatter
, UIGraphics
を使います
まずレンダラーの設定を行い、希望の紙のサイズを指定します
let renderer = UIPrintPageRenderer()
let paperSize = CGSize(width: 595.2, height: 841.8) //B6
let paperFrame = CGRect(origin: .zero, size: paperSize)
renderer.setValue(paperFrame, forKey: "paperRect")
renderer.setValue(paperFrame, forKey: "printableRect")
HTML文字列をフォーマッターに入力します
let formatter = UIMarkupTextPrintFormatter(markupText: fromHTML)
renderer.addPrintFormatter(formatter, startingAtPageAt: 0)
UIGraphics
を使ってHTML文字列をPDFに変換します
UIGraphicsBeginPDFContextToData(pdfData, .zero, [:])
for pageI in 0..<renderer.numberOfPages {
UIGraphicsBeginPDFPage()
renderer.drawPage(at: pageI, in: UIGraphicsGetPDFContextBounds())
}
UIGraphicsEndPDFContext()
作成されたPDFデータを一時ファイルに保存します
データをアプリの一時ストレージに保存するのに使える便利な機能を紹介しています
/*
この関数は、特定の `data` をアプリの一時ストレージに保存します。さらに、そのファイルが存在する場所のパスを返します。
*/
func saveToTempDirectory(data: NSData) -> URL? {
let tempDirectory = NSURL.fileURL(withPath: NSTemporaryDirectory(), isDirectory: true)
let filePath = tempDirectory.appendingPathComponent("receipt-" + UUID().uuidString + ".pdf")
do {
try data.write(to: filePath)
return filePath
} catch {
print(error.localizedDescription)
return nil
}
}
ユーザーへのPDFのプレゼンテーション
さて、デバイスにPDFファイルが保存されているので、 QLPreviewController
を通してそれを表示することが可能となりました:
PDFファイルまでのローカルパスを変数に保存する必要があります。
self.PDFpath = savedPath
let previewController = QLPreviewController()
previewController.dataSource = self
present(previewController, animated: true, completion: nil)
さて今度は、デリゲート・ファンクションを実装し、 QLPreviewController
がファイルの読み取りとロードする場所を認識できるようにします。
extension ViewController: QLPreviewControllerDataSource {
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
if self.PDFpath != nil {
return 1
} else {
return 0
}
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
guard let pdfFilePath = self.PDFpath else {
return "" as! QLPreviewItem
}
return pdfFilePath as QLPreviewItem
}
}