Коли OS Android тільки з'явилася, багато, і я в тому числі, мріяли, щоб на неї як можна швидше портували Qt. На жаль, корпорація добра не виправдала наших сподівань, повідомивши, що SDK Андроїда буде тільки на Java. Новина про купівлю Trolltech компанією Nokia теж не додала оптимізму.

Через деякий час до нас привалила неждана радість - для Андроїда вийшов NDK для нативної розробки на C + +, і, звичайно ж, знайшлися люди, які стали портувати Qt на Android. На даний час порт вже більш-менш юзабелен - працюють (і майже не глючать) практично всі модулі. Ну що ж, подивимося, які можливості відкриває нам цей порт.
Як воно працює?

Спочатку здається, що цей порт - це дуже великий милицю. Без Java все одно не обійшлося - за допомогою NDK не можна створювати виконувані файли, можна тільки бібліотеки. So. На Java, по суті, потрібно написати всього один рядок, яка завантажує нашу бібліотеку на Qt. Далі віртуальна машина Android запускає Java-додаток, яке, у свою чергу, вантажить нашу либу.
Збірка QT

Весь процес дуже добре описаний у Wiki проекту, але він містить кілька граблів, тому деякі пояснення нам дати все ж доведеться.

Невелика обмовка - процес описується для Ubuntu 10.04, але на інших дистрибутивах, в принципі, все має відбуватися так само. А от для того, щоб провернути цю справу під вінди, тобі доведеться трохи пострибати з бубном (яка тонка іронія, а?).

Отже, поїхали:

Створюємо директорію для SDK. Пишемо в консоль:

wget http://android-lighthouse.googlecode.co … s.tar.lzma
tar xvfa qadk-1.x-2.x-rtti-exceptions.tar.lzma

Клонуємо репозиторій Lighthouse:

git clone git: / / gitorious.org / ~ taipan / qt / androidlighthouse.git

Редагуємо файл mkspecs / android-g + + / qmake.conf. У ньому потрібно змінити NDK_ROOT і ANDROID_PLATFORM (у мене - / data / local / qt і android-5 відповідно). Ці параметри відповідають за розташування зібраної бібліотеки та її версію. Також потрібно відредагувати файл androidconfig.sh. Настійно рекомендую замінити shared на static (для статичної збірки бібліотеки та додатків). Все, конфігуруємо (. / Androidconfig.sh) і збираємо (make-j X, де X - кількість ядер твого процесора).

Все? Не тут-то було! Не знаю, як йдуть справи з іншими збірками, але на Ubuntu "make" вилітав з помилкою, що говорить про недоступність заголовних файлів OpenGL. Чого тільки я не робив ... Поставив все, що можна було, але рішення виявилося куди простіше - треба було просто перевстановити наявні в системі заголовні файли OpenGL. Після цього можна повторювати команду make-j X і йти ... ні, не пити пиво, а палити мануали по розробці під Android - інформація зайвою не буває ніколи, а збиратися воно буде довго =).
Створення додатка

Запускай Qt Creator, створюй нове GUI-додаток. У ньому (вірніше, у файлі. Pro) нам потрібно буде змінити кілька рядків. Вони повинні виглядати так:

TEMPLATE = lib
CONFIG + = dll

У налаштуваннях Qt Creator потрібно також вказати шлях до нашого (андроідовского) qmake - у мене це / data / local / qt / bin / qmake.

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

До речі, я ж іще не говорив, що за додаток ми будемо писати? Це буде додаток для відправки СМС на номери самих різних операторів. Це можливо завдяки сервісу smste.ru, який ми і будемо використовувати. Не буду вдаватися в подробиці сніффінга, скажу тільки, що я використовую для цих цілей Wireshark.

Розберемо алгоритм відправлення повідомлення:

   1. Робимо GET рута - головної сторінки сайту, видирає звідти потрібні нам значення input'ов (ті, які hidden), а заразом і кукіси.
   2. Запитуємо капчу за номером телефону і показуємо її користувачеві.
   3. Відправляємо POST-запит з повідомленням.

Для відправки HTTP-запитів в Qt існує клас QHttp. До речі, не забудь підключити модуль QtNetwork (QT + = network) у файлі проекту!

