26 мая 2016 в 15:05

Разработка Android приложений с использованием qt и android studio из песочницы tutorial

Неактуально, кроме постановки задачи. Правильное решение в следующей статье.
Добрый день, уважаемые хабровчане! В этой статье я хочу рассказать о своём опыте использования qt и android studio. А именно о том, как мне надо было в qt нарисовать текст и передать в андроид студию. Несмотря на простоту задачи, решение её заняло у меня довольно много времени и может быть кому-нибудь когда-нибудь где-нибудь сэкономит массу времени. Статья в каком-то смысле претендует на изобретение велосипеда, но в интернете я не нашёл решения. Кому интересно — добро пожаловать под кат!

Немного о самой задаче


Недавно встала передо мною задача портировать приложение с ios на андроид. Основной болью при портировании была работа с SDK приложения. Оно было написано на Qt и исопльзовалось для рисования текста/стрелочек/областей и всего прочего. То есть, приложение было написано на objective c, и использовало qt библиотеку, а не было qt проектом. Поэтому, первым делом встал вопрос среды разработки. Поскольку, я совсем в этом деле новичок, мой выбор пал на андроид студию. Всё-таки весь графический интерфейс, как мне показалось, лучше делать в андроид студии, а вычислительные задачи пущай делает наше qtшное SDK. В интернете не так уж много пишут об использовании qt под андроид, а здесь была задача подружить qt и андроид студию. Для работы с плюсами используется Android NDK и реализуется всё через использование JNI. Работа с JNI — вещь сама по себе довольно интересная. В нете можно найти массу статей на эту тему (например этот замечательный цикл). Однако меня интересует JNI в разрезе использования его с Qt. Опять же, в чём проблема, спросите вы? Берём сишные сорсы, делаем шаред либу, подключаем к проекту в андроид студии и получаем profit! Вот, как например тут. А вот здесь и начинается самое интересное…

Использование qt в андроид студии


Как вы помните, я указал выше, что
оно было написано на Qt и исопльзовалось для рисования текста/стрелочек/областей и всего прочего
.
Чтобы нарисовать графический примитив в QT, нам не требуется создавать экземпляр QApplication или QGuiApplication. Даже QCoreApplication — и тот не нужен! А вот для рисования текста без QApplication или QGuiApplication уже никак нельзя обойтись. Так в чём проблема, спросите вы? Проблема наступает как раз на момент вызова конструктора:

QApplication a(argc, argv);

Если вы создадите билиблиотеку, в ней какую-либо функцию, вызывающую конструктор QApplication, а затем вызовите её через JNI из приложения андроид студии, то сразу же словите:
This application failed to start because it could not find or load the Qt platform plugin «android».

Кто винов Что делать?


Вариант классический. Учить матчасть!


Первое, что я решил сделать — нагуглить решение проблемы в интернете. Точного совпадения я не нашёл, но в довольно большом количестве постов люди жаловались на похожие проблемы для плагина под винду. Вот и я перепробовал всё, что было указано здесь, но, увы, решения (работающего для меня! ) не было найдено.

В поисках ответа на свои вопросы, я наткнулся на такой довольно любопытный блог, как я понял автора qt под андроид. Блог весьма интересный, но в нём автор делает акцент (опять же, моё имхо) на разработку со стороны с++ и запуска всего добра из qt creator. Меня такой подход, если честно, не очень устраивал по одной причине: отладка Java части из Qt практически невозможна (можно только компилировать код, потом ждать приаттачивания из андроид студии и уже оттуда наблюдать происходящее), а также у меня довольно большое количество различных layoutov, кастомных вьюх, асинхронных задач, а как это добро засунуть в qt проект и нормально отлаживать? Честно говоря, я не знаю.

Эксперименты


