PullToRefresh.jsとWKWebViewを使ってリフレッシュ時に触角フィードバックを実装する
ニコニコログの開発の中ではタイムラインの更新機能のために "PullToRefresh.js" を利用しています。また、iOS版のニコニコログも基本的には TAppKit をベースに開発しているため、表示部分の多くは WKWebView を使用しています。
ニコニコログ開発の記録の連載記事の初期にも書いている通り、
PullToRefresh.js 側の処理
以下のコードは CoffeeScript ですが、JavaScript や TypeScript の場合は便宜置き換えてみてください。
PullToRefresh.init({
mainElement: SELECTOR
onRefresh: ->
if window.webkit isnt undefined
window.webkit.messageHandlers.callbackHandler.postMessage('runHapticTouchSuccess')
})
window.webkit.messageHandlers.callbackHandler.postMessage('runHapticTouchSuccess')
の部分で、WKWebView 側に通知を送ります。
WKWebView 側の実装
最初、Storyboard で WKWebView も置いてたんですが、WKWebViewConfiguration を定義してやらなきゃいけなかった都合、WKWebView の初期化プロセスは以下のようになりました。
var webview: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let webviewConfiguration:WKWebViewConfiguration = WKWebViewConfiguration()
let webviewUserContentController:WKUserContentController = WKUserContentController()
webviewUserContentController.add(self, name: "callbackHandler")
webviewConfiguration.userContentController = webviewUserContentController
// UINotificationFeedBackGenerator を初期化しておく
self.feedbackGenerator = UINotificationFeedbackGenerator()
self.feedbackGenerator?.prepare()
webview = WKWebView(frame: self.view.bounds, configuration: webviewConfiguration)
self.view.addSubview(webview)
}
それから、ViewController も以下のように拡張しておきます。
class ViewController: UIViewController, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if (message.body as? String) != nil {
let msg:String = message.body as! String
if msg == "runHapticTouchSuccess" {
self.feedbackGenerator?.notificationOccurred(.success)
} else if msg == "runHapticTouchError" {
self.feedbackGenerator?.notificationOccurred(.error)
}
}
}
}
この userContentController が JavaScript 側から送った postMessage() を拾ってくれます。postMessage() で何が送られてきたかに応じて、UINotificationFeedbackGenerator に対して .notificationOccurred() を使って触角フィードバックを送ります。
ちなみに .notificationOccurred() で使える触角フィードバックは以下の通りです。
- .success
- .error
- .warning
試してみるとわかりますが、.success と .error は明らかに違うんですが、.warning と .success のフィードバックの違いはよくわかりませんでした。
あとこの触角フィードバックは、最近の iPhone で 3D Touch や Haptic Touch に対応しているものでは当然動きますが、iPad や iPhone SE などの触角フィードバックに対応していない端末では機能しません。ただし例外処理など書く必要はないようで、単純に非対応端末の場合は上のコードを書いてあっても触角フィードバックが発生しないだけでちゃんと動きます。
最近、Swift もいろいろ書いているのでネタはまだまだいろいろ出てきそうです。