Twitterクライアントやその他公開されてるAPIにアクセスするアプリを作る時、サービス側にアプリを登録してIDやKEYを発行してそれをクライアント側に組み込むなんてのはよくある話だけど、GitHubとかでソースを公開する時にこれが丸々公開されちゃうのはあまりうまくない。
そんなことは言うまでもないのでみんないろいろな方法で公開されたソースコードに直接IDやKEYが載らないように工夫してるんだと思うんだけど、QtCreator使ってQt(QML)アプリを書くにあたって使える方法の一つを試してみた。
#qmakeの追加オプションでID/KEYを指定する
IDやKEYに限らず、ソースのあちこちで使う可能性があって且つ後で変更する可能性があるような定数は#defineで定義しちゃったりするのかなと思う。
#define ID 'foo'
#define KEY 'bar'
これはgccの-Dオプション等、ビルド時コンパイラに渡すことで直接ソースに書かなくても指定できる。
gcc -DID=¥"foo¥" -DKEY=¥"bar¥"
で、Qtの場合qmakeでMakefileを生成する(という説明で合ってるのかな?)ので、qmakeにそういうオプションを付けろという指示をしてあげる事になる。
その手のことはいちいちコマンドラインオプションで書くのは大変なので、原則はプロジェクトファイル(*.pro)に書くんだけど、今回の目的は「公開されているソースに載せない」ことなので、コマンドラインオプションとして追記する。
qmake 'DEFINES+=ID=¥¥¥"foo¥¥¥" KEY=¥¥¥"bar¥¥¥"'
注意するのは「"」の受け渡し。文字列としてコンパイラオプションに渡す時には「¥"」で囲まないとダメっぽいので「¥」と「"」をそれぞれエスケープして「¥¥」「¥"」として渡す。
#QtCreatorで使うとき
プロジェクトを開いた状態で「プロジェクト」→「ビルドステップ」→「qmake」を開いて「追加の引数」にDEFINESを書いとけばいい。上に書いたように複数渡す時にはスペース入れたりするから、全体を「'」で囲んで書いておこう。
'DEFINES+=ID=¥¥¥"foo¥¥¥" KEY=¥¥¥"bar¥¥¥"'
#うまくいかないとき
OSやQt(QtCreator)のバージョンに依っては単純に上の文字列を追加しても¥や"が意図した通りに処理されなくて「-DID=foo」とか「-DID="foo"」のようになり、C++のソース側でちゃんと文字列として扱ってもらえなくなるケースがあった。そんな時はプロジェクトファイルに
DEFINES += ID=¥¥¥"$$_ID¥¥¥" ¥
KEY=¥¥¥"$$_KEY¥¥¥"
のようにしておいて、qmakeへのオプションは
_ID="foo" _KEY="bar"
としておけばうまく渡せるっぽい。
#渡したID/KEYをQMLで使う
C++で書く分にはID、KEYという定数として使えばいいんだけど、QtQuickアプリで使いたいならQQmlContextを使って渡せばいいらしい。
...
#include <QQmlContext>
...
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("app_id", ID);
engine.rootContext()->setContextProperty("app_key", KEY);
こうしておくと、QML側で「app_id」「app_key」というプロパティが使えるようになる。
#QtCreatorでqmakeに渡す追加オプションはどこに保存される?
プロジェクトファイル(.pro)とは別に個別の環境で生成されるユーザファイル?(.pro.user)があって、こっちに他のローカル設定と一緒に保存されてる。プロジェクト生成時にバージョン管理を指定しても(手動で明示的に追加しない限りは)gitの管理範囲外になるし、環境毎に生成されるファイルだから公開されるソースに含まれていなくても全く支障はない(というか、普通は公開しないファイルだし)。
#〆
とゆーことで、わりと簡単にソースコードから生のID/KEYを取り除くことができた。
ただ、GitHubから取得したソースでは当然ビルドが通らなくなるから、どうやってID/KEYを指定すればいいかreadme.txtなりソース中のコメントなりで説明しといた方がいいと思う。