Я попробовал создать также Qt приложение и запустить его на андроиде. Запускал я его через qt-creator и как ни странно оно благополучно запустилось. Я стал смотреть более подробно как устроен манифест, граддл, код приложения. Я обнаружил такую интересную вещь в манифесте:
<!-- Deploy Qt libs as part of package -->
            <meta-data android:name="android.app.bundle_local_qt_libs" android:value="1"/>
            <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="1"/>
            <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="plugins/platforms/android/libqtforandroid.so"/>
            <meta-data android:name="android.app.load_local_jars" android:value="jar/QtAndroid.jar:jar/QtAndroidAccessibility.jar:jar/QtAndroid-bundled.jar:jar/QtAndroidAccessibility-bundled.jar"/>
            <meta-data android:name="android.app.static_init_classes" android:value=""/>

Вкратце смысл его понятен. Когда я собирал apk приложения, я указал, что qt библиотеки должны находиться внутри apk и именно оттуда надо их грузить своему приложению. Подключение соответстсвующих jar-ов в проект на андроиде, прописывание в андроидовском манифесте того, что было в qt, размещение qtшных .so плагинов в папке jniLibs не дало никакого эффекта.

Изучение плагинов


Я попробовал уже наконец грузить самостоятельно со стороны java этот несчастный плагин libqtforandroid.so (до создания QApplication) путём
System.loadLibrary(«plugins_platforms_android_libqtforandroid»);
, но всё равно падало! Правда, здесь исключение было уже другое и более интересное:
I/Qt: qt start
05-17 11:12:33.975 11084-11084/имя проекта A/libc: Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 11084 (ndroid.gribview)
05-17 11:12:33.978 11084-11084/имя проекта A/libc: Send stop signal to pid:11084 in void debuggerd_signal_handler(int, siginfo_t, void)

По крайней мере есть у нас зацепка, где можно смотреть. Оперативно по qt start находим интересующий нас метод:

Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
{
    QT_USE_NAMESPACE
    typedef union {
        JNIEnv *nativeEnvironment;
        void *venv;
    } UnionJNIEnvToVoid;
    __android_log_print(ANDROID_LOG_INFO, "Qt", "qt start");
    UnionJNIEnvToVoid uenv;
    uenv.venv = Q_NULLPTR;
    m_javaVM = Q_NULLPTR;
    if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
        __android_log_print(ANDROID_LOG_FATAL, "Qt", "GetEnv failed");
        return -1;
    }
    JNIEnv *env = uenv.nativeEnvironment;

    if (!registerNatives(env)
           || !QtAndroidInput::registerNatives(env)
            || !QtAndroidMenu::registerNatives(env)
            || !QtAndroidAccessibility::registerNatives(env)
            || !QtAndroidDialogHelpers::registerNatives(env)) {
        __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
        return -1;
    }
    m_javaVM = vm;
    return JNI_VERSION_1_4;
}

Судя по логу, он упал где-то в каком-то из registerNatives.Так и было (я прописал логи в каждом из registerNatives). Он падал в

registerNatives(env)

А именно:

jmethodID methodID;
    GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
         __android_log_print(ANDROID_LOG_INFO, "Check Class 8", "activity ");
    jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
         __android_log_print(ANDROID_LOG_INFO, "Check Class 9 ", " methodID ");
    GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;");
    __android_log_print(ANDROID_LOG_INFO, "Check Class 10", " classLoader ");

    if(activityObject!=nullptr)
    {
        __android_log_print(ANDROID_LOG_INFO, "No tull activityObject", " Not Null ");
    }



    if(methodID!=nullptr)
    {
        __android_log_print(ANDROID_LOG_INFO, "No tull methodID", " Not Null ");
    }

    m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID));

    if(m_classLoaderObject!=nullptr)
    {
        __android_log_print(ANDROID_LOG_INFO, "No tull m_classLoaderObject", " Not Null ");
    }
    
    clazz = env->GetObjectClass(m_classLoaderObject);

Падение произошло на последней строчке. classLoaderObject оказался равен null. А это произошло, что activityObject тоже равен null. Окей. Перед тем, как грузить этот злосчастный плагин попробуем создать активити для JNI. Для этого пропишем в Java коде следующие строчки:

        QtNative.setActivity(this, null);
        QtNative.setClassLoader(getClassLoader());

