Chapter 20

PhoneGap: Native Apps from Your HTML, CSS, and JavaScript

WHAT YOU WILL LEARN IN THIS CHAPTER:

  • Creating a PhoneGap project in Xcode
  • Adding your web app code into PhoneGap
  • Tweaking the project to fit your needs

Worlds collide. At least that’s what happens when you use a tool like PhoneGap or one of its competing tools to combine native and web technologies. The solution is actually a quite ingenious solution for web developers: Get around the greatest limitations of an IOS web app by wrapping it in a native shell. The native wrapper enables you to make your app available on the App Store, enables users to install it on an IOS device’s home screen, yet still enables you to keep the application UI and logic in the technology you want to utilize: HTML, CSS, and JavaScript.

In this chapter, I walk you through the steps to transform an IOS web app into a native app using PhoneGap. You don’t have to know any Objective-C to pull it off, though you need to dive into the Xcode IDE to do everything you want to do.

INSTALLING PHONEGAP

If you worked through Chapter 19 already, you have already installed Xcode onto your development computer. If you haven’t, be certain you do that before proceeding because the PhoneGap installer adds an application template to Xcode. Follow these steps:

1. Go to www.phonegap.com and download the latest release of PhoneGap.

2. Extract the contents of the zip file and then navigate to the IOS subdirectory to locate the IOS installer .dmg file.

3. Extract the .dmg file and then double-click the PhoneGap .pkg file launch the Installer.

4. Navigate through the steps in the Installer to install the tool onto your computer.

CREATING A NEW PHONEGAP PROJECT IN XCODE

With PhoneGap installed, you are ready to create a new project in Xcode.

TRY IT OUT: Creating a PhoneGap Project

I walk you through how to take the Top Filmz app that you created in Chapter 4 and package it as a native iPhone app. Follow these steps:

1. Launch Xcode.

2. Choose File ⇒ New Project from the menu.

3. In the template selection dialog box, click the PhoneGap-based Application (see Figure 20-1).

4. Click Next.

5. In the next dialog box (see Figure 20-2), enter the name of your project in the Product Name field. I am calling mine Top Filmz.

6. Enter a unique company id in a “reverse domain” syntax. I am using com.richwagner.app.

7. Uncheck the Use Automatic Reference Counting box. This is an important step with the current version of PhoneGap.

8. Click Next.

9. Choose a directory for your project.

10. Xcode creates your PhoneGap project and takes you to the IDE.

How It Works

When creating an IOS project using PhoneGap, you use the PhoneGap template to create all of the Objective-C “plumbing” you need to run your web app inside the native shell. In these steps, I showed you how to do that inside of Xcode.

RUNNING THE BASE PROJECT

Before continuing, you need to confirm that the Xcode part of your app is compiling and functioning correctly by running it inside of the IOS Simulator. Check out the Scheme combo box that lists your project name (e.g., Top Filmz) next to the targets on which to run the app on. Click the right-side of the Scheme combo box to display a list of deployment targets, including iPhone Simulators, iPad Simulators, and IOS devices. Select iPhone 5.0 Simulator or the latest iPhone version shown in the list. Click the Run button and the app is launched in the IOS Simulator (see Figure 20-3).

You’ll receive an error message in the browser saying “Start page at ‘www/index.html” was not found”. That’s to be expected, as you have not added the web files into the core app.

ADDING WEB FILES TO THE XCODE PROJECT

After you have the basic Xcode project running successfully, you are ready to add the web app to it by performing the following steps:

1. Go to Finder and locate the www folder in your project directory. This folder and its contents are included as part of the PhoneGap template that you used to create the Xcode project.

2. Drag the www folder from the Finder window onto the TopFilmz project in the Project Navigator pane in Xcode.

3. In the dialog that is displayed (see Figure 20-4), select the Create Folder References for Any Added Folders option.

4. Make sure that the Copy Items into Destination Group’s Folder box is unchecked.

5. Click Finish.

As shown in Figure 20-5, the Xcode project now has a direct link with the www folder.

Click the Run button to run the app again in the IOS Simulator. Now that you have a connection with the www folder in the app, the Top Filmz app loads the dummy index.html file that is located in the directory and displays an alert box indicating success (see Figure 20-6).

MERGING YOUR WEB APP CODE

