iphoneアプリ開発日記その9
webview のリンク長押しをなんとかする 一日目
やりたいこと
リンク長押しを検知して、リンクのURLとタイトルを取得したい
ということでやってみる
native からアプローチ
とりあえず長押しのジェスチャーを仕込めばいいのではないか。
そういう風に考えていた時期がありました。
とりあえずやってみる
ここを参考に、以下のコードを追加
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; [self.view addGestureRecognizer:longPress]; } -(void)handleLongPress:(UILongPressGestureRecognizer *)gesture { if (gesture.state == UIGestureRecognizerStateBegan) { NSLog(@"long pressed."); } }
あれ? 上手くいかないな…
もう少し調べてみると、次の関数も必要なようだった
参考
- (void)viewDidLoad { 〜〜略 longPress.delegate = self; } -(void)handleLongPress:(UILongPressGestureRecognizer *)gesture { if (gesture.state == UIGestureRecognizerStateBegan) { NSLog(@"long pressed."); } }
結果
2013-06-20 20:00:51.273 webTest[52816:11303] long pressed.
一応長押しのイベントは取れたが、リンクURLはどうすればいいのだろうか。
ここで手詰まりになった。
ググってみても、ほとんど javascript を使っているようだ。
じゃあ javascript でやってみることにしよう
javascript からアプローチ
この辺を参考にやってみる
UIWebViewのリンク長押しを簡単にハックする | エンジニア開発記
ARX Developers Blog: jQuery Mobileを使わずにスマートフォンのtapholdイベント
まず標準のロングプレスジェスチャを無効化
[self.webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout = 'none';"];
できた
次は関数定義か。リンクなんでaタグを取ればいいのかな?
NSString* script = @"$( document ).ready( function(){var interval = 500;$( \"a\" ).bind( \"touchstart\", function(){timer = setTimeout(function(){alert( \"リンク長押しされたっす\" );}, interval);function clearFunction(){clearTimeout(timer);}$( \"a\" ).bind( \"touchend touchmove touchcancel\", clearFunction );});});"; [self.webView stringByEvaluatingJavaScriptFromString:script];
うむ、見にくい。今後は普通にjavascript 書いて vi 辺りで置換しよう。
とりあえず動いたが、何をやっているのかよくわからない。
アラートを出してみる
$( document ).ready( function() { var interval = 500; $( "a" ).bind( "touchstart", function() { timer = setTimeout(function() { alert( "リンク長押しされたっす" ); }, interval); function clearFunction(){ clearTimeout(timer); alert("touch cancel!"); } $( "a" ).bind( "touchend touchmove touchcancel", clearFunction ); }); });
あれ? これだと長押しとキャンセルのアラートが両方出て、おかしくなってしまった。
ふむ、touchend って辺りが怪しいな。
このへんで関数とイベントをバインドしている、ということか。
touchcancel の時は別関数にしてみたが、どうにもcancelイベントが発生しない。
今の状況では起きないのかも
//これを追加 function cancelFunction(){ clearFunction; return "touch cancel!"; } //cancel 時の処理を分離 $( "a" ).bind( "touchend touchmove", clearFunction ); $( "a" ).bind( "touchcancel", cancelFunction );
ぐぬぬ…動きがよく掴めない
ログを吐こうとしたのだが、console.log も出ないし、return やってもうまくいかない。
そうだ native 連携しよう。
javascript → native 連携をやる
とりあえずログ吐きたいだけだが、どのみちやるつもりだったしいいよね!
ふむふむ、要は javascript から URL リクエスト飛ばして、native 側で URL 読み込むときに判別する感じか。
となると、こんな感じでいけそう
timer = setTimeout(function() { //alert( "リンク長押しされたっす" ); window.location = 'nativecode://touchstart/hoge'; }, interval);
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSURL* url = request.URL; if([[url scheme] isEqualToString:@"nativecode"]){ NSLog(@"from js. request: %@", request); NSLog(@" url: %@", url); NSLog(@" scheme: %@", url.scheme); NSLog(@" host: %@", url.host); NSLog(@" path: %@", url.path); } }
結果
2013-06-20 20:45:19.494 harafuwa[55203:11303] from js. request: <NSMutableURLRequest nativecode://touchstartxxx/hoge> 2013-06-20 20:45:19.494 harafuwa[55203:11303] url: nativecode://touchstartxxx/hoge 2013-06-20 20:45:19.494 harafuwa[55203:11303] scheme: nativecode 2013-06-20 20:45:19.495 harafuwa[55203:11303] host: touchstartxxx 2013-06-20 20:45:19.495 harafuwa[55203:11303] path: /hoge
これで結果を表示できる
というか今更ですが、javascript を別ファイルに書いてるので、普通に読み込んでロードすればいいですよね。
そうしましょう。