Небольшое отступление. Класс QtNative лежит в jar файлах, которые мы подключаем к проекту. Более того, это весьма любопытный класс. В нём есть методы:

       QtNative.loadBundledLibraries();
       QtNative.loadQtLibraries();

которые и должны подгружать требуемые плагины. Пока запомним это, и вернёмся к подключению нашего плагина вручную. Вызов методов QtNative setActivity и setClassLoader помог проскочить:

registerNatives(env)

но засада была уже в QtAndroidInput::registerNatives(env). Не совпадали сигнатуры функций для события keyDown. В принципе, мне ничего не нужно кроме шрифтов и я закомментировал следующий участок кода:

  if (!registerNatives(env)
          /* || !QtAndroidInput::registerNatives(env)
            || !QtAndroidMenu::registerNatives(env)
            || !QtAndroidAccessibility::registerNatives(env)
            || !QtAndroidDialogHelpers::registerNatives(env)*/) {
        __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
        return -1;
    }

и вроде как-бы благополучно загрузил этот плагин. Запускаем приложение, грузим плагин, вызываем QApplication и… ловим наше остознакомое исключение:
This application failed to start because it could not find or load the Qt platform plugin «android».

Более того, вызов

       QtNative.loadBundledLibraries();
       QtNative.loadQtLibraries();

тоже не решил проблемы. Хорошо. Ладно. Полезем в сорсы создания конструктора. По исключению быстро находим метод:

static void init_platform(const QString &pluginArgument, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv)
{
    // Split into platform name and arguments
    QStringList arguments = pluginArgument.split(QLatin1Char(':'));
    const QString name = arguments.takeFirst().toLower();
    QString argumentsKey = name;
    argumentsKey[0] = argumentsKey.at(0).toUpper();
    arguments.append(QLibraryInfo::platformPluginArguments(argumentsKey));

   // Create the platform integration.
    QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath);
    if (QGuiApplicationPrivate::platform_integration) {
        QGuiApplicationPrivate::platform_name = new QString(name);
    } else {
        QStringList keys = QPlatformIntegrationFactory::keys(platformPluginPath);

        QString fatalMessage
                = QStringLiteral("This application failed to start because it could not find or load the Qt platform plugin \"%1\".\n\n").arg(name);
       ....

Хорошо. Ищем, откуда вызываем сей метод:

void QGuiApplicationPrivate::createPlatformIntegration()
{
    // Use the Qt menus by default. Platform plugins that
    // want to enable a native menu implementation can clear
    // this flag.
    QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true);

    // Load the platform integration
    QString platformPluginPath = QLatin1String(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH"));


    QByteArray platformName;
#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
    platformName = QT_QPA_DEFAULT_PLATFORM_NAME;
#endif
    QByteArray platformNameEnv = qgetenv("QT_QPA_PLATFORM");
    if (!platformNameEnv.isEmpty()) {
        platformName = platformNameEnv;
    }

    QString platformThemeName = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORMTHEME"));

    // Get command line params

    QString icon;

    int j = argc ? 1 : 0;
    for (int i=1; i<argc; i++) {
        if (argv[i] && *argv[i] != '-') {
            argv[j++] = argv[i];
            continue;
        }
        const bool isXcb = platformName == "xcb";
        QByteArray arg = argv[i];
        if (arg.startsWith("--"))
            arg.remove(0, 1);
        if (arg == "-platformpluginpath") {
            if (++i < argc)
                platformPluginPath = QLatin1String(argv[i]);
        } else if (arg == "-platform") {
            if (++i < argc)
                platformName = argv[i];
        } else if (arg == "-platformtheme") {
            if (++i < argc)
                platformThemeName = QString::fromLocal8Bit(argv[i]);
        } else if (arg == "-qwindowgeometry" || (isXcb && arg == "-geometry")) {
            if (++i < argc)
                windowGeometrySpecification = QWindowGeometrySpecification::fromArgument(argv[i]);
        } else if (arg == "-qwindowtitle" || (isXcb && arg == "-title")) {
            if (++i < argc)
                firstWindowTitle = QString::fromLocal8Bit(argv[i]);
        } else if (arg == "-qwindowicon" || (isXcb && arg == "-icon")) {
            if (++i < argc) {
                icon = QString::fromLocal8Bit(argv[i]);
            }
        } else {
            argv[j++] = argv[i];
        }
    }

    if (j < argc) {
        argv[j] = 0;
        argc = j;
    }

    init_platform(QLatin1String(platformName), platformPluginPath, platformThemeName, argc, argv);

    if (!icon.isEmpty())
        forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon);
}