Now that you have the Xcode part of the puzzle working, you may be tempted to directly overwrite the default index.html file that is contained in the www folder with your own file and recompile. However, don’t do that. The PhoneGap template index.html file contains essential HTML/JavaScript parts of a PhoneGap app, such as a reference to a PhoneGap JavaScript library file, default event handlers used to allow your app to work within the PhoneGap environment, and advanced event handlers that you can uncomment if you want to utilize them in your app. The template index.html file is shown here:

<!DOCTYPE html>
<html>
  <head>
  <title></title>
 
    <meta name="viewport" content="width=device-width,
      initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" />
    <meta charset="utf-8">
 
    <!-- iPad/iPhone specific css below, add after your main css >
    <link rel="stylesheet"
      media="only screen and (max-device-width: 1024px)"
      href="ipad.css" type="text/css" />
    <link rel="stylesheet"
      media="only screen and (max-device-width: 480px)"
      href="iphone.css" type="text/css" />
    -->
    <!-- If your application is targeting IOS BEFORE 4.0 you MUST put json2.js
     from http://www.JSON.org/json2.js into your www directory and include
     it here -->
    <script type="text/javascript" charset="utf-8" src="phonegap-1.1.0.js">
    </script>
    <script type="text/javascript">
 
    // If you want to prevent dragging, uncomment this section
    /*
    function preventBehavior(e)
    {
      e.preventDefault();
    };
    document.addEventListener("touchmove", preventBehavior, false);
    */
        /* If you are supporting your own protocol, the var invokeString will
           contain any arguments to the app launch. See         
           http://iphonedevelopertips.com/cocoa/launching-your-own-
           application-via-a-custom-url-scheme.html
           for more details -jm */
    /*
    function handleOpenURL(url)
    {
        // TODO: do something with the url passed in.
    }
    */
  
    function onBodyLoad()
    {
        document.addEventListener("deviceready", onDeviceReady, false);
    }
  
    /* When this function is called, PhoneGap has been initialized and is
      ready to roll */
    /* If you are supporting your own protocol, the var invokeString will
     contain any arguments to the app launch.
    see http://iphonedevelopertips.com/cocoa/launching-your-own-application-
    via-a-custom-url-scheme.html
    for more details -jm */
    function onDeviceReady()
    {
        // do your thing!
        navigator.notification.alert("PhoneGap is working")
    }
  
    </script>
  </head>
  <body onload="onBodyLoad()">
    <h1>Hey, it's PhoneGap!</h1>
    <p>Don't know how to get started? Check out <em><a target="_blank"
       href="http://www.phonegap.com/start#ios-x4">PhoneGap Start</a></em>
    <br />
    <ol>
        <li>Check your console log for any white-list rejection errors.</li>
        <li>Add your allowed hosts in PhoneGap.plist/ExternalHosts (wildcards OK)
        </li>
    </ol>
  </body>
</html>

TRY IT OUT: Migrating Your Web App to PhoneGap

Follow the steps in this section to insert the essential parts of the Top Filmz index.html into the existing PhoneGap index.html file.

1. In Xcode (or your favorite editor), open the index.html file in your www folder.

2. Insert the header declarations from the Top Filmz file into the index.html file:

image
<!DOCTYPE html>
    <link rel="stylesheet"
      href="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css" />
    <script type="text/javascript"
      src="http://code.jquery.com/jquery-1.6.3.min.js"></script>
    <script type="text/javascript"
      src="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.js"/>
    <style>
    img.poster
    {
        display: block;
        margin-left: auto;
        margin-right: auto
    }  
    </style>

Code snippet BIDHJ-Ch20-Ex1.html

3. Replace the existing boilerplate text in the body with the body code in the Top Filmz file.

4. Save the updated file.

5. Top Filmz app doesn’t have any supporting CSS, JS, or image files, but if your app had them you would copy them into www folder now.

How It Works

In this exercise, you added the web app code into the PhoneGap template. Although you want to replace the body content in the PhoneGap template, you want to keep the header code intact to ensure that the app functions properly in the PhoneGap project. The full source code is shown below.

