Background file transfer best practices for Windows Phone 8
[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]
This topic provides general guidance and best practices for applications that use background file transfers. For an introduction to the Background Transfer Service and information about the technical constraints of the service, see Background file transfers for Windows Phone 8. For a step-by-step walkthrough of creating an application that uses background file transfers, see How to implement background file transfers for Windows Phone 8.
In addition to the requirements for general applications, there are additional certification requirements for applications that use background file transfers that must be met for an application to be listed in Store. You should consider these requirements as you design and implement your application. For more information, see Additional requirements for specific app types for Windows Phone.
This topic contains the following sections.
Most applications that use background file transfers will implement the following common development tasks.
After your application launches
For each request, register a handler for the TransferStatusChanged event so that your application can respond to changes in state that occur while the application is running.
For each request, register a handler for the TransferProgressChanged event. This is useful for informing the user about the progress of active transfers.
For each request, examine the TransferStatus property to determine whether any transfers have completed or changed state while the application was inactive.
Use the aforementioned callbacks to update the application UI instead of using a timer or some other mechanism to poll the service for changes.
When you add new transfer requests
Use the Add(BackgroundTransferRequest) method of the BackgroundTransferService object.
First, check to see whether the application has reached the per-application limit of twenty-five simultaneous transfers. If so, you can either alert the user, prompting them to wait for existing transfers to complete or cancel an existing transfer. You can also store the information about the new transfer in isolated storage and then load this information and initiate the transfer at some point in the future when the file transfer queue is below the limit.
Place the call to Add in a try block and catch any exceptions. You should provide the user with a usable message if the attempt to create a new transfer fails.
Use “/shared/transfers” as the local directory root for all transfer operations. For file downloads, set the DownloadLocation property to a file name in this directory. This is where the file will reside when the transfer completes. For file uploads, set the UploadLocation property to a file name in this directory to specify the file to be uploaded.
Use the RequestUri property to specify the remote server address for the file transfer. The Background Transfer Service uses the OriginalString property of the Uri. For this reason, you should escape any special characters in the Uri using the Uri.EscapeUriString method if the Uri is not already escaped.
If the file to be transferred is larger than 100 MB, set the TransferPreferences property of the transfer to None. If you do not, the system will automatically change the transfer settings to this value, meaning that the transfer will only proceed when the phone is connected to external power and has a Wi-Fi connection.
When a transfer completes
Determine whether the transfer was successful by checking the StatusCode property which contains the HTTP status code returned from the target server. The value will be 200 or 206 if the transfer was successful, depending on the server configuration. We recommend that you check for both. Any other status codes indicate a server error. How you handle server errors depends on your application.
Check the TransferError property to help determine why a failed transfer was unsuccessful.
If a file download is successful, you may want to move the file from the “/shared/transfers” directory to a new location in isolated storage so that it is not exposed to future background transfer operations.
Remove the transfer request from the queue by calling the Remove(BackgroundTransferRequest) method of the BackgroundTransferService. Applications are limited to twenty-five simultaneous transfer requests, including pending, active, and completed requests. The system does not automatically remove completed transfers. If you fail to remove old transfers and exceed the application limit, an exception will be thrown when you attempt to add new transfers.
Applications that use background file transfers should implement the following user interface elements.
Background file transfers should be initiated by the user, such as by tapping on a button. If the user does not initiate the transfer, then the application should alert the user that a transfer is being initiated on their behalf.
You must provide UI that allows the user to view the status and transfer progress of all background transfers.
You must provide a mechanism for the user to cancel any and all current transfers.
Use the default transfer preferences that restrict file transfers to occur only over Wi-Fi and with external power connected. Provide UI for the user to choose to allow transfers over cellular connections and without external power. The user’s choice can be set with the TransferPreferences property.
If a background transfer has the status WaitingForExternalPower, WaitingForExternalPowerDueToBatterySaverMode, WaitingForWiFi, or WaitingForNonVoiceBlockingNetwork, provide a message to the user that informs them the reason that their transfers are waiting and, if applicable, informs them the steps they can take to resume the transfer (for example, connect to a Wi-Fi network).
Applications that use background transfers should follow these recommendations:
Do not attempt to access or modify the target file in the “/shared/transfers” directory until the associated transfer operation is complete.
The Tag property of the BackgroundTransferRequest object can be used to associate custom data associated with a transfer. The application can set the value when the transfer request is created. When the transfer request is retrieved, using the Requests property or the Find(String) method, the Tag property will contain the previously set data. The maximum length of this property is 4000 characters, but we recommend that you keep the size of the data smaller to improve performance.
When you access the Requests property, new instances of BackgroundTransferRequest are created. To help prevent memory leaks, we recommend that you avoid accessing this property frequently, such as in a game loop, to query the number of requests. We also recommend that you dispose of the returned objects quickly, as soon as you are no longer using them. The same recommendation applies to the Find(String) method, which creates a new instance whenever the supplied transfer ID is found.
The event handlers for the TransferStatusChanged and TransferProgressChanged events should return quickly so that the user interface does not become sluggish. Reading from and writing to isolated storage can be slow and should be performed on a separate worker thread, if possible.
The TotalBytesToReceive property indicates the total size of a file download. If this value is -1, the file size is unknown.
Servers should be configured to return Content-length in the HTTP response headers to allow users to know the size and progress of the transfer.
Servers must support Range requests from clients to improve performance. It is likely that background transfers will be paused and resumed as they progress. Not supporting Range requests will result in poor performance because the transfer must be restarted whenever it is paused.
We recommend that you test server-side functionality in a browser or by some other mechanism outside of the background transfer application to verify that is working properly.