Написать программу для просмотра qml-файлов не составляет большого труда и сделать это можно несколькими способами, но хотелось бы получить простое и удобное решение - запуск файла после его выбора. Для этого создадим приложение (сервис без интерфейса и даже без консольного окна), а после укажем его в качестве программы, запускаемой при выборе файлов с расширением qml. Получится сервис для запуска локальных qml-файлов. Если потребуется открывать удалённые файлы, то это можно осуществить в коде локального qml-файла.
Откроем Qt Creator и создадим пустое приложение Qt Quick (Qt Quick Controls 2). Данный шаблон выбран для более удобного вывода сообщений и логов на экран при возникновении ошибок. После создания проекта в папке ресурсов появится файл main.qml, который и будет использоваться для этого.
Код главного файла проекта main.cpp выглядеть как-то так:
QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1;
Нам необходимо вместо "qrc:/main.qml" указать путь к открываемому файлу.
Файл передаётся сервису в виде параметра командной строки и в Windows это выгладит очень просто. Проверяем количество параметров в командной строке и загружаем файл, полный путь к которому указан во втором параметре:
if(argc==2){ engine.load(argv[1]); }
Если параметр не указан (сервис вызван напрямую и количество аргументов равно 1) то можно вывести сообщение о необходимости указания второго параметра. Для взаимодействия между Qt С++ и Qml создаётся класс С++ с нужными свойствами и методами, а затем производится связь контекстов. Добавим к проект новый класс Utils. Тогда связь будет выглядеть так:
Utils ut;
engine.rootContext()->setContextProperty("qtc", &ut); // "qtc" - свойство Qml, &ut - ссылка на объект класса.
После этого открытые методы класса Utils будут доступны через объект qtc. Добавьте в класс свойство для обмена сообщениями мижду C++ и Qml.
Для отображения командной строки на вкладке "Проекты" выберите для заданного комплекта сборки опцию "Запуск". Создайте тестовый qml-файл, укажите в этой командной строке путь к нему запустите сервис для проверки его работы.
Получение параметров запуска на Android выглядит на java так:
Intent intent = getIntent(); Uri data = intent.getData(); String path = data.getPath();
Для доступ к Java из Qt служит интерфнйс JNI - Java Native Interface, который предоставляет объект QAndroidJniObject. Воспользуемся им для получения эквивалентного кода:
QAndroidJniObject activity = QtAndroid::androidActivity(); if (activity.isValid()) { QAndroidJniObject intent = activity.callObjectMethod("getIntent", "()Landroid/content/Intent;"); if (intent.isValid()) { QAndroidJniObject data = intent.callObjectMethod("getData", "()Landroid/net/Uri;"); if (data.isValid()) { QAndroidJniObject path = data.callObjectMethod("getPath", "()Ljava/lang/String;"); if (path.isValid()){ ut.engine.load("file://"+ut.getPath()); } } } }
Для разделения кода, включая и объявления подключаемых библиотек, используются директивы:
#ifdef Q_OS_WIN // код для работы в среде Windows #endif #ifdef Q_OS_ANDROID // код для работы в среде Android #endif
Если в процессе работы сервиса или открытия файла возникнет ошибка, то приложение закроется с кодом -1 и будет непонятно, ошибка возникла при работе сервиса или связана с открытием файла. Для отслеживания этого потребуется дополнительный код:
Пытаемся открыть qml-файл. Если он не загружается (в сервисе или файле возникла ошибка), то открываем заведомо исправный файл ресурса main.qml и пробуем загрузить qml-файл в нём при помощи блока Loader. Если ресурсный файл main.qml не открывается - ошибка при работе сервиса. Если же не выполняется содержимое qml-файла, то ошибка в его коде.
Для реализации этого в main.cpp добавим код:
if (engine.rootObjects().isEmpty()){ engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); } if (engine.rootObjects().isEmpty()) return -1;
Для загрузки файла в Qml нужно передать путь к нему. Для этого в класс Utils добавим методы setPath(QString path) и getPath(), а коде Qml вызовем его методом qtc.getPath()
Для запуска сервиса на Android при открытии файла qml необходимо дополнить манифест сервиса:
<intent-filter> <action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/*.qml"/> </intent-filter>
Для генерации файла манифеста перейдите на вкладку "Проекты", далее выберите опцию "Сборка" для комплекта сборки под Android, на панели перейдите в раздел "Собрать Android APK" и нажмите кнопку "Создать шаблоны". В проекте появится новая папка "Другие файлы", в которой и находится файл манифеста AndroidManifest.xml
Исходный код можно загрузить здесь.