Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdesktopservices.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#ifndef QT_NO_DESKTOPSERVICES
8
9#include <qdebug.h>
10
11#include <qstandardpaths.h>
12#include <qhash.h>
13#include <qobject.h>
14#include <qcoreapplication.h>
15#include <private/qguiapplication_p.h>
16#include <qurl.h>
17#include <qmutex.h>
18#include <qpa/qplatformservices.h>
19#include <qpa/qplatformintegration.h>
20#include <qdir.h>
21
23
39
40Q_GLOBAL_STATIC(QOpenUrlHandlerRegistry, handlerRegistry)
41
42/*!
43 \class QDesktopServices
44 \brief The QDesktopServices class provides methods for accessing common desktop services.
45 \since 4.2
46 \ingroup desktop
47 \inmodule QtGui
48
49 Many desktop environments provide services that can be used by applications to
50 perform common tasks, such as opening a web page, in a way that is both consistent
51 and takes into account the user's application preferences.
52
53 This class contains functions that provide simple interfaces to these services
54 that indicate whether they succeeded or failed.
55
56 The openUrl() function is used to open files located at arbitrary URLs in external
57 applications. For URLs that correspond to resources on the local filing system
58 (where the URL scheme is "file"), a suitable application will be used to open the
59 file; otherwise, a web browser will be used to fetch and display the file.
60
61 The user's desktop settings control whether certain executable file types are
62 opened for browsing, or if they are executed instead. Some desktop environments
63 are configured to prevent users from executing files obtained from non-local URLs,
64 or to ask the user's permission before doing so.
65
66 \section1 URL Handlers
67
68 The behavior of the openUrl() function can be customized for individual URL
69 schemes to allow applications to override the default handling behavior for
70 certain types of URLs.
71
72 The dispatch mechanism allows only one custom handler to be used for each URL
73 scheme; this is set using the setUrlHandler() function. Each handler is
74 implemented as a slot which accepts only a single QUrl argument.
75
76 The existing handlers for each scheme can be removed with the
77 unsetUrlHandler() function. This returns the handling behavior for the given
78 scheme to the default behavior.
79
80 This system makes it easy to implement a help system, for example. Help could be
81 provided in labels and text browsers using \uicontrol{help://myapplication/mytopic}
82 URLs, and by registering a handler it becomes possible to display the help text
83 inside the application:
84
85 \snippet code/src_gui_util_qdesktopservices.cpp 0
86 \snippet code/src_gui_util_qdesktopservices.cpp setUrlHandler
87
88 If inside the handler you decide that you can't open the requested
89 URL, you can just call QDesktopServices::openUrl() again with the
90 same argument, and it will try to open the URL using the
91 appropriate mechanism for the user's desktop environment.
92
93 Combined with platform specific settings, the schemes registered by the
94 openUrl() function can also be exposed to other applications, opening up
95 for application deep linking or a very basic URL-based IPC mechanism.
96
97 \sa QSystemTrayIcon, QProcess, QStandardPaths
98*/
99
100/*!
101 Opens the given \a url in the appropriate Web browser for the user's desktop
102 environment, and returns \c true if successful; otherwise returns \c false.
103
104 If the URL is a reference to a local file (i.e., the URL scheme is "file") then
105 it will be opened with a suitable application instead of a Web browser.
106
107 The following example opens a file on the Windows file system residing on a path
108 that contains spaces:
109
110 \snippet code/src_gui_util_qdesktopservices.cpp 2
111
112 If a \c mailto URL is specified, the user's e-mail client will be used to open a
113 composer window containing the options specified in the URL, similar to the way
114 \c mailto links are handled by a Web browser.
115
116 For example, the following URL contains a recipient (\c{user@foo.com}), a
117 subject (\c{Test}), and a message body (\c{Just a test}):
118
119 \snippet code/src_gui_util_qdesktopservices.cpp 1
120
121 \warning Although many e-mail clients can send attachments and are
122 Unicode-aware, the user may have configured their client without these features.
123 Also, certain e-mail clients (e.g., Lotus Notes) have problems with long URLs.
124
125 \warning A return value of \c true indicates that the application has successfully requested
126 the operating system to open the URL in an external application. The external application may
127 still fail to launch or fail to open the requested URL. This result will not be reported back
128 to the application.
129
130 \warning URLs passed to this function on iOS will not load unless their schemes are
131 listed in the \c LSApplicationQueriesSchemes key of the application's Info.plist file.
132 For more information, see the Apple Developer Documentation for
133 \l {iOS: canOpenURL:}{canOpenURL:}.
134 For example, the following lines enable URLs with the HTTPS scheme:
135
136 \snippet code/src_gui_util_qdesktopservices.cpp 3
137
138 \note For Android Nougat (SDK 24) and above, URLs with a \c file scheme
139 are opened using \l {Android: FileProvider}{FileProvider} which tries to obtain
140 a shareable \c content scheme URI first. For that reason, Qt for Android defines
141 a file provider with the authority \c ${applicationId}.qtprovider, with \c applicationId
142 being the app's package name to avoid name conflicts. For more information, also see
143 \l {Android: Setting up file sharing}{Setting up file sharing}.
144
145 \sa setUrlHandler()
146*/
147bool QDesktopServices::openUrl(const QUrl &url)
148{
149 QOpenUrlHandlerRegistry *registry = handlerRegistry();
150 QMutexLocker locker(&registry->mutex);
151 static bool insideOpenUrlHandler = false;
152
153 if (!insideOpenUrlHandler) {
154 QOpenUrlHandlerRegistry::HandlerHash::ConstIterator handler = registry->handlers.constFind(url.scheme());
155 if (handler != registry->handlers.constEnd()) {
156 insideOpenUrlHandler = true;
157 bool result = QMetaObject::invokeMethod(handler->receiver, handler->name.constData(), Qt::DirectConnection, Q_ARG(QUrl, url));
158 insideOpenUrlHandler = false;
159 return result; // ### support bool slot return type
160 }
161 }
162 if (!url.isValid())
163 return false;
164
165 QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
166 if (Q_UNLIKELY(!platformIntegration)) {
167 QCoreApplication *application = QCoreApplication::instance();
168 if (Q_UNLIKELY(!application))
169 qWarning("QDesktopServices::openUrl: Please instantiate the QGuiApplication object "
170 "first");
171 else if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(application)))
172 qWarning("QDesktopServices::openUrl: Application is not a GUI application");
173 return false;
174 }
175
176 QPlatformServices *platformServices = platformIntegration->services();
177 if (!platformServices) {
178 qWarning("The platform plugin does not support services.");
179 return false;
180 }
181 // We only use openDocument if there is no fragment or query for the URL to
182 // avoid it being lost when using openDocument
183 if (url.isLocalFile() && !url.hasFragment() && !url.hasQuery())
184 return platformServices->openDocument(url);
185 return platformServices->openUrl(url);
186}
187
188/*!
189 Sets the handler for the given \a scheme to be the handler \a method provided by
190 the \a receiver object.
191
192 This function provides a way to customize the behavior of openUrl(). If openUrl()
193 is called with a URL with the specified \a scheme then the given \a method on the
194 \a receiver object is called instead of QDesktopServices launching an external
195 application.
196
197 The provided method must be implemented as a slot that only accepts a single QUrl
198 argument.
199
200 \snippet code/src_gui_util_qdesktopservices.cpp 0
201
202 If setUrlHandler() is used to set a new handler for a scheme which already
203 has a handler, the existing handler is simply replaced with the new one.
204 Since QDesktopServices does not take ownership of handlers, no objects are
205 deleted when a handler is replaced.
206
207 Note that the handler will always be called from within the same thread that
208 calls QDesktopServices::openUrl().
209
210 You must call unsetUrlHandler() before destroying the handler object, so
211 the destruction of the handler object does not overlap with concurrent
212 invocations of openUrl() using it.
213
214 \target configuring qdesktopservices url handler on ios and macos
215 \section1 iOS and \macos
216
217 To use this function for receiving data from other apps on iOS/\macos
218 you also need to add the custom scheme to the \c CFBundleURLSchemes
219 list in your Info.plist file:
220
221 \snippet code/src_gui_util_qdesktopservices.cpp 4
222
223 For more information, see the Apple Developer Documentation for
224 \l {iOS: Defining a Custom URL Scheme for Your App}{Defining a Custom URL Scheme for Your App}.
225 \warning It is not possible to claim support for some well known URL schemes, including http and
226 https. This is only allowed for Universal Links.
227
228 To claim support for http and https the above entry in the Info.plist file
229 is not allowed. This is only possible when you add your domain to the
230 Entitlements file:
231
232 \snippet code/src_gui_util_qdesktopservices.cpp 7
233
234 iOS/\macos will search for /.well-known/apple-app-site-association on your domain,
235 when the application is installed. If you want to listen to
236 \c{https://your.domain.com/help?topic=ABCDEF} you need to provide the following
237 content there:
238
239 \snippet code/src_gui_util_qdesktopservices.cpp 8
240
241 For more information, see the Apple Developer Documentation for
242 \l {iOS: Supporting Associated Domains}{Supporting Associated Domains}.
243
244 \target configuring qdesktopservices url handler on android
245 \section1 Android
246
247 To use this function for receiving data from other apps on Android, you
248 need to add one or more intent filter to the \c activity in your app manifest:
249
250 \snippet code/src_gui_util_qdesktopservices.cpp 9
251
252 For more information, see the Android Developer Documentation for
253 \l {Android: Create Deep Links to App Content}{Create Deep Links to App Content}.
254
255 To immediately open the corresponding content in your Android app, without
256 requiring the user to select the app, you need to verify your link. To
257 enable the verification, add an additional parameter to your intent filter:
258
259 \snippet code/src_gui_util_qdesktopservices.cpp 10
260
261 Android will look for \c{https://your.domain.com/.well-known/assetlinks.json},
262 when the application is installed. If you want to listen to
263 \c{https://your.domain.com:1337/help}, you need to provide the following
264 content there:
265
266 \snippet code/src_gui_util_qdesktopservices.cpp 11
267
268 For more information, see the Android Developer Documentation for
269 \l {Android: Verify Android App Links}{Verify Android App Links}.
270
271 \sa openUrl(), unsetUrlHandler()
272*/
273void QDesktopServices::setUrlHandler(const QString &scheme, QObject *receiver, const char *method)
274{
275 QOpenUrlHandlerRegistry *registry = handlerRegistry();
276 QMutexLocker locker(&registry->mutex);
277 if (!receiver) {
278 registry->handlers.remove(scheme.toLower());
279 return;
280 }
281 QOpenUrlHandlerRegistry::Handler h;
282 h.receiver = receiver;
283 h.name = method;
284 registry->handlers.insert(scheme.toLower(), h);
285}
286
287/*!
288 Removes a previously set URL handler for the specified \a scheme.
289
290 Call this function before the handler object that was registered for \a scheme
291 is destroyed, to prevent concurrent openUrl() calls from continuing to call
292 the destroyed handler object.
293
294 \sa setUrlHandler()
295*/
296void QDesktopServices::unsetUrlHandler(const QString &scheme)
297{
298 setUrlHandler(scheme, nullptr, nullptr);
299}
300
301QT_END_NAMESPACE
302
303#endif // QT_NO_DESKTOPSERVICES
QHash< QString, Handler > HandlerHash
QOpenUrlHandlerRegistry()=default
\inmodule QtCore
Definition qmutex.h:342