The base routine used to fetch the string is <tt>+localizedStringForKey:inFile:fromBundle:</tt>, and the other three simply pull together the parameters for that call. The <tt>+applicationLocalizedStringForKey:inFile:</tt> call is used to locate a string within the bundle of the actual current application (i.e. the Finder). The other two are used to fetch data from the BackRow framework or from the bundle of the calling appliance. For strings within your appliance's default strings file 'Localizable.strings', you would use:

The base routine used to fetch the string is <tt>+localizedStringForKey:inFile:fromBundle:</tt>, and the other three simply pull together the parameters for that call. The <tt>+applicationLocalizedStringForKey:inFile:</tt> call is used to locate a string within the bundle of the actual current application (i.e. the Finder). The other two are used to fetch data from the BackRow framework or from the bundle of the calling appliance. For strings within your appliance's default strings file 'Localizable.strings', you would use:

We now have a controller class which performs a useful function -- downloading content from the internet -- and is prepared to make use of it. If such use requires that another controller be put onto the stack, it is advisable to use <tt>[[self stack] swapController: newController]</tt> to perform that task, so that the download controller does not appear again after pressing the menu button.

We now have a controller class which performs a useful function -- downloading content from the internet -- and is prepared to make use of it. If such use requires that another controller be put onto the stack, it is advisable to use <tt>[[self stack] swapController: newController]</tt> to perform that task, so that the download controller does not appear again after pressing the menu button.

−

