SpeakerDeckのスライドをPDF形式で表示できるiOSアプリを作った
背景
勉強会のスライドなど、Speaker Deckに掲載されているスライドをよく閲覧するのですが、1ページずつしか進めないし、数ページ前に戻りたくても1ページずつしか戻れないし...なにより保存できないし...
もう少しスマートに閲覧したいと思い、PDF形式で保存・表示できるアプリをRxSwiftの練習を兼ねて作ってみました。
作ったもの
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から直接アプリに取り込めるようにしたい!