Qt for AndroidのQtライブラリを自前で用意してロードする

つまり、Ministro 2を使用しないでアプリを実行する方法です。
この方法では、Ministroがインストールされてなくても大丈夫になります。

誤解の無いように。
通常のNecessitas SDKをインストールした状態でOKです。
ソースからビルドする必要はありません。


/// プロジェクトの設定 ///
 「実行時の設定」→「Deploy configurations」
  「Deploy local qt libs」 : 端末にライブラリを転送するかの設定(1回だけでOK)
  「Use local qt libs」 : 上の設定で転送されたライブラリを使うかの設定
 を、ONにする。
 これで、端末にライブラリが転送(adb pushされる)されて使用されます。
 何度も転送してるとadb serverがおかしくなって途中で固まったりするのでよっぽどじゃなければ1回だけにしておくといいです。
 

※注意
・プロジェクトを閉じるたびに上記設定はデフォルトに戻ります。
・ローカルライブラリを使用する設定はQt Creatorから実行した時のみ。
・SSLのルート証明書はデプロイされません。

2つ目がいけてません。
どうせデバッグで使ってるので普段からローカルライブラリを使いたいです。
Qt Creatorから起動する時にインテントでローカルライブラリを使う設定を付加して起動しているので通常のランチャからの起動ではこの情報が無くてMinistro経由になってしまいます。

なので、ちょこっといじって通常のランチャからの起動でもローカルライブラリを使用するように変更してみます。
あとデバッグとリリースでソースを切り替えるのは面倒だしミスの元なので、ローカルライブラリがある時はそっちを使うようにしてみます。

3つ目については、アプリでSSLを使用する場合に限って「Qt for AndroidのQtライブラリを自前でビルドしてかつ、SSLを使用する時のルート証明書を用意する」を参照して証明書をコピーしてください。


補足情報
API Levelにあわせて使用するライブラリが変わるので以下の情報をチェックしてSDKのバージョンが変わった時などに修正します。
「プロジェクト」→「実行時の設定」→「Deploy configurations」→「Edit rules file」
で確認可能。
実体は、「<SDK DIR>/android-qt/lib/rules.xml」



/// サンプル ///
修正するソースはプロジェクトの設定でAPI Levelを変更すると上書きされたりするので消えても大丈夫なように最小限の変更にとどめます。
なので、必要なコードは別クラスのstaticなメソッドにしておきます。

