Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

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な部分ではないでしょうか。

ofl
Ruby on RailsやJavascriptを使った開発を行います。
https://impala-web.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away