1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-16 00:34:19 +00:00

URL: Allow specifying shared container for downloads on iOS

This commit is contained in:
reuk 2021-08-25 17:40:21 +01:00
parent fb09a97be4
commit f87582a013
No known key found for this signature in database
GPG key ID: 9ADCD339CFC98A11
7 changed files with 110 additions and 52 deletions

View file

@ -554,9 +554,9 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
};
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost)
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options)
{
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost);
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options);
}
//==============================================================================

View file

@ -648,9 +648,9 @@ public:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
};
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost)
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options)
{
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost);
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options);
}
} // namespace juce

View file

@ -607,9 +607,9 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
};
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost)
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options)
{
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost);
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options);
}
#endif

View file

@ -412,10 +412,8 @@ struct BackgroundDownloadTask : public URL::DownloadTask
{
BackgroundDownloadTask (const URL& urlToUse,
const File& targetLocationToUse,
String extraHeadersToUse,
URL::DownloadTask::Listener* listenerToUse,
bool shouldUsePostRequest)
: listener (listenerToUse),
const URL::DownloadTaskOptions& options)
: listener (options.listener),
uniqueIdentifier (String (urlToUse.toString (true).hashCode64()) + String (Random().nextInt64()))
{
targetLocation = targetLocationToUse;
@ -429,11 +427,11 @@ struct BackgroundDownloadTask : public URL::DownloadTask
auto nsUrl = [NSURL URLWithString: juceStringToNS (urlToUse.toString (true))];
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL: nsUrl];
if (shouldUsePostRequest)
if (options.usePost)
[request setHTTPMethod: @"POST"];
StringArray headerLines;
headerLines.addLines (extraHeadersToUse);
headerLines.addLines (options.extraHeaders);
headerLines.removeEmptyStrings (true);
for (int i = 0; i < headerLines.size(); ++i)
@ -445,10 +443,14 @@ struct BackgroundDownloadTask : public URL::DownloadTask
[request addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)];
}
session =
[NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: juceStringToNS (uniqueIdentifier)]
delegate: delegate
delegateQueue: nullptr];
auto* configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: juceStringToNS (uniqueIdentifier)];
if (options.sharedContainer.isNotEmpty())
[configuration setSharedContainerIdentifier: juceStringToNS (options.sharedContainer)];
session = [NSURLSession sessionWithConfiguration: configuration
delegate: delegate
delegateQueue: nullptr];
if (session != nullptr)
downloadTask = [session downloadTaskWithRequest:request];
@ -648,9 +650,9 @@ struct BackgroundDownloadTask : public URL::DownloadTask
HashMap<String, BackgroundDownloadTask*, DefaultHashFunctions, CriticalSection> BackgroundDownloadTask::activeSessions;
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool usePostRequest)
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options)
{
std::unique_ptr<BackgroundDownloadTask> downloadTask (new BackgroundDownloadTask (*this, targetLocation, extraHeaders, listener, usePostRequest));
auto downloadTask = std::make_unique<BackgroundDownloadTask> (*this, targetLocation, options);
if (downloadTask->initOK() && downloadTask->connect())
return downloadTask;
@ -663,9 +665,9 @@ void URL::DownloadTask::juce_iosURLSessionNotify (const String& identifier)
BackgroundDownloadTask::invokeNotify (identifier);
}
#else
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool usePost)
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options)
{
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, usePost);
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options);
}
#endif
@ -929,9 +931,9 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState)
};
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost)
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options)
{
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost);
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options);
}
JUCE_END_IGNORE_WARNINGS_GCC_LIKE

View file

@ -650,9 +650,9 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailA
return mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS;
}
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost)
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options)
{
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost);
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options);
}
} // namespace juce

View file

@ -106,29 +106,26 @@ struct FallbackDownloadTask : public URL::DownloadTask,
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FallbackDownloadTask)
};
void URL::DownloadTask::Listener::progress (DownloadTask*, int64, int64) {}
URL::DownloadTask::Listener::~Listener() {}
void URL::DownloadTaskListener::progress (DownloadTask*, int64, int64) {}
//==============================================================================
std::unique_ptr<URL::DownloadTask> URL::DownloadTask::createFallbackDownloader (const URL& urlToUse,
const File& targetFileToUse,
const String& extraHeadersToUse,
Listener* listenerToUse,
bool usePostRequest)
const DownloadTaskOptions& options)
{
const size_t bufferSize = 0x8000;
targetFileToUse.deleteFile();
if (auto outputStream = targetFileToUse.createOutputStream (bufferSize))
{
auto stream = std::make_unique<WebInputStream> (urlToUse, usePostRequest);
stream->withExtraHeaders (extraHeadersToUse);
auto stream = std::make_unique<WebInputStream> (urlToUse, options.usePost);
stream->withExtraHeaders (options.extraHeaders);
if (stream->connect (nullptr))
return std::make_unique<FallbackDownloadTask> (std::move (outputStream),
bufferSize,
std::move (stream),
listenerToUse);
options.listener);
}
return nullptr;
@ -1005,4 +1002,15 @@ std::unique_ptr<InputStream> URL::createInputStream (bool usePostCommand,
.withHttpRequestCmd (httpRequestCmd));
}
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation,
String extraHeaders,
DownloadTask::Listener* listener,
bool usePostCommand)
{
auto options = DownloadTaskOptions().withExtraHeaders (std::move (extraHeaders))
.withListener (listener)
.withUsePost (usePostCommand);
return downloadToFile (targetLocation, std::move (options));
}
} // namespace juce