QtActivity.javaの修正
「startApp」というメソッドを修正します。
01.// 略
02. 
03.// 追加
04.import org.kde.necessitas.origo.QtActivityExtension;
05. 
06.// 略
07. 
08.public class QtActivity extends Activity
09.{
10. 
11.    // 略
12. 
13.    private void startApp(final boolean firstStart)
14.    {
15.        try
16.        {
17.            ActivityInfo ai=getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
18.            if (ai.metaData.containsKey("android.app.qt_libs_resource_id"))
19.            {
20.                int resourceId = ai.metaData.getInt("android.app.qt_libs_resource_id");
21.                m_qtLibs=getResources().getStringArray(resourceId);
22.            }
23. 
24.            // 追加 ここから
25.            if(firstStart){
26.                Bundle params = QtActivityExtension.loadLocalLibrary(this, m_qtLibs);
27.                if(params == null){
28.                    // can't load
29.                }else{
30.                    // loaded
31.                    loadApplication(params);
32.                    return;
33.                }
34.            }
35.            // 追加 ここまで
36. 
37.            if (getIntent().getExtras()!= null && getIntent().getExtras().containsKey("use_local_qt_libs")
38.                    && getIntent().getExtras().getString("use_local_qt_libs").equals("true"))
39.            {
40.                ArrayList<String> libraryList= new ArrayList<String>();
41. 
42.                String localPrefix="/data/local/qt/";
43.                if (getIntent().getExtras().containsKey("libs_prefix"))
44.                    localPrefix=getIntent().getExtras().getString("libs_prefix");
45. 
46.    // 略
47.}


QtActivityExtension.javaの追加
001.package org.kde.necessitas.origo;
002. 
003.import java.util.ArrayList;
004.import java.io.File;
005. 
006.import android.app.Activity;
007.import android.content.Intent;
008.import android.util.Log;
009.import android.os.Environment;
010.import android.os.Bundle;
011.import android.os.Build;
012. 
013.public class QtActivityExtension
014.{
015.    //ここの定数はQtActivityからコピーしてくる
016.    private static final String ERROR_CODE_KEY="error.code";
017.    private static final String ERROR_MESSAGE_KEY="error.message";
018.    private static final String DEX_PATH_KEY="dex.path";
019.    private static final String LIB_PATH_KEY="lib.path";
020.    private static final String LOADER_CLASS_NAME_KEY="loader.class.name";
021.    private static final String NATIVE_LIBRARIES_KEY="native.libraries";
022.    private static final String ENVIRONMENT_VARIABLES_KEY="environment.variables";
023.    private static final String APPLICATION_PARAMETERS_KEY="application.parameters";
024.    private static final String BUNDLED_LIBRARIES_KEY="bundled.libraries";
025. 
026.    // Qtライブラリの保存パス
027.    private static final String LOCAL_PREFIX_BASE = "/data/local/qt/";
028. 
029.    // libの名称のバージョン番号取得配列
030.    // ~user/android-qt/lib/rules.xmlに合わせる
031.    private static final String[] SDK_2_LIB_VERSION = {
032.                                    "4"     // unknown
033.                                    , "4"   // unknown
034.                                    , "4"   // unknown
035.                                    , "4"   // unknown
036.                                    , "4"   // API Level 4
037.                                    , "5"   // API Level 5
038.                                    , "5"   // API Level 6
039.                                    , "5"   // API Level 7
040.                                    , "8"   // API Level 8
041.                                    , "9"   // API Level 9
042.                                    , "9"   // API Level 10
043.                                    , "9"   // API Level 11
044.                                    , "9"   // API Level 12
045.                                    , "9"   // API Level 13
046.                                    , "9"   // API Level 14
047.                                    };
048.    // jarの名称のバージョン番号取得配列
049.    // ~user/android-qt/lib/rules.xmlに合わせる
050.    private static final String[] SDK_2_JAR_VERSION = {
051.                                    "4"     // unknown
052.                                    , "4"   // unknown
053.                                    , "4"   // unknown
054.                                    , "4"   // unknown
055.                                    , "4"   // API Level 4
056.                                    , "7"   // API Level 5
057.                                    , "7"   // API Level 6
058.                                    , "7"   // API Level 7
059.                                    , "8"   // API Level 8
060.                                    , "14"   // API Level 9
061.                                    , "14"   // API Level 10
062.                                    , "14"   // API Level 11
063.                                    , "14"   // API Level 12
064.                                    , "14"   // API Level 13
065.                                    , "14"   // API Level 14
066.                                    };
067. 
068.    public static Bundle loadLocalLibrary(Activity activity, String[] qtLibs){
069.        Bundle ret = null;
070.        try
071.        {
072.            if(activity == null){
073.            }else{
074.                String sdcard_path = null;
075.                Intent intent = activity.getIntent();
076.                if(intent.getExtras()!= null){
077.                    Log.d("Qt", "--- Intent Info ---");
078.                    Log.d("Qt", "use_local_qt_libs="+intent.getExtras().containsKey("use_local_qt_libs"));
079.                    Log.d("Qt", "use_local_qt_libs="+intent.getExtras().getString("use_local_qt_libs"));
080.                    Log.d("Qt", "libs_prefix="+intent.getExtras().containsKey("libs_prefix"));
081.                    Log.d("Qt", "libs_prefix="+intent.getExtras().getString("libs_prefix"));
082.                    Log.d("Qt", "load_local_libs="+intent.getExtras().containsKey("load_local_libs"));
083.                    Log.d("Qt", "load_local_libs="+intent.getExtras().getString("load_local_libs"));
084.                    Log.d("Qt", "load_local_jars="+intent.getExtras().containsKey("load_local_jars"));
085.                    Log.d("Qt", "load_local_jars="+intent.getExtras().getString("load_local_jars"));
086.                    Log.d("Qt", "loader_class_name=" + intent.getExtras().containsKey("loader_class_name"));
087.                    Log.d("Qt", "loader_class_name="+ intent.getExtras().getString("loader_class_name"));
088.                }else if((new File(LOCAL_PREFIX_BASE)).exists()){
089.                    // パスのディレクトリがある
090. 
091.                    ArrayList<String> libraryList= new ArrayList<String>();
092. 
093.                    String localPrefix = LOCAL_PREFIX_BASE;
094.                    Log.d("Qt", "localPrefix=" + localPrefix);
095. 
096.                    // ライブラリの登録
097.                    if (qtLibs != null){
098.                        for(int i=0;i<qtLibs.length;i++)
099.                        {
100.                            libraryList.add(localPrefix+"lib/lib"+qtLibs[i]+".so");
101.                            Log.d("Qt", "add=" + localPrefix+"lib/lib"+qtLibs[i]+".so");
102.                        }
103.                    }
104.                    String lib = "plugins/platforms/android/libandroid-" + getLibVersionString() + ".so";
105.                    libraryList.add(localPrefix + lib);
106.                    Log.d("Qt", "add=" + localPrefix + lib);
107. 
108.                    // 中継jarの登録
109.                    String dexPaths = new String();
110.                    dexPaths = localPrefix + "jar/QtIndustrius-" + getJarVersionString() + ".jar";
111.                    Log.d("Qt", "dexPaths=" + dexPaths);
112. 
113.                    // ライブラリの存在確認
114.                    boolean libraryExist = true;
115.                    for (String item : libraryList) {
116.                        File file = new File(item);
117.                        if(file.exists() && file.isFile()){
118.                            //ok
119.                            Log.d("Qt", "exist=" + item);
120.                        }else{
121.                            Log.d("Qt", "not exist=" + item);
122.                            libraryExist = false;
123.                        }
124.                    }
125.                    if(libraryExist && (new File(dexPaths)).exists()){
126.                        Log.d("Qt", "exist=" + dexPaths);
127.                    }else{
128.                        Log.d("Qt", "not exist=" + dexPaths);
129.                        libraryExist = false;
130.                    }
131. 
132.                    // ロード設定作成
133.                    if(libraryExist){
134.                        String loaderClassName = "org.kde.necessitas.industrius.QtActivityDelegate";
135.                        String variablesKey = "QML_IMPORT_PATH="+ localPrefix + "imports"
136.                                                        + "\tQT_PLUGIN_PATH=" + localPrefix + "plugins"
137.                                                        + "\tMINISTRO_SSL_CERTS_PATH=" + localPrefix + "ssl";
138. 
139.                        Bundle loaderParams = new Bundle();
140.                        loaderParams.putInt(ERROR_CODE_KEY, 0);
141.                        loaderParams.putString(DEX_PATH_KEY, dexPaths);
142.                        loaderParams.putString(LOADER_CLASS_NAME_KEY, loaderClassName);
143.                        loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);
144.                        loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, variablesKey);
145.                        loaderParams.putString(APPLICATION_PARAMETERS_KEY,"-platform\tandroid");
146. 
147.                        ret = loaderParams;
148.                    }
149.                }else{
150.                }
151.            }
152.        }catch(Exception e){
153.            Log.e("Qt", "can't load locat library");
154.        }
155.        return ret;
156.    }
157. 
158. 
159.    // libのバージョン番号を文字列で取得する
160.    public static String getLibVersionString(){
161.        return SDK_2_LIB_VERSION[Build.VERSION.SDK_INT];
162.    }
163. 
164.    // jarのバージョン番号を文字列で取得する
165.    public static String getJarVersionString(){
166.        return SDK_2_JAR_VERSION[Build.VERSION.SDK_INT];
167.    }
168.}