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」というメソッドを修正します。
// 略

// 追加
import org.kde.necessitas.origo.QtActivityExtension;

// 略

public class QtActivity extends Activity
{

    // 略

    private void startApp(final boolean firstStart)
    {
        try
        {
            ActivityInfo ai=getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
            if (ai.metaData.containsKey("android.app.qt_libs_resource_id"))
            {
                int resourceId = ai.metaData.getInt("android.app.qt_libs_resource_id");
                m_qtLibs=getResources().getStringArray(resourceId);
            }

            // 追加 ここから
            if(firstStart){
                Bundle params = QtActivityExtension.loadLocalLibrary(this, m_qtLibs);
                if(params == null){
                    // can't load
                }else{
                    // loaded
                    loadApplication(params);
                    return;
                }
            }
            // 追加 ここまで

            if (getIntent().getExtras()!= null && getIntent().getExtras().containsKey("use_local_qt_libs")
                    && getIntent().getExtras().getString("use_local_qt_libs").equals("true"))
            {
                ArrayList<String> libraryList= new ArrayList<String>();

                String localPrefix="/data/local/qt/";
                if (getIntent().getExtras().containsKey("libs_prefix"))
                    localPrefix=getIntent().getExtras().getString("libs_prefix");

    // 略
}


QtActivityExtension.javaの追加
package org.kde.necessitas.origo;

import java.util.ArrayList;
import java.io.File;

import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.os.Environment;
import android.os.Bundle;
import android.os.Build;

public class QtActivityExtension
{
    //ここの定数はQtActivityからコピーしてくる
    private static final String ERROR_CODE_KEY="error.code";
    private static final String ERROR_MESSAGE_KEY="error.message";
    private static final String DEX_PATH_KEY="dex.path";
    private static final String LIB_PATH_KEY="lib.path";
    private static final String LOADER_CLASS_NAME_KEY="loader.class.name";
    private static final String NATIVE_LIBRARIES_KEY="native.libraries";
    private static final String ENVIRONMENT_VARIABLES_KEY="environment.variables";
    private static final String APPLICATION_PARAMETERS_KEY="application.parameters";
    private static final String BUNDLED_LIBRARIES_KEY="bundled.libraries";

    // Qtライブラリの保存パス
    private static final String LOCAL_PREFIX_BASE = "/data/local/qt/";

    // libの名称のバージョン番号取得配列
    // ~user/android-qt/lib/rules.xmlに合わせる
    private static final String[] SDK_2_LIB_VERSION = {
                                    "4"     // unknown
                                    , "4"   // unknown
                                    , "4"   // unknown
                                    , "4"   // unknown
                                    , "4"   // API Level 4
                                    , "5"   // API Level 5
                                    , "5"   // API Level 6
                                    , "5"   // API Level 7
                                    , "8"   // API Level 8
                                    , "9"   // API Level 9
                                    , "9"   // API Level 10
                                    , "9"   // API Level 11
                                    , "9"   // API Level 12
                                    , "9"   // API Level 13
                                    , "9"   // API Level 14
                                    };
    // jarの名称のバージョン番号取得配列
    // ~user/android-qt/lib/rules.xmlに合わせる
    private static final String[] SDK_2_JAR_VERSION = {
                                    "4"     // unknown
                                    , "4"   // unknown
                                    , "4"   // unknown
                                    , "4"   // unknown
                                    , "4"   // API Level 4
                                    , "7"   // API Level 5
                                    , "7"   // API Level 6
                                    , "7"   // API Level 7
                                    , "8"   // API Level 8
                                    , "14"   // API Level 9
                                    , "14"   // API Level 10
                                    , "14"   // API Level 11
                                    , "14"   // API Level 12
                                    , "14"   // API Level 13
                                    , "14"   // API Level 14
                                    };

    public static Bundle loadLocalLibrary(Activity activity, String[] qtLibs){
        Bundle ret = null;
        try
        {
            if(activity == null){
            }else{
                String sdcard_path = null;
                Intent intent = activity.getIntent();
                if(intent.getExtras()!= null){
                    Log.d("Qt", "--- Intent Info ---");
                    Log.d("Qt", "use_local_qt_libs="+intent.getExtras().containsKey("use_local_qt_libs"));
                    Log.d("Qt", "use_local_qt_libs="+intent.getExtras().getString("use_local_qt_libs"));
                    Log.d("Qt", "libs_prefix="+intent.getExtras().containsKey("libs_prefix"));
                    Log.d("Qt", "libs_prefix="+intent.getExtras().getString("libs_prefix"));
                    Log.d("Qt", "load_local_libs="+intent.getExtras().containsKey("load_local_libs"));
                    Log.d("Qt", "load_local_libs="+intent.getExtras().getString("load_local_libs"));
                    Log.d("Qt", "load_local_jars="+intent.getExtras().containsKey("load_local_jars"));
                    Log.d("Qt", "load_local_jars="+intent.getExtras().getString("load_local_jars"));
                    Log.d("Qt", "loader_class_name=" + intent.getExtras().containsKey("loader_class_name"));
                    Log.d("Qt", "loader_class_name="+ intent.getExtras().getString("loader_class_name"));
                }else if((new File(LOCAL_PREFIX_BASE)).exists()){
                    // パスのディレクトリがある

                    ArrayList<String> libraryList= new ArrayList<String>();

                    String localPrefix = LOCAL_PREFIX_BASE;
                    Log.d("Qt", "localPrefix=" + localPrefix);

                    // ライブラリの登録
                    if (qtLibs != null){
                        for(int i=0;i<qtLibs.length;i++)
                        {
                            libraryList.add(localPrefix+"lib/lib"+qtLibs[i]+".so");
                            Log.d("Qt", "add=" + localPrefix+"lib/lib"+qtLibs[i]+".so");
                        }
                    }
                    String lib = "plugins/platforms/android/libandroid-" + getLibVersionString() + ".so";
                    libraryList.add(localPrefix + lib);
                    Log.d("Qt", "add=" + localPrefix + lib);

                    // 中継jarの登録
                    String dexPaths = new String();
                    dexPaths = localPrefix + "jar/QtIndustrius-" + getJarVersionString() + ".jar";
                    Log.d("Qt", "dexPaths=" + dexPaths);

                    // ライブラリの存在確認
                    boolean libraryExist = true;
                    for (String item : libraryList) {
                        File file = new File(item);
                        if(file.exists() && file.isFile()){
                            //ok
                            Log.d("Qt", "exist=" + item);
                        }else{
                            Log.d("Qt", "not exist=" + item);
                            libraryExist = false;
                        }
                    }
                    if(libraryExist && (new File(dexPaths)).exists()){
                        Log.d("Qt", "exist=" + dexPaths);
                    }else{
                        Log.d("Qt", "not exist=" + dexPaths);
                        libraryExist = false;
                    }

                    // ロード設定作成
                    if(libraryExist){
                        String loaderClassName = "org.kde.necessitas.industrius.QtActivityDelegate";
                        String variablesKey = "QML_IMPORT_PATH="+ localPrefix + "imports"
                                                        + "\tQT_PLUGIN_PATH=" + localPrefix + "plugins"
                                                        + "\tMINISTRO_SSL_CERTS_PATH=" + localPrefix + "ssl";

                        Bundle loaderParams = new Bundle();
                        loaderParams.putInt(ERROR_CODE_KEY, 0);
                        loaderParams.putString(DEX_PATH_KEY, dexPaths);
                        loaderParams.putString(LOADER_CLASS_NAME_KEY, loaderClassName);
                        loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);
                        loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, variablesKey);
                        loaderParams.putString(APPLICATION_PARAMETERS_KEY,"-platform\tandroid");

                        ret = loaderParams;
                    }
                }else{
                }
            }
        }catch(Exception e){
            Log.e("Qt", "can't load locat library");
        }
        return ret;
    }


    // libのバージョン番号を文字列で取得する
    public static String getLibVersionString(){
        return SDK_2_LIB_VERSION[Build.VERSION.SDK_INT];
    }

    // jarのバージョン番号を文字列で取得する
    public static String getJarVersionString(){
        return SDK_2_JAR_VERSION[Build.VERSION.SDK_INT];
    }
}