То бишь, нам можно через argc и argv передать аргументы, где надо искать этот плагин. Сразу оговорюсь, я пробовал в дебаггере qt запускать приложение под андроид, и там argc и argv соответственно равны: 1 и имя_нашей_библиотеки_которую_собирает_qt, но никак не плагин. Попробуем присвоить argc и argv соответствующие значения:

char *SDKEnvironment::argv[] = {"-platform libplugins_platforms_android_libqtforandroid.so:plugins/platforms/android/libqtforandroid.so -platformpluginpath /data/app-lib/папка_для_jniLibs"};

Неа, не сработало.

Решение


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

  1. Создадим в qt не apk, не so, а aar. Для этого идём в qt creator и находим gradle файл, а в нём меняем строчку apply plugin: 'com.android.applicatioin' на apply plugin: 'com.android.library' . Таким образом мы создаём aar файл, а не apk
  2. Теперь добавим его в наше приложение в андроид студии. Идём в New->Module выбираем import aar, затем правой кнопкой мышки щёлкаем на наш модуль, выбиараем Open Module Settings, идём во вкладку dependency и добавляем зависимость к qtному модулю

Затем я перенёс всё jni, которое было у меня в андроид студии, в qt. Попробовал снова создать QApplication — и всё заработало.

Резюме


Я почти что уверен, что есть и другой способ решить эту проблему. Если кто-нибудь укажет, где я ошибся — то было бы просто замечательно. В интернете я не нашёл решения проблемы, поэтому предлагаю своё.
Андрей Самойлов @Rogvold91
карма
5,7
рейтинг 0,0
Пользователь
Похожие публикации
Самое читаемое Разработка

