Chris Yunker's weblog

Friday, May 29, 2009

HDCP In Action

I’m a big fan of Breaking Bad and missed this week’s episode. I don’t have a DVR, but still have a working VCR and use it on occasion to record a must see show. Since Breaking Bad is on AMC, I assumed I could watch the missed episode on Hulu since Mad Men, another AMC show, was carried on Hulu. But to my surprise, they don’t have it.

So I had to turn to iTunes to get the missed episode. For $2.99 you can download an HD version of the show. A few hours later (after waiting for 1.5 GB to download) I was ready to watch the episode. I hit play and this is what I saw.




My Mac home setup is my MacBook attached to an external VGA monitor. This gives me a dual screen setup, with the VGA as the primary screen since it’s the largest. When I got this message the iTunes player was located on the VGA screen.

HDCP (http://en.wikipedia.org/wiki/High-bandwidth_Digital_Content_Protection) is basically a DRM for HD video. It only allows the video to be displayed on devices that support HDCP to prevent unauthorized copies. Interestingly enough, when I dragged the iTunes player back to the MacBook screen, it played the video OK.

Friday, May 1, 2009

Nice Firefox Add-On for Mobile Website Testing

I'm working on a website which will render differently depending on whether or not it's being accessed from an iPhone web broswer. I came across this Firefox Add-On which is perfect for some of my testing.

It's called User Agent Switcher and it's written by Chris Pederick.

http://chrispederick.com/work/user-agent-switcher/

This add-on allows you to change the User Agent field in your browser HTTP requests. In the case of the Firefox browser I'm currently using on my macbook, here is the User Agent field:
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.10) Gecko/2009042315 Firefox/3.0.10 GTB5
For my testing, I want to change this field to what it would be if I was browsing from my iPhone. This is the User Agent field my iPhone is currently using:
Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/3.1.1 Mobile/7A300g Safari/525.20
The User Agent Switcher allows you to create new User Agent profiles and adds a pull-down button on Firefox so you can easily switch back and forth between browser types.

Once you've added your profile and enabled it, an easy test is to simply go to google.com since it should render a simple page for mobile devices.

Thursday, April 23, 2009

Writing iPhone applications to handle Low Memory Situations

Part of writing a robust iPhone application is making sure it can recover from low memory situations. These can be not uncommon if you use memory hungry components such as the UIImagePickerController or UIWebView. When a low memory situation happens, the OS will try to free up memory from your application. If enough memory can’t be freed up, the OS will terminate your application.

Low Memory Events

In low memory situations, the OS will invoke the didReceiveMemoryWarning method on all of your view controller objects. You should override this method in your view controllers if there is an opportunity to free up any memory. I always override this method with at least a warning log message for testing purposes. If the view controller is not currently being displayed, the OS might release its view object.

Note: The documentation seems to suggest it will always do this, but in testing I’ve noticed this is not the case. It seems for less critical situations it will only call the didReceiveMemoryWarning method, and for more critical situations it will call didReceiveMemoryWarning and release the view object if not currently displayed.

Consequently, your view controllers must be designed such that they can recover in the case that its view object is released. This means that it must be written such that the view object can be unexpectedly released and then initialized again without leaking memory or putting the view in an unexpected or corrupted state.

When the view controller releases its view object, it calls the method setView:(UIView *)view with view set to nil. You can override this method to add code that will help to cleanly release the view and all the objects it contains.

Example

In the following example, the view contains an imageview object which is a member variable of the view controller. In order to release the imageview when the view gets released the setView method needs to be overridden to explicitly release the imageview (only for the condition of view == nil).

(Note that this example is for a non-NIB initialized view controller)
@interface MyViewController : UIViewController
{
    UIImageView *imageView;
}
@end

@implementation MyViewController

- (void)setView:(UIView *)aView
{
    if (aView == nil)
    {
        [imageView release];
    }    
    [super setView:aView];
}

- (void)loadView
{
    ...

    imageView = [[UIImageView alloc] initWithImage:myImage];

    ...
}

@end
Note that if the imageview was not a view controller member variable and was autoreleased into the view, then it would automatically be released when the view was released and this wouldn’t be necessary.

You can obviously choose not to release the objects in a view during low memory situations. If they are small objects, it’s probably safe to do so. However, the code for creating the view needs to check for the existence of previously created objects so they are not overwritten causing memory leaks and possibly putting the objects in corrupt or unexpected states:
- (void)loadView
{
    if (!imageView)
    {
        imageView = [[UIImageView alloc] initWithImage:myImage];
    }
}

Testing

Simulating low memory events should be an integral part of your testing. You can do this with the iPhone simulator by selecting the menu option: iPhone Simulator -> Hardware -> Simulate Memory Warning. If you did like me and put log statements inside the didReceiveMemoryWarning methods, you will see these messages in the console window. Also be sure to run the simulator with the Instruments tool in Leaks mode to check for memory leaks.

Tuesday, March 17, 2009

Mapping Services for iPhone Applications

