[PencilKit]Webブラウザに直接メモを書き込めるアプリを作った


イントロ

6月にあった WWDC 2019 でPencilKitが発表されました。

これは純正メモアプリなどで使用されているペンツールをサードパーティーアプリでも使用できるようにするもので、Apple Pencil関連のアプリ開発のハードルが一気に下がります。

PencilKit 概要

PencilKitの主なパーツについて書いていきます。
間違いがありましたらご指摘いただけると幸いです。

PKCanvasView

Apple Pencilでの書き込みを受け付けるViewです。
UIScrollViewを継承しており、ContentSizeを拡大することでスクロールなども行うことができます。

PKDrawing

Apple Pencilによる書き込みデータです。
Codableを継承しているので、エンコードしてファイルとして保存することもできます。

PKToolPicker

ペンの色を選択したり、消しゴムを選択したりするペンツールセットです。
viewではなくwindowに対して紐付けして使用します。

PencilKit周りのいろいろ

var canvasView: PKCanvasView!
var toolPicker : PKToolPicker?

PKCanvasViewの初期化

指での書き込みを無効化

canvasView.allowsFingerDrawing = false

背景の透明化

canvasView.isOpaque = false

PKToolPickerの表示

AppleのDocumentationにあるExampleが大変参考になりました。
https://developer.apple.com/documentation/pencilkit/drawing_with_pencilkit

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    if let window = parent?.view.window, let toolPicker = PKToolPicker.shared(for: window) {
        self.toolPicker = toolPicker
        self.toolPicker!.setVisible(true, forFirstResponder: canvasView)
        self.toolPicker!.addObserver(canvasView)
        self.toolPicker!.addObserver(self)
        canvasView.becomeFirstResponder()
    }
    parent?.view.window?.windowScene?.screenshotService?.delegate = self
}

ツールの表示・非表示の切り替えはsetVisible()で行うことができます。

func togglePickerTool(_ visible : Bool){
    if toolPicker != nil {
        toolPicker!.setVisible(visible, forFirstResponder: canvasView)
    }
}

PKDrawingの保存

PKDrawing単体で管理するのは大変なので、IDなどと一緒に保存します。
保存するデータのひとまとまりを次のクラスで定義します。

public class Note : Codable {
    public var drawing: PKDrawing
    public var uuid = UUID()
    // その他タイトルや最終更新日など必要なものを定義
}

ファイルへの保存

let note = Note(drawing: canvasView.drawing)
let localDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let url = localDirectory.appendingPathComponent("\(note.uuid).custom")

let encoder = PropertyListEncoder()

do {
    let data = try encoder.encode(note)
    try data.write(to: url)
    print("successfully saved item \(note.uuid)")
} catch {
    os_log("Could not save data model: %s", type: .error, error.localizedDescription)
}

ファイルの読み込み

var loadedNote: Note

let decoder = PropertyListDecoder()

do {
    let data = try Data(contentsOf: url)
    loadedNote = try decoder.decode(Note.self, from: data)
} catch {
    os_log("Could not load data model: %s", type: .error, error.localizedDescription)
}

おわりに

今回簡単にApple Pencilを用いたアプリが開発できるようになったので、PencilKitとWKWebViewを組み合わせたアプリケーションを作成しました。

個人的にはQiitaやMedium等の記事に色々思ったことを書き込んでいく、、、ということを想定して作っています。

よろしければぜひ使ってみてください。

Notewind