Накидай форму (мою ти можеш побачити на скріншоті) і приступай до кодінгу.

Від об'єкта http класу QHtpp нам потрібні лише два сигнали - done () і readyRead (). Одразу при створенні головного віджета відправимо GET-запит головної сторінки:

http.setHost ("smste.ru");
http.get ("/");

Сигнал done (), по суті, і не використовується - по ньому можна буде тільки пізнати помилку мережевого рівня (наприклад, відключення Wi-Fi). Розглянемо деякі частини слота onHttpReadyRead (const QHttpResponseHeader & resp):

QString str (http.readAll ());
qint32 index = str.indexOf ("value = \" code ") +7;
if (index! = 6)
codeMod = str.mid (index, str.indexOf ("\" /> ", index) - index);

Тут ми копіюємо "заховану" (hidden) змінну codeMod з ісходника сторінки. Йдемо далі:

QString cookieStr;
for (qint8 i = 0; i <resp.values (). count (); i + +)
{
if (resp.values (). at (i). first == "Set-Cookie") cookieStr.append (resp.values (). at (i). second + '\ n');
}
cookies = QNetworkCookie:: parseCookies (cookieStr.toAscii ());

Ну, а в цьому шматку коду, як ти, напевно, здогадався, ми Парс печеньки. cookies - це QList з QnetworkCookie.

qint32 index = str.indexOf ("<image> / pix /") + 12;
image = str.mid (index, str.indexOf (". jpg") - index);
QHttpRequestHeader header = createHeader ("GET", QString ("/ pix /% 1.jpg"). Arg (image));
http.request (header);

Тут копіюється адресу капчі (запит адреси я покажу трохи пізніше) і надсилається запит цього самого JPEG'а.

А ось так він зберігається:

if (resp.value ("Content-Type") == "image / jpeg")
{
ui-> captchaLb-> setPixmap (QPixmap:: fromImage (QImage:: fromData (http.readAll ())));
return;
}

Так, з цим слотом розібралися.

Капчу потрібно запитувати, як тільки користувач введе номер телефону, тобто, коли закінчиться редагування тексту ui-> numberLE. Для цього є спеціальний слот:

void MainWidget:: on_numberLE_editingFinished ()
{
if (ui-> numberLE-> text (). length ()! = 11)
return;
QHttpRequestHeader header = createHeader ("GET", QString ("/ netxml.php? Number =% 1 & rnd = 94728"). Arg (ui-> numberLE-> text ()));
http.request (header);
}

Функцію createHeader () дивись на урізанні - вона створює хедер HTTP-запиту (взагалі, можна й простіше, але нам треба відправляти ще і куки).

    Створення HTTP-заголовка

    QHttpRequestHeader MainWidget:: createHeader (
    const QString & method,
    const QString & path
    )
    {
    QHttpRequestHeader header (method, path);
    header.addValue ("Host", "smste.ru");
    header.addValue ("Connection", "keep-alive");
    header.addValue ("User-Agent", "Mozilla/5.0");
    header.addValue ("Referer", "http://smste.ru");
    header.addValue ("Accept", "*/*");
    QString cookie;
    for (qint8 i = 0; i <cookies.length (); i + +)
    cookie + = (cookies.at (i). toRawForm (QNetworkCookie:: NameAndValueOnly) + ";");
    header.addValue ("Cookie", cookie);
    return header;
    }

Залишився останній слот - натискання кнопки "Відправити", і він гранично простий:

QHttpRequestHeader header = createHeader ("POST", "/");
header.addValue ("", QString ("number =% 1 & message =% 2 & sign = ax-soft.ru & event =% 3 & codemod =% 4 &% 5 =% 6"). arg (ui-> numberLE-> text () ). arg (ui-> textPTE-> toPlainText ()). arg (image). arg (codeMod). arg (codeMod). arg (ui-> captchaLE-> text ()));
qDebug () <<header.toString ();
http.request (header);

Ось і все! Роби Build All, збирай. Apk-пакет:).
Створення віртуальної машини

