The DownloadableResource item allows to download additional assets from the Internet. More...
Import Statement: | import Felgo 4.0 |
Since: | Felgo 2.17.0 |
DownloadableResource allows downloading app and game assets on demand during runtime. That way not all resources must be included in the app binary and therefore result in smaller downloads from the app stores.
The most popular use cases for downloadable packages are:
DownloadableResource can load files from any HTTP(S)
web addresses. You can add a secret to protect and restricts downloads to your app or game only. You
can download single files or entire .zip
-archives, which are automatically extracted for further usage.
The item downloads and extracts to a standard path or custom location. You can then use downloaded resources from within your app or game as you do with local resources.
The DownloadableResource item currently supports all kinds of files that you use with Felgo components. Examples are:
Assets downloaded with DownloadableResource are persisted between app starts, so they are cached for offline usage as well.
You can set the path where to download and extract the files to with the storageLocation property. Depending on your usecase, you can choose one of the available FileUtils standard paths. You can alternatively set the full path with the storagePath property.
The default value of storageLocation is FileUtils.AppDataLocation
, which is a default location for your app's private files that are then
available for as long as the app is installed on a device.
To set the file name of the resulting file, use the storageName property.
The following table lists the platform-specific paths for FileUtils.AppDataLocation
:
Platform | Path |
---|---|
Android | "<APPROOT>/files" |
iOS | "<APPROOT>/Library/Application Support" |
Linux | "~/.local/share/<APPNAME>" |
macOS | "~/Library/Application Support/<APPNAME>" |
Windows | "C:/Users/<USER>/AppData/Roaming/<APPNAME>" |
To download multiple files at once, create an archive files with .zip
file ending. You can use any data compression application that supports the zip archive file type.
The item supports subfolders within the zip archive to structure downloadable resources.
To just download a single file from a web server, use the following example code:
import Felgo App { DownloadableResource { id: resource1 extractAsPackage: false // false for single files source: "https://felgo.com/web-assets/girl.jpg" } }
Likewise, you can download and extract a .zip
package like the following (note the extractAsPackage):
import Felgo App { DownloadableResource { id: resource1 extractAsPackage: true // true for zip archives source: "https://felgo.com/web-assets/girl.zip" } }
To start the actual download, call the download() method.
To check the status of a package, use the status property. The convenience property available is
true
after the status changes to DownloadableResource.Available
.
If you download single files (i.e. extractAsPackage is false
), storagePath
contains the full URL to the downloaded file.
Use the available property to display a placeholder image while downloading:
AppImage { source: resource1.available ? resource1.storagePath : "local-image.png" }
If you extract packages, you can retrieve the path to an extracted file using getExtractedFileUrl(). The parameter is a relative path to a file within a
downloaded and extracted .zip
package. This returns the full URL to the file which you can use anywhere within your app or game (i.e. the source property of an AppImage).
In the following example, extracted-image.png
is a file within the downloaded .zip
archive. local-image.png
is a local file at the same path as the QML file.
AppImage { source: resource1.available ? resource1.getExtractedFileUrl("extracted-image.png") : "local-image.png" }
You can also use sub-folders within extracted .zip
archives. getExtractedFileUrl() supports relative paths to nested files:
AppImage { source: resource1.available ? resource1.getExtractedFileUrl("content/images/extracted-image.png") : "local-image.png" }
Additionally you can split up resources over multiple download packages. The extraction path of each package is registered with FileUtils using FileUtils::addSearchPath(). This allows FileUtils::getMultiPathUrl() to find files from any downloaded package. For
example, if you have a file called "image.png"
that is part of one of multiple download packages, you can display the image like the following:
AppImage { source: FileUtils.getMultiPathUrl("image.png") }
If the file is not found in any extracted package, a fallback file with the same name can be loaded from other search paths.
Note: The search order for files with the same filename is not defined. To use FileUtils::getMultiPathUrl(), keep the filename unique across all downloads. Also make sure to avoid resources with the same relative file path in different extracted packages.
You can open files you have downloaded with an external application using FileUtils::openFile(). If you download single files, you can directly use storagePath with this method.
The following example downloads a PDF file and then opens it with the default installed PDF viewer:
import Felgo import QtQuick App { id: app DownloadableResource { source: "http://www.orimi.com/pdf-test.pdf" storageLocation: FileUtils.DocumentsLocation storageName: "pdf-test.pdf" extractAsPackage: false Component.onCompleted: { if(status === DownloadableResource.UnAvailable) { download() } else { openDownloadedFile() } } onStatusChanged: openDownloadedFile() function openDownloadedFile() { if(status === DownloadableResource.Available) { FileUtils.openFile(storagePath) } } } }
You can also open files extracted from .zip
packages. For this, you can use getExtractedFileUrl() to open extracted files like in the
following example:
FileUtils.openFile(resource1.getExtractedFileUrl("extracted-file.pdf"))
Sometimes you want to protect your resources from downloads outside your app. For this usecase the DownloadableResource item provides the secret property. If the secret property is set, the item appends HTTP GET
parameters to your provided
source. This looks like the following:
https://example.com/resource1.zip?token=3fcdb553d1abd6e57d5d4496c5f86eb690fbd319×tamp=1524706331
The token consists of the following checksum:
shasum( appid + ":" + secret + ":" + timestamp )
appid
is the identifier given in your config.json
file.Your server-side implementation should check the token against the following criteria:
If the token meets all criteria, you can return the requested zip file. Otherwise return a HTTP 401
status code.
Note: Use the source property with HTTPS
protocol when using secured package functionality.
The download and extraction process is performed asynchronously in the background.
Downloading and extracting large files may take a while depending on the file size. It is good practice to display a progress bar during the download. You can do so with the progress property. You can check individual progress with the downloadProgressChanged and extractionProgressChanged signals.
It is thread-save to call download() and then listen to the available property. See more in Example Usage.
DownloadableResource offers advanced properties, functions and signals. Use these to control the download and extraction process.
You can set a standard location for download with the storageLocation property. Use one of the FileUtils storage location constants. Choose a name a name for the downloaded or extracted file or folder with storageName. To set the complete path manually, use the storagePath property. This overrides both storageLocation and storageName.
You can supply additional HTTP
headers using headerParameters.
Use status and progress to query the current status of the download and extraction progress. You can cancel an ongoing operation using cancel().
This QML example app uses all the available features of DownloadableResource:
import Felgo import QtQuick import QtQuick.Controls App { id: app //all enum values to be able to select in a dialog readonly property var allStandardPaths: [ FileUtils.DocumentsLocation, FileUtils.DownloadLocation, FileUtils.CacheLocation, FileUtils.DesktopLocation, FileUtils.FontsLocation, FileUtils.ApplicationsLocation, FileUtils.MusicLocation, FileUtils.MoviesLocation, FileUtils.PicturesLocation, FileUtils.TempLocation, FileUtils.HomeLocation, FileUtils.DataLocation, FileUtils.GenericDataLocation, FileUtils.RuntimeLocation, FileUtils.ConfigLocation, FileUtils.GenericCacheLocation, FileUtils.GenericConfigLocation, FileUtils.AppDataLocation, FileUtils.AppConfigLocation, FileUtils.AppLocalDataLocation ] DownloadableResource { id: dl //shorthand property if status is busy property bool busy: status === DownloadableResource.Downloading || status === DownloadableResource.Extracting //download and extract .zip source: "https://www.dropbox.com/s/z2dxyn2847stnq3/multiResolutionImage.zip?dl=1" //set storage folder from standard path storageLocation: FileUtils.DownloadLocation //set file/folder name for storage storageName: "multiResolutionImage" //additional HTTP headers headerParameters: ({ "X-Custom-Header": "header-value1", "X-Custom-Header2": "header-value2" }) //show progress in bar onProgressChanged: progressBar.value = progress } AppPage { anchors.fill: parent anchors.topMargin: Theme.statusBarHeight ProgressBar { id: progressBar anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top height: dp(32) minimumValue: 0 maximumValue: 100 } AppListView { anchors.fill: parent anchors.topMargin: progressBar.height //model defines the UI items model: [ { text: "Available: " + dl.available, enabled: false }, { text: "Status: " + dl.statusText, enabled: false }, { text: "Source:", detailText: dl.source, action: "source" }, { text: "Extract as package?", action: "extract", checked: dl.extractAsPackage }, { text: "Storage location: " + dl.storageLocationDisplayName, action: "storageLocation", enabled: !dl.busy }, { text: "Storage name: " + dl.storageName, action: "storageName", enabled: !dl.busy }, { text: "Storage path:", detailText: dl.storagePath, action: "storagePath", enabled: !dl.busy }, { text: "Remove", action: "remove", enabled: dl.available }, { text: "Start download", action: "download", enabled: !dl.busy && !dl.available }, { text: "Cancel", action: "cancel", enabled: dl.busy }, { text: "Full URL of image in package:", detailText: dl.available ? dl.getExtractedFileUrl("+hd/testContentScaling.png") : "(unavailable)", enabled: dl.available, action: "showImage" } ] //delegate defines the list item + interaction delegate: SimpleRow { style.backgroundColor: enabled ? "white" : "#ddd" iconSource: modelData.action === "extract" ? IconType.check : "" icon.color: modelData.checked ? "black" : "#40000000" onSelected: { switch(modelData.action) { case "extract": dl.extractAsPackage = !dl.extractAsPackage break; case "remove": dl.remove() break; case "download": dl.download() break; case "cancel": if(dl.busy) { dl.cancel() } break; case "source": InputDialog.inputTextSingleLine(app, "Enter URL:", "https://", function(accepted, text) { if(accepted) dl.source = text }, true) break; case "storagePath": InputDialog.inputTextSingleLine(app, "Enter file path:", "/", function(accepted, text) { if(accepted) dl.storagePath = text }, true) break; case "storageName": InputDialog.inputTextSingleLine(app, "Enter file name:", "", function(accepted, text) { if(accepted) dl.storageName = text }, true) break; case "storageLocation": selectDialog.open() break; case "showImage": var url = dl.getExtractedFileUrl("+hd/testContentScaling.png") if(url) { dialogImage.source = url imgDialog.open() } break; } } } } } // dialog to select one of the standard path enum values Dialog { id: selectDialog contentHeight: itemList.height title: "Select storage location" positiveAction: false onCanceled: close() AppListView { id: itemList width: parent.width height: dp(48) * 6 // max. 6 items model: allStandardPaths.map(FileUtils.storageLocationDisplayName) delegate: SimpleRow { text: modelData onSelected: { dl.storageLocation = allStandardPaths[index]; selectDialog.close(); } } } } // dialog to show an image from inside the downloaded package Dialog { id: imgDialog contentHeight: dialogImage.height title: "Image" positiveAction: false onCanceled: close() AppImage { id: dialogImage width: parent.width height: dp(120) fillMode: Image.PreserveAspectFit } } }
See also FileUtils.
available : bool |
extractAsPackage : bool |
This property indicates if the file to download is a .zip
package archive and needs to be extracted after download.
Set this property to true
to open and extract the .zip
package after download. Set this property to false
to download a single file.
The default value of this property is true
.
headerParameters : var |
You can use this property to add additional HTTP
request header fields for the download.
Set a JavaScript object containing the additional headers for the HTTP
request. Each key/value pair in the object will be used as a header. Use strings as keys and values, like in this example:
DownloadableResource { source: "https://example.com/package1.zip" headerParameters: ({ "Accept-Language": "en-us", "Authorization": "Basic abcdefghi", }) }
Note: Make sure to add an extra pair of parenthesis around the header map object: headerParameters: ({...})
to ensure the object is not interpreted as a code block.
progress : int |
This property indicates the progress of an ongoing download or extraction.
The download and extraction of large files may take some time. Use this property to report the progress with the help of a progress bar or text output.
If the status is DownloadableResource.Downloading
or DownloadableResource.Extracting
, the property is set to the download or extraction
status in percentage between 0
and 100
.
If the status is DownloadableResource.UnAvailable
, the property is set to 0
.
If the status is DownloadableResource.Available
, the property is set to 100
.
See also downloadProgressChanged() and extractionProgressChanged().
secret : string |
You can use this property to protect the file download from access outside of your app or game.
If set, the item appends a generated token to the given source property. For more information see Using a Secret to Protect Your Downloads.
source : url |
This property holds the source URL with either HTTP
or HTTPS
scheme of the downloadable file.
See How to Create Downloadable Packages for more information about package creation.
status : enumeration |
A read-only property indicating the current status of the download. Possible values are:
DownloadableResource.UnAvailable
- The package is not available or was cleared from temporary locations, call download() to start the download
(again).
DownloadableResource.Available
- The package was successfully downloaded and optionally extracted and is ready to use.DownloadableResource.Downloading
- The package is currently downloading. You can check the download status with downloadProgressChanged() and progress.
DownloadableResource.Extracting
- The content of the package is currently extracting. You can check the extraction status with extractionProgressChanged() and progress.
See also available and statusText.
statusText : string |
A read-only property indicating the current status of the download as a readable string. Use this property to display the current status to the user.
Possible values are UnAvailable, Available, Downloading and Extracting.
See also status.
storageLocation : enumeration |
This property determines the storage location for the downloaded and/or extracted files. It sets the storagePath based on one of the following FileUtils constants:
FileUtils.DesktopLocation
FileUtils.DocumentsLocation
FileUtils.FontsLocation
FileUtils.ApplicationsLocation
FileUtils.MusicLocation
FileUtils.MoviesLocation
FileUtils.PicturesLocation
FileUtils.TempLocation
FileUtils.HomeLocation
FileUtils.DataLocation
FileUtils.CacheLocation
FileUtils.GenericDataLocation
FileUtils.RuntimeLocation
FileUtils.ConfigLocation
FileUtils.DownloadLocation
FileUtils.GenericCacheLocation
FileUtils.GenericConfigLocation
FileUtils.AppDataLocation
FileUtils.AppConfigLocation
FileUtils.AppLocalDataLocation
The default value is FileUtils.AppDataLocation
, which is a default location for your app's private files that are then available for as long as the app is installed on a device.
The following table lists the platform-specific paths for FileUtils.AppDataLocation
:
Platform | Path |
---|---|
Android | "<APPROOT>/files" |
iOS | "<APPROOT>/Library/Application Support" |
Linux | "~/.local/share/<APPNAME>" |
macOS | "~/Library/Application Support/<APPNAME>" |
Windows | "C:/Users/<USER>/AppData/Roaming/<APPNAME>" |
If you use a temporary location, like FileUtils.CacheLocation
, the system might delete files automatically to regain storage space. To prevent side-effects when using such locations, use the available property to check if downloaded and/or extracted files still exist or need to be downloaded again.
The full storagePath gets set by appending the storageName to the path of the storageLocation.
For example, you can extract an archive to <downloads directory>/myArchiveContents
: Set storageLocation to FileUtils.DownloadLocation
and storageName to "myArchiveContents"
.
Use a unique combination of storageLocation and storageName to prevent overwriting files.
Use storagePath to get the resulting path where files get downloaded and extracted. It contains the full path after assigning storageLocation and storageName.
See also storageName and storagePath.
storageLocationDisplayName : string |
This read-only property contains a textual representation of the storageLocation property.
storageName : string |
This property sets the file or folder name for the storageLocation if set.
The full storagePath is set by appending the storageName to the path of the storageLocation.
For example, you can extract an archive to <downloads directory>/myArchiveContents
: Set storageLocation to
FileUtils.DownloadLocation
and storageName to "myArchiveContents"
.
Note: make sure to use a unique combination of storageLocation and storageName to prevent overwriting files.
If not set, the item uses a name based on the source property.
Use storagePath to get the resulting path where files get downloaded and extracted. It contains the full path after assigning storageLocation and storageName.
See also storageLocation and storagePath.
storagePath : url |
This property is used as the storage base path of your downloaded resources. This overrides both the storageName and storageLocation properties. If used, set this property to a full path where you want to download and extract the file.
This property allows to check the resulting path for the specific files.
If not set, it ist set to a default path based based on the storageName and storageLocation properties. This is useful to check the downloaded and/or extracted file contents on Desktop platforms during development. Keep in mind that access to these directories may be limited on mobile platforms due to sandboxing and file system design.
See also storageName, storageLocation, and getExtractedFileUrl().
downloadFinished(error) |
This signal is emitted as soon as the download and extraction has finished.
The error parameter indicates the result as one of the following values:
DownloadableResource.NoError
- The download and extraction finished successfully and the files are ready to use.DownloadableResource.NetworkError
- The download couldn't be finished because of a network error. This usually means that the device has no Internet connection.DownloadableResource.UnauthorizedError
- The web service at the given source returned a 401/403 error. This usually means that the provided secret is
invalid.
DownloadableResource.FilePathError
- The files can't be saved under the given path.DownloadableResource.FileExtractionError
- The package can't be extracted. This usually means the downloaded file is no valid zip
archive file. It can also mean the extraction was canceled with
cancel().
DownloadableResource.DownloadCancelledError
- The user canceled the download with cancel().
DownloadableResource.UnknownError
- There occurred an unspecified error while downloading or extracting.Note: The corresponding handler is onDownloadFinished
.
downloadProgressChanged(progress) |
This signal is emitted when the download status of the package changes.
The download of large files may take some time. Use this property to report the progress with the help of a progress bar or text output.
The progress parameter indicates the download status in percentage between 0
and 100
. You can also check the progress with the property progress.
Note: The corresponding handler is onDownloadProgressChanged
.
See also progress and extractionProgressChanged().
downloadStarted() |
This signal is emitted as soon as the download of the packages started after calling download().
Note: The corresponding handler is onDownloadStarted
.
extractionProgressChanged(progress) |
This signal is emitted when the extraction status of the downloaded archive changes.
The extraction of large files may take some time. Use this property to report the progress with the help of a progress bar or text output.
The progress parameter indicates the extraction status in percentage between 0
and 100
. You can also check the progress with the property progress.
Note: The corresponding handler is onExtractionProgressChanged
.
See also progress and downloadProgressChanged().
void cancel() |
Call this method to cancel a currently running download or extraction process. This cleans up already downloaded and/or extracted files. After this call, status is
DownloadableResource.UnAvailable
.
If status is anything other than DownloadableResource.Downloading
or DownloadableResource.Extracting
, calls to that method are
ignored.
See also download().
void download() |
Starts the download from the given source. You can check the status of the download with the downloadProgressChanged() signal.
A download only starts if status is DownloadableResource.UnAvailable
, otherwise calls to that method are ignored.
See also cancel().
Returns a full URL to a file inside a downloaded and extracted package.
This function is only required for files from archives
with extractAsPackage set to true. For all other files without extraction, you can
just use storagePath.
The return value is a file://
URL to the storagePath with appended relativePath
.
See also storagePath.
void remove() |