Комментарии (19)

  • +1
    Не пойму, что мешало загрузить проект в QtCreator и добавить поддержку андроида там
    • 0
      Поддержка в QtCreator Java очень слабая. Хотелось просто всё отлаживать через андроид студию и работать именно с ней, а не в Qt
      • +1
        Извините, но разве Вам не нужно было уже написанное на Qt/C++ приложение под iOS портировать на Android? То есть, нужно было решить задачу настройки проекта для сборки под Android? Ну и разрешить некоторые возможные проблемы, но делать это не с помощью JAVA, а с использованием C++ или если повезёт, то QML?
        • +1
          не. приложение на objective c. Оно использовало SDK, написанное на qt (процентов 10 всего приложения), Поэтому, так сходу сделать нельзя было. Smog1on1the1water постом следующим комментом более точно описал проблему
        • +1
          >> Извините, но разве Вам не нужно было уже написанное…

          Нет, не нужно.

          Прикладная библиотека реализует общую для всех платформ бизнес-логику. При этом UI под каждой платформой в общем случае отличается, поскольку решает различные задачи, создается для различных условий и различных/различными сторонними компаниями.

          Поэтому речь не о портировании UI вообще, а о создании нового UI свойственными платформе средствами с использованием кросс-платформенной библиотеки, содержащей реализацию бизнес-логики.
    • +1
      Ничего не мешало, так и было сделано. Автор статьи просто акцентировался на злоключениях, поэтому некоторые другие моменты описания исходной задачи были недостаточно ацентированы.

      SDK, о которой идет речь — это прикладная библиотека, которая работает со сложными данными и выполняет достаточно интенсивные вычисления в single precision float. Она оптимизирована с использованием SIMD SSE/NEON и работает в (разных!) реальных проектах под Windows, OS X/iOS, Fedora x64/ARM и др. Использование Qt исторически обусловлено рисованием графических 2D примитивов (плюс сторонние ограничения, но речь не о них), и вот сейчас подошла очередь Android, под который данная прикладная библиотека и была безо всяких проблем собрана. Да, проект был загружен в QtCreator, нажаты «те самые две кнопки» для поддержки андроида, внесены необходимые изменения под специфику runtime libraries, и все благополучно собралось.

      Так что проблема не с ней, а с UI в виде конечного приложения. Этот UI, как и ранее на других платформах, был выполнен посредством естественных средств, предоставляемых самой средой. Т.е. в данном случае на Java/Android Studio. Повторю еще раз: весь UI сделан на Java, а не на QT/C++, методы прикладной библиотеки благополучно вызываются через JNI.

      Такая связка прекрасно работает (и прекрасно зарекомендовала себя на всех предыдущих платформах), но за исключением тех случаев в Android (только в нем и только для текста), когда библиотеке необходимо вывести текст (QPainter::drawText). Для этого требуется наличие созданного экземпляра QApplication, который, в свою очередь, хочет иметь загруженным плагин платформы (в данном случае libqtforandroid). Который и не хочет грузиться. QtCore, QtGui грузятся, а libqtforandroid — нет. Причем QGuiApplication (именно в нем вызывается загрузка платформенного плагина) не может никак увидеть плагин загруженным даже в том случае, если он предварительно был принудительно и успешно загружен «руками» посредством средств самого Qt.

      Изучение проблемы выявило, что андроидная реализация Qt отличается своей спецификой от других платформ. В частности, Qt неявно предполагает, что оно было загружено посредством специального Java Qt Activity, которое через JNI загружает .so библиотеку от собранной C++ части, ищет в нем символ main и передает в него управление. Поэтому, если UI выполнено на С++ и собрано в QtCreator — QtActivity.class там неявно присутствует, и загрузка libqtforandroid проходит благополучно. А вот в случае, если UI собирается в Android Studio и Java Activity свое собственное — инициализацию выполнить не удается (по крайней мере, нам пока не удалось найти правильного решения).
      • +1
        Возможно настало время переписать UI на Qt/QML и решить проблему раз и навсегда?
        • +1
          К сожалению, в данном случае это будет сродни заметанию сора под ковер:

          1. Android UI уже написано, работает (за исключением ситуации с отрисовкой текста), и тратить ресурсы на его переделку на данном конкретном цикле разработки бессмысленно
          2. В следующих циклах разработки планируется отказаться от Qt части в принципе (можно было бы поперечислять причины, но тема совсем не об этом).
  • 0
    Чукча купил себе Камаз, приехал домой, собрал родню у себя в чуме, сидит, рассказывает:
    — Хорошая машина Камаз. В кабине тепло, фары тайгу освещают… одно плохо — собаки быстро устают.
    • –3
      Забавный анекдот, вот только не разобравшись в ситуации, ошибочно интерпретировав слова автора и посчитав его идиотом, кем в итоге вы показали себя?

      Минус в карму можете себе добавить самостоятельно.
      • +1
        Господа, вы уж извините, но отредактировать статью, а потом отвечать на комментарии к первоначальной версии в таком ключе — это грубое нарушение сетевого этикета, если говорить мягко. Гугл все помнит, я сейчас даже скрин сделал с кеша, раз такие претензии появились.

        Было:
        Недавно встала передо мною задача портировать приложение с ios на андроид. Основной болью при портировании была работа с SDK приложения. Оно было написано на Qt и исопльзовалось для рисования текста/стрелочек/областей и всего прочего.
        Речь идет о портировании приложения, мельком замечание про какое-то загадочное SDK и дальше некое «оно». Логично предположить, что речь о портировании приложения, которое написано на Qt, хотя по факту это вообще написание нативного приложения, которое просто использует библиотеку на Qt

        Сейчас добавилось предложение:
        То есть, приложение было написано на objective c, и использовало qt библиотеку, а не было qt проектом.
        Это меняет картину, и конечно, выставляет меня человеком который даже читать не умеет, не то что думать.

        Так что если кому и минус в карму, так точно не мне.
        • –1
          Ну если для вас является нормой считать окружающих идиотами (ну да, ведь это же логично предположить, правильно?), то я вас понял, да. Голова и язык — они же только для этого и предназначены, чтобы травить анекдоты на хабре.
  • 0
    Статья в каком-то смысле претендует на изобретение велосипеда, но в интернете я не нашёл решения… В интернете не так уж много пишут об использовании qt под андроид, а здесь была задача подружить qt и андроид студию.
    Конечно, не нашли, так просто никто не делает.
    Недавно встала передо мною задача портировать приложение с ios на андроид.
    Для этого нужно нажать две кнопки в QtCreator
    Всё-таки весь графический интерфейс, как мне показалось, лучше делать в андроид студии
    Что? Зачем? Чем лучше? Что значит показалось? Лучше потратить месяц чем нажать две кнопки?

    Вы сами себе на ровном месте создали проблемы и героически их преодолели, статья о том, как нельзя делать ни в коем случае.
    • 0
      Для этого нужно нажать две кнопки в QtCreator

      Был бы весьма признателен, если бы сказали какие. Не хочу в будущем повторять ошибок.
      • +1
        Открываем .pro файл в QtCreator, появляется нечто вроде этого:
        Настройка проекта


        В левом нижнем углу нажимаем на play
        Play


        Выбираем подключенный телефон или симулятор, создастся .apk, зальется и запустится автоматически.

        Чтобы появился профиль на первом экране, нужно зайти в настройки QtCreator и указать путь до Android SDK и NDK.
        • 0
          Вы не поняли меня. У меня на Qt небольшая библиотека, которая занимается расчётом и рисованием, а не весь проект. Весь гуи написан был на чистом objective c. Когда я начинал портирование, то передо мною стоял вопрос: на чём реализовывать основную часть? Либо Android Studio, либо всё писать в Qt. Я выбрал андроид студию потому, что по ней масса литературы и я знаком с Java. Знал бы я, что так трудно подключить qt в неё, то сразу бы делал всё в qt.
          Очень хорошо смысл проблемы описал Smog1on1the1water немного выше
  • 0
    Для Qt под Android, особенно на момент начального запуска, в итоге сам пришёл к использованию Ministro. Тогда Qt получается отдельно и некоторые вещи, типа по какой поверхности рисовать приложение и что там с потоками обработки событий — Ministro это решает лучше, чем встраиваемый в apk Qt.

    Другое дело, что Ministro — совсем внешняя зависимость и недавно у download.qt-project.org кончился SSL-сертификат, и Ministro поэтому отказался запускать наше приложение :-)

    Вопрос решился созданием своего зеркала Ministro, о чём и хочу предупредить коллег :-)
    • 0
      >> download.qt-project.org кончился SSL-сертификат, и Ministro поэтому отказался запускать наше приложение

      Welcome to DLL hell, now on Android!

      А вот про зеркало было бы любопытно послушать для общего развития.
      • 0
        Очень просто, нашёл на cdimages.debian.org зеркало Министро в виде тупо файлов, wget'ом выкачал (опциями типа -np -m) всё, что выкачалось (получилось порядка 1 гигабайта), выложил на свой сервер так, чтобы пути получались такие же, как у qt.io и download.qt-project.org, в нужной мне xml'ке (libs.xml, относящийся к qt 5.4) поменял sed'ом старый адрес сервера на новый, попутно убедившись, что нигде-нигде нет ни одного слова про https, в котором возможны проблемы с сертификатом. В своём приложении в xml настройке Министро прописал свой адрес. Заработало :-)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.