よく出来てて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の制限で上手に渡して工夫しないとダメかも知れません。
とりあえずってことで。
サンプル本体
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
Kenji Sugita
※1※2eval したら関数オブジェクトになるものを設定または渡すようにしてできませんか。
あやね
> Kenji Sugita さん
アドバイスありがとうございます。
その方法でダメだと思ってましたが関数オブジェクトは渡せることがわかりましたので記事を修正しました。
自分としては最終的にシグナルを渡したかったので、それをstringに一旦変換出来るのか?を調べないとです。