to pagetop
:)
spec5zigen Creator's Lab.

プログラマーの鷺谷です。

HTML5とアプリの分業

カタログやアンケートのようにコンテンツの分量が多かったり、
更新を容易にしたいiPhone/iPadアプリを作るケースでは、
HTML5で作成したコンテンツをUIWebviewで表示させてあとはデータベース等の処理だけを
アプリで分担すると分業もしやすいので便利です。

HTML5側とアプリ側をどうやって連携させるかCANVASで描画した内容をアプリで受け取ってさらにカメラロールに保存する処理を試してみました。

処理の概要

・アプリの機能呼び出し専用にスキーマ名を決めておく。
・JavascriptでCANVASの内容をtoDataURLで取得する。
・Javascriptで専用スキーマ名でURLへ移動。
・専用スキーマ名で判別してパラメタの内容をUIImageに変換する。
・UIImageをファイルとしてカメラロールに保存する。

Javascript側

toDataURLでCANVASの描画内容を
こんな感じのBASE64データとして取り出せます。
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAA(以下略)

Javascriptからアプリの機能を呼び出すためにアプリで独自に定義したスキーマ名を使ってURLへ移動します。

はじめうっかりスキーマ名をsp5canvas2_appとしてしまって認識してくれませんでした。使用可能な記号は+.-だけです。(rfc1738)

今回はスキーマ名をsp5canvas2appにしました。

var cv = $('#drawCanvas');
var drawImg = cv[0].toDataURL("image/png");
var execURL = 'sp5canvas2app://?save=' + drawImg;
window.location = execURL;

アプリ側

アプリ側ではUIWebviewのデリゲートで拾います。

JavascriptのtoDataURLの出力のうち、data:image/png;base64,のあとに続く部分をデコードしてNSDataにします。

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
  if(![[request.URL.scheme] isEqualToString:@"sp5canvas2app"]){
    return YES;
  }

  NSString * requestString = [[request URL] absoluteString];
  NSArray *params = [requestString componentsSeparatedByString:@"data:image/png;base64,"];//データ部分を切り出す

  // dataFromBase64String
  // NSData+Base64 Copyright 2009 Matt Gallagher. All rights reserved.
  // http://www.cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html
  NSData * decodedData = [NSData dataFromBase64String:[params objectAtIndex:1]];//decode base64 to NSData

  UIImage *image = [UIImage imageWithData:decodedData];
  UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);//カメラロールに保存
  return NO;
}

もっと分量の多いデータをやり取りするには

データ量はさほどでない場合ならよりシンプルな上記の方法が向いていますが、
getパラメタでデータが渡されるのでよりサイズの大きい内容をやり取りするには不向きです。

shouldStartLoadWithRequestを
処理きっかけと簡単なパラメタのやり取りだけに使って、データの受け渡しは
stringByEvaluatingJavaScriptFromString経由で
jsonデータでやり取りするとデータのサイズに依存しない処理ができます。