QMLからhttpアクセスする場合は「XMLHttpRequest」を使用します。
よく出来ててURLに「https://hogehoge」とすれば自動的にopensslのプラグインを使用してくれます。
配布する場合は当然DLLを追加で同梱する必要があります。
実際に必要になるファイルはこちらを参照してください。
「QML(Qt)でWeb系機能を使用した場合に必要になるライブラリ(Dll)」
で、タイトルの通りなのですがアプリから初めて使用する場合に、自分の開発環境(Windows 7 / Core i7 / Memory 16GByte)では1秒程度かかりました。
細かく行くと「XMLHttpRequest::send()」の呼出の時に時間がかかってました。
Nokia N9では、100msec程度。
Httpアクセスのところを非同期で実行してくれるのにキックする所がブロックして時間かかるんじゃ本末転倒だよっ!という状況です。
「WorkerScript」エレメントを使ってアプリ起動時に裏で1回httpsで空振りさせておけば良いような気もしますが、負けた気がしたので下記のようなアクセス用のスクリプト?を作ってみた。
/// サンプル仕様? ///
・WorkerScriptエレメントを使用する。
・上位の呼び出し元へのコールバック関数の情報を管理するためのIDを作成する。
・WorkerScriptへHttpアクセスに必要な情報と上記IDをJavaScript Objectで渡す。(※1)
・別のJavaScriptファイルでコールバック関数の情報を管理する。(※2)
ここで上記IDとコールバックを結びつけて登録と引き出し用のインターフェースを用意。
これで呼出とコールバックの順番が入れ子になっても大丈夫。(な、予定)
※1 WorkerScriptには関数オブジェクトシグナルを渡せないため。
※2 エレメントのプロパティには関数オブジェクトシグナルが保存できないため。
追記 関数オブジェクトを.toString()して保存してevalで戻せばOKでした。
さすがにシグナルはダメっぽいです。
いちおう、POSTデータも送り込めるように変数は用意していますが実際に試してません。
WorkerScriptの制限で上手に渡して工夫しないとダメかも知れません。
とりあえずってことで。
よく出来ててURLに「https://hogehoge」とすれば自動的にopensslのプラグインを使用してくれます。
配布する場合は当然DLLを追加で同梱する必要があります。
実際に必要になるファイルはこちらを参照してください。
「QML(Qt)でWeb系機能を使用した場合に必要になるライブラリ(Dll)」
で、タイトルの通りなのですがアプリから初めて使用する場合に、自分の開発環境(Windows 7 / Core i7 / Memory 16GByte)では1秒程度かかりました。
細かく行くと「XMLHttpRequest::send()」の呼出の時に時間がかかってました。
Nokia N9では、100msec程度。
Httpアクセスのところを非同期で実行してくれるのにキックする所がブロックして時間かかるんじゃ本末転倒だよっ!という状況です。
「WorkerScript」エレメントを使ってアプリ起動時に裏で1回httpsで空振りさせておけば良いような気もしますが、負けた気がしたので下記のようなアクセス用のスクリプト?を作ってみた。
/// サンプル仕様? ///
・WorkerScriptエレメントを使用する。
・上位の呼び出し元へのコールバック関数の情報を管理するためのIDを作成する。
・WorkerScriptへHttpアクセスに必要な情報と上記IDをJavaScript Objectで渡す。(※1)
・別のJavaScriptファイルでコールバック関数の情報を管理する。(※2)
ここで上記IDとコールバックを結びつけて登録と引き出し用のインターフェースを用意。
これで呼出とコールバックの順番が入れ子になっても大丈夫。(な、予定)
※1 WorkerScriptには
※2 エレメントのプロパティには
追記 関数オブジェクトを.toString()して保存してevalで戻せばOKでした。
さすがにシグナルはダメっぽいです。
いちおう、POSTデータも送り込めるように変数は用意していますが実際に試してません。
WorkerScriptの制限で上手に渡して工夫しないとダメかも知れません。
とりあえずってことで。
サンプル本体
/// 追記 ///
※1・2についてKenji Sugitaさんよりアドバイスをいただきましたので調べて見ました。
もともと試してできないと思ってたのですが若干乗り越えました。
関数オブジェクトはプロパティに保存したりWorkerScriptへ渡せることがわかりました。
ただし、シグナルは渡せませんでした。そもそもシグナルの型は「object」で「function」じゃないので当然かもしれませんが・・・。
上のサンプルにこんなコードを追加して試してみました。
実行するとこんな感じ
typeof param = object
typeof param.func = string
typeof test = object
typeof test.func = string
typeof test.func(eval) = function
response1:
call 1 ok?(eval)
typeof param = object
typeof param.func = string
typeof test = object
typeof test.func = string
:1: SyntaxError: Parse error
おまけ
QtSDK 4.8RCでは、sslに必要なdllが「C:\QtSDK\Desktop\Qt\4.8.0\mingw\bin」にありませんでした。
なのでエラーがでます。
4.7.4の環境から以下のファイルをコピーすれば使えます。
libeay32.dll
libssl32.dll
ssleay32.dll
<Category : Qt>
import QtQuick 1.0 Rectangle { width: 360 height: 360 Text { id: _text text: qsTr("Http test") anchors.centerIn: parent } MouseArea { anchors.fill: parent property int counter: 1 onClicked: { var url; url = "https://www.google.co.jp/"; //url = "http://www.google.co.jp/" _text.text = counter; counter ++; // Httpアクセス url = "https://www.google.co.jp/"; _http.requestHttp("", "GET", url, response); // url = "https://www.twitter.com/"; // _http.requestHttp("", "GET", url, response2); } } // HTTPアクセス補助エレメント HttpAccess{ id: _http } function response(text){ console.debug("response1:"); console.debug(text.substring(0,100)); } function response2(text){ console.debug("response2:"); console.debug(text.substring(0,100)); } }Httpアクセスの補助エレメント
// HttpAccess.qml import QtQuick 1.0 import "httpAccessParam.js" as HttpAccessParam WorkerScript { id: _root source: "HttpAccess.js" onMessage: { // Workerスレッドからの通信イベント var func = HttpAccessParam.shift(messageObject.id).func; func(messageObject.text); } // 呼出し簡略化用 function requestHttp( data , method , url, on_func){ // ユニークID作成 var id = HttpAccessParam.getId(); // httpアクセス情報作成 var request = {"data": data , "method": method , "url": url , "id": id}; // コールバック情報保存 var callback = {"id" : id , "func": on_func}; HttpAccessParam.push(callback); // スレッド開始 _root.sendMessage(request); } }WorkerScriptの本体
// HttpAccess.js // data // method // url // id WorkerScript.onMessage = function(message) { console.debug("start worker:" + message.id); requestHttp(message.data, message.method, message.url, message.id); } function requestHttp( data , method , url, param) { //XMLHttpRequestオブジェクト生成 var httpoj = new XMLHttpRequest(); //open メソッド httpoj.open( method , url , true ); //受信時に起動するイベント httpoj.onreadystatechange = function(){ //readyState値は4で受信完了 if (httpoj.readyState==4){ //コールバック responseHttp(httpoj, param); } } //send メソッド httpoj.send( data ); } function responseHttp(httpoj, param) { console.debug("finish worker:" + param); WorkerScript.sendMessage({ "text": httpoj.responseText, "id": param }) }コールバック情報の管理
// HttpAccessParams.js var params = []; //ユニークなIDを作るっぽい var id_counter = 0; function getId(){ return (id_counter++) + ""; } // 後ろに追加 function push(obj){ params.push(obj); } // 特定のIDの情報を取り出す // 基本は先入れ先だしの予定 // 後から登録したのより遅く来るのはきっと後ろに入れても問題ない・・・ function shift(id){ var obj = params.shift(); while(obj.id !== id){ // 目的のものじゃなければ後ろに入れなおす params.push(obj); obj = params.shift(); } return obj; }
/// 追記 ///
※1・2についてKenji Sugitaさんよりアドバイスをいただきましたので調べて見ました。
もともと試してできないと思ってたのですが若干乗り越えました。
関数オブジェクトはプロパティに保存したりWorkerScriptへ渡せることがわかりました。
ただし、シグナルは渡せませんでした。そもそもシグナルの型は「object」で「function」じゃないので当然かもしれませんが・・・。
上のサンプルにこんなコードを追加して試してみました。
property variant test: "" signal response3(string text) onResponse3: { console.debug("response3:"); console.debug(text.substring(0,100)); _text.text = text; } // 中略 // 通常の関数を渡せるか var param = {"func": response.toString()}; console.debug("typeof param = " + typeof param); console.debug("typeof param.func = " + typeof param.func); test = param; console.debug("typeof test = " + typeof test); console.debug("typeof test.func = " + typeof test.func); var func = eval("(" + test.func + ")"); console.debug("typeof test.func(eval) = " + typeof func); func("call 1 ok?(eval)"); // シグナルを渡せるか param = {"func": response3.toString()}; console.debug("typeof param = " + typeof param); console.debug("typeof param.func = " + typeof param.func); test = param; console.debug("typeof test = " + typeof test); console.debug("typeof test.func = " + typeof test.func); func = eval("(" + test.func + ")"); // ここでパースエラー console.debug("typeof test.func(eval) = " + typeof func); func("call 3 ok?(eval)");
実行するとこんな感じ
typeof param = object
typeof param.func = string
typeof test = object
typeof test.func = string
typeof test.func(eval) = function
response1:
call 1 ok?(eval)
typeof param = object
typeof param.func = string
typeof test = object
typeof test.func = string
おまけ
QtSDK 4.8RCでは、sslに必要なdllが「C:\QtSDK\Desktop\Qt\4.8.0\mingw\bin」にありませんでした。
なのでエラーがでます。
4.7.4の環境から以下のファイルをコピーすれば使えます。
libeay32.dll
libssl32.dll
ssleay32.dll
コメント (2)
※1※2eval したら関数オブジェクトになるものを設定または渡すようにしてできませんか。
投稿者: Kenji Sugita | 2012年01月28日 23:37
日時: 2012年01月28日 23:37
> Kenji Sugita さん
アドバイスありがとうございます。
その方法でダメだと思ってましたが関数オブジェクトは渡せることがわかりましたので記事を修正しました。
自分としては最終的にシグナルを渡したかったので、それをstringに一旦変換出来るのか?を調べないとです。
投稿者: あやね | 2012年01月29日 10:55
日時: 2012年01月29日 10:55