[Из песочницы] Нативный код Android и iOS в Qt на примере status bar
Здравствуйте! Уверен, многие слышали о том, что Qt очень хорош для кросплатформенной разработки мобильных приложений. Однако, для решения некоторых задач приходится иметь дело с нативным кодом (Java, Objective-C), к примеру, вызов камеры, галереи, вызов стороннего api.
В этой статье на простом примере задания прозрачности для status bar я покажу, как осуществляется вызов нативного кода Java и Objective-C.
Andoid
Возможность использования прозрачного status bar появилась в Android 4.4 KitKat. Для того, чтобы status bar стал прозрачным, необходимо в Activity нашего проекта указать флаг прозрачности для Window (не путать с QQuickWindow, который используется для отображения QML).
Открываем вкладку Проекты → Добавить сборку под Andoid → «Сборка» → Нажимаем «Подробнее» в «Собрать Android APK» → «Создать шаблоны».
Тем самым мы создали AndroidManifest, папку с ресурсами и файлы gradle, которые будут находится в папке android. Для размещения нашего java класса создадим папку src в папке android.
Создадим файл MyActivity.java. Важно, чтобы путь до файла совпадал с именем пакета, т.е. используя пакет с именем com.example.myPackage, путь должен быть android/src/com/example/myPackage/MyActivity.java
package com.example.myPackage;
import org.qtproject.qt5.android.bindings.QtActivity;
import android.app.Activity;
import android.os.Bundle;
public class MyActivity extends QtActivity
{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
Теперь, нам надо задать имя Activity в AndroidManifest.xml. Ищем
android:name="com.example.myPackage.MyActivity"
и меняем на
android:name="org.qtproject.qt5.android.bindings.QtActivity"
Этими нехитрыми манипуляциями мы переопределили стандартную QtActivity.
Функция выставляющая флаг прозрачности status bar и пример её применения:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTranparentStatusBar();
}
void function setTranparentStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
getWindow().setStatusBarColor(Color.TRANSPARENT);
} else {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
Функция, возвращающая высоту status bar:
public int statusBarHeight() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return 0;
}
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
Для того, чтобы вызвать метод Java класса из QML потребуется написать С++ класс, который будет использовать JNI. Для работы с JNI добавим в наш *.pro файл модуль Android:
QT += androidextras.
Создадим singleton класс DeviceInfo.
DeviceInfo.h:
#pragma once
#include
class DeviceInfo : public QObject
{
Q_OBJECT
Q_PROPERTY(int statusBarHeight READ statusBarHeight)
public:
DeviceInfo(QObject *parent = NULL);
static DeviceInfo &instance(QObject *parent = 0);
Q_INVOKABLE int statusBarHeight();
private:
static DeviceInfo _instance;
};
DeviceInfo.cpp:
#include "DeviceInfo.h"
#if defined(Q_OS_ANDROID)
#include
#include
#include
#endif
DeviceInfo::DeviceInfo(QObject *parent)
: QObject(parent)
{}
DeviceInfo &DeviceInfo::instance(QObject *parent)
{
static DeviceInfo instance(parent);
return instance;
}
int DeviceInfo::statusBarHeight()
{
#if defined (Q_OS_ANDROID)
QAndroidJniObject activity = QtAndroid::androidActivity();
jint height = activity.callMethod("statusBarHeight");
return (int) height;
#endif
return 0;
}
Далее, определим наш класс в QML:
view.rootContext()->setContextProperty("DeviceInfo", &DeviceInfo::instance());
Всё готово, осталось лишь вызвать метод statusBarHeight в QML:
Rectangle {
width: parent.width
height: DeviceInfo.statusBarHeight()
}
Итог на экране:
iOS
Возможность задания различного стиля у status bar в iOS появилась в iOS 7.0. Для того, чтобы status bar в нашем приложение был прозрачен, нам нужно сделать 3 вещи:
- Изменить info.plist, а именно, изменить ключ UIViewControllerBasedStatusBarAppearance:
UIViewControllerBasedStatusBarAppearance
- Для отображения QQuickView или QQuickWindow использовать метод showFullScreen () вместо show ().
- Выставить у status bar стиль UIStatusBarStyleLightContent
Если с первыми двумя пунктами всё понятно, разберём третий более подробно. Изменить стиль у status bar’a можно следующим методом на Objective-C:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
Функция, возвращающая высоту status bar«a:
[UIApplication sharedApplication].statusBarFrame.size.height
Для того, чтобы код на Objective-C работал в классе DeviceInfo, нам потребуется поменять разрешение исходника с .cpp на .mm. Поэтому в .pro файле сделаем следующее:
HEADERS += \
Include/DeviceInfo.h
!ios {
SOURCES += \
Source/DeviceInfo.cpp
}
ios {
OBJECTIVE_SOURCES += \
Source/DeviceInfo.mm
}
DeviceInfo.mm:
#include "DeviceInfo.h"
#import
DeviceInfo::DeviceInfo(QObject *parent)
: QObject(parent)
{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
DeviceInfo &DeviceInfo::instance(QObject *parent)
{
static DeviceInfo instance(parent);
return instance;
}
int DeviceInfo::statusBarHeight()
{
return [UIApplication sharedApplication].statusBarFrame.size.height;
}
Итог на экране:
Заключение
Я постарался осветить как можно подробнее каждый шаг, чтобы на основе примеров из статьи вы могли легко дополнить свой мобильный проект нативным кодом. Исходный код примера смотрите на GitHub.
Комментарии (1)
28 января 2017 в 18:34
+1↑
↓
Какой объем у apk и ipa получается на таком простом примере?