Home > iOS, Mobile Development, Objective-C, PhoneGap > PhoneGap Tutorial Series – #3 Extending the PhoneGap API

PhoneGap Tutorial Series – #3 Extending the PhoneGap API

 

Extending the PhoneGap API

 
If you’ve had a chance to play with PhoneGap a bit, chances are you have wanted it to do something that it doesn’t already do. Alas, don’t worry! You don’t have to put in a ticket and hope that the PhoneGap developers agree with you and implement it in some future release, if you can write a little Objective-C then you can do it yourself and use it in your own iOS project.

The topic at hand is all about extending the PhoneGap API whether it’s by editing existing PhoneGap classes, downloading a third-party plugin from somewhere, or by writing your own plugin from scratch. For this post I will concentrate on editing the PhoneGap classes, in later posts I’ll give step-by-step instructions on using a third-party plugin and how to create your own plugin.

If you haven’t already had a chance to read my earlier posts on PhoneGap internals and using the PhoneGap API – you may want to peruse them before reading on.
 

Adding Functionality to the PhoneGap Classes

 
Off the top of my head, one of the things that I want PhoneGap to do is to take a picture (which it already can) and save it in the photo library (which it doesn’t do). Who knows why this isn’t already in the API but it’s something that I would like. So I could just write all my own Objective-C to take the picture and save but I don’t really want to redo something that is there, I just want to add a little something more to it.

How to Save a Photo to the Library

So the first thing that I need to find out is how to actually save an image to the photo library. After googling around a bit I found that the following UIKit reference from Apple indicates that this method: UIImageWriteToSavedPhotosAlbum should accomplish what we want.

//Adds the specified image to the user’s Camera Roll album.
void UIImageWriteToSavedPhotosAlbum (
   UIImage  *image,
   id       completionTarget, //optional
   SEL      completionSelector, //optional
   void     *contextInfo //optional
);


How Does the Camera API Work?

Next we need to take a look under the hood at what the PhoneGap Camera API already does when we tell it to take a picture and find an appropriate place to inject our own code. Since PhoneGap is open source we can do this and make all the changes that we want on our own behalf – but keep in mind that if you upgrade you will have to make your changes again.

This is one of many reasons to write a new plugin instead of editing PhoneGap directly – the instructions for which will be in a future post.

In the Camera.h file from the PhoneGapLib project (version 0.9.4) we see that they define a CameraPicker interface that extends the UIImagePickerController and that the Camera implements the UIImagePickerControllerDelegate.

The delegate defines the imagePickerController:didFinishPickingMediaWithInfo method that is called when the UIImagePickerController has selected an image.

@interface CameraPicker : UIImagePickerController
//removed ....
@end
@interface Camera : PhoneGapCommand<UIImagePickerControllerDelegate, UINavigationControllerDelegate>
{
	CameraPicker* pickerController;
}

For those that are interested, the Camera Programming for iOS Guide from Apple explains in detail how to use the UIImagePicker API to interact with the camera and the photo library.

The following excerpt is from the Camera.m file from the PhoneGapLib project (version 0.9.4):

- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
{
	CameraPicker* cameraPicker = (CameraPicker*)picker;
	CGFloat quality = (double)cameraPicker.quality / 100.0; 
	[picker dismissModalViewControllerAnimated:YES];
	NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
	if ([mediaType isEqualToString:(NSString*)kUTTypeImage])
	{
		if (cameraPicker.successCallback) {
			
			NSString* jsString = NULL;
							// get the image
				UIImage* image = nil;
				if (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]){
					image = [info objectForKey:UIImagePickerControllerEditedImage];
				}else {
					image = [info objectForKey:UIImagePickerControllerOriginalImage];
				}

				NSData* data = UIImageJPEGRepresentation(image, quality);
				if (cameraPicker.returnType == DestinationTypeFileUri){
					// write to temp directory and reutrn URI
					// removed for brevity...
				}else{
					jsString = [NSString stringWithFormat:@"%@(\"%@\");", cameraPicker.successCallback, [data base64EncodedString]];
				}
			[webView stringByEvaluatingJavaScriptFromString:jsString];
		}
	}
}

The imagePickerController:didFinishPickingMediaWithInfo delegate method is doing a number of things:


  • line 6 – making sure that an image was selected
  • line 9 – making sure that a successCallback was defined
  • lines 13-18 – getting a reference to the selected image
  • lines 20-26 – writing the image to disk or defining an encoded string
  • line 27 – executing the JavaScript successCallback method

Where to Add Your Code?

The most appropriate place for us to inject our code to save the image is at line 19 just after we have gotten a reference to the image. The following code snippet checks to make sure that the image source was from the camera (not the library) and then saves the image into the photo library using the UIKit UIImageWriteToSavedPhotosAlbum method.

                //save the photo to the album
                if (cameraPicker.sourceType == UIImagePickerControllerSourceTypeCamera)
                {
                    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
                }

Since taking a picture with the PhoneGap API requires that you be running on a device, you must build and deploy to your iPhone in order to test that our code works.

    The expected outcome is:
  1. Without the changes, the Camera API should allow you to take a picture BUT will not save it to the photo library.
  2. With the changes, the Camera API should allow you to take a picture AND will save it to the photo library. You should be able to open the camera roll and see your new pic.

That’s all for now — stay tuned for more upcoming posts on PhoneGap…

About these ads
  1. May 18, 2011 at 6:11 PM | #1

    Thanks so much of for this blog post. It’s like a page from a Phonegap textbook. I was looking for suggestions for saving an image but didn’t think I’d come across a complete answer. Thanks.

  2. Jeff
    June 24, 2011 at 10:34 PM | #2

    Perhaps I’m missing something, but is there a way to simple tap an HTML link and run the script to save the image to the camera roll automatically?

    • June 27, 2011 at 10:13 PM | #3

      Yes. See the camera.html in the HelloPhoneGap project on github.

      • Jeff
        June 28, 2011 at 11:14 AM | #4

        Thanks for the quick reply.

        I took a look at the code. I don’ think I’m being very specific. Let me try again:

        Suppose I have an image embedded on a page.

        I want to be able to have the user tap on that image and (automatically) save that image to the camera roll.

        Can this be done?

      • June 29, 2011 at 2:22 PM | #5

        Yes that can be done but you would have to write your own phonegap plugin to do it. It would require some objective-C work (for iOS) to get it to do what you want as I don’t believe the current PhoneGap library will do it for you.

  3. Adrian3
    July 20, 2011 at 12:07 AM | #6

    I think the If Statement doesn’t work in Phonegap 9.6. I can get the images to save to the camera roll without the if statement just fine. But that has the the negative side effect of saving all images to the library. Any chance you can troubleshoot this for 9.6?

  4. July 24, 2011 at 2:23 AM | #7

    I have been trying to get this to work without success. I am on Xcode4 using Phonegap 9.6. It seems like the camera.m file has changed since your example here. If it would be possible to get an example of how this would work on 9.6 I would be very grateful. If this turned into a plugin I think it would be popular. Seems like functionality that should be built into Phonegap. Thanks!

  5. July 24, 2011 at 5:30 PM | #8

    Just a follow up. I was never able to get the code here to work but I did have success using a plugin called SaveImage that is available here:
    https://github.com/myfreeweb/PhoneGap-Plugins/tree/master/SaveImage

    It required a bit of editing as described here:
    http://wiki.phonegap.com/w/page/41733808/PhoneGap-iOS-Plugins-Problems

    Hopefully this helps anyone else looking to save images from their phonegap app into the camera roll.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 33 other followers

%d bloggers like this: