Apple iPhone Web Kit with Activity Indicator

Welcome to the club of searching for an overly simple UIWebView a.k.a. WebKit example! In this example, I’ll show you simply how to hand code a quick UIWebView into your program as well as to add a UIActivityIndicatorView a.k.a. an activity indicator. Without jabbing Apple too hard here, the documentation is pretty bad and that is why it’s nice to have an example just shown to you as-is. I hope this example helps shine a light on the situation for anyone wanting to implement a nice and quick Apple iPhone WebKit solution.

 
#import <UIKit/UIKit.h>
 
@interface FirstViewController : UIViewController <UIWebViewDelegate>
{
	UIWebView *myWebView;
	UIActivityIndicatorView *activityIndicator;	
}
/*
Inside the @implementation FirstViewController ... 
*/
- (void)viewDidLoad { //We have a NIB file in play here, so I dropped the loadView here.  Just make sure that your loadView is not getting called twice!
    [super viewDidLoad];
    [self loadView];
}
 
- (void)loadView {
	UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
	self.view = contentView;	
 
	CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
	webFrame.origin.y = 0.0f;
	myWebView = [[UIWebView alloc] initWithFrame:webFrame];
	myWebView.backgroundColor = [UIColor blueColor];
	myWebView.scalesPageToFit = YES;
	myWebView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
	myWebView.delegate = self;
	[self.view addSubview: myWebView];
	[myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.maxpowersoft.com/"]]];
 
	activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
	activityIndicator.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
	activityIndicator.center = self.view.center;
	[self.view addSubview: activityIndicator];
}
 
- (void)dealloc {
	[activityIndicator release];
	[myWebView release];
        [super dealloc];
}
 
#pragma mark WEBVIEW Methods
 
- (void)webViewDidStartLoad:(UIWebView *)webView
{
	// starting the load, show the activity indicator in the status bar
	[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
	[activityIndicator startAnimating];
}
 
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
	// finished loading, hide the activity indicator in the status bar
	[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
	[activityIndicator stopAnimating];
}
 
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
	// load error, hide the activity indicator in the status bar
	[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
 
	// report the error inside the webview
	NSString* errorString = [NSString stringWithFormat:
							 @"<html><center><br /><br /><font size=+5 color='red'>Error<br /><br />Your request %@</font></center></html>",
							 error.localizedDescription];
	[myWebView loadHTMLString:errorString baseURL:nil];
}

That is all there is to it. It’s really simple as you can see. Feel free to copy and paste accordingly.

, , , , ,

3 Comments

Zend RESTful XML Generic Functions

It has been argued that the Zend RESTful API should not only automate the JSON data returned (which it does a fine job of), but automate the XML data. Unfortunately, the Zend engine doesn’t do this for REST. The solution is left to the developer to implement their own strategy. In my opinion, there is no better place for a simple recursive function that will dynamically crawl the returned objects and arrays and generate XML in a way that just makes sense. As was promised in a comment from one of my previous blogs, here is a set of functions that works well for dynamically generating XML from your PHP objects and arrays. It’s been pointed out that this process should have been included in the Zend framework. As of this writing, I believe that it still has not been implemented. Anyways, here it is. Take note that you really only need two functions from this post getXML(…) and _xmlHelper(…)

abstract class BaseController extends Zend_Rest_Controller
{
//Please know that the init() method has been snipped out.	
 
	public static function getXML($obj)
    {
    	$doc = new DOMDocument();
		$doc->formatOutput = true;
		$root_element = $doc->createElement("response");
		$doc->appendChild($root_element);
 
    	foreach($obj as $var => $value) {
        	$statusElement = $doc->createElement($var);
			if (!is_array($value)) {
				$statusElement->appendChild($doc->createTextNode($value));
				$root_element->appendChild($statusElement);
			} else {
				BaseController::_xmlHelper(&$doc, &$root_element, &$statusElement, &$value);
			}
		}
		print $doc->saveXML();
    }
	public static function _xmlHelper(&$doc, &$root_element, &$statusElement, &$value) {
		if (is_array($value)) {
			foreach ($value as $key => $val) {
				if (is_array($val)) {
					BaseController::_xmlHelper(&$doc, &$root_element, &$statusElement, $val);
				} else if (is_object($val)) {
					$se = $doc->createElement(str_replace('object','',get_class($val)));
					$arr = get_object_vars($val);
					BaseController::_xmlHelper(&$doc, &$root_element, &$se, $arr);
					$root_element->appendChild($se);
 
				} else {
					//print $key . " => " . $val . "\n";
					$se = $doc->createElement($key);
					$se->appendChild($doc->createTextNode($val));
					$statusElement->appendChild($se);
				}
			}
			//print_r($value);
		} else {
			$statusElement->appendChild($doc->createTextNode($value));
			$root_element->appendChild($statusElement);
		}
	}
}

Now the only thing left to do is show an example implementation.

class VersionController extends BaseController 
{ 
/*  implement the methods as show in the blog referenced at the top of this blog post */
public function init()
    {
       $this->view->hello = array('a'=>'1', 'b'=>'2');
    }
}

Now, the last thing to do is edit the view for the XML document which would be in this case:

/application/views/scripts/version/index.xml.phtml

The index.xml.phtml should then only contain:

<?php
BaseController::getXML($this);
?>

This will automate the process of generating the XML data you want returned. It’s an easy way to quickly and effectively get XML without having to rebuild the entire wheel. Feel free to modify and distribute.

, , ,

2 Comments

Creating a PHP REST API Using the Zend Framework

I don’t know about you, but I spent hours pouring over the Zend documentation and searching the Internet for some sort of understanding or example regarding how to do REST the correct way in PHP.  I found a handful of one-offs, where everyone was writing their own core REST engine from scratch. I figure why write all the code to handle this, if you already have the Zend Framework in your code base. I believe that the ideal solution will effectively use the the Zend_Rest_Controller and ContextSwitch objects as well as offering JSON and XML formatting options. My goal here is simple. I want to give you the building blocks to aid in writing an easily maintainable REST API in PHP using the Zend Framework.

This code example will support REST data in the format of XML and JSON.

Prerequisites:

  1. PHP version > 5
  2. Zend Framework 1.9.2 (at the minimum) The generic download page can found here.

Download ZendRestExample Source. You will want to download this example in order to effectively run and better understand the project. Make sure to rename the 1.htaccess file to .htaccess (if interested in using it). As well, take note that there are other files not listed below that are required to run this project. These are contained within the zip’d source code. Finally, the Zend framework is not zip’d into the source code. You’ll need to download this and install it on your own.

Basic Directory Structure:

/
/.htaccess
/index.php
/applications/
/applications/configs/
/applications/controllers/
/applications/forms/
/applications/layouts/
/applications/views/
/library/  (optional where the Zend folder containing the framework should reside)

URLS used in this example:


http://yourSite/version/format/xml

http://yourSite/version/format/json

//with other parameters you can do:

http://yourSite/version/format/xml/id/1234/param2/6789

One of the tricky things with REST is that the URLs need to be formatted properly. In Apache, all you need is the mod_rewrite module enabled and a .htaccess in the root of your current web project.

?Download .htaccess
SetEnv APPLICATION_ENV development
 
RewriteEngine On
#RewriteBase /~myUserName/myDirectory
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

Now that we have adjusted the .htaccess, let’s look into the application/configs/application.ini as well as the important Bootstrap.php.

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
bootstrap.class = "Bootstrap"
 
[staging : production]
 
[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
 
[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

The core kick-start of this whole REST application is contained in the applications/Bootstrap.php

<?php
 
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
	protected function _initAutoload()
    {
        $autoloader = new Zend_Application_Module_Autoloader(array(
            'namespace' => 'Default_',
            'basePath'  => dirname(__FILE__),
        ));
        return $autoloader;
    } 
 
	protected function _initRestRoute()
	{
		$this->bootstrap('Request');	
		$front = $this->getResource('FrontController');
		$restRoute = new Zend_Rest_Route($front, array(), array(
			'default' => array('version')
		));
		$front->getRouter()->addRoute('rest', $restRoute);
	} 
 
	protected function _initRequest()
    {
        $this->bootstrap('FrontController');
        $front = $this->getResource('FrontController');
        $request = $front->getRequest();
    	if (null === $front->getRequest()) {
            $request = new Zend_Controller_Request_Http();
            $front->setRequest($request);
        }
    	return $request;        
    } 		
 
}

Now we need to wire up the ability for web requests to move through this engine. We do this in our /index.php file.

?Download index.php
<?php
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/application'));
 
// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
 
// Ensure library/ is on include_path
/*
If you do not have the Zend library already included in your PHP installation...
 
1.  Create a directory named library and place the Zend Framework into it.
 
NOTE: In my instance, I have the Zend library residing under /usr/share/php/   
Because of this, the following lines are commented.
*/
/*set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/library'),
    get_include_path(),
)));
*/
 
/** Zend_Application */
require_once 'Zend/Application.php'; 
 
// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV, 
    APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap()->run();

Well now that the core is in place, all we need is to integrate our controllers. This is where our business logic will reside.

<?php
 
class VersionController extends Zend_Rest_Controller
{  
	public function init()
    {
        $bootstrap = $this->getInvokeArg('bootstrap');
 
		$options = $bootstrap->getOption('resources');
 
		$contextSwitch = $this->_helper->getHelper('contextSwitch');
		$contextSwitch->addActionContext('index', array('xml','json'))->initContext();
 
		//$this->_helper->viewRenderer->setNeverRender();	
		$this->view->success = "true";
		$this->view->version = "1.0";
	}
 
    /**
     * The index action handles index/list requests; it should respond with a
     * list of the requested resources.
     */ 
    public function indexAction()
    {
		//if you want to have access to a particular paramater use the helper function as follows:
		//print $this->_helper->getParam('abc');
               //To test with this use:  http://myURL/format/xml/abc/1002
	}
 
    public function listAction()
    {
        $this->_forward('index');
    }
 
    public function getAction()
    {
		$this->_forward('index');
    }
 
    public function newAction() {   	
		$this->_forward('index');
    }
    public function postAction() {
		$this->_forward('index');
    }
    public function editAction() {    	 
		$this->_forward('index');
    }
    public function putAction() {
		$this->_forward('index');
    } 
    public function deleteAction() {
		$this->_forward('index');
    }
}

Now that we’ve done this, the URL for format of JSON just works as-is thanks to the Zend ContextSwitch engine. No other changes are needed. If you are interested in having the output in XML format, then you’ll need to make a few additions. Now that we’ve taken care of the Controller, we’re going to have to add in the views to make the XML work with the ContextSwitch. So under /applications/views/scripts/version/ you’ll need a file: index.xml.phtml

<?php
$doc = new DOMDocument();
$doc->formatOutput = true;
$root_element = $doc->createElement("response");
$doc->appendChild($root_element);
 
$statusElement = $doc->createElement("success");
$statusElement->appendChild($doc->createTextNode($this->success));
$root_element->appendChild($statusElement);
 
$versionElement = $doc->createElement("version");
$versionElement->appendChild($doc->createTextNode($this->version));
$root_element->appendChild($versionElement);
 
print $doc->saveXML();
?>

And that is all there is to it. We’ve now made a basic index/list REST API for listing the version of your product. This is an overly simple example of how to integrate quickly the Zend REST engine.

, , , , , , ,

18 Comments

Release iPhone/iPod Touch FreeSWITCH Console

fs_logo_57_57 Well, it has been a long battle.  Fought since June 5th, 2009, but at long last Apple has come through and allowed the FreeSWITCH Console application into the app store.

FreeSWITCH is an open source telephony platform designed to facilitate the creation of voice and chat driven products scaling from a soft-phone up to a soft-switch.  It can be used as a simple switching engine, a PBX, a media gateway or a media server to host IVR applications using simple scripts or XML to control the callflow.

So without much further ado, here is the iTunes link: App Store, FreeSWITCH Console.

FreeSWITCH Console Screenshot

The application requires that you have the event socket layer (ESL) module installed in your FreeSWITCH instance.

, , , , ,

2 Comments

Mounting MobileMe iDisk Using WebDav and Linux

Anyone have a MobileMe account and wondered if you can access the iDisk from a mount command in your Linux environment? It’s handy for backing up your data and general file sharing.

This simple step by step process will allow you to gain read and write access to your MobileMe user account’s iDisk drive space. The first pre-cursor you need to fulfill is that you need the davfs (on debian/ubuntu flavors just run: apt-get install davfs2) package installed.

Next we’re going to create a mount point that will be used as a point of reference for the iDisk drive.

sudo mkdir /mnt/idisk

Using the root user account, modify your /etc/fstab file by adding the following at the bottom. Just change the {account_name} section below:

https://idisk.me.com/{account_name}    /mnt/idisk      davfs   rw,noauto,user  0       0

Now that you’ve completed the modification of the mount.  Let’s run a test.

mydev:/mnt# mount /mnt/idisk
 
Please enter the username to authenticate with server
  https://idisk.me.com/{acccount_name}
or hit enter for none.
Username: {acccount_name}
 
Please enter the password to authenticate {acccount_name} with server
  https://idisk.me.com/{acccount_name}
or hit enter for none.
Password:
mydev:/mnt# ls -al /mnt/idisk
total 11
drwxr-xr-x 15 root root  256 2009-08-13 08:11 .
drwxr-xr-x  4 root root 4096 2009-08-13 07:59 ..
drwxr-xr-x  2 root root   68 2009-06-16 14:33 Backup
drwxr-xr-x  2 root root   36 2009-06-16 14:33 Documents
drwxr-xr-x  2 root root   68 2009-06-17 07:14 Groups
drwxr-xr-x  5 root root  132 2009-07-02 09:11 iPhone Development
drwxr-xr-x  5 root root  100 2009-06-17 07:48 Library
drwx------  2 root root   36 2009-08-13 08:11 lost+found
drwxr-xr-x  2 root root   36 2009-06-16 14:33 Movies
drwxr-xr-x  2 root root   36 2009-06-16 14:33 Music
drwxr-xr-x  2 root root   36 2009-06-16 14:33 Pictures
drwxr-xr-x  2 root root   36 2009-06-17 07:49 Public
drwxr-xr-x  2 root root   36 2009-06-16 14:33 Sites
drwxr-xr-x  3 root root   88 2008-07-10 01:11 Software
drwxr-xr-x  3 root root   52 2009-06-17 07:53 Web

That’s great isn’t it? Now the only trouble is it keeps on prompting you for your username and password. In my situation I want this automated. Luckily for us, davfs has a mechanism built into it for managing this. It’s located in the /etc/davfs2/secrets file. So as the root user run the following commands.

mydev:/# umount /mnt/idisk
mydev:/# echo "https://idisk.me.com/{account_name}   {account_name}   {account_password}" >> /etc/davfs2/secrets
mydev:/# mount /mnt/idisk
mydev:/# ls -al /mnt/idisk
total 11
drwxr-xr-x 15 root root  256 2009-08-13 08:11 .
drwxr-xr-x  4 root root 4096 2009-08-13 07:59 ..
drwxr-xr-x  2 root root   68 2009-06-16 14:33 Backup
drwxr-xr-x  2 root root   36 2009-06-16 14:33 Documents
drwxr-xr-x  2 root root   68 2009-06-17 07:14 Groups
drwxr-xr-x  5 root root  132 2009-07-02 09:11 iPhone Development
drwxr-xr-x  5 root root  100 2009-06-17 07:48 Library
drwx------  2 root root   36 2009-08-13 08:11 lost+found
drwxr-xr-x  2 root root   36 2009-06-16 14:33 Movies
drwxr-xr-x  2 root root   36 2009-06-16 14:33 Music
drwxr-xr-x  2 root root   36 2009-06-16 14:33 Pictures
drwxr-xr-x  2 root root   36 2009-06-17 07:49 Public
drwxr-xr-x  2 root root   36 2009-06-16 14:33 Sites
drwxr-xr-x  3 root root   88 2008-07-10 01:11 Software
drwxr-xr-x  3 root root   52 2009-06-17 07:53 Web
mydev:/# umount /mnt/idisk

And that is it! No more prompting for the username and password. Pretty simple implementation and we’re off to the races.

, , , , , ,

13 Comments