image
<!DOCTYPE html>
<!DOCTYPE html>
<html>
  <head>
  <title>Top Filmz</title>
 
    <meta name="viewport"
    content="width=device-width, initial-scale=1.0, maximum-scale=1.0,
    user-scalable=no;" />
    <!--meta charset="utf-8"-->
  
    <link href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css"
       rel="stylesheet" type="text/css" />
    <script src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
    <script src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js">
     </script>
 
    <style>
    img.poster
    {
        display: block;
        margin-left: auto;
        margin-right: auto
    }  
    </style>
 
    <!-- iPad/iPhone specific css below, add after your main css >
    <link rel="stylesheet" media="only screen and (max-device-width: 1024px)"
     href="ipad.css" type="text/css" />
    <link rel="stylesheet" media="only screen and (max-device-width: 480px)"
     href="iphone.css" type="text/css" />
    -->
    <!-- If your application is targeting IOS BEFORE 4.0 you MUST put json2.js
     from http://www.JSON.org/json2.js into your www directory and include it
     here -->
    <script type="text/javascript" charset="utf-8" src="phonegap-1.1.0.js">
    </script>
    <script type="text/javascript">
 
    // If you want to prevent dragging, uncomment this section
    /*
    function preventBehavior(e)
    {
      e.preventDefault();
    };
    document.addEventListener("touchmove", preventBehavior, false);
    */
  
    /* If you are supporting your own protocol, the var invokeString will
    contain any arguments to the app launch.
    see http://iphonedevelopertips.com/cocoa/launching-your-own-application-via-a-
    custom-url-scheme.html for more details -jm */
    /*
    function handleOpenURL(url)
    {
        // TODO: do something with the url passed in.
    }
    */
  
    function onBodyLoad()
    {      
        document.addEventListener("deviceready", onDeviceReady, false);
    }
  
    /* When this function is called, PhoneGap has been initialized and is ready
       to roll */
    /* If you are supporting your own protocol, the var invokeString will
       contain any arguments to the app launch.
       see http://iphonedevelopertips.com/cocoa/launching-your-own-application-via-
       a-custom-url-scheme.html for more details -jm */
    function onDeviceReady()
    {
        // do your thing!
        //navigator.notification.alert("PhoneGap is working")
    }
  
    </script>
 
 
 
 
  </head>
  <body onload="onBodyLoad()">
 
<!-- Page -->
<div data-role="page" id="home">
    <div data-role="header">
        <h1>Top Filmz</h1>
    </div>
  
    <div data-role="content">
        <ul data-role="listview" data-theme="b">
            <li><a href="#theShawshankRemption">The Shawshank Redemption</a></li>
            <li><a href="#casablanca">Casablanca</a></li>
            <li><a href="#larsAndTheRealGirl">Lars and the Real Girl</a></li>
            <li><a href="#babettesFeast">Babette's Feast</a></li>
            <li><a href="#groundhogDay">Groundhog Day</a></li>
            <li><a href="#lesMiserables">Les Miserables</a></li>
            <li><a href="#thePrincessBride">The Princess Bride</a></li>
            <li><a href="#chariotsOfFire">Chariots of Fire</a></li>
            <li><a href="#signs">Signs</a></li>
            <li><a href="#vertigo">Vertigo</a></li>
        </ul>  
    </div>
  
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
<!-- Subpages -->
 
