Re:

感銘高き名言は「1%のひらめきがなければ99%の努力は無駄である」(トーマス・エジソン)

タグ:iOS

※はじめに、ここで言うWEB技術ってのは単に webView を指します(・ω<)

今回の(とは、ポケットウォーズのこと)技術的な部分と言ったらバーコードスキャンなんだけれども、Mobile Safari でもう一点「音の同時再生ができない」という制約もある。

シングルトンなんだってさ。

プリロードも効かないから少しの遅延も起こる(これはテクニックで回避可能っちゃ可能(らしい)。まあ予めインスタンス化しておくとか、そんな感じ?)。


そのため、webView からスキームでネイティブのメソッドを実行させることで、BGMとSEの同時再生だったり、ボタン連打の連続した音だったり、バーコードスキャンを立ち上げたりといった連携技が可能だ。可能だ、というか、そのために側はネイティブで実装し AppStore から世に出す!


ちなみに、スキームの呼び出しは location.href だと連続でコケるので、iframe を作って消しての呼び出しにすれば解決する。


ネイティブ側での拾い方は、UIWebViewDelegate に自身クラスを設定して(self.webView.delegate = self とか。ヘッダでプロトコル追加も忘れずに <UIWebViewDelegate>)、リクエストがロードされるときに呼び出されるメソッド

相変わらずなげーなあああ

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;

でフックすれば(・∀・)イイ!!ってばよ!

{

if ([request.URL.scheme isEqualToString:@"native"]) {
// native://scan?key1=value1 とか呼び出された時に処理する内容
return NO; // ロード中断

}

--

そんでもって、行ったからには戻ることもたまには必要ってことで、ネイティブ側からウェブ側も最後に操作する。

こんな関数がウェブのコードに書かれていたら

function fromNative(message)
{
alert(message);
}

ネイティブ側からは webView に対して JavaScript 文字列を渡せば良いだけだってよ!実に簡単である。

NSString *message = @"ネイティブのメッセージだよ!";

NSString *javascript = [NSString stringWithFormat:@"fromNative(%@)", message];

[self.webView stringByEvaluatingJavaScriptFromString:javascript];

ブラウザに返すのかサーバに返すのか引数で処理分けとかしておくのも良さそう。

クエリ(native://scan?key1=value1 の key1=value1 部分)は
request.URL.query で取り出せる。また、ホスト( scan の部分)は request.URL.host で取り出せる。


あとは、バーコードからのモンスター出現ロジックをどうしよう。

けっこう深刻。

だって動かないんだからw

ホントかよーって思ったけど、確かに2回目以降はサーバサイドにリクエストは投げず、ブラウザがキャッシュしてるレスポンスデータで処理されてた。

なんてこったい!


とりあえず引用サイトでサンプルコード載せてくれてるので、ほぼそのまま実装しとけば $.ajax({type:'POST'}) や $.post() によるキャッシュ回避が可能。

タイムスタンプ付けて違うリクエストとして処理させる騙し技で十分な場合のみね。

iOS6 Mobile SafariがAjax POSTでキャッシュする問題を回避する方法 | クラスメソッド開発ブログ
http://dev.classmethod.jp/smartphone/ios6-safari-post-jquery/

ただ、jQueryMobile の section 動作においては GET, POST いずれでもなく、originalOptions に type プロパティが存在しないので、 jQueryMobile を導入したサイトでは上記サイトのサンプルコードそのままではエラーが起こってしまう。

なので、undefined チェックを追加しておく。以下。

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
+ if(originalOptions.type == undefined) {
+   return;
+ }
  if(originalOptions.type.toLowerCase() == 'post'){
    options.data = jQuery.param($.extend(originalOptions.data||{}, {
      timeStamp: new Date().getTime()
   }));
  }
});

↑このページのトップヘ