Как использовать HockeyApp SDK с Qt на Android

Я пытаюсь интегрировать HockeyApp Android SDK в его последняя версия 4.1.2 в наше приложение Qt для Android. Я мало знаю о разработке для Android или Java в целом, равно как и о внутренностях Qt или HockeyApp.

Существует некоторая общая официальная документация о включении сторонних библиотек Android (например, Java) в проект Qt; однако в настройках развертывания упоминается кнопка Создать AndroidManifest.xml, которой нет в текущей версии Qt Creator 4.2.0, поэтому я не уверен, насколько устарела эта документация или какие части, возможно, еще применить.

документация HockeyApp охватывает только стандартную разработку Android с использованием Android Studio и их поддержка не поддерживает.

Кстати, интеграция HockeyApp iOS SDK заняла всего пару часов и в основном заключалась в написании кода моста на Objective C.

Шаг 1. Добавьте SDK в проект

Первый подход

Я попытался следовать приведенной выше документации и добавил разархивированную папку HockeySDK-Android-4.1.2 и файл project.properties с содержимым.

android.library.reference.1=HockeySDK-Android-4.1.2/libs/

в папку проекта; Я также установил ANDROID_PACKAGE_SOURCE_DIR в <my project>.pro в эту папку проекта.

Проблема: на этапе сборки androiddeployqt выдается сообщение об ошибке (обернутое для удобочитаемости)

Error: <path to build folder>/android-build/HockeySDK-Android-4.1.2/libs
  is not a valid project (AndroidManifest.xml not found).

но все равно продолжается и, наконец, завершается с сообщением об ошибке (также завернутым для удобства чтения)

BUILD FAILED
/opt/Android/android-sdk-macosx/tools/ant/build.xml:573:
  HockeySDK-Android-4.1.2/libs/ resolve to a path
  with no project.properties file for project <path to build folder>/android-build

Запуск androiddeployqt с переключателем --verbose добавляет значительно больше выходных данных, но ноль полезной информации.


Второй подход

Загруженный ZIP-архив HockeyApp Android SDK содержит, помимо некоторой документации, файл libs/HockeySDK-4.1.2.aar; из этот ответ и этот комментарий, я собираю формат AAR — это просто zip-архив, который, среди прочего, содержит файл AndroidManifest.xml. Я распаковал libs/HockeySDK-4.1.2.aar на место, потом удалил; теперь первое сообщение об ошибке в сборке исчезло.

Проблема: сборка завершается с ошибкой

BUILD FAILED
/opt/Android/android-sdk-macosx/tools/ant/build.xml:597:
  The following error occurred while executing this line:
/opt/Android/android-sdk-macosx/tools/ant/build.xml:649:
  The following error occurred while executing this line:
/opt/Android/android-sdk-macosx/tools/ant/build.xml:655:
  <path to build folder>/android-build/HockeySDK-Android-4.1.2/libs/src does not exist.

Опять же, добавление работающих --verbose к androiddeployqt не добавляет ничего, кроме шума. Изучение упомянутых build.xml мест также не помогает.

Обновление:

Я попытался просто создать недостающую папку из сообщения об ошибке; теперь сборка терпит неудачу следующим образом:

-dex:
      [dex] input: <path to build folder>/android-build/bin/classes
      [dex] input: <path to build folder>/android-build/HockeySDK-Android-4.1.2/libs/bin/classes.jar
      [dex] input: <path to build folder>/android-build/libs/QtAndroid-bundled.jar
      [dex] input: <path to build folder>/android-build/libs/QtAndroidBearer-bundled.jar
      [dex] Pre-Dexing <path to build folder>/android-build/libs/QtAndroid-bundled.jar -> QtAndroid-bundled-a06280f40655c27b25038380a4d7f67c.jar
      [dex] Pre-Dexing <path to build folder>/android-build/libs/QtAndroidBearer-bundled.jar -> QtAndroidBearer-bundled-a69fa323dbfa477411ea082423128813.jar
      [dex] Converting compiled files and external libraries into <path to build folder>/android-build/bin/classes.dex...
       [dx]
       [dx] UNEXPECTED TOP-LEVEL EXCEPTION:
       [dx] java.io.FileNotFoundException: <path to build folder>/android-build/HockeySDK-Android-4.1.2/libs/bin/classes.jar (No such file or directory)
       [dx]     at java.util.zip.ZipFile.open(Native Method)
       [dx]     at java.util.zip.ZipFile.<init>(ZipFile.java:219)
       [dx]     at java.util.zip.ZipFile.<init>(ZipFile.java:149)
       [dx]     at java.util.zip.ZipFile.<init>(ZipFile.java:163)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:244)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
       [dx]     at com.android.dx.command.dexer.Main.processOne(Main.java:677)
       [dx]     at com.android.dx.command.dexer.Main.processAllFiles(Main.java:574)
       [dx]     at com.android.dx.command.dexer.Main.runMonoDex(Main.java:311)
       [dx]     at com.android.dx.command.dexer.Main.run(Main.java:277)
       [dx]     at com.android.dx.command.dexer.Main.main(Main.java:245)
       [dx]     at com.android.dx.command.Main.main(Main.java:106)
       [dx] 1 error; aborting

BUILD FAILED
/opt/Android/android-sdk-macosx/tools/ant/build.xml:888: The following error occurred while executing this line:
/opt/Android/android-sdk-macosx/tools/ant/build.xml:890: The following error occurred while executing this line:
/opt/Android/android-sdk-macosx/tools/ant/build.xml:902: The following error occurred while executing this line:
/opt/Android/android-sdk-macosx/tools/ant/build.xml:283: null returned: 1

Я, очевидно, не могу просто составить какой-то файл classes.jar, но в <path to build folder>/android-build/HockeySDK-Android-4.1.2/libs есть один-единственный файл с таким именем, поэтому я могу создать недостающую папку bin и создать в ней симлинк на ../classes.jar.

Теперь сборка прошла успешно. Шаг 1 завершен.

Шаг 2. Используйте SDK в проекте

Возвращаясь к соответствующей документации HockeyApp, я понимаю, что мне нужно изменить код, похожий на

public class YourActivity extends Activity
  ...

В проекте <path to build folder>/android-build/src/org/qtproject/qt5/android/bindings/QtActivity.java есть один единственный случай такого кода:

public class QtActivity extends Activity
  ...

Этот файл копируется туда с помощью инструмента androiddeployqt (часть Qt SDK) из исходной папки внутри Qt SDK по адресу $QTDIR/src/android/java, то есть /opt/Qt/Qt_5.7.1/5.7/android_armv7/src/android на моей машине.

Глядя на исходный код androiddeployqt, я вижу, что нет способа (например, с помощью параметра командной строки) изменить исходную папку, из которой взяты эти .java файлы, поэтому невозможно предоставить свой собственный набор файлов и иметь androiddeployqt скопируйте это вместо этого. Следовательно, для того, чтобы это работало, я должен либо расширить/исправить функциональность androiddeployqt (извините, я не буду трогать этот код — фу!) Экземпляр Qt SDK.

В качестве третьего подхода я мог бы попробовать исправить исходные коды Java после того, как androiddeployqt скопировал их в папку сборки. К сожалению, это не только делает рабочий процесс разработки и сборки абсурдно болезненным; это также становится совершенно невозможным из-за androiddeployqt одного инструмента делает все неудачным при проектировании (см. ниже): В процессе сборки нет момента времени, когда в проекте существуют исходные коды Java, а пакет .apk еще не собран. Я думал, что параметр androiddeployqt --no-build позволит это сделать:

--no-build: Do not build the package, it is useful to just install
   a package previously built.

но сборка здесь относится к созданию кода моста Qt/Java, а не фактического приложения, так что этот параметр оказывается практически бесполезным для поставленной задачи; сборка завершается с ошибкой с этим сообщением, что само по себе является ошибкой, поскольку файл .apk из сообщения не существует, и поэтому сборка пакета Android не была успешной:

Android package built successfully in 1.011 ms.
  -- File: <path to build folder>/android-build//bin/QtApp-release-unsigned.apk

Конечно, я мог бы скопировать исходники куда угодно, исправить и скопировать их вручную в конечный пункт назначения, но я думаю, что здесь я подвожу черту.

На самом деле, просмотр исходного кода androiddeployqt — вот где останавливается доллар. Слишком много времени уже было потрачено впустую, пытаясь заставить неработающие инструменты работать:

  • Я не буду комментировать, насколько умно было бы написать инструмент сборки на C++ в первую очередь — в одном, ~3000 строк main.cpp файле
  • Я не буду комментировать практику жесткого кодирования пути src/android/java (и многих других путей) в исходниках androiddeployqt не один раз, а многократно раз — вместо const QString, который хотя бы подготавливает соответствующую (т.е. внешнюю) конфигурацию инструмента
  • Я не буду комментировать, насколько умно было бы нарушить 50-летнюю передовую практику один инструмент, одна цель — и дублировать большое количество функций, предоставляемых инструментами Qt, Android или Java, такими как создание , подписание, развертывание, установка пакетов и т. д.
  • Однако тот факт, что этот инструмент прошел проверку кода и стал одним из основных выпусков Qt, не что иное, как пугающий — и, вероятно, хороший показатель того, что пришло время рассмотреть вопрос об отказе от Qt как технологии в целом.

Пока я пишу это, установка Qt 5.8.0 продолжает зависать, максимально загружая одно ядро ​​​​ЦП, и это происходит в течение последних ~ 12 часов. Я считаю так.

Мои вопросы

  • Кто-нибудь добился успеха с Qt, Android и HockeyApp?
  • Есть ли у кого-нибудь намеки/указатели/дикие догадки относительно того, что здесь не так?
  • никаких дополнительных вопросов; я видел достаточно

Шаг 3. Вызовите Java-код SDK из C++.

(отменено из-за кирпичной стены на шаге 2)


person ssc    schedule 24.01.2017    source источник


Ответы (2)


Отвечая на мой собственный вопрос:

Использование HockeyApp SDK с Qt на Android невозможно без исправления исходного кода инструмента Qt SDK или исходных файлов шаблонов Qt SDK Java.

На самом деле, насколько я понял, невозможно использовать какие-либо сторонние библиотеки с Qt на Android, если они требуют модификации исходного кода Java.

person ssc    schedule 25.01.2017

FWIW это AndroidManifest.xml, который я использую для приложения, но без зависимостей от внешних библиотек. Вы можете попробовать добавить + изменить это, чтобы заставить развертывание работать?

Структура файла:

/my-project-dir
├── android
│   ├── AndroidManifest.xml
│   └── res
│       └── drawable-mdpi
│           └── icon.png
├── my-project.pro

AndroidManifest.xml:

<?xml version="1.0"?>
<manifest package="my_package_name" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
    <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="my_app_name" android:icon="@drawable/icon">
        <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="my_app_name" android:screenOrientation="unspecified" android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
            <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
            <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
            <meta-data android:name="android.app.repository" android:value="default"/>
            <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
            <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
            <!-- Deploy Qt libs as part of package -->
            <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
            <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
            <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
            <!-- Run with local libs -->
            <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
            <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
            <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
            <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
            <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
            <!--  Messages maps -->
            <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
            <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
            <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
            <!--  Messages maps -->

            <!-- Splash screen -->
            <!--
            <meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/>
            -->
            <!-- Splash screen -->
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="14"/>
    <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>

    <!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
         Remove the comment if you do not require these default permissions. -->

    <!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
         Remove the comment if you do not require these default features. -->
    <!-- %%INSERT_FEATURES -->

<!-- %%INSERT_PERMISSIONS -->
</manifest>
person Adversus    schedule 25.01.2017
comment
@ssc Я не возражал, но все равно удалил его, хотя он останется в вашем комментарии; ) В стороне: в качестве среднего способа вы можете создать новый комплект с помощью QtCreator, например. android_armv7_hockey и изменить там QtActivity.java? Или вызовите методы Java из С++, хотя это, вероятно, приведет к еще одной кроличьей норе. - person Adversus; 26.01.2017
comment
Спасибо за ваш ответ! ???? Ваш файл AndroidManifest.xml вроде бы соответствует тому, что есть у меня в проекте, но в более старой версии. - person ssc; 26.01.2017