<div data-role="page" id="theShawshankRemption">
    <div data-role="header">
        <h1>The Shawshank Redemption</h1>
    </div>
    <div data-role="content" style="background-color:#ffffff">
        <img class="poster"
          src="http://ecx.images-amazon.com/images/I/
          519NBNHX5BL._SL500_AA300_.jpg"/>
        <a href="http://www.imdb.com/title/tt0111161/"
          data-role="button">Go to IMDB Page</a>
        <a href="#home" data-role="button" data-icon="home">Return to List</a>
    </div>
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
<div data-role="page" id="casablanca">
    <div data-role="header">
        <h1>Casablanca</h1>
    </div>
    <div data-role="content" style="background-color:#ffffff">
        <img class="poster"
           src="http://ecx.images-amazon.com/images/I/
           51Mg3kdJ5KL._SL500_AA300_.jpg"/>
        <a href="http://www.imdb.com/title/tt0034583/"
           data-role="button">Go to IMDB Page</a>
        <a href="#home" data-role="button" data-icon="home">Return to List</a>
    </div>
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
<div data-role="page" id="larsAndTheRealGirl">
    <div data-role="header">
        <h1>Lars and the Real Girl</h1>
    </div>
    <div data-role="content" style="background-color:#ffffff">
        <img class="poster"
         src="http://ecx.images-amazon.com/images/I/
         51Sn3wcuNGL._SL500_AA300_.jpg"/>
        <a href="http://www.imdb.com/title/tt0805564/"
           data-role="button">Go to IMDB Page</a>
        <a href="#home" data-role="button" data-icon="home">Return to List</a>
    </div>
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
<div data-role="page" id="babettesFeast">
    <div data-role="header">
        <h1>Babette's Feast</h1>
    </div>
    <div data-role="content" style="background-color:#ffffff">
        <img class="poster"
         src="http://ecx.images-amazon.com/images/I/
         51A2BJ1WTML._SL500_AA300_.jpg"/>
        <a href="http://www.imdb.com/title/tt0092603/"
         data-role="button">Go to IMDB Page</a>
        <a href="#home" data-role="button" data-icon="home">Return to List</a>
    </div>
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
<div data-role="page" id="groundhogDay">
    <div data-role="header">
        <h1>Groundhog Day</h1>
    </div>
    <div data-role="content" style="background-color:#ffffff">
        <img class="poster"
          src="http://ecx.images-amazon.com/images/I/
          51EVxBEKg6L._SL500_AA300_.jpg"/>
        <a href="http://www.imdb.com/title/tt0107048/"
          data-role="button">Go to IMDB Page</a>
        <a href="#home" data-role="button" data-icon="home">Return to List</a>
    </div>
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
<div data-role="page" id="lesMiserables">
    <div data-role="header">
        <h1>Les Miserables</h1>
    </div>
    <div data-role="content" style="background-color:#ffffff">
        <img class="poster"  
           src="http://ecx.images-amazon.com/images/I/
           51MeImdd92L._SL500_AA300_.jpg"/>
        <a href="http://www.imdb.com/title/tt0119683/"
           data-role="button">Go to IMDB Page</a>
        <a href="#home" data-role="button" data-icon="home">Return to List</a>
    </div>
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
<div data-role="page" id="thePrincessBride">
    <div data-role="header">
        <h1>The Princess Bride</h1>
    </div>
    <div data-role="content" style="background-color:#ffffff">
        <img class="poster"
         src="http://ecx.images-amazon.com/images/I/
         51%2BOCP1DUSL._SL500_AA300_.jpg"/>
        <a href="http://www.imdb.com/title/tt0093779/"
         data-role="button">Go to IMDB Page</a>
        <a href="#home" data-role="button" data-icon="home">Return to List</a>
    </div>
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
<div data-role="page" id="chariotsOfFire">
    <div data-role="header">
        <h1>Chariots of Fire</h1>
    </div>
    <div data-role="content" style="background-color:#ffffff">
        <img class="poster"
          src="http://ecx.images-amazon.com/images/I/
          51PyP5bti7L._SL500_AA300_.jpg"/>
        <a href="http://www.imdb.com/title/tt0082158/"
          data-role="button">Go to IMDB Page</a>
        <a href="#home" data-role="button" data-icon="home">Return to List</a>
    </div>
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
<div data-role="page" id="signs">
    <div data-role="header">
        <h1>Signs</h1>
    </div>
    <div data-role="content" style="background-color:#ffffff">
        <img class="poster"
          src="http://ecx.images-amazon.com/images/I/
          51c02AOAyCL._SL500_AA300_.jpg"/>
        <a href="http://www.imdb.com/title/tt0286106/"
         data-role="button">Go to IMDB Page</a>
        <a href="#home" data-role="button" data-icon="home">Return to List</a>
    </div>
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
<div data-role="page" id="vertigo">
    <div data-role="header">
        <h1>Vertigo</h1>
    </div>
    <div data-role="content" style="background-color:#ffffff">
        <img class="poster"
          src="http://ecx.images-amazon.com/images/I/
          51JF1C6DF5L._SL500_AA300_.jpg"/>
        <a href="http://www.imdb.com/title/tt0052357/"
          data-role="button">Go to IMDB Page</a>
        <a href="#home" data-role="button" data-icon="home">Return to List</a>
    </div>
    <div data-role="footer">
        <h5>Hello World Apps</h5>
    </div>
