WKWebViewにHTML表示させ、PDF化する(Swift2.2, XCode7.3.1)のつづき
したいこと
iPad側でPDF作成して、Windowsサーバに送信する。
サーバ側はジェネリックハンドラ(ashx)で受信して、PDFを保存する。
サーバ側の処理をPHPで行えば、とても簡単にできました。
PHPの場合の参考URL
PHPがNGでジェネリックハンドラで処理しなければいけなかったので、苦労したのでメモしておきます。
コード
ViewController.swift
import UIKit
import WebKit
extension NSMutableData {
func appendString(string: String) {
let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
appendData(data!)
}
}
class ViewController: UIViewController, WKNavigationDelegate, UIScrollViewDelegate {
private var subView: UIView!
private var webView: WKWebView!
override func viewDidLoad()
{
super.viewDidLoad()
let size = view.frame.size
subView = UIView(frame: CGRectMake(0, 0, size.width, size.height - 50))
let btn = UIButton(type: .System)
btn.frame = CGRectMake(0, size.height - 50, 90, 40)
btn.setTitle("set HTML", forState: .Normal)
btn.addTarget(self, action: #selector(ViewController.tapBtn(_:)), forControlEvents: .TouchUpInside)
let btn2 = UIButton(type: .System)
btn2.frame = CGRectMake(size.width * 0.35, size.height - 50, 90, 40)
btn2.setTitle("set from web", forState: .Normal)
btn2.addTarget(self, action: #selector(ViewController.tapBtn2(_:)), forControlEvents: .TouchUpInside)
let btn3 = UIButton(type: .System)
btn3.frame = CGRectMake(size.width * 0.7, size.height - 50, 90, 40)
btn3.setTitle("create pdf", forState: .Normal)
btn3.addTarget(self, action: #selector(ViewController.tapBtn3(_:)), forControlEvents: .TouchUpInside)
view.addSubview(subView)
view.addSubview(btn)
view.addSubview(btn2)
view.addSubview(btn3)
webView = WKWebView()
setupSubViews(subView)
}
internal func tapBtn(sender: UIButton) {
// webView.loadHTMLString(getStrFromFile("test.html"), baseURL: nil)
webView.loadHTMLString("hoge<br>piyo<br>foo<br>bar<br>hogeeeeeeeeeeeeeeeee", baseURL: nil)
}
internal func tapBtn2(sender: UIButton) {
let req = NSURLRequest(URL: NSURL(string:"http://www.yahoo.co.jp/")!)
webView.loadRequest(req)
}
internal func tapBtn3(sender: UIButton) {
// let path = NSHomeDirectory().stringByAppendingString("/hoge.pdf")
// PDFMaker.make([webView], path: path)
// PDFファイルは作成せずにNSData化する
let data = PDFMaker.make([webView])
// data.writeToURL(NSURL(fileURLWithPath: path), atomically: true)
uploadPDF(data)
}
private func setupSubViews(v: UIView)
{
// webView.navigationDelegate = self
// webView.scrollView.delegate = self
webView.translatesAutoresizingMaskIntoConstraints = false
v.addSubview(webView)
var viewBindingsDict = [String: AnyObject]()
viewBindingsDict["webView"] = webView
v.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[webView]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewBindingsDict))
v.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[webView]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewBindingsDict))
}
private func uploadPDF(pdfData: NSData) -> Bool {
var ret = true
let request = NSMutableURLRequest(URL: NSURL(string: "ashxファイルのURL")!)
request.HTTPMethod = "POST"
let param = [
"userId" : "12345"
]
let boundary = generateBoundaryString()
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
request.HTTPBody = createBodyWithParameters(param, filePathKey: "file", dataKey: pdfData, boundary: boundary)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
ret = false
}
print("******* response = \(response)")
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("****** response data = \(responseString!)")
dispatch_async(dispatch_get_main_queue(),{
});
}
task.resume()
return ret
}
private func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, dataKey: NSData, boundary: String) -> NSData {
let body = NSMutableData()
if parameters != nil {
for (key, value) in parameters! {
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString("\(value)\r\n")
}
}
// let filename = "user-profile.jpg"
let filename = "1234567890.pdf"
// let mimetype = "image/jpg"
let mimetype = "application/pdf"
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
body.appendString("Content-Type: \(mimetype)\r\n\r\n")
body.appendData(dataKey)
body.appendString("\r\n")
body.appendString("--\(boundary)--\r\n")
return body
}
private func generateBoundaryString() -> String {
return "Boundary-\(NSUUID().UUIDString)"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// プロジェクトに追加したローカルファイルの文字列取得
private func getStrFromFile(fname: String) -> String {
var ret = ""
var path = NSString(string: fname)
// Encode 日本語ファイル対応
path = path.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
let ext = path.pathExtension
let filename = path.stringByDeletingPathExtension
do {
if let path = NSBundle.mainBundle().pathForResource(filename, ofType: ext) {
ret = try String(contentsOfFile: path, encoding: NSUTF8StringEncoding)
}
} catch {
print("error getStrFromFile")
}
return ret
}
}
// PDF作成クラス
class PDFMaker {
private class func renderViews(views: [UIView]) {
guard let context = UIGraphicsGetCurrentContext() else {
return
}
views.forEach {
if let scrollView = $0 as? UIScrollView {
let tmpInfo = (offset: scrollView.contentOffset, frame: scrollView.frame)
scrollView.contentOffset = CGPointZero
scrollView.frame = CGRect(origin: CGPointZero, size: scrollView.contentSize)
UIGraphicsBeginPDFPageWithInfo(scrollView.frame, nil)
$0.layer.renderInContext(context)
scrollView.frame = tmpInfo.frame
scrollView.contentOffset = tmpInfo.offset
} else {
UIGraphicsBeginPDFPageWithInfo($0.bounds, nil)
$0.layer.renderInContext(context)
}
}
}
class func make(views: [UIView], path: String) {
UIGraphicsBeginPDFContextToFile(path, CGRectZero, nil)
renderViews(views)
UIGraphicsEndPDFContext()
}
class func make(views: [UIView]) -> NSData {
let data = NSMutableData()
UIGraphicsBeginPDFContextToData(data, CGRectZero, nil)
renderViews(views)
UIGraphicsEndPDFContext()
return data
}
}
サーバ側.ashx.vb
Imports System.Web
Imports System.Web.Services
Imports System.IO
Public Class emsapp
Implements System.Web.IHttpHandler
Private resp As HttpResponse = Nothing
Private context As HttpContext = Nothing
Private dirPath As String = System.Configuration.ConfigurationManager.AppSettings("dirPath")
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
resp = context.Response
Me.context = context
context.Response.ContentType = "text/plain"
If Not IO.Directory.Exists(dirPath) Then
IO.Directory.CreateDirectory(dirPath)
End If
Dim files = context.Request.Files
For i As Integer = 0 To files.Count - 1
Dim file = files(i)
Dim fnameTmp = context.Server.MapPath("~/" + file.FileName)
file.SaveAs(fnameTmp)
Dim fname = IO.Path.Combine(dirPath, file.FileName)
If IO.File.Exists(fname) Then
IO.File.Delete(fname)
End If
IO.File.Move(fnameTmp, fname)
println(fname)
Next
'' PDFはできるが真っ白・・・
'Dim str = New StreamReader(context.Request.InputStream, context.Request.ContentEncoding).ReadToEnd()
''Dim sr As New System.IO.StreamReader(context.Request.InputStream)
''Dim str = New StreamReader(context.Request.InputStream).ReadToEnd
'Dim path = IO.Path.Combine(dirPath, "hoge.pdf")
''Dim sw = New StreamWriter(path, True, System.Text.Encoding.ASCII)
'Dim sw = New StreamWriter(path, True, System.Text.Encoding.Default)
'sw.Write(str)
'sw.Close()
End Sub
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
Private Sub print(ByVal s As String)
resp.Write(s)
End Sub
Private Sub println(ByVal s As String)
resp.Write(s + vbCrLf)
End Sub
End Class