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
140 obtain a shareable \c content scheme URI first. For that reason, Qt for
141 Android defines a file provider with the authority
142 \c ${applicationId}.qtprovider, with \c applicationId being the app's
143 package name to avoid name conflicts. If the application declares a file
144 provider of its own, Qt uses that one in preference, which lets the
145 application decide which directories may be shared. For more information,
146 also see \l {Android: Setting up file sharing}{Setting up file sharing}.
147
148 \sa setUrlHandler()
149*/
150bool QDesktopServices::openUrl(const QUrl &url)
151{
152 QOpenUrlHandlerRegistry *registry = handlerRegistry();
153 QMutexLocker locker(&registry->mutex);
154 static bool insideOpenUrlHandler = false;
155
156 if (!insideOpenUrlHandler) {
157 QOpenUrlHandlerRegistry::HandlerHash::ConstIterator handler = registry->handlers.constFind(url.scheme());
158 if (handler != registry->handlers.constEnd()) {
159 insideOpenUrlHandler = true;
160 bool result = QMetaObject::invokeMethod(handler->receiver, handler->name.constData(), Qt::DirectConnection, Q_ARG(QUrl, url));
161 insideOpenUrlHandler = false;
162 return result; // ### support bool slot return type
163 }
164 }
165 if (!url.isValid())
166 return false;
167
168 QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
169 if (Q_UNLIKELY(!platformIntegration)) {
170 QCoreApplication *application = QCoreApplication::instance();
171 if (Q_UNLIKELY(!application))
172 qWarning("QDesktopServices::openUrl: Please instantiate the QGuiApplication object "
173 "first");
174 else if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(application)))
175 qWarning("QDesktopServices::openUrl: Application is not a GUI application");
176 return false;
177 }
178
179 QPlatformServices *platformServices = platformIntegration->services();
180 if (!platformServices) {
181 qWarning("The platform plugin does not support services.");
182 return false;
183 }
184 // We only use openDocument if there is no fragment or query for the URL to
185 // avoid it being lost when using openDocument
186 if (url.isLocalFile() && !url.hasFragment() && !url.hasQuery())
187 return platformServices->openDocument(url);
188 return platformServices->openUrl(url);
189}
190
191/*!
192 Sets the handler for the given \a scheme to be the handler \a method provided by
193 the \a receiver object.
194
195 This function provides a way to customize the behavior of openUrl(). If openUrl()
196 is called with a URL with the specified \a scheme then the given \a method on the
197 \a receiver object is called instead of QDesktopServices launching an external
198 application.
199
200 The provided method must be implemented as a slot that only accepts a single QUrl
201 argument.
202
203 \snippet code/src_gui_util_qdesktopservices.cpp 0
204
205 If setUrlHandler() is used to set a new handler for a scheme which already
206 has a handler, the existing handler is simply replaced with the new one.
207 Since QDesktopServices does not take ownership of handlers, no objects are
208 deleted when a handler is replaced.
209
210 Note that the handler will always be called from within the same thread that
211 calls QDesktopServices::openUrl().
212
213 You must call unsetUrlHandler() before destroying the handler object, so
214 the destruction of the handler object does not overlap with concurrent
215 invocations of openUrl() using it.
216
217 \target configuring qdesktopservices url handler on ios and macos
218 \section1 iOS and \macos
219
220 To use this function for receiving data from other apps on iOS/\macos
221 you also need to add the custom scheme to the \c CFBundleURLSchemes
222 list in your Info.plist file:
223
224 \snippet code/src_gui_util_qdesktopservices.cpp 4
225
226 For more information, see the Apple Developer Documentation for
227 \l {iOS: Defining a Custom URL Scheme for Your App}{Defining a Custom URL Scheme for Your App}.
228 \warning It is not possible to claim support for some well known URL schemes, including http and
229 https. This is only allowed for Universal Links.
230
231 To claim support for http and https the above entry in the Info.plist file
232 is not allowed. This is only possible when you add your domain to the
233 Entitlements file:
234
235 \snippet code/src_gui_util_qdesktopservices.cpp 7
236
237 iOS/\macos will search for /.well-known/apple-app-site-association on your domain,
238 when the application is installed. If you want to listen to
239 \c{https://your.domain.com/help?topic=ABCDEF} you need to provide the following
240 content there:
241
242 \snippet code/src_gui_util_qdesktopservices.cpp 8
243
244 For more information, see the Apple Developer Documentation for
245 \l {iOS: Supporting Associated Domains}{Supporting Associated Domains}.
246
247 \target configuring qdesktopservices url handler on android
248 \section1 Android
249
250 To use this function for receiving data from other apps on Android, you
251 need to add one or more intent filter to the \c activity in your app manifest:
252
253 \snippet code/src_gui_util_qdesktopservices.cpp 9
254
255 For more information, see the Android Developer Documentation for
256 \l {Android: Create Deep Links to App Content}{Create Deep Links to App Content}.
257
258 To immediately open the corresponding content in your Android app, without
259 requiring the user to select the app, you need to verify your link. To
260 enable the verification, add an additional parameter to your intent filter:
261
262 \snippet code/src_gui_util_qdesktopservices.cpp 10
263
264 Android will look for \c{https://your.domain.com/.well-known/assetlinks.json},
265 when the application is installed. If you want to listen to
266 \c{https://your.domain.com:1337/help}, you need to provide the following
267 content there:
268
269 \snippet code/src_gui_util_qdesktopservices.cpp 11
270
271 For more information, see the Android Developer Documentation for
272 \l {Android: Verify Android App Links}{Verify Android App Links}.
273
274 \sa openUrl(), unsetUrlHandler()
275*/
276void QDesktopServices::setUrlHandler(const QString &scheme, QObject *receiver, const char *method)
277{
278 QOpenUrlHandlerRegistry *registry = handlerRegistry();
279 QMutexLocker locker(&registry->mutex);
280 if (!receiver) {
281 registry->handlers.remove(scheme.toLower());
282 return;
283 }
284 QOpenUrlHandlerRegistry::Handler h;
285 h.receiver = receiver;
286 h.name = method;
287 registry->handlers.insert(scheme.toLower(), h);
288}
289
290/*!
291 Removes a previously set URL handler for the specified \a scheme.
292
293 Call this function before the handler object that was registered for \a scheme
294 is destroyed, to prevent concurrent openUrl() calls from continuing to call
295 the destroyed handler object.
296
297 \sa setUrlHandler()
298*/
299void QDesktopServices::unsetUrlHandler(const QString &scheme)
300{
301 setUrlHandler(scheme, nullptr, nullptr);
302}
303
304QT_END_NAMESPACE
305
306#endif // QT_NO_DESKTOPSERVICES
QHash< QString, Handler > HandlerHash
QOpenUrlHandlerRegistry()=default
\inmodule QtCore
Definition qmutex.h:342
Combined button and popup list for selecting options.