iOS: Guard all uses of APIs not available in application extensions
Change-Id: Ic058a0c07f6cdd0a015f46db96fce1536a712711 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>bb10
parent
8058380904
commit
a15db3a81a
|
|
@ -5,8 +5,6 @@ TARGET = qios
|
|||
# application's main() when the plugin is a shared library.
|
||||
qtConfig(shared): CONFIG += static
|
||||
|
||||
CONFIG += no_app_extension_api_only
|
||||
|
||||
QT += \
|
||||
core-private gui-private \
|
||||
clipboard_support-private fontdatabase_support-private graphics_support-private
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ static void qRegisterApplicationStateNotifications()
|
|||
QLatin1String("Extension loaded, assuming state is active"));
|
||||
} else {
|
||||
// Initialize correct startup state, which may not be the Qt default (inactive)
|
||||
UIApplicationState startupState = [UIApplication sharedApplication].applicationState;
|
||||
UIApplicationState startupState = qt_apple_sharedApplication().applicationState;
|
||||
QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application loaded"));
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +95,7 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterApplicationStateNotifications)
|
|||
QIOSApplicationState::QIOSApplicationState()
|
||||
{
|
||||
if (!qt_apple_isApplicationExtension()) {
|
||||
UIApplicationState startupState = [UIApplication sharedApplication].applicationState;
|
||||
UIApplicationState startupState = qt_apple_sharedApplication().applicationState;
|
||||
QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application launched"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@
|
|||
#include <QtGui/qwindow.h>
|
||||
#include <QDebug>
|
||||
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
|
||||
#include "qiosfiledialog.h"
|
||||
#include "qiosintegration.h"
|
||||
#include "qiosoptionalplugininterface.h"
|
||||
|
|
@ -94,7 +96,7 @@ bool QIOSFileDialog::showImagePickerDialog(QWindow *parent)
|
|||
}
|
||||
|
||||
UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window
|
||||
: [UIApplication sharedApplication].keyWindow;
|
||||
: qt_apple_sharedApplication().keyWindow;
|
||||
[window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
#include "qiosviewcontroller.h"
|
||||
#include "qiosscreen.h"
|
||||
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application");
|
||||
|
|
@ -50,13 +52,16 @@ Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
|
|||
|
||||
bool isQtApplication()
|
||||
{
|
||||
if (qt_apple_isApplicationExtension())
|
||||
return false;
|
||||
|
||||
// Returns \c true if the plugin is in full control of the whole application. This means
|
||||
// that we control the application delegate and the top view controller, and can take
|
||||
// actions that impacts all parts of the application. The opposite means that we are
|
||||
// embedded inside a native iOS application, and should be more focused on playing along
|
||||
// with native UIControls, and less inclined to change structures that lies outside the
|
||||
// scope of our QWindows/UIViews.
|
||||
static bool isQt = ([[UIApplication sharedApplication].delegate isKindOfClass:[QIOSApplicationDelegate class]]);
|
||||
static bool isQt = ([qt_apple_sharedApplication().delegate isKindOfClass:[QIOSApplicationDelegate class]]);
|
||||
return isQt;
|
||||
}
|
||||
|
||||
|
|
@ -152,8 +157,13 @@ QT_END_NAMESPACE
|
|||
|
||||
+ (id)currentFirstResponder
|
||||
{
|
||||
if (qt_apple_isApplicationExtension()) {
|
||||
qWarning() << "can't get first responder in application extensions!";
|
||||
return nil;
|
||||
}
|
||||
|
||||
QtFirstResponderEvent *event = [[[QtFirstResponderEvent alloc] init] autorelease];
|
||||
[[UIApplication sharedApplication] sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event];
|
||||
[qt_apple_sharedApplication() sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event];
|
||||
return event.firstResponder;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@
|
|||
#include "qioswindow.h"
|
||||
#include "quiview.h"
|
||||
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QtGui/private/qwindow_p.h>
|
||||
|
||||
|
|
@ -536,6 +538,11 @@ void QIOSInputContext::scroll(int y)
|
|||
if (!rootView)
|
||||
return;
|
||||
|
||||
if (qt_apple_isApplicationExtension()) {
|
||||
qWarning() << "can't scroll root view in application extension";
|
||||
return;
|
||||
}
|
||||
|
||||
CATransform3D translationTransform = CATransform3DMakeTranslation(0.0, -y, 0.0);
|
||||
if (CATransform3DEqualToTransform(translationTransform, rootView.layer.sublayerTransform))
|
||||
return;
|
||||
|
|
@ -574,7 +581,7 @@ void QIOSInputContext::scroll(int y)
|
|||
|
||||
// Raise all known windows to above the status-bar if we're scrolling the screen,
|
||||
// while keeping the relative window level between the windows the same.
|
||||
NSArray *applicationWindows = [[UIApplication sharedApplication] windows];
|
||||
NSArray *applicationWindows = [qt_apple_sharedApplication() windows];
|
||||
static QHash<UIWindow *, UIWindowLevel> originalWindowLevels;
|
||||
for (UIWindow *window in applicationWindows) {
|
||||
if (keyboardScrollIsActive && !originalWindowLevels.contains(window))
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ QIOSIntegration::QIOSIntegration()
|
|||
, m_accessibility(0)
|
||||
, m_optionalPlugins(new QFactoryLoader(QIosOptionalPluginInterface_iid, QLatin1String("/platforms/darwin")))
|
||||
{
|
||||
if (Q_UNLIKELY(![UIApplication sharedApplication])) {
|
||||
if (Q_UNLIKELY(!qt_apple_isApplicationExtension() && !qt_apple_sharedApplication())) {
|
||||
qFatal("Error: You are creating QApplication before calling UIApplicationMain.\n" \
|
||||
"If you are writing a native iOS application, and only want to use Qt for\n" \
|
||||
"parts of the application, a good place to create QApplication is from within\n" \
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@
|
|||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <qpa/qplatformtheme.h>
|
||||
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
|
||||
#include "qiosglobal.h"
|
||||
#include "quiview.h"
|
||||
#include "qiosmessagedialog.h"
|
||||
|
|
@ -126,7 +128,7 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win
|
|||
[m_alertController addAction:createAction(NoButton)];
|
||||
}
|
||||
|
||||
UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window : [UIApplication sharedApplication].keyWindow;
|
||||
UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window : qt_apple_sharedApplication().keyWindow;
|
||||
[window.rootViewController presentViewController:m_alertController animated:YES completion:nil];
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
#include "qiosviewcontroller.h"
|
||||
#include "quiview.h"
|
||||
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
|
||||
#include <QtGui/private/qwindow_p.h>
|
||||
#include <private/qcoregraphics_p.h>
|
||||
|
||||
|
|
@ -271,17 +273,19 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
|
|||
m_physicalDpi = 96;
|
||||
}
|
||||
|
||||
for (UIWindow *existingWindow in [[UIApplication sharedApplication] windows]) {
|
||||
if (existingWindow.screen == m_uiScreen) {
|
||||
m_uiWindow = [m_uiWindow retain];
|
||||
break;
|
||||
if (!qt_apple_isApplicationExtension()) {
|
||||
for (UIWindow *existingWindow in qt_apple_sharedApplication().windows) {
|
||||
if (existingWindow.screen == m_uiScreen) {
|
||||
m_uiWindow = [m_uiWindow retain];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_uiWindow) {
|
||||
// Create a window and associated view-controller that we can use
|
||||
m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]];
|
||||
m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease];
|
||||
if (!m_uiWindow) {
|
||||
// Create a window and associated view-controller that we can use
|
||||
m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]];
|
||||
m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease];
|
||||
}
|
||||
}
|
||||
|
||||
updateProperties();
|
||||
|
|
@ -327,17 +331,20 @@ void QIOSScreen::updateProperties()
|
|||
|
||||
#ifndef Q_OS_TVOS
|
||||
if (m_uiScreen == [UIScreen mainScreen]) {
|
||||
Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation));
|
||||
|
||||
QIOSViewController *qtViewController = [m_uiWindow.rootViewController isKindOfClass:[QIOSViewController class]] ?
|
||||
static_cast<QIOSViewController *>(m_uiWindow.rootViewController) : nil;
|
||||
|
||||
if (qtViewController.lockedOrientation) {
|
||||
Q_ASSERT(!qt_apple_isApplicationExtension());
|
||||
|
||||
// Setting the statusbar orientation (content orientation) on will affect the screen geometry,
|
||||
// which is not what we want. We want to reflect the screen geometry based on the locked orientation,
|
||||
// and adjust the available geometry based on the repositioned status bar for the current status
|
||||
// bar orientation.
|
||||
|
||||
Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(
|
||||
UIDeviceOrientation(qt_apple_sharedApplication().statusBarOrientation));
|
||||
|
||||
Qt::ScreenOrientation lockedOrientation = toQtScreenOrientation(UIDeviceOrientation(qtViewController.lockedOrientation));
|
||||
QTransform transform = transformBetween(lockedOrientation, statusBarOrientation, m_geometry).inverted();
|
||||
|
||||
|
|
@ -487,8 +494,8 @@ Qt::ScreenOrientation QIOSScreen::orientation() const
|
|||
// the orientation the application was started up in (which may not match
|
||||
// the physical orientation of the device, but typically does unless the
|
||||
// application has been locked to a subset of the available orientations).
|
||||
if (deviceOrientation == UIDeviceOrientationUnknown)
|
||||
deviceOrientation = UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation);
|
||||
if (deviceOrientation == UIDeviceOrientationUnknown && !qt_apple_isApplicationExtension())
|
||||
deviceOrientation = UIDeviceOrientation(qt_apple_sharedApplication().statusBarOrientation);
|
||||
|
||||
// If the device reports face up or face down orientations, we can't map
|
||||
// them to Qt orientations, so we pretend we're in the same orientation
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@
|
|||
#include "qiosservices.h"
|
||||
|
||||
#include <QtCore/qurl.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
|
||||
#include <QtGui/qdesktopservices.h>
|
||||
|
||||
#import <UIKit/UIApplication.h>
|
||||
|
|
@ -48,6 +51,11 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
bool QIOSServices::openUrl(const QUrl &url)
|
||||
{
|
||||
if (qt_apple_isApplicationExtension()) {
|
||||
qWarning() << "openUrl not implement for application extensions yet";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (url == m_handlingUrl)
|
||||
return false;
|
||||
|
||||
|
|
@ -55,12 +63,25 @@ bool QIOSServices::openUrl(const QUrl &url)
|
|||
return openDocument(url);
|
||||
|
||||
NSURL *nsUrl = url.toNSURL();
|
||||
UIApplication *application = [UIApplication sharedApplication];
|
||||
UIApplication *application = qt_apple_sharedApplication();
|
||||
|
||||
if (![application canOpenURL:nsUrl])
|
||||
return false;
|
||||
|
||||
[application openURL:nsUrl options:@{} completionHandler:nil];
|
||||
static SEL openUrlSelector = @selector(openURL:options:completionHandler:);
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
|
||||
[UIApplication instanceMethodSignatureForSelector:openUrlSelector]];
|
||||
invocation.target = application;
|
||||
invocation.selector = openUrlSelector;
|
||||
|
||||
static auto kEmptyDictionary = @{};
|
||||
// Indices 0 and 1 are self and _cmd
|
||||
[invocation setArgument:&nsUrl atIndex:2];
|
||||
[invocation setArgument:&kEmptyDictionary atIndex:3];
|
||||
// Fourth argument is nil, so left unset
|
||||
|
||||
[invocation invoke];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
|
||||
#include <QtGui/private/qinputmethod_p.h>
|
||||
#include <QtCore/private/qobject_p.h>
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
|
||||
#include "qiosglobal.h"
|
||||
#include "qiostextinputoverlay.h"
|
||||
|
|
@ -475,7 +476,7 @@ static void executeBlockWithoutAnimation(Block block)
|
|||
|
||||
if (enabled) {
|
||||
_focusView = [reinterpret_cast<UIView *>(qApp->focusWindow()->winId()) retain];
|
||||
_desktopView = [[UIApplication sharedApplication].keyWindow.rootViewController.view retain];
|
||||
_desktopView = [qt_apple_sharedApplication().keyWindow.rootViewController.view retain];
|
||||
Q_ASSERT(_focusView && _desktopView && _desktopView.superview);
|
||||
[_desktopView addGestureRecognizer:self];
|
||||
} else {
|
||||
|
|
@ -991,6 +992,11 @@ QIOSTextInputOverlay::QIOSTextInputOverlay()
|
|||
, m_selectionRecognizer(nullptr)
|
||||
, m_openMenuOnTapRecognizer(nullptr)
|
||||
{
|
||||
if (qt_apple_isApplicationExtension()) {
|
||||
qWarning() << "text input overlays disabled in application extensions";
|
||||
return;
|
||||
}
|
||||
|
||||
connect(qApp, &QGuiApplication::focusObjectChanged, this, &QIOSTextInputOverlay::updateFocusObject);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
|
||||
#include <QtGui/QFont>
|
||||
|
||||
|
|
@ -103,7 +104,7 @@ bool QIOSTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const
|
|||
switch (type) {
|
||||
case FileDialog:
|
||||
case MessageDialog:
|
||||
return true;
|
||||
return !qt_apple_isApplicationExtension();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#import "qiosviewcontroller.h"
|
||||
|
||||
#include <QtCore/qscopedvaluerollback.h>
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QWindow>
|
||||
|
|
@ -307,15 +308,17 @@
|
|||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
Q_ASSERT(!qt_apple_isApplicationExtension());
|
||||
|
||||
#ifndef Q_OS_TVOS
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center addObserver:self selector:@selector(willChangeStatusBarFrame:)
|
||||
name:UIApplicationWillChangeStatusBarFrameNotification
|
||||
object:[UIApplication sharedApplication]];
|
||||
object:qt_apple_sharedApplication()];
|
||||
|
||||
[center addObserver:self selector:@selector(didChangeStatusBarOrientation:)
|
||||
name:UIApplicationDidChangeStatusBarOrientationNotification
|
||||
object:[UIApplication sharedApplication]];
|
||||
object:qt_apple_sharedApplication()];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -455,7 +458,6 @@
|
|||
focusWindow = qt_window_private(focusWindow)->topLevelWindow();
|
||||
|
||||
#ifndef Q_OS_TVOS
|
||||
UIApplication *uiApplication = [UIApplication sharedApplication];
|
||||
|
||||
// -------------- Status bar style and visbility ---------------
|
||||
|
||||
|
|
@ -479,6 +481,8 @@
|
|||
|
||||
// -------------- Content orientation ---------------
|
||||
|
||||
UIApplication *uiApplication = qt_apple_sharedApplication();
|
||||
|
||||
static BOOL kAnimateContentOrientationChanges = YES;
|
||||
|
||||
Qt::ScreenOrientation contentOrientation = focusWindow->contentOrientation();
|
||||
|
|
|
|||
Loading…
Reference in New Issue