View file

@ -428,6 +428,64 @@ public:
std::unique_ptr<OutputStream> createOutputStream() const;
//==============================================================================
class DownloadTask;
/** Used to receive callbacks for download progress. */
struct JUCE_API DownloadTaskListener
{
virtual ~DownloadTaskListener() = default;
/** Called when the download has finished. Be aware that this callback may
come on an arbitrary thread.
*/
virtual void finished (DownloadTask* task, bool success) = 0;
/** Called periodically by the OS to indicate download progress.
Beware that this callback may come on an arbitrary thread.
*/
virtual void progress (DownloadTask* task, int64 bytesDownloaded, int64 totalLength);
};
/** Holds options that will can be specified when starting a new download
with downloadToFile().
*/
class DownloadTaskOptions
{
public:
String extraHeaders;
String sharedContainer;
DownloadTaskListener* listener = nullptr;
bool usePost = false;
/** Specifies headers to add to the request. */
auto withExtraHeaders (String value) const { return with (&DownloadTaskOptions::extraHeaders, std::move (value)); }
/** On iOS, specifies the container where the downloaded file will be stored.
If you initiate a download task from inside an app extension on iOS,
you must supply this option.
This is currently unused on other platforms.
*/
auto withSharedContainer (String value) const { return with (&DownloadTaskOptions::sharedContainer, std::move (value)); }
/** Specifies an observer for the download task. */
auto withListener (DownloadTaskListener* value) const { return with (&DownloadTaskOptions::listener, std::move (value)); }
/** Specifies whether a post command should be used. */
auto withUsePost (bool value) const { return with (&DownloadTaskOptions::usePost, value); }
private:
template <typename Member, typename Value>
DownloadTaskOptions with (Member&& member, Value&& value) const
{
auto copy = *this;
copy.*member = std::forward<Value> (value);
return copy;
}
};
/** Represents a download task.
Returned by downloadToFile() to allow querying and controlling the download task.
@ -435,22 +493,7 @@ public:
class JUCE_API DownloadTask
{
public:
/** Used to receive callbacks for download progress. */
struct JUCE_API Listener
{
virtual ~Listener();
/** Called when the download has finished. Be aware that this callback may
come on an arbitrary thread.
*/
virtual void finished (URL::DownloadTask* task, bool success) = 0;
/** Called periodically by the OS to indicate download progress.
Beware that this callback may come on an arbitrary thread.
*/
virtual void progress (URL::DownloadTask* task, int64 bytesDownloaded, int64 totalLength);
};
using Listener = DownloadTaskListener;
/** Releases the resources of the download task, unregisters the listener
and cancels the download if necessary.
@ -493,7 +536,7 @@ public:
private:
friend class URL;
static std::unique_ptr<DownloadTask> createFallbackDownloader (const URL&, const File&, const String&, Listener*, bool);
static std::unique_ptr<DownloadTask> createFallbackDownloader (const URL&, const File&, const DownloadTaskOptions&);
public:
#if JUCE_IOS
@ -505,6 +548,13 @@ public:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DownloadTask)
};
/** This function is replaced by a new overload accepting a DownloadTaskOptions argument. */
[[deprecated ("Use the overload with a DownloadTaskOptions argument instead")]]
std::unique_ptr<DownloadTask> downloadToFile (const File& targetLocation,
String extraHeaders = String(),
DownloadTaskListener* listener = nullptr,
bool usePostCommand = false);
/** Download the URL to a file.
This method attempts to download the URL to a given file location.
@ -515,9 +565,7 @@ public:
network re-connections and continuing your download while your app is suspended.
*/
std::unique_ptr<DownloadTask> downloadToFile (const File& targetLocation,
String extraHeaders = String(),
DownloadTask::Listener* listener = nullptr,
bool usePostCommand = false);
const DownloadTaskOptions& options);
//==============================================================================
/** Tries to download the entire contents of this URL into a binary data block.