LoginSignup
3
3

More than 5 years have passed since last update.

iOSでTi.UI.WebView内のTi.APP.fireEventが実行できる仕組み

Posted at

Titaniumのネイティブ側とWebViewのHTML内のJavascriptでメソッドの実行やデータを橋渡しする仕組みとしては、evalJS()とTi.App.fireEvent/Ti.App.addEventListenerの二通りがあります。

iOSではもともとevalJSにあたる機能は用意されていますがWebViewからネイティブ側を呼び出せるようにはなっていません。ではどうやって実装されているのでしょうか?。

WebViewでHTMLをロードした際にTitaniumは こちらのJavascriptを追加します。
このうち、HTML側で呼び出されたTi.App.xxxやTi.API.xxxは

webview.js
Ti.App.fireEvent = function (name, evt) {
    Ti._broker('App', 'fireEvent', {
        name: name,
        event: evt
    })
};

のようにTi._broker(module, method, data)を呼び出します。
次にTi._broker()では「app://〜」で始まるURLにidやデータをシリアライズしたパラメータを追加したXMLHttpRequestを発行します。

webview.js
Ti.App._xhr = XMLHttpRequest;
Ti._broker = function (module, method, data) {
    try {
        var url = 'app://' + Ti.appId + '/_TiA0_' + Ti.pageToken + '/' + module + '/' + method + '?' + Ti.App._JSON(data, 1);
        var xhr = new Ti.App._xhr();
        xhr.open('GET', url, false);
        xhr.send()
    } catch (X) {}
};

「え、もしかしてTitaniumは内部にサーバーを起動させていて、、、?」いやそんなことはなく、単にネイティブ側はWebViewから呼び出されるURLの宛先を監視していて、そのうちapp://〜についてパラメータを解析することで実行するTitanium側のメソッドや引数を決定しているようです。

逆にネイティブ側からHTML側のTi.App.addEventListener (name, callback)でイベントを受け取る仕組みは、

webview.js
Ti.App._listeners = {};
Ti.App._listener_id = 1;

//(略)

Ti.App.addEventListener = function (name, fn) {
    var listeners = Ti.App._listeners[name];
    if (typeof (listeners) == 'undefined') {
        listeners = [];
        Ti.App._listeners[name] = listeners
    }
    var newid = Ti.pageToken + Ti.App._listener_id++;
    listeners.push({
        callback: fn,
        id: newid
    });
    Ti._broker('App', 'addEventListener', {
        name: name,
        id: newid
    })
};

で受け取るイベントをlisteners配列を登録しておきます。
そしてネイティブ側は登録されたlistenersに対するイベントがfireされるとTi.App._dispatchEvent(type, evtid, evt)を呼び出します。

webview.js
Ti.App._dispatchEvent = function (type, evtid, evt) {
    var listeners = Ti.App._listeners[type];
    if (listeners) {
        for (var c = 0; c < listeners.length; c++) {
            var entry = listeners[c];
            if (entry.id == evtid) {
                entry.callback.call(entry.callback, evt)
            }
        }
    }
};

こうしてネイティブとHTML内でメソッドやデータを受け渡しが他のグローバルイベントと同じ書き方で手軽に利用できる点はTitaniumのCoolな部分ではないでしょうか。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3