📜 ⬆️ ⬇️

Native Android and iOS code in Qt using the status bar example

Hello! I'm sure many have heard that Qt is very good for cross-platform mobile application development. However, to solve some problems, you have to deal with native code (Java, Objective-C), for example, a camera call, galleries, a third-party api call.


In this article, using a simple example of setting transparency for a status bar, I will show how to call native Java code and Objective-C.


in life


Andoid


The ability to use a transparent status bar appeared in Android 4.4 KitKat . In order for the status bar to become transparent, it is necessary in the Activity of our project to specify the transparency flag for the Window (not to be confused with QQuickWindow , which is used to display QML).


If anyone does not know how to override their Activity from QtActivity

Open the Projects tab → Add assembly under Andoid → “Assembly” → Click “Details” in “Build Android APK” → “Create templates”.


Thus, we created AndroidManifest, a folder with resources and gradle files, which will be located in the android folder. To accommodate our java class, create a folder src in the android folder.


Create the file MyActivity.java . It is important that the path to the file matches the package name, i.e. using a package named com.example.myPackage, the path should be 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); } } 

Now, we need to set the name of the Activity in AndroidManifest.xml . Are looking for


 android:name="com.example.myPackage.MyActivity" 

and change to


 android:name="org.qtproject.qt5.android.bindings.QtActivity" 

With these simple manipulations, we have redefined the standard QtActivity.


The function sets the status bar transparency flag and an example of its use:


 @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); } } 

A function that returns the status bar height:


 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; } 

In order to call a Java class method from QML, you will need to write a C ++ class that will use JNI . To work with JNI, add the Android module to our * .pro file:


 QT += androidextras. 

Create a singleton DeviceInfo class.


DeviceInfo.h:


 #pragma once #include <QObject> 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 <QAndroidJniObject> #include <QtAndroidExtras> #include <QtAndroid> #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<jint>("statusBarHeight"); return (int) height; #endif return 0; } 

Next, we define our class in QML:


 view.rootContext()->setContextProperty("DeviceInfo", &DeviceInfo::instance()); 

Everything is ready, it remains only to call the statusBarHeight method in QML:


 Rectangle { width: parent.width height: DeviceInfo.statusBarHeight() } 

The result on the screen:


android screenshot


iOS


The ability to set a different style for the status bar in iOS appeared in iOS 7.0 . In order for the status bar in our application to be transparent, we need to do 3 things:


  1. Edit info.plist, namely, change the UIViewControllerBasedStatusBarAppearance key:

 <key>UIViewControllerBasedStatusBarAppearance</key> <false/> 

  1. To display QQuickView or QQuickWindow, use the showFullScreen () method instead of show ().

  1. Set the status bar to UIStatusBarStyleLightContent

If everything is clear with the first two points, let’s look at the third one in more detail. You can change the style of the status bar using the following method on Objective-C:


 [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; 

A function that returns the status bar status:


 [UIApplication sharedApplication].statusBarFrame.size.height 

In order for Objective-C code to work in the DeviceInfo class, we will need to change the source resolution from .cpp to .mm. Therefore, in the .pro file we will do the following:


 HEADERS += \ Include/DeviceInfo.h !ios { SOURCES += \ Source/DeviceInfo.cpp } ios { OBJECTIVE_SOURCES += \ Source/DeviceInfo.mm } 

DeviceInfo.mm:


 #include "DeviceInfo.h" #import <UIKit/UIKit.h> 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; } 

The result on the screen:


ios screenshot


Conclusion


I tried to highlight every step as much as possible so that, based on the examples from the article, you could easily supplement your mobile project with native code. See the source code for the sample on GitHub .


')

Source: https://habr.com/ru/post/320696/


All Articles