Для тестування програми нам потрібно створити віртуальну машину. До речі, сподіваюся, у тебе встановлена Java Runtime Environment? Якщо ні, то, ставлячи, річ потрібна. Крім того, для створення. Apk-пакетів знадобиться ant. Ставиться він легко - sudo apt-get install ant. Тепер переходь в сабдіректорію tools в Android SDK і вводь. / Android. Запуститься менеджер налаштувань і віртуальних машин.

Спочатку скачай потрібні API (розібратися неважко, для цього прикладу потрібна версія 8), далі переходь на вкладку Virtual Devices, тисни New. У Name - будь-яке ім'я, Target - Android 2.2, Skin - який хочеш (я вибрав WVGA800), і натискай Create AVD. Потім вибирай машину і тисни Start, Launch. Все, будемо чекати. На моєму нетбуці воно запускалося близько десяти хвилин, на десктопі - 1,5-2 хвилини. Працює емулятор так само повільно, як і запускається (бо емулює ARM за допомогою QEMU). З одного боку це погано, що все гальмує, а з іншого боку - ми отримуємо достовірні на 100% результати. Як тільки з'явиться робочий стіл Android, віртуальну машину можна буде залишити в спокої.
Створення тестового проекту

Переходимо в директорію tools Android SDK (в консолі). Відкриваємо документацію, починаємо вкурівать. Вводимо:. / Android create project. Опс, помилочка! Дивимося, чого від нас хочуть. Ага, ми не вказали параметри нашого майбутнього проекту, а точніше: мета. Потрібна версія API, шлях до проекту, його ім'я, ім'я Activity та ім'я простору імен для програми. У мене вийшло ось так:

. / Android create project - target 8 - name hello - path. / TestPro - activity helloActivity - package com.example.hello

Робимо ls ... ага, ось вона - директорія TestPro. Входимо до неї, і знову викликаємо ls. Далі в директорії libs потрібно створити сабдіректорію armeabi. У неї ми копіюємо нашу зібрану Qt'шную либу (. So).

У каталог src / треба скопіювати весь вміст androidlighthouse / src / android / java / com, щоб вийшло src / com / nokia / qt. Після цього йдемо в src / com / example / hello / і редагуємо там головний Activity - helloActivity.java. Видаляємо onCreate, додаємо функцію:

public helloActivity ()
{
setApplication ("Hello");
}

Тут Hello - назва програми. Отже, наша бібліотека. So повинна називатися libHello.so.

Ну і, нарешті, йдемо в консолі в корінь проекту і командуємо ant install. Чекаємо (довго, оскільки Ліба статична і важить багато. У мене, наприклад - 12.5 Мб). Після того, як в консолі з'явиться заповітне SUCCESSFUL, можна йти в головне меню Андроїда і запускати звідти своє застосування.
Висновок

Колись (чи то у 2007, чи то в 2008) у мене на телефоні (Motorola A1200e, один з перших телефонів з Linux, і, до речі, з гуем, написаним на Qt 2) з'явилася QTopia, також відома як Qt Embedded - вбудовувана ОС від Trolltech на базі Linux Kernel 2.6 з оболонкою на Qt 4, покинута після покупки тролів Нокією. З'явилася вона завдяки трудівникам з форуму motofan, що зумів перенести її на ядро 2.4 (другий у A1200 не було і не буде, тому не буде і Андроїда). Так от, коли я її поставив, був здивований простотою портування програм з десктопа на телефон - іноді потрібно просто перезібрати його крос-компілятором, і все!

На жаль, новомодного Qt 4.5 платформа не отримала (і дарма - на мій погляд, вона була не гірше, ніж Maemo). Тепер такий метод портування можливий і на Android, але ж за ним майбутнє. І, до речі, щосили йде портування Qt Mobility, класного фреймворку для телефонів Nokia. Шкода, поки що портуванням працює лише одна, нехай і дуже крутий чоловік (до речі, допомогти не бажаєш?). Загалом, нам залишилося дочекатися портування Qt на iOS (там, на жаль, все далеко не так райдужно), і тоді можна буде сміливо заявляти, що гасло Qt Software не висмоктаний з пальця.

Qt Everywhere!
Thanks to:

Величезне спасибі румунові taipanromania (автор порту) і marflon (раніше, до речі, писав в] [) за допомогу з створенням. Apk, ну і, традиційно, групі І-3-1 (Прикладна Математика) МГТУ "Станкин".