iOSでガワネイティブで、WebViewで動かしてるJavaScriptからSwiftにURLのパラメータに乗せてデータを渡すことができたが、普通URLの長さには制限があるので、もっとでかいデータを渡す場合には違う方法をとる必要がある。

JSからネイティブにでかいデータを受け渡す方法

URLパラメータじゃなく、POSTで送ればある程度のサイズの制限は回避できる。JSからPOSTを送るには例によってAjaxを使う:

// test.js
function foobar(url, stringData) {
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (200 <= xhr.status && xhr.status < 300) {
      // 成功
    } else if (xhr.status >= 400) {
      // 失敗
    }
  };
  xhr.open('POST', url, false);  // 第3引数=asyncかどうか
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  xhr.send(stringData);
}

foobar('http://native/foobar', 'BigData')
  • 受け渡すデータはa=x&b=y&...という形式でなくても、改行などを含んでいても受け渡すことができる

SwiftでPOSTデータを受け取る

iOSガワネイティブでSwiftから値を受け取ると同様に、NSURLProtocolを継承して拡張したクラスを定義して、所定のURLをフックしてPOSTのデータを受け取る:

// MyURLProtocol.swift
import UIKit

class NativeURLProtocol: NSURLProtocol {
  // 以下のメソッドで所定のURLをフック
  //override class func canInitWithRequest(request: NSURLRequest) -> Bool
  //override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest

  override func startLoading() {
    // POSTデータを受け取る
    let httpBody: NSData? = request.HTTPBody
    ...
  }
}
  • 注意点として、POSTを受け取るURLのスキームはhttphttpsである必要がある。これを自分で独自に定義したスキームを使うとrequest.HTTPBodynilになってしまい、受け取れない。