Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Web Development

Creating WAP Services


Jul00: Creating WAP Services

Luca works for Cell Network and specializes in software development for mobile systems. He can be contacted at lucap@ cellnetwork.no.


The Wireless Application Protocol (WAP) is a communications architecture designed for wireless networks. Sponsored by the nonprofit WAP Forum (http://www.wapforum.com/), the specification includes an XML-based markup language, scripting language, microbrowser specification, framework for wireless telephony applications, lightweight protocol stack, and secure connections. (See also http://wap.colorline .no/wap-faq/.)

In "The Wireless Application Protocol" (DDJ, October 1999), Steve Mann provided a detailed overview of the WAP specification. In this article, I'll focus on the creation of WAP services by describing a fully functioning WAP application based on a project I was recently involved in for a Scandinavian telecommunication company. The WAP application I present is a fictitious radio station, WAPRadio, which lets listeners pick songs from a database of available music, write a dedication, and request a song. To build this application, I use the Apache web server (with PHP support) and the MySQL database.

WAP's power lies in a system's ability to communicate without needing a PC. While the possibility of browsing static documents is necessary, the Wireless Markup Language (WML), which is an XML-based markup language, and WMLScript, which is a scripting language loosely based on JavaScript, can hardly suffice for creating valuable WAP services. What you need is a system that will deliver dynamically generated WML to the mobile phone to reflect the current status of your system -- available seats, flight schedules, information about the caller's bank account, or whatever. WAP's adoption of established Internet protocols (particularly HTTP) means that you can implement WAP services via CGI and derivates. In other words, if you know Perl, ASP, PHP, Java servlets, or any other similar technology, you can create a WAP service.

To access a WAP service you need either a WAP-enabled telephone or emulator. The example I present here has been tested with a Nokia 7110 mobile phone and the emulator that comes with Nokia Toolkit 1.3 (freely available at http://www .nokia.com/corporate/wap/ sdk.html), a WML-based development environment. You will also need to install the Java Virtual Machine 1.2.2 (freely available from Sun) to use the emulator for testing your WAP service from your PC. Finally, most telephones sold in the U.S. will use the microbrowser from Phone.com (freely available at http:// www.phone.com/).

WAP Development Issues

Even though WAP development concepts are simple, we're still in the first generation of WAP services. This means, for instance, that different WAP telephones have minor differences in their implementations, thereby making a functioning WAP site problematic for different mobiles.

The Nokia 7710, for example, does not support the POST method correctly when sending data to the web server, even though this is part of the specification, and the reference material by Nokia claims just the opposite. As a result, you have to use the GET method.

The WAP 1.1 specification does not try to standardize how WML documents and navigational elements should be rendered. Consequently, each device implements them in a different way. It is easy to fall in the trap of coding a functionality because of how it looks on a certain phone/emulator. If you do this, you'll get burned.

One limitation is the maximum size of a deck. (The basic WAP application metaphor is a deck of cards, where each deck is a program, or document with a unique URL, delivered from a server. Each card is a single visible user interaction, such as a choice list or data-entry form.) Some telephones (notably the 7710) won't accept a WML deck greater than 1.4 Kbytes. First-generation WAP phones have similar limitations. The Nokia 7110 does not render tables and many of the tags used for emphasis. This is why I haven't used them in my application. In addition, the fieldset element is ignored.

WAP devices are not PCs; they can only handle correct WML. If you have coded in HTML, you will find that WAP browsers do not forgive as easily. Your code must be correct and last minute changes can wreck havoc in the entire application. You should architect the interaction flow carefully in advance. (I suggest you start with paper and pencil.)

The emulator in the Nokia Toolkit 1.3 supports cookies, but the first-generation WAP systems probably don't. This is bad news, since this implies that you won't be able to exploit a handy mechanism to monitor user sessions. Of course, some gateways support cookies on behalf of the device, so you may have the opportunity to exploit this feature in your particular project.

The traditional human-computer interaction principles applied in web applications are not valid when it comes to WAP-enabled devices. WAP devices have many constraints web applications don't have, including:

  • Maximum size of compiled decks is limited. For the Nokia 7119, that's 1461 bytes.
  • Bandwidth is limited to 9600 bps. In the future, GPRS (General Packet Radio Service) will improve significantly on that.

  • Display capabilities are limited to 5×16 text-only screens.

  • Poor input facilities. Typing a URL on the Nokia 7110 simply takes too long.

Clearly, all this necessitates a special set of guidelines for WAP development, such as:

  • Words used in applications should be short yet meaningful. Too much text forces users to scroll. I provide context-sensitive help to explain what's going on in a different deck.

  • Text insertion should be avoided whenever possible. Use "select/option" elements and list links whenever possible.

  • Use the "alt" attribute for images.

  • Do not rely on the look of a page on a particular emulator. I saw people abuse the onpick event because it looked cool on the Toolkit emulator, but the results were poor on the real 7110.

The Application

Figure 1 illustrates the decks that implement an application. Listing One contains three cards, starting with the splash screen in Figure 2, which is displayed for three seconds before the microbrowser moves to another card in the same deck. WAP pictures must be in a bitmap format called "WBMP." You can produce WBMP pictures with Adobe Photoshop or PaintShop Pro and a free plug-in is available at http://www.rcp.co.uk/ distributed/Downloads. Remember to register the appropriate MIME types on your web server (see Table 1), since this is the origin of many frustrating problems.

The frontpage card (Figure 3) is a portal for all of the radio station's WAP services. (The last two links are not part of the demo; they just give you the idea of what could be there.) The first link brings you to the picksong (Figure 4) card. Users can insert a word and request a list of matching song titles and artists.

I inserted a link to the help document for this deck; see Listing Two. Each deck (or card, in some cases) should have a dedicated help document that compensates for the conciseness of the text in cards. (That's why Figure 1 has shadows behind each deck.)

Putting as many cards as possible in a deck improves the user's experience, since no connection to the server is required to move from one card to the other. Of course, this is not possible when a card is generated dynamically by the server.

Upon submitting the search keyword to the server, PHP dynamically produces a WML deck with the requested information. The first lines in Listing Three make sure that the right MIME type for WML is returned to the client. The rest is standard PHP programming. I make sure that there is a search key and that it is not too short. I then execute a SQL query that matches the search key against the artist and song columns in the song table in the database. The database schema consists of only two tables. The Songs table contains all the songs listeners are supposed to choose from. song_id, title, and artist are the column names. The Playlist table contains the list of songs users have chosen. A new record is inserted for each request. The file database.sql (available electronically; see "Resource Center," page 5) is a MySQL database dump that lets you reproduce my configuration.

The search query can have one of three possible results:

  • A match is not available. I provide a message, and an input box is presented to users. I leave the previous search key there.
  • Only one record matches the search key. The match automatically becomes the user choice.

  • Multiple records match the search key; see Figure 5. I generate a select element that will let users easily select a song from a set of options.

In second and third cases, users are given the option of inserting a dedication to be associated with the song they choose. postfield elements are used to build a request to the system in a way that is similar to how web developers employ hidden fields in HTML.

I did not implement much error handling in this example, but you will want to in real applications. PHP (and similar environments) react to errors with HTML messages. This, in turn, can be the cause of a meaningless error message on your emulator. In practice, debugging WAP may prove more difficult than debugging web applications.

The last deck (see Listing Four and Figure 6) displays a confirmation message and updates the Playlist table with the data of the request (artist, title, and dedication). Of course, I assume that the radio staff has some other database front end that lets them see listener requests. I inserted a link to the first page of the application at the end of the deck. Navigating with WAP is difficult, but omitting such a link would be deadly. This is at least as important as implementing a Back button in each card.

Conclusion

The application presented here is straightforward. If you have done web development with PHP (or ASP or JSP), you should be able to leverage your knowledge and build successful WAP services quite easily.

DDJ

Listing One

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" 
                             "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
 <template>
  <do type="accept" label="Help">
   <go href="index_help.wml"/> 
  </do>
 </template>
 <card id="logo" title="WAP Radio" ontimer="#frontpage">
  <timer value="30"/>
  <p>
   Welcome to
   <img src="pix/radio.wbmp" alt="WAP Radio"/>
  </p>
 </card>
 <card id="frontpage" title="WAP Radio">
  <p>
   <anchor>Pick up a song
    <go href="#picksong" />
   </anchor>
   <anchor>Today's programs
    <go href="programs.wml" />
   </anchor>
   <anchor>news
    <go href="news.wml" />
   </anchor>
  </p>  
 </card>
  <card id="picksong" title="Pick up a song">
  <do type="prev" label="Back">
   <prev/>
  </do>
    <p> Artist or song title: <input type="text" name="searchkey" value="" />
    <anchor title="search">Search
            <go href="songlist.php3" method="get">
         <postfield name="searchkey" value="$(searchkey)" />
      </go>
    </anchor>
    </p>
   </card>
</wml>

Back to Article

Listing Two

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
                     "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<template>
 <do type="prev" label="Back">
  <prev/>
 </do>
</template>
  <card id="index_hlp" title="help">
   <p>  
    This text is supposed to explain what happens in this deck. It should 
tell users that they can browse the news, see today's programs on the radio, 
and even pick up a song to be sent later on.
 <br />
Associating a  help deck to each deck that implements a certain
function is an excellent way to provide context-sensitive help.
 <br />
 Generally speaking having a context-sensitive help system is a good idea in 
the case of WAP services. Screens real estate is limited and the text used 
to guide users can be cryptic.
<br />
Don't forget a back button
   </p> 
  </card>
</wml>

Back to Article

Listing Three

<?php //header("content-type:application/xml"); 
  header("content-type:text/vnd.wap.wml"); 
  echo "<?xml version=\"1.0\" ?>\n";
  echo '<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" ';
  echo '"http://www.wapforum.org/DTD/wml_1.1.xml">'; 
?> 
<wml>
<template>
 <do type="prev" label="Back">
  <prev/>
 </do>
</template>
<?php
 //there are several things that can go wrong
 $ok = false;
 if ($searchkey && strlen($searchkey) > 2) { //good start. 
                                         // We have something to search for
    mysql_connect("localhost:3306", "root", "");
    $query = "SELECT * FROM songs " . 
             "WHERE title LIKE '%$searchkey%' OR artist LIKE '$searchkey%'";
    $result = mysql_db_query("wap", $query);
 
    if ($result && mysql_numrows($result) > 0) {
       $ok = true;
    }
 }
 if ($ok) {
    //if there are multiple hits, user should choose one
    if (mysql_numrows($result) > 1) {
?>
 <card id="pickup" title="Choose from hitlist">
  <do type="accept" label="Help">
   <go href="songlist_help.wml"/> 
  </do>
  <p>
Pick up song: 
<select name='song'>
<?php   
  while ($r = mysql_fetch_array($result)) {
    //echo("<option value='".$r["song_id"]."'>".$r["title"]." - 
                                              ".$r["artist"]."</option>\n");
    //display is too small. create entry for song and entry for artist
    echo("<option value='".$r["song_id"]."'>".$r["artist"]."</option>\n");
    echo("<option value='".$r["song_id"]."'>".$r["title"]."</option>\n");
  } ?>
</select>
<?
  } else { //only one hit, selected by default
     echo("<card id=\"pickup\" title=\"Choose from hitlist\">\n");
     $r = mysql_fetch_array($result);
     //one way to do it is with setvar (as follows)--but consider 
     //                                                   the side effects
?>
 <do type="accept" label="Help">
   <go href="songlist_help.wml"/> 
  </do>
 <p>
   you chose: <br />
<?
   echo($r["artist"].":".$r["title"]."<br />\n"); 
  }
?>
your message:
<input type="text" name="message" />
<anchor title="next">Next
  <go href="confirm.php3" method="get">
<?
   //if there are multiple entries, use the one selected
   //by the user. Otherwise, use the only hit available
   if (mysql_numrows($result) > 1) { 
     echo("<postfield name=\"song\" value=\"$(song)\" />\n");
   } else {
     echo("<postfield name=\"song\" value=\"".$r["song_id"]."\" />\n");
   }
?>
   <postfield name="message" value="$(message)" />
 </go>
</anchor>
  </p>
 </card>
<?
} else { //something went wrong, try again
?>
 <card id="sorry" title="No song found">
  <do type="accept" label="Help">
   <go href="songlist_help.wml"/> 
  </do>
 <p>No match. Try with a different search key:
  <input type="text" name="searchkey" value="<?php echo($searchkey) ?>" />
    <anchor title="search">Search
            <go href="songlist.php3" method="get">
         <postfield name="searchkey" value="$(searchkey)" />
      </go>
    </anchor>
  </p>  
 </card>
<?php
 }
?>
</wml>

Back to Article

Listing Four

<?php //header("content-type:application/xml"); 
  header("content-type:text/vnd.wap.wml"); 
  echo "<?xml version=\"1.0\" ?>\n";
  echo '<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" ';
  echo '"http://www.wapforum.org/DTD/wml_1.1.xml">'; 
?>
<wml>
<template>
 <do type="prev" label="Back">
  <prev/>
 </do>
</template>
<?
  mysql_connect("localhost:3306", "root", "");
  $query = "SELECT * FROM songs " . 
             "WHERE song_id = $song";
  $result = mysql_db_query("wap", $query);

  //not much error handling for simplicity sake
  $r = mysql_fetch_array($result);
?>
  <card id="confirm" title="Thank you!">
   <p>  
 You picked:<br/> <?php echo($r["title"]); ?> by 
                                      <?php echo($r["artist"]); ?><br />
 Your message:<br />
 <?php echo($message); ?><br />
<?
  //let's insert the data in the playlist table
  $query = "INSERT INTO playlist VALUES (NULL,".$r["song_id"].",
                  \"".$r["title"]."\",\"".$r["artist"]."\",\"$message\")";
  //echo("<!-- $query -->"); 
  $result = mysql_db_query("wap", $query);
?>
 Thank you for listening to WAP Radio 105 FM.<br />
<a href="index.wml">Go to front page</a>
   </p> 
  </card>
</wml>

Back to Article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.