Beyond that, the sky is the limit. The example project available [http://www.zerowaitingtime.com/19211-download-QuDownloader.zip here] contains a few more functions, more error checking, and will play the downloaded file through a BRQTKitVideoPlayer, for example.

+

Beyond that, the sky is the limit. The example project available [http://alanquatermain.net/sample-code/QuDownloader.zip here] contains a few more functions, more error checking, and will play the downloaded file through a BRQTKitVideoPlayer, for example.

==Contact Details==

==Contact Details==

I can be reached at [irc://irc.moofspeak.net/awkwardtv #awkwardtv] on irc.moofspeak.net, username alan_quatermain, or at http://forum.awkwardtv.org/, username Quatermain.

I can be reached at [irc://irc.moofspeak.net/awkwardtv #awkwardtv] on irc.moofspeak.net, username alan_quatermain, or at http://forum.awkwardtv.org/, username Quatermain.

+

+

==Take 2 Update==

+

+

I decided to add a little archive of a take 2 compatible updated version of this useful QuDownloader tutorial, i didn't update the information in the tutorial itself here, didn't really have the time. The updated zip is available [http://nitosoft.com/appletv_examples/QuDownloader_2.0.zip here] --[[User:Nito|Nito]] 23:08, 23 August 2008 (CEST)

+

+

[[Category:Tutorials]][[Category:Plugins]]

Latest revision as of 14:11, 3 February 2011

<Google>WIKI</Google>

Back in the first article in this series we created a BRControl wrapper around the ProgressBar widget. I said then that we would put this to use shortly, and so we will. In today's tutorial we will look at a more substantive example of plugin development, including localizations and resources, some preferences, and asynchronous download from the internet.

Our end result will be a controller which downloads from a URL stored in our preferences, displaying the progress of the download as it does so. It will also show a method for supporting resumption of an interrupted download.

Plugin Developers' Toolkit

Since we're going to look at a real-world example today, it seems right that we introduce some important items for your toolkit: resources, localizations, and the preferences system.

Resource Access

This is the simplest of the three; the interface to access your own resources and those of the BackRow framework is simply the NSBundle class. For you own resources, you fetch the bundle containing your own class, like so:

The base routine used to fetch the string is +localizedStringForKey:inFile:fromBundle:, and the other three simply pull together the parameters for that call. The +applicationLocalizedStringForKey:inFile: call is used to locate a string within the bundle of the actual current application (i.e. the Finder). The other two are used to fetch data from the BackRow framework or from the bundle of the calling appliance. For strings within your appliance's default strings file 'Localizable.strings', you would use:

If you have other strings files, you can specify the name of the one you want (minus the '.strings' extension) in the last parameter of that call.

So, we have an easy way of reading our own localized strings, but that's only good for reading. When we use the NSLocalizedString() macro normally, we are able to use the genstrings command-line utility to generate the strings files themselves. Fortunately, genstrings can be told to look for a different form of macro from the default 'NSLocalizedString', meaning we can define our own BackRow-based versions. To do this, create a file in your project called something like 'BRLocalizations.h', and put this inside it:

You can then run the following command from your project directory to generate your strings files:

genstrings -s BRLocalizedString -o English.lproj/

Preferences

You can, as always, use NSUserDefaults to manage your own preferences. However, BackRow provides an interface for both the FrontRow preferences and those for specific named domains. To retrieve a value from the FrontRow preferences you can use the RUIPreferences object:

Directory Locations

This section isn't much to do with BackRow, admittedly, but it is useful in the context of the tutorial in general, since we'll be using this method to locate the folder used to hold our downloads.

The file at <Foundation/NSPathUtilities.h> contains the values you'll need for this, and a handy Objective-C wrapper for the NSSystemDirectories API (in <NSSystemDirectories.h>). You can use this to get lists of directories matching certain criteria. Within that header file you'll find two enumerations; the top one identifies a specific folder (Application Support, Documents, Library, etc.), and the lower one specifies masks for the different domains in which they can exist (System, Local, User, Network, etc.). So, to get a list of all paths for the Application Support folders in the Local and User domains, you would use:

/Users/[username]/Library/Application Support
/Library/Application Support

In the main example, we'll use this to place our downloaded data into the user's Caches folder.

Downloading to a File

To download data to a file (as opposed to simply retrieving an NSData object) we'll use the NSURLDownload class. This supports resumption of data and also in-transit decoding of certain MIME types: MacBinary, BinHex, and GZip. Note that partially-downloaded files decoded from Gzip format cannot be resumed, so if resumption is more important you might choose to disable decoding of that MIME type by implementing -download:shouldDecodeSourceDataOfMIMEType: and returning NO for the Gzip MIME type.

To begin a new download, you need to create an NSURLRequest and hand that to the NSURLDownload constructor. Since we would like to resume any partial downloads, we'll tell the downloader not to delete the file when it fails (or is cancelled).

To resume an existing download, we can pass the resume data (from a prior call to NSURLDownload's -resumeData method) into a new NSURLDownload instance. If the initializer returns nil in this case, resumption wasn't possible and the download must be restarted from the beginning.

The Download Controller

Unlike the last couple of examples, there is a fair amount of code involved in this class, so I won't include all of it here. However, you can download the sample project provided at the end to see the whole thing. Here I will include the main parts needed for starting the download and maintaining progress, but I'll leave out some of the NSURLDownload delegate methods and such.

Member Variables

Our class will need a few member variables to maintain state nicely. Firstly we'll have some UI controls for the title, the URL, and the download progress:

NSURLDownload * _downloader;
NSString * _outputPath;
long long _totalLength;
long long _gotLength;

Implementation

Output Path

Firstly, let's define a useful method for determining the name of our downloaded file. Here we'll use NSSearchPathForDirectoriesInDomains() to get the path for the current user's Caches folder, then append some items to it. We'll use a .download folder similar to that used by Safari, so that we can store resume data within there if the user presses the menu button before we've finished downloading. This function will return the path to the actual file within the .download folder, however.

NSURLDownload Delegate

Since we're using the NSURLDownload class, we will need to implement some delegate methods. I'll leave error-handling out of this article for now (an example can be found in the sample project at the end of this article), but the remainder are important enough to cover here.

User Interface

Now that we've gone through the download process, we just need to finalize the UI code to wrap things up. We'll have three routines here: the initializer, deallocator, and a method to set the source text. The last item has its own method because it is the one item whose frame is likely to change.

Firstly, the initializer. This sets up the default content based on the URL loaded from our preferences.

Conclusion

We now have a controller class which performs a useful function -- downloading content from the internet -- and is prepared to make use of it. If such use requires that another controller be put onto the stack, it is advisable to use [[self stack] swapController: newController] to perform that task, so that the download controller does not appear again after pressing the menu button.

Beyond that, the sky is the limit. The example project available here contains a few more functions, more error checking, and will play the downloaded file through a BRQTKitVideoPlayer, for example.

Contact Details

Take 2 Update

I decided to add a little archive of a take 2 compatible updated version of this useful QuDownloader tutorial, i didn't update the information in the tutorial itself here, didn't really have the time. The updated zip is available here --Nito 23:08, 23 August 2008 (CEST)