For my next iPhone project, I'm considering an application that uses geolocation to render a map of the user's current location. I therefore need to find a mapping service that I can use free of charge since I won’t be charging for the application.

Listed below are some of the services I've considered. I don't plan to do anything more than to render the user's current location and allow him or her to adjust it slightly if it's not accurate. No need for routing or other extra features. So most mapping services should work, the only issue is the terms and conditions that will allow me to use it free of charge.


1) Google Maps

http://code.google.com/apis/maps/

This is my first choice based on my experience using it as the Maps application on the iPhone. I have also played around with Google Maps on my web site and have found the API very easy to use.

The terms of service might be a problem.

ToS: http://code.google.com/apis/maps/signup.html


9.1 Free, Public Accessibility to Your Maps API Implementation. Your Maps
API Implementation must be generally accessible to users without charge. You
may require users to log in to your Maps API Implementation if you do not
require users to pay a fee. Unless you have entered into a separate written
agreement with Google or obtained Google's written permission, your Maps
API Implementation must not:

(a) require a fee-based subscription or other fee-based restricted access; or
(b) operate only behind a firewall or only on an internal network (except
during the development and testing phase).


Since I'm not charging, this should be OK.


10. License Restrictions. Except as expressly permitted under the Terms, or
unless you have received prior written authorization from Google (or, as
applicable, from the provider of particular Content), Google's licenses above
are subject to your adherence to all of the restrictions below. Except as
explicitly permitted in Section 7, you must not (nor may you permit anyone
else to):

10.8 use the Static Maps API other than in an implementation in a web
browser;


However, this does not look OK. Since my plan is to use the map in the UIWebView object, I think this might violate the ToS. After doing some searching, I came across this thread:

http://groups.google.com/group/Google-Maps-API/browse_thread/thread/2f42bc5e4c3368d8/fbdc4ecdc3b96096?pli=1

A Google employee weighed in and said basically that if the application were accessing a web site that could be viewed separate from the application, than the UIWebView use case should be OK.

I have seen applications that use Google Maps which can’t be used in a separately in a browser. One example is iBus, a free Portland mass transit application:

http://zhenwang.yao.googlepages.com/ibus-portland

So it appears the way I’d use Google Maps falls into the gray area of the ToS.

I should also point out that there is a nice, BSD licensed library that can help to integrate the Google Maps API into an iPhone project. This helps to make a simple API even easier to use.

http://code.google.com/p/iphone-google-maps-component/


2) Yahoo Maps

http://developer.yahoo.com/maps/

I’ve used Yahoo Maps with Flickr geotagging and the maps look just as good as Google’s. I have not, however, seen any iPhone applications that use this service.

ToS: http://info.yahoo.com/legal/us/yahoo/maps/mapsapi/mapsapi-2141.html

One big issue with the ToS is the attribution part:

http://developer.yahoo.com/attribution/

Yahoo Maps require displaying an attribution badge or label that is not overlaid on the map. It’s placed below the map. This will take away from valuable screen real estate, and for me is enough of a reason to not use Yahoo Maps. Perhaps this is why I haven’t seen it used in any iPhone applications.


3) Microsoft Virtual Earth

http://www.microsoft.com/virtualearth/

I’ve used Microsoft’s Virtual Earth from a browser and have been really impressed. I’ve also seen it used with the Loopt iPhone application.

ToS: http://www.microsoft.com/virtualearth/product/terms.html

The ToS looks OK for Non-Commercial use. That is, of course, if deploying a free iPhone application is considered Non-Commerical use.

There’s a good write-up about using Virtual Earth with the iPhone here:

http://www.geo2web.com/2008/11/13/developing-virtual-earth-iphone-applications-with-objective-c/

From reading this, it seems use of the Virtual Earth API is non-trivial. Apparently, it requires the use of SOAP requests instead of JavaScript (which Google Maps uses). Also, the returned tile images have to be programmatically assembled into a nice iPhone image. The blog post directs you to a 3rd party framework library (BSD license) that can ease implementation:

http://consonancesw.com/developers/virtualearthkit/


4) CloudMade

http://cloudmade.com/

