はりまや日記

なんか適当にいろいろ綴ったりなんかするところ

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 を別ファイルに書いてるので、普通に読み込んでロードすればいいですよね。
そうしましょう。