post Image
SpeakerDeckのスライドをPDF形式で表示できるiOSアプリを作った

SpeakerDeckのスライドをPDF形式で表示できるiOSアプリを作った

背景

IMG_6577.PNG

勉強会のスライドなど、Speaker Deckに掲載されているスライドをよく閲覧するのですが、1ページずつしか進めないし、数ページ前に戻りたくても1ページずつしか戻れないし…なにより保存できないし…
もう少しスマートに閲覧したいと思い、PDF形式で保存・表示できるアプリをRxSwiftの練習を兼ねて作ってみました。

作ったもの

https://github.com/natmark/SlideStock

IMG_6577.gif
Speaker Deckのユーザ名 / スライド名もしくはスライドURLを入力したら、
スライド情報を保存してPDF表示できるものを作ってみました。

やったこと

スライドのURLを入力

Kanna を用いてスクレイピング

スライドIDなどの情報を保存

webViewでPDFを表示

スライドURLの入力

URLTextField.rx.controlEvent([.editingDidEnd])
    .flatMap({
        self.URLTextField.text.flatMap(Observable.just) ?? Observable.empty()
    })
    .bind(to: viewModel.urlString)
    .addDisposableTo(disposeBag)

textFieldの入力終了後に、textFieldに入力されているtextの内容をviewModelのurlStringに渡すようにしました。

Kannaを用いたスクレイピング

今回、Swift製のHTMLパーサKannaを使用してスクレイピングを行いました。

Swift製HTMLパーサ「Kanna」
詳しい使い方はこちらを参考にしてください。

//HTMLソースをData形式で取得
let data = try FetchSlideRequest.getHTML(path: path)
//HTMLDocument形式に変換
let doc = HTML(html: data, encoding: String.Encoding.utf8)
guard let details = doc?.body?.css("div#talk-details").first else { return }

//スライドのタイトルを取得
guard let title = details.css("h1").first?.innerHTML else { return }
//スライドの作者を取得
guard let author = details.css("a").first?.innerHTML else { return }
//PDF形式のスライドのURLを取得
guard let pdfURL = doc?.body?.css("#share_pdf").first?["href"] else { return }

スライドIDなどの情報を保存

 var importSlide: Observable<Void> {
    return Observable
        .zip(slideTitle, slideAuthor, slideId, pdfURL, importTrigger) { slideTitle, slideAuthor, slideId, pdfURL, importTrigger -> Void in
            let slide = Slide()
            slide.title = slideTitle
            slide.author = slideAuthor
            slide.id = slideId
            slide.pdfURL = pdfURL
            let realm = try! Realm()
            try? realm.write {
                realm.add(slide, update: true)
            }
    }
}

importTriggerが発火したときに、取得していたタイトルや作者などをRealmに保存するようにしてみました。

PDFの表示

WebViewを使用することでPDFビューワーを実装しなくても済むようにしました。
URLRequestのキャッシュを使用しているので、PDFファイル自体は保存していません。

guard let url = URL(string: slide.pdfURL) else {
     return
}
self.WKView.load(URLRequest(url: url))

今回、プログレスバーを使用したかったため、WKWebViewを使用しました。

self.WKView.rx.estimatedProgress.bind(onNext: {
    self.navigationController?.setProgress(Float($0), animated: false)
}).addDisposableTo(disposeBag)

RxSwiftを使用していたので、こんな感じに書けました。
Rx+WebKit.swift : WebKitのRxExtensionを使用させてもらいました。

まとめ

個人的に結構使い勝手がいいです。
Safariから直接アプリに取り込めるようにしたい!


『 Swift 』Article List