</div>
 
  </body>
</html>
 

Code snippet BIDHJ-Ch20-Ex1.html

TWEAKING THE XCODE PROJECT

Although you could compile the Xcode project and run it in the IOS Simulator, you would find that the app would neither function nor look as you expect. That’s because you need to make some additional tweaks and adjustments in the PhoneGap project in Xcode.

Allowing External References

Recall from Chapter 4 that Top Filmz uses jQuery Mobile as its UI framework, which is integrated into the app through three external links — one CSS style sheet and two JS files. It also references movie poster images located on an external server. However, in order for PhoneGap to allow an external domain, you need to explicitly add it to the PhoneGap white list by doing the following:

1. In the Xcode Project Navigator, locate the PhoneGap.plist file in the TopFilmz ⇒ Supporting Files folder.

2. In the key-value pairs displayed in Xcode, locate the External Hosts key.

3. Click the + button next to the External Hosts key and enter∗. jquery.com in the value field.

4. Click the + button again next to the External Hosts key and enter∗. images-amazon.com in the value field.

5. Choose File ⇒ Save to save results.

Figure 20-7 shows the added domains.

Opening External Links in Safari

Each of the movie detail pages of the Top Filmz app contains a button to jump to the film’s IMDb page listing. However, within an app environment, suppose I’d prefer to jump to Safari on IOS for those external links rather than being inside the app itself. I can make a second tweak to examine the web links that are clicked and route it to the appropriate app. For internal app links I keep within the PhoneGap app. For external links, I call Safari to display them.

In order to do this, you need to modify an Objective-C method. However, you only need to copy and paste the code. Here’s how to do this:

1. In the Xcode Project Navigator, locate the AppDelegate.m file inside of the TopFilmz ⇒ Classes folder.

2. Locate the shouldStartLoadWithRequest method:

(BOOL)webView:(UIWebView *)theWebView
    shouldStartLoadWithRequest:(NSURLRequest *)request
                navigationType:(UIWebViewNavigationType)navigationType
 

3. Replace the existing method code with the following updated source code:

(BOOL)webView:(UIWebView *)theWebView
    shouldStartLoadWithRequest:(NSURLRequest *)request
                navigationType:(UIWebViewNavigationType)navigationType
{
  NSURL *url = [request URL];
 
  // If external URL, use Safari
  if ([[url scheme] isEqualToString:@"http"] ||
   [[url scheme] isEqualToString:@"https"])
  {
    [[UIApplication sharedApplication] openURL:url];
    return NO;
  }
  // Otherwise, treat as internal link
  else
  {
    return [ super webView:theWebView
    shouldStartLoadWithRequest:request navigationType:navigationType ];
  }
 
}
 

4. Save the file.

Adding an Icon and Launch Image

Your final step is to create an app icon and launch image. The icon is obviously used for the home screen, and the launch image is displayed when the app loads. Because you need to provide support for both Retina Display (4 and higher) and standard (3GS and lower), the files should be according the following specifications:

  • Standard icon 57 × 57, named Icon.png
  • Retina Display icon 114 × 114, named [email protected]
  • Standard launch image 320 × 480, named Default.png
  • Retina Display launch image 640 × 960, named [email protected]

After you have these created according these standard size and naming conventions, replace the canned files that PhoneGap already added by overwriting them in your project folder. Figure 20-8 shows the Summary page with the updated images.

RUNNING THE FINISHED APP

When you have made all of the final adjustments, you are ready to test your finished app. Click the Run button in Xcode and run the app in IOS Simulator. Figure 20-9 shows the app when it loads, and Figure 20-10 shows the app running.

EXERCISES

1. True/False. When adding your web app code to the PhoneGap project, you should overwrite the existing index.html file that is supplied by PhoneGap.

2. Why won’t a PhoneGap web app access an external resource by default?

3. What are the naming conventions and the dimensions of the icon and launch images used for your app?

Answers to the Exercises can be found in Appendix A.

• WHAT YOU LEARNED IN THIS CHAPTER

TOPIC KEY CONCEPTS
Installing PhoneGap Download and install PhoneGap after you have installed Xcode
Create a PhoneGap project Use the PhoneGap-based Application template when you create a new Xcode project
Merging your web app code Insert your code into the PhoneGap boilerplate index.html file
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset