In Part 1 of this tutorial series, we introduced our sample application, described the page flow, and discussed how to construct the pages in the application via jQuery Mobile. In Part 2, we completed the implementation of our web application. In this final part, we will migrate the web application into a native Android application.
Converting Into A Native Android Application
The web application completed in Part 2 will now be converted into a native Android application. The discussion below applies to Android OS 2.2 & 2.3.
The Android application will use index.html
as its UI component. We will write an android.app.Activity
class to define the integration point between index.html
and the native application. We will also write an android.webkit.WebViewClient
class to make sure that the News Detail page is displayed inside the original android.webkit.WebView
instance where the News application is launched.
Changes In index.html
We will update the NEWS_URI
variable as follows:
var NEWS_URI = 'http://rss.news.yahoo.com/rss/';
We do not need bridge.php
in the native Android application to forward AJAX calls to Yahoo! News. This is because the same-origin restriction does not apply here. When packaged as part of the native application, the index.html
file is not downloaded from a web server. As such, it can make AJAX calls to remote URLs.
In addition, we add the following function:
var EMPTY = ''; ... function changeLocation(varURI){ showProgress(); $.get(EMPTY,function(data){ window.location = varURI; }); }
The changeLocation()
function will be called from the android.webkit.WebViewClient
, which will be shown momentarily. The purpose of the function is to show the progress page during transition from the News page to the News Detail page.
- The first step in
changeLocation()
is to display the progress page. - Remember that the jQuery
get()
function is a specialized jQueryajax()
function. We callget()
passing to it an empty URL and a callback handler, that sets thewindow.location
variable to the input argument. The input argument is the URL in the<a href='...'>
attribute enclosed within ana
tag for a news item, as discussed in Part 2, "Going To The News Detail Page From The News Page". When the URL loads, the progress page is replaced with contents from that URL. - As we point out below, the function
changeLocation()
is not an essential part of migrating the web application into a native one. It is only needed to display a progress page when transitioning from the News page to the News Detail page in the native application. - A progress page is not needed in the web application when transitioning from the News page to the News Detail page. This is because during the transition the web browser itself displays a progress indicator to the user. For example, in Android, both the native and Dolphin browsers display a spinning wheel and a progress bar in the navigation toolbar. In iOS, the Safari browser displays a similar progress indicator.
The Activity Class
The initial portion of our Activity
class, named NewsActivity
is shown below:
package com.news; import android.app.Activity; import android.webkit.WebView; import android.os.Bundle; ... public class NewsActivity extends Activity { WebView mWebView; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mWebView = (WebView) findViewById(R.id.webview); mWebView.setWebViewClient(new NewsClient()); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setDomStorageEnabled(true); mWebView.loadUrl("android_asset/www/index.html"); } ... }
- In the
onCreate()
method, we first call the default implementation from the super class and then invokesetContentView()
to load the layout file for this Activity. The input argument tosetContentView()
isR.layout.main
which is a reference tomain.xml
in theres/layout
folder. - We get a handle to the
WebView
viafindViewById(R.id.webview)
. We set a customWebViewClient
on theWebView
, namedNewsClient
(to be reviewed soon). Then, we configure theWebView
to allow JavaScript execution and the DOM storage API (the latter is necessary to use HTML5localStorage
). - Finally, we ask the
WebView
to load theindex.html
page that has the UI code.
On the News Detail page, pressing the back button of the device will take the user back to the Categories page. To be assured of that, we first need to handle the onKeyDown
event in our NewsActivity
. This is shown below:
public class NewsActivity extends Activity { WebView mWebView; public void onCreate(Bundle savedInstanceState) { ... } public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) { mWebView.goBack(); return true; } return super.onKeyDown(keyCode, event); } ... }
If the key event corresponds to the back button of the device and the WebView
has history to go back to, we then ask the WebView
to go back a single step in its history. In the News Detail page, this will correspond to index.html
. When history goes one step back, the Categories page will be displayed following the steps described in Part 2, "Application Startup".
Lastly, let us look at the custom WebViewClient
which is implemented as an inner class of NewsActivity
.
public class NewsActivity extends Activity { WebView mWebView; public void onCreate(Bundle savedInstanceState) { ... mWebView.setWebViewClient(new NewsClient()); ... } public boolean onKeyDown(int keyCode, KeyEvent event) { ... } private class NewsClient extends WebViewClient { public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl("javascript:changeLocation('" + url + "')"); return true; } } ... }
The only operation we override from the parent class is shouldOverrideUrlLoading()
where we instruct the WebView
to call the JavaScript function changeLocation()
in index.html
.
- Had we not defined a custom
WebViewClient
, the News Detail page would be displayed in a separate browser application, outside the News application. Therefore, defining a customWebViewClient
is essential to display the News Detail page as part of the News application (i.e. in the sameWebView
that hosts theindex.html
). - We could have written
shouldOverrideUrlLoading()
in a more simplified manner, as follows:public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; }
That would be sufficient to display the News Detail page in the same
WebView
that hostsindex.html
. However, the transition from the News page to the News Detail page would not include showing the progress page.
Having reviewed the Activity
class, let us look at other components of our application.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.news" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".NewsActivity" android:configChanges="orientation|keyboardHidden" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET" /> </manifest>
For a general discussion on the AndroidManifest.xml
file refer to the official reference. In that file, there are two particular items worthy of commenting on.
- As described in the
android.app.Activity
documentation, by default, a configuration change, including a change in orientation or keyboard accessibility, results in the current activity being destroyed. To prevent the default behavior, we configure our application by specifying the configuration changes that will be handled by the application itself. This is defined in theconfigChanges
attribute whereorientation
corresponds to orientation change andkeyboardHidden
corresponds to a keyboard accessibility change (e.g. a user lays open the device keyboard). We are configuring the application so that if any of those changes occur, the current activity is not destroyed. - The element
<uses-permission android:name="android.permission.INTERNET" />
allows the application to access the Internet.
strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">News</string> </resources>
This file defines the constant named app_name
which is used to identify the News application. The value of that attribute is displayed in various places in our Android device, as shown below. From left to right: under the application launch icon, the application title bar, Settings - Manage applications.
Integrating The HTML-based UI With android.app.Activity
We implement the UI in our native Android application using index.html
and the supporting JavaScript and css
libraries. An integration point between index.html
and the custom android.app.Activity
class is the following line:
mWebView.loadUrl("android_asset/www/index.html");
In addition, observe in "The Activity Class" that we enable JavaScript and DOMStorage in the android.webkit.WebView
object as index.html
needs to run JavaScript and access HTML5 localStorage
.
mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setDomStorageEnabled(true);
Finally, in the AndroidManifest.xml
we allow Internet connections from our application via:
<uses-permission android:name="android.permission.INTERNET" />
Screen Images of the Android Application
The previously shown Figures 1 - 4 in Part 1 of this series are the screen images of the native Android application.
Application Launch Icon
To create the launch icon for the News application, we followed the icon design guidelines for Android applications. In that resource, various templates in Adobe PSD format are available for download. We downloaded icon_templates-v2.0.zip
and extracted Launcher-icon-template.psd
. In that file, we selected two templates to create our launch icon:
We placed those templates in two separate layers in Adobe Photoshop and added a graphical text, News
, on an additional layer at the top to compose the launch icon. Per the guideline, we created three versions of the icon for low, medium and high density screens with 36 x 36, 48 x 48, and 72 x 72 pixel sizes, respectively. Each of those icons is named icon.png
and they are placed in the Android project folders according to the following table:
Folder name | File name | Pixel size |
res\drawable-ldpi |
icon.png |
36 x 36 |
res\drawable-mdpi |
icon.png |
48 x 48 |
res\drawable-hdpi |
icon.png |
72 x 72 |
As an example, this is the 36 x 36 launch icon:
Native Android Application Development Environment
As part of this tutorial, we provided the necessary project files to import the native Android News application into Eclipse development environment. The project prerequisites are:
- Android SDK revision 8.
- Eclipse IDE version 3.5.
- Android Development Tools (ADT), which is an Eclipse plugin, version 8.0.1.
The project has been successfully tested against both Android platform 2.2 API level 8 and platform 2.3 API level 9.
Importing The Project
Before importing the project into your Eclipse environment, make sure that Eclipse ADT plugin points to the correct location of Android SDK in your local system. To check this, in the Eclipse menu go to Window -> Preferences -> Android
. The SDK Location
window must be set to the location of the Android SDK. Once set up correctly, you should see something similar to the image below:
The project files are provided in an archive file named news.zip
. To import the project in the Eclipse menu, go to File -> Import
and then in the file import wizard select General -> Existing Projects into Workspace
(see below).
On the next page of the wizard, choose the Select archive file
radio button and browse to where news.zip
is located in your file system. The Projects
window will be automatically populated where the News
project is already selected. This is shown below. Press the Finish
button to complete the import.
Eclipse will build the application automatically after import. Now, you should see the News project in the project explorer, as shown below:
For building/debugging your project, you can choose between Android OS 2.3 and 2.2 platforms as the build target. To do this, select the News
project in the project explorer and from the right-click menu choose Properties
. On the left hand side listing of properties, select Android
as the property. The available build targets are displayed on the right, as shown below:
File Listing
A listing of files in the project is given below.
We have already discussed some of those files. Below is a quick review/recap:
- The
src
folder contains the source code for theNewsActivity
class. - The
gen
folder contains the files automatically generated by Eclipse ADT. - The
assets\www
folder and its subfolders contain all the files needed for the UI, includingindex.html
;assets\www\css-js
has thecss
and JavaScript files used byindex.html
. In particular:-
jquery-1.4.4.min.js, jquery.mobile-1.0a2.min.js, jquery.mobile-1.0a2.min.css
are the jQuery Mobile framework libraries. -
jquery.ba-dotimeout.js
is the jquery-dotimeout-plugin library. -
jquery.dst.js
is the DST.js plugin library. -
assets\www\css-js\images\icons-18-white.png
is an image file referenced by the jQuery Mobile framework libraries.
-
-
assets\www\img\wait.gif
is the spinning icon used in progress page. - The
res\drawable*
folders store the launch icons, as discussed in the "Application Launch Icon" section of this tutorial. - The
res\layout\main.xml
file is the Android XML layout file. Since the UI in our application is defined inindex.html
using jQuery Mobile framework, this file is very simple and needs no further explanation. - We have already reviewed
res\values\strings.xml
andAndroidManifest.xml
. - The file
default.properties
defines the build target and is part ofnews.zip
. It will be overwritten by Eclipse ADT depending on your selection of the build target.
Conclusions
In addition to developing cross-platform mobile web applications, the jQuery Mobile framework can be used to implement native Android applications. In this tutorial series, we developed a web application using jQuery Mobile and then migrated it into a native Android application with only slight modifications. The main idea is to use the android.webkit.WebView
object as a container to run the html file of the web application and the jQuery Mobile JavaScript code it contains. Some closing remarks are given below.
- When packaged as part of a native Android application, an html page running in
android.webkit.WebView
is not subjected to same-origin restrictions when making AJAX calls. - The jquery-dotimeout-plugin and the DST.js plugin, although originally developed for the jQuery framework, perform well for jQuery Mobile. There are a vast amount of plugins written for jQuery and, although case-by-case analysis is needed, those might be readily available for jQuery Mobile. This is an immense asset for this new framework!
- We tested the web application with an Android OS 2.2 phone and an iPod Touch iOS 4.1 & 4.2. The native Android application was tested with Android OS 2.2 & 2.3 emulators and an Android OS 2.2 phone. In all cases, the look and feel and functional attributes were very similar.
- In the Android platform, there are known techniques to establish JavaScript-to-Java and Java-to-JavaScript method calls. In fact, we demonstrated how to call back a jQuery Mobile JavaScript function from Java code in our application. It is possible that with a reasonable amount of effort, one could develop jQuery Mobile plugins to access native Android APIs. This indicates further opportunities for the jQuery Mobile framework to develop native Android applications.
Comments