CloudMade uses the maps from OpenStreetMap (http://www.openstreetmap.org/). I’ve seem OpenStreetMap used with the iPhone application MotionX-GPS, however, I’m not sure if it’s used through the CloudMade API.

According to the following link, they place no restrictions on the API.

http://developers.cloudmade.com/projects/show/iphone-api


Just like our other APIs, we don't want to restrict the uses of this API - you are
free to create applications that use our maps in any way you like, as long as
they comply with the terms of the iPhone SDK agreement.


To implement, the user needs to download the API code and integrate with the iPhone application. CloudMade provides some iPhone application examples to learn from.

CloudMade looks like a viable solution. And I’d prefer to use an open source solution, given that Google/Yahoo/Microsoft all seem to have vague terms of service agreements that allow them to cut off service for a variety of reasons.


Summary

So which one have I chosen? I think I’ll go with Google Maps. The ToS does give me some pause, however, my application is free and just for my own experience. If they shut it down, I’ll just switch to another mapping API.

Friday, March 13, 2009

Ruby/Rails With Apache/MySQL on Mac OS (Leopard)

I'm a new Mac user after many years of working on both Linux and Microsoft systems. This last week I went through the process of setting up my system for web development using the Ruby/Rails/Apache/MySQL platform. I was a little surprised to find out it was not as straightforward as working on Linux, given the Mac OS has a BSD core and is the development platform of a lot of high profile programmers.

I'm writing this blog post primarily for my own reference. However, if it can help any others, all the better. Plus I welcome any feedback that may improve my setup.


Terminal Application

All command line actions should be done through the Terminal application. This can be found at Application/Utilities/Terminal.app.


MacPorts

MacPorts is a faculty similar to Aptitude in Ubuntu/Debian for installing software packages from the command line.

MacPorts software is installed in a separate location under /opt/local/. Therefore, you can always determine whether or not an executable is part of MacPorts by running a which [command] and seeing if it's located under this directory.

The current Leopard .dmg installer is version 1.7.0 and can be downloaded here:

http://www.macports.org/install.php


Once installed, open up a Terminal window and run the following command to make sure MacPorts is up to date


$ sudo port selfupdate



The Terminal PATH should have the MacPorts directories (/opt/local/bin, /opt/local/sbin) preceding the standard directories. The MacPorts installer set this for me automatically. If this is not the case for you, be sure to change this in the /etc/profile file.


$ echo $PATH
/opt/local/bin:/opt/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin



Ruby

Install Ruby and RubyGems via MacPorts.


$ sudo port install ruby
$ sudo port install rb-rubygems



The Leopard Mac OS includes older versions of both of these programs which we do not want to use. Check to make sure that the MacPorts version is the version called from the command line:


$ which ruby
/opt/local/bin/ruby

$ which gem
/opt/local/bin/gem



These are the current versions


$ ruby ‐v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin9]

$ gem ‐v
1.3.1



Rails Framework

Install Rails framework files via RubyGems package manager.


$ sudo gem install rake
$ sudo gem install rails
$ sudo gem install capistrano
$ sudo gem install mongrel



This will install these packages with all dependencies. The following files should be installed


$ gem list

*** LOCAL GEMS ***

actionmailer (2.3.2)
actionpack (2.3.2)
activerecord (2.3.2)
activeresource (2.3.2)
activesupport (2.3.2)
capistrano (2.5.5)
cgi_multipart_eof_fix (2.5.0)
daemons (1.0.10)
fastthread (1.0.1)
gem_plugin (0.2.3)
highline (1.5.0)
mongrel (1.1.5)
net-scp (1.0.2)
net-sftp (2.0.2)
net-ssh (2.0.11)
net-ssh-gateway (1.0.1)
rails (2.3.2)
rake (0.8.4)



MySQL

MySQL can be installed through MacPorts or through a dmg installer. Since it’s not that important to me to have the latest version, I chose the dmg installer for simplicity.

The installer can be downloaded here. The current version is 5.1.32.

http://dev.mysql.com/downloads/mysql/5.1.html#macosx-dmg


The installer includes three parts:

Database: mysql-5.1.32-osx10.5-x86.pkg
Preference Pane: MySQL.prefPane
Launch Manager: MySQLStartupItem.pkg

I installed all three parts.

Now install the Ruby MySQL interface package:


$ sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql



Add the MySQL bin folder to the PATH variable for command line use. Append the following line to the local profile file (~/.profile).


# MySQL Command Line
export PATH=$PATH:/usr/local/mysql/bin



Apache

For Apache, I used the version included with the Mac OS.

The Passenger gem package integrates Apache with the Rails framework. Install using the following commands.


$ sudo gem install passenger
$ sudo passenger-install-apache2-module



The output of the last command should list some config settings to add to the Apache configuration. I added a separate file to put these in.


/etc/apache2/other/Passenger.conf

LoadModule passenger_module \
/opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.6/ext/apache2/mod_passenger.so
PassengerRoot /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.6
PassengerRuby /opt/local/bin/ruby



I create a config file for each separate Rails project. The following example is for a project called ‘project1’.


/etc/apache2/other/project1.conf

<VirtualHost *:80>

ServerName www.project1.com
ServerAdmin admin@project1.com
DocumentRoot /Users/username/Work/web/project1/public
ServerSignature On

CustomLog /var/log/apache2/project1_access.log combined
ErrorLog /var/log/apache2/project1_error.log
LogLevel info

<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /Users/username/Work/project1/public/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
Allow from all
</Directory>

</VirtualHost>



In order to view my web site in a local browser, I need to add a setting in the hosts file to redirect to the local host. See the last line of the following file. Of course, you need to make sure to remove this once you deploy your web site to a real server.


/etc/hosts

#
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
fe80::1%lo0 localhost

127.0.0.1 www.project1.com project1.com

Followers

About Me