UIWebViewのJavascriptとSwiftの相互のやり取りについて調べてみた。WKWebViewを使えばスマートに出来そうだけど、ios7で使いたかったので、WKWebViewを使わない方向で実装してみました。
ライブラリ(というほど大層なものではないですが)にしたので参考までにどうぞ。
https://github.com/gomo/JsNoty
PullToRefreshでAjaxを読み込みたい場合などに活躍すると思います。
SwiftからJavascriptへ
これは単純にstringByEvaluatingJavaScriptFromString
でイベントをfireしてあげればいけますね。
let script = String(format: "document.dispatchEvent(new CustomEvent(\"%@\", {detail:%@}))", name, "{foo:\"bar\"}");
データを渡したい時は{detail:%@}
というキーに入れるとJS側で取得できます。jQueryを使ってる時はevent. originalEvent.detail
になるのでそこを探してください。
JavascriptからSwiftへ
これは適当はprotocolでページをロードし、UIWebViewDelegate::shouldStartLoadWithRequest
で捕まえるのが一般的なようです。
Javascript側からは
location.href = 'jsnoty://foobar/';
Swift側では
class ViewController: UIViewController, UIWebViewDelegate, JsNotyDelegate {
private var jsNoty:JsNoty!;
override func viewDidLoad() {
super.viewDidLoad()
self.jsNoty = JsNoty(webView: self.webView)
self.jsNoty.delegate = self
let url = NSURL(string: "http://www.expample.com/path/to/page.html")
let request = NSURLRequest(URL: url!)
self.webView.loadRequest(request)
}
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if(request.URL!.scheme == "jsnoty"){
//ここで何かする
return false;
}
return true
}
気をつけないといけないのはwindow.onload
の中で呼ばないと、jsnoty://foobar/
が出ちゃいます。Chromeではページが読み込まれた後だと、存在しないprotocalの場合ページ遷移をしないようですが、ブラウザの互換を調べてないので、UIWebViewからのアクセス以外はしない方がいいかもしれません。
もう1点、Swift側で受信してから次を呼ばないと認識できないっぽいです。なのでJsNotyではキューイングして、Swift側の処理をまって次を呼ぶようにしました。自分で実装するとここがちょっと面倒かも。
ちなみに、iosからの接続時にUserAgentを書き換える方法も書いておきます。この3つを組み合わせれば、UIWebViewとWebページとの連携は大抵のことが出来ると思います。
UserAgentの書き換えは、最初の送信の前にやらないとダメなようです。なのでAppDelegate
でやるようです。
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//UserAgentを上書き
let webView:UIWebView = UIWebView()
let userAgent:String! = webView.stringByEvaluatingJavaScriptFromString("navigator.userAgent")
let customUserAgent:String = userAgent.stringByAppendingString(" from.ios.UIWebView")
let dic:NSDictionary = ["UserAgent":customUserAgent]
NSUserDefaults.standardUserDefaults().registerDefaults(dic as [NSObject : AnyObject])
return true
}