Reputation: 667
Ive spent many hours trying to get a simple QML IOS application to start the UIApplication delegate as well as start and display the Main.qml component for a larger app I would like to create.
Im using Qt 6.8.1 on MacOS Sonoma 14.6.1, Qt Creator 15.0.0 Ive tried running it on both the IOS Simulator as well as an Iphone Device w/same result.
The problem is that everything seems to work except that the Main.qml is not showing. The Screen is just black. I can close the app and open it and the UIApplication delegates are getting called as expected but the screen is always black. Ive tried multiple other solutions none of which I have been able to get thing to work correctly.
Ive included the output when I run it so you can see things appear to be working as expected except for the visual display.
Any help and/or suggestions are appreciated. Thank you!
Main.qml:
import QtQuick
import QtQuick.Window
import QtQuick.Controls
ApplicationWindow {
width: 640
height: 480
visible: true
color: "green"
Component.onCompleted: {
console.log("Main.qml Completed")
}
onVisibleChanged: console.log("Main.qml: visible: " + visible)
Text {
text: "My Application"
color: "white"
anchors.centerIn: parent
font.pixelSize: 26
}
}
AppDelegate.h:
#import <UIKit/UIKit.h>
@interface QIOSApplicationDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
AppDelegate.mm
// AppDelegate.mm
#import "AppDelegate.h"
extern void setContinueLaunchingQML();
@implementation QIOSApplicationDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSLog(@"------------ App applicationDidFinishLaunching");
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"==== didFinishLaunchingWithOptions");
setContinueLaunchingQML();
NSLog(@"==== applicationDidFinishLaunching return YES ====");
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
NSLog(@"IOS_APP_DEL: applicationWillResignActive");
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(@"IOS_APP_DEL: applicationDidEnterBackground");
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
NSLog(@"IOS_APP_DEL: applicationWillEnterForeground");
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSLog(@"IOS_APP_DEL: applicationDidBecomeActive");
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
@end
main.cpp:
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <unistd.h>
static bool waiting_for_ios_delegate_ = true;
int main(int argc, char *argv[])
{
qDebug() << "MAIN CPP start";
while(waiting_for_ios_delegate_) {
sleep(1);
qApp->processEvents();
}
qDebug() << "Continue main cpp Startup...";
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QQmlComponent component(&engine);
component.loadFromModule("iosDelegate", "Main");
if (component.isReady()) {
qDebug() << "Component Main.qml READY...now create it";
if (!component.create()) {
qWarning() << "ERROR - Main.qml failed to create";
_exit(1);
}
}
else {
qWarning() << "ERROR - Main.qml is not ready - " << component.errorString();
_exit(1);
}
qDebug() << "exec()";
return app.exec();
}
void setContinueLaunchingQML()
{
qDebug() << "setContinueLaunchingQML";
waiting_for_ios_delegate_ = false;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(iosDelegate VERSION 0.1 LANGUAGES CXX OBJCXX)
find_package(Qt6 REQUIRED COMPONENTS
Core
Qml
Gui
Quick
QuickControls2
Widgets)
qt_standard_project_setup(REQUIRES 6.5)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -x objective-c++ -fobjc-arc
-I./*.h
-iwithprefix /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/
-iwithprefix /Library/Developer/CommandLineTools/SDKs/MacOSX15.1.sdk/System/Library/Frameworks/
")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}
-framework Foundation
-framework UIKit
")
if(APPLE)
set(APPLE_SDK_TOP /Applications/Xcode.app/Contents/Developer/Platforms)
set(IOS_SYS_LIB_FRAMEWORK System/Library/Frameworks)
if(CMAKE_OSX_SYSROOT STREQUAL "iphonesimulator")
set(IOS_PLATFORM iPhoneSimulator)
elseif (CMAKE_OSX_SYSROOT STREQUAL "iphoneos")
set(IOS_PLATFORM iPhoneOS)
else()
warning(IOS_PLATFORM NOT FOUND)
endif()
endif(APPLE)
qt_add_executable(appiosDelegate
main.cpp
AppDelegate.h
AppDelegate.mm
)
qt_add_qml_module(appiosDelegate
URI iosDelegate
VERSION 1.0
QML_FILES
Main.qml
)
set_target_properties(appiosDelegate PROPERTIES
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
target_link_libraries(appiosDelegate
PRIVATE
Qt6::Core
Qt6::Qml
Qt6::Quick
Qt6::Gui
Qt6::QuickControls2
Qt6::Widgets
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(${TARGET})
endif()
set(CMAKE_OSX_INFOPLIST_FILE "${CMAKE_CURRENT_LIST_DIR}/Info.plist")
set(MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_LIST_DIR}/Info.plist")
include(GNUInstallDirs)
install(TARGETS appiosDelegate
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
Output:
2025-01-17 11:05:07.432 appiosDelegate[50772:16574720] ==== didFinishLaunchingWithOptions
setContinueLaunchingQML
2025-01-17 11:05:07.434 appiosDelegate[50772:16574720] ==== applicationDidFinishLaunching return YES ====
MAIN CPP start
Continue main cpp Startup...
Component Main.qml READY...now create it
qml: Main.qml: visible: true
qml: Main.qml Completed
exec()
2025-01-17 11:05:08.229 appiosDelegate[50772:16574720] IOS_APP_DEL: applicationDidBecomeActive
2025-01-17 11:12:39.336 appiosDelegate[50772:16574720] IOS_APP_DEL: applicationWillResignActive
2025-01-17 11:12:39.972 appiosDelegate[50772:16574720] IOS_APP_DEL: applicationDidEnterBackground
2025-01-17 11:12:44.486 appiosDelegate[50772:16574720] IOS_APP_DEL: applicationWillEnterForeground
2025-01-17 11:12:44.764 appiosDelegate[50772:16574720] IOS_APP_DEL: applicationDidBecomeActive
[EDIT]
NOTE: Main.qml is now visible but now the other IOS UIApplicationDelegates are not being called (other than didFinishLaunchingWithOptions after doing the following:
The only 2 changes I made are as follows:
// AppDelegate.h
#import <UIKit/UIKit.h>
@interface QIOSApplicationDelegate
@end
@interface QIOSApplicationDelegate (MyIOSApplicationDelegate)
@property (strong, nonatomic) UIWindow *window;
@end
I also removed the wait flag entirely: waiting_for_ios_delegate_
Now the output is:
2025-01-28 05:24:04.223 appiosDelegate[81506:24556235] ==== didFinishLaunchingWithOptions
2025-01-28 05:24:04.223 appiosDelegate[81506:24556235] ==== applicationDidFinishLaunching return YES ====
MAIN CPP start
Component Main.qml READY...now create it
qml: Main.qml: visible: true
qml: Main.qml Completed
exec()
stale focus object 0x0 , doing manual update
In my first examples the other delegates were called when I simulated the "HOME" screen and also restarted the app. After my 2 changes I only get the 1 delegate called, no others are being called.
I also tried other suggestions from articles with the same result as what I just described here using:
extern "C" int qt_main_wrapper(int argc, char **argv[]);
and implementing the IOS entry point _qt_main_wrapper:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}
-Wl,-e,_qt_main_wrapper
-u _qt_registerPlatformPlugin
-framework Foundation
-framework UIKit")
However it also seems that if I dont include -Wl,-e,_qt_main_wrapper I get the exact same result in my output:
2025-01-28 07:25:02.170 appiosDelegate[93577:24696424] ==== didFinishLaunchingWithOptions
2025-01-28 07:25:02.170 appiosDelegate[93577:24696424] ==== applicationDidFinishLaunching return YES ====
MAIN CPP start
Continue main cpp Startup...
Component Main.qml READY...now create it
qml: Main.qml: visible: true
qml: Main.qml Completed
exec()
stale focus object 0x0 , doing manual update
Other articles:
QT IOS linker error entry point (_main) undefined
Allow dynamic builds of Qt for iOS - Tech Preview
How to get didFinishLaunchingWithOptions called in IOS delegate?
I have not been able to find a Qt document describing how to accomplish this other than the bug report link I provided.
I also tried setting:
export QT_LOGGING_RULES="lcEventDispatcher.debug=true"
When I tried -Wl,-e,_qt_main_wrapper link flag to see if qt_main_wrapper was being called I did not see any output for that event (This should come from qioseventdispatcher.mm). I have no idea why that linker flag would not work since I am seeing it in the compiler output and I did add the:
extern "C" int qt_main_wrapper(int argc, char *argv[])
to my main.cpp when I tried it. It seems like Im one step away from solving this however it still eludes me. Any help is appreciated.
Upvotes: 0
Views: 52