EXPLORING CROSS-PLATFORM MOBILE APPLICATION DEVELOPMENT A Project

advertisement
EXPLORING CROSS-PLATFORM MOBILE APPLICATION DEVELOPMENT
A Project
Presented to the faculty of the Department of Computer Science
California State University, Sacramento
Submitted in partial satisfaction of
the requirements for the degree of
MASTER OF SCIENCE
in
Computer Science
by
Iryna Paliychuk
FALL
2012
EXPLORING CROSS-PLATFORM MOBILE APPLICATION DEVELOPMENT
A Project
by
Iryna Paliychuk
Approved by:
__________________________________, Committee Chair
Dr. Jinsong Ouyang
__________________________________, Second Reader
Dr. Chung-E Wang
____________________________
Date
ii
Student: Iryna Paliychuk
I certify that this student has met the requirements for format contained in the University format
manual, and that this project is suitable for shelving in the Library and credit is to be awarded for
the project.
__________________________, Graduate Coordinator
Dr. Nik Faroughi
Department of Computer Science
iii
___________________
Date
Abstract
of
EXPLORING CROSS-PLATFORM MOBILE APPLICATION DEVELOPMENT
by
Iryna Paliychuk
Many people consider mobile development to be a big next step in the software world,
just like client-server architecture was in 1990s, or web development 2000s [1]. I am in
their numbers and think that mobile development skills are necessary for a career as a
software professional these days. When a new system is designed, if the mobile platform
doesn’t take the main focus at least the extension of mobility is present. The challenge
comes with the variety of smartphone platforms introduced in recent years. Being
proficient in one of the programming languages, how can we capture the maximum
number of platforms without starting each platform specific app implementation from
scratch? For software engineers that are experienced in C# programming language, the
answer is MonoCross open source framework and MonoDevelop IDE for iPhone and
Android and Visual Studio 2010 IDE for Windows Phone 7. For this project, I took the
opportunity to learn and utilize the latest available technologies. I wrote a simple
smartphone app for iPhone, Android, and Windows Phone 7.
_______________________, Committee Chair
Dr. Jinsong Ouyang
_______________________
Date
iv
DEDICATION
This work is dedicated to my friend
who is excited to see this app in App Stores and to start using it.
v
ACKNOWLEDGEMENTS
I would like to thank my advisor, Dr. Jinsong Ouyang, for his time and suggestions that
made this project more challenging and interesting.
vi
TABLE OF CONTENTS
Page
Dedication ..................................................................................................................... v
Acknowledgements ..................................................................................................... vi
List of Tables .............................................................................................................. ix
List of Figures ............................................................................................................... x
Chapter
1. INTRODUCTION ....................................................................................................1
2. DEVELOPMENT ENVIRONMENT ........................................................................2
2.1 Development Tools for Windows Phone 7 ......................................................2
2.2 Development Tools for iOS ..............................................................................2
2.3 Development Tools for Android .......................................................................3
3. CASE STUDY .......................................................................................................... 4
3.1 Expense Management Description ............................................................. 6
3.2 Requirements ...............................................................................................6
3.3 User Interface Design ................................................................................. 7
3.4 View Models ..............................................................................................11
3.5 Data Model.................................................................................................13
3.6 Core Functionality .....................................................................................14
3.7 Implementation ..........................................................................................14
3.7.1 Data Service Implementation ......................................................16
3.7.2 Application Layer Implementation .............................................23
3.7.2.1 Connecting to Azure Cloud ...........................................24
3.7.2.2 Controller Implementation .............................................25
3.7.3 Presentation Layer Implementation ............................................35
3.7.3.1 Platform Specific Views ................................................35
3.7.3.2 iOS View Implementation .............................................37
vii
3.7.3.3 Android View Implementation ......................................42
3.7.3.4 Windows Phone View Implementation ..........................46
3.8 Solution Organization ................................................................................50
4. CONCLUSION AND FUTURE WORK ................................................................52
References ................................................................................................................... 54
viii
LIST OF TABLES
Tables
Page
2.1 OS Requirements for Target Platform ...................................................................... 2
ix
LIST OF FIGURES
Figures
Page
3.1 Architecture with Platform Specific AL .................................................................. 4
3.2 Architecture with Shared AL ................................................................................... 5
3.3.1 Activity Diagram ................................................................................................... 7
3.3.2 Category List Screen on iPhone, Android, and Windows Phone 7 ....................... 8
3.3.3 Category Items Screen on iPhone, Android, and Windows Phone 7..................... 8
3.3.4 Item Details Screen on iPhone, Android, and Windows Phone 7 ......................... 9
3.3.5 Category Screen on iPhone, Android, and Windows Phone 7 .............................. 9
3.3.6 Report Filters Screen on iPhone, Android, and Windows Phone 7 ..................... 10
3.3.7 Report Screen on iPhone, Android, and Windows Phone 7 ................................ 10
3.7.1 Application Architecture ...................................................................................... 15
3.7.1.1 Data Service Solution ....................................................................................... 16
3.7.2.1 Traditional MVC (left) vs. MonoCross MVC Pattern (right) ........................... 24
3.7.3.1.1 Presentation Layer Project for iOS, Android, and Windows Phone 7 ........... 36
3.8.1 Solution Organization for Windows Phone 7, Android, and iOS ........................ 50
x
1
CHAPTER 1
INTRODUCTION
When Apple came along with the iPhone, Google introduced the Android and Windows
presented the Windows Phone 7, cross-platform mobile application development become
centric. Software professionals started looking for a way to capture as many customers as
possible with a minimum investment in effort and cost of development. Many developers
turned to HTML5 as a solution to their cross-platform applications. While most mobile
browsers support HTML5, there are some things a web-based application cannot do.
Access to a device’s native features – such as GPS, camera, accelerometer, file access
and storage - all require interactions via native frameworks [1]. Alternatively, Xamarin
provided a compelling path toward enabling code reuse and code sharing principles by
software developers when writing native applications in C# for Android and iOS devices.
The release of MonoTouch and Mono for Android enabled .Net developers to deliver the
cross-platform native applications with a single language - C# - and framework - .NET –
across the dominant smartphone and tablet platforms: iOS, Android and Windows. I took
one of the above approaches for this project and implemented a native client for iPhone, Android
and Windows Phone 7.
2
CHAPTER 2
DEVELOPMENT ENVIRONMENT
Windows 7 OS requires Visual Studio 2010 IDE while Mac OSX requires MonoDevelop
IDE for iPhone and Android. The operating system and hardware requirements are
presented in the table below.
Development Target
iOS/MonoTouch
Android/Mono for Android
MAC OS
X
(Intel base Macintosh
running OSX10.6 or newer)
X
Windows
Windows Phone
X
X
Table 2.1: OS Requirements for Target Platform [1]
2.1 Development Tools for Windows Phone 7
Visual Studio 2010 or newer is required for Windows Phone 7 application development.
I used a copy of Ultimate version for this implementation. With the upcoming release of
Visual Studio 2012, development for Windows Phone 8 will be available. However,
Windows Phone 8 development requires Windows 8 OS. When Visual Studio 2010 is
installed, Visual Studio Service Pack needs to be downloaded and executed. In order to
start the development of Windows Phone apps, the Windows Phone SDK 7.1 has to be
installed since Visual Studio 2010 out-of-the-box doesn’t include it.
2.2 Development Tools for iOS
iOS application development requires MonoDevelop IDE; optionally it can be used for
Android app development. I used MonoDevelop 3.0.4.7 version downloaded from
http://monodevelop.com/download for both iOS and Android development. In addition to
3
MonoFramework and MonoDevelop IDE, Xcode and the iOS SDK need to be installed.
The download of the last two requires an Apple ID, which is free. When all components
mentioned above are installed, MonoTouch trial version from http://xamarin.com/trial is
required since it generates native code from compiled .Net assemblies using iOS SDK
and its compiler. The licensed version is essential for publishing the application to the
App Store, otherwise the trial version will suffice.
2.3 Development Tools for Android
Mac OSX 10.7 doesn’t require JDK, but for previous OSX versions it needs to be
installed prior to any other installations. The next step is Android SDK installation from
http://developer.android.com/sdk. The entire package is quite large, so I selected only
two versions - 2.2 and 3.5 - in addition to SDK Platform tools. Mono for Android uses
these tools to package and deploy the solution. Unlike the Windows Phone emulator and
iOS simulator, Android emulators must be created and configured which has positive and
negative aspects. The positive one enables a developer to test and debug the application
targeting a specific device version while the disadvantage is the additional time needed
during the debugging.
4
CHAPTER 3
CASE STUDY
The case study, Expense Management, is a simple CRUD (Create, Read, Update, and
Delete) smartphone application. I intentionally selected a simple application so that I
could concentrate on the architecture of cross-platform development with a focus on code
sharing rather than on the app’s functionality or complexity. My original implementation
of this app for all three platforms was no different from regular client-server architecture,
where a server side is shared between platforms and each client is implemented
separately for a specific platform. The only advantage in my initial approach was a single
programming language – C# - and .Net Framework for all three platforms.
Figure 3.1Architecture with Platform Specific AL
5
After getting familiar with MonoCross open source framework, I reviewed my original
implementation and was able to extract the Application Layer (AL) to the code shared
between platforms.
Figure 3.2Architecture with Shared AL
By choosing the MonoCross platform with AL sharing implementation, I noticed a
tremendous reduction in the effort and time invested. In addition, I am confident that
adding a new client for example windows desktop standalone client or event web based
client that communicates to AL will take minimal effort and time.
6
3.1 Expense Management Description
The Expense Management app is designed to help an end user to shop while replacing the
need for a piece of paper and a pencil to mark what items a customer has already placed
in the shopping cart. The only requirement will be to start the application, select the
picked item and mark it as done. Additionally, a user can enter an item’s price while
marking it, where it automatically accumulates and adds to the other items’ prices and
keeps purchase dates of each item for reporting purposes. Another benefit of this
application is awareness of the shopping cart cost before checking out at the cash register.
From a long-term spending standpoint, a user can create a category and specify items per
category that need to be purchased at some point in time. The idea of category is for
organized layout and functionality organization. At any moment, a user can pull a report
of spending based on the date range and spending view that can be grouped by category
or itemized.
3.2 Requirements
The first step in designing an application is to identify the features it needs to have. The
Expense Management app has the following goals:
1. View a list of categories
2. Ability to add and delete a category
3. View a list of items in a category
4. Ability to add, edit and delete a category item
7
5. Generate an itemized or grouped by a category report of spending for a particular
date range
3.3 User Interface Design
Designing the UI for smaller screens requires a careful consideration to what should be
placed on each screen to keep it simple and to what activity flow provides the most
natural navigation. The activity flow is important to define before starting
implementation to ensure that every screen has an entry point, an exit point and that
navigation is consistent between platforms. The Expense Management application has the
following activity flow.
Figure 3.3.1 Activity Diagram
In the diagram above, the green smaller boxes contain descriptions of the actions that can
be taken from the screen. The blue boxes identify the screen and the data displayed. The
details of each screen are illustrated below.
8
Figure 3.3.2 Category List Screen on iPhone, Android, and Windows Phone 7
Figure 3.3.3 Category Items Screen on iPhone, Android, and Windows Phone 7
9
Figure 3.3.4 Item Details Screen on iPhone, Android, and Windows Phone 7
Figure 3.3.5 Category Screen on iPhone, Android, and Windows Phone 7
10
Figure 3.3.6 Report Filters Screen on iPhone, Android, and Windows Phone 7
Figure 3.3.7 Report Screen on iPhone, Android, and Windows Phone 7
11
3.4 View Models
The cross-platform MVC pattern (presented later in 2.7.2) requires that each screen data
was loaded from a corresponding model that represents its view. In other words the
model data should be sufficient to render the view and populate all screen controls with
data. The Expense Management application requires four view models to represent the
six views above:
1. List<string> model for Category screen
It is recommended for mobile applications development, to deliver the
information the end users need at the time they need it for performance
optimization. Since the category is the only property from ShopListItem class
visible on this screen, I chose a list of strings as the model for category screen by
extracting distinct categories from a list of items saved in the database.
2. CategoryItems model for Category Items and Report screens
This model contains all properties necessary to display items under the selected
category or the purchased items in the report view. The main component of this
12
model is a list of items - Items. Total is the supplementary member used to
inform the total value of checked items’ or accumulated items’ values in the
report. To avoid hardcoding and still keep the same format I added TotalToString
member that represents formatted Total with a currency sign ready for display on
all platforms. The Header property is used in the report view only to indicate the
report date range.
3. ShopListItem model for Item Details and Category screens
This model contains all information necessary to present an item in the Item
Details screen. The same model is used for adding a new category. In the case of a
new category, it makes sense to use ShopListItem and not a
string
as a model,
since a new item is created in the database for a newly added category.
4. ReportFilters model for Report Filters screen
public class ReportFilters
13
{
public ReportFilters()
{
End = DateTime.Now;
Start = End.AddMonths(-1);
Group = false;
}
public DateTime Start { get; set; }
public DateTime End { get; set; }
public bool Group { get; set; }
}
ReportFilters model is designed to populate the report criteria screen with default
values. The default date range for a report is one month, ending with the current date.
Sum by Category checkbox defines a report type. If this checkbox is not selected, the
generated report is built on the list of items purchased during the specified date range
otherwise it is built of the list of the items’ categories with a total accumulated per
category.
3.5 Data Model
The Expense Management app has very simple data storage needs. It requires only the
following properties for each item:
1. ID – int, primary key
2. Name – nvarchar(50)
3. Notes – nvarchar(50)
4. Category – nvarchar(50)
5. Done – bit
6. DateAdded – datetime
7. DateModified – datetime
14
3.6 Core Functionality
The Expense Management core functionality uses the following methods to meet the
application requirements:
1.
Get all distinct categories – to display a list of all available categories on the main
screen
2. Get category items – to display a list of category items on a particular category
selection
3. Delete a category – to delete a category with all items it contains on a particular
category row hold
4. Get an item – to display an item’s details on this item row touched
5. Delete an item – to delete an item on this item row hold
6. Save an item – to update an existing item or insert a new item per category or
save a newly added category as a default item with assigned category
3.7 Implementation
The Expanse Management app is a Service Oriented Architecture (SOA) app that utilizes
the well-known client-server approach. The server part is stored in the Windows Azure
cloud and the client part utilizes MonoCross framework to accomplish the application
layer (AL) sharing between platforms. The AL consumes the data service core
functionality methods and populates views with the retrieved data.
15
Figure 3.7.1 Application Architecture
The Expanse Management app consists of three main architectural components:
1. Data Service - a single implementation project exposed with WCF SOAP to be
consumed by a client and hosted together with the database in the cloud.
2. Application Layer (AL) – a single code implementation shared between platforms
through linking the implemented classes to the platform specific projects so that
platform specific presentation layer projects can reference them. AL is a client of
the Data Service and the source of presentation layer views.
16
3. Presentation Layer (PR) – is a platform specific implementation and is built of UI
control layouts for rendering view models defined by AL.
3.7.1 Data Service Implementation
The data service consists of three projects:
1. Data Service project that generates the dynamic queries based on the
parameters in an intended functionality, establishes a connection to the database and
executes these queries
2. WCF project that exposes data services to the client through SOAP
3. Windows Azure deployment project
Figure 3.7.1.1 Data Service Solution
17
The core functionality of this application is implemented in the DataAccess where view
models’ data and the user requests are converted into the database SQL statements.
1. GetItem() – to retrieve an item data by id and populate the ShopListItem model
using LINQ.
public ShopListItem GetItem(int id)
{
ShopListItem item = null;
DataTable dt = this.connectDS.GenericQuery("SELECT * FROM ShopList WHERE
ID=" + id);
if (dt != null && dt.Rows.Count > 0)
{
var query = from dr in dt.AsEnumerable()
select new ShopListItem()
{
ID = (dr.Field<int?>("ID").HasValue) ?
dr.Field<int?>("ID").Value : 0,
Name = dr.Field<string>("Name"),
Category = dr.Field<string>("Category"),
Notes = dr.Field<string>("Notes"),
Price = (dr.Field<double?>("Price").HasValue) ?
dr.Field<double?>("Price").Value : 0,
Done = (dr.Field<bool?>("Done").HasValue) ?
dr.Field<bool?>("Done").Value : false,
DateAdded = (dr.Field<DateTime?>("DateAdded").HasValue)
? dr.Field<DateTime?>("DateAdded").Value : DateTime.MinValue,
DateModified =
(dr.Field<DateTime?>("DateModified").HasValue) ?
dr.Field<DateTime?>("DateModified").Value :
DateTime.MinValue
};
if (query != null)
{
if (query.Count() > 0)
{
foreach (var q in query)
{
item = new ShopListItem()
{
ID = q.ID, Name = q.Name,
Notes = q.Notes, Category = q.Category,
Price = q.Price, Done = q.Done,
DateAdded = q.DateAdded, DateModified = q.DateModified
};
}
}
}
}
return item;
18
}
2. GetCategories() - to retrieve a list of distinct categories for the default app view
public IEnumerable<string> GetCategories()
{
List<string> categories = new List<string>();
DataTable dt = this.connectDS.GenericQuery("SELECT DISTINCT(Category)
FROM ShopList WHERE Category IS NOT NULL");
if (dt != null && dt.Rows.Count > 0)
categories = (from dr in dt.AsEnumerable() select
dr.Field<string>("Category")).ToList();
return categories;
}
3. DeteleCategory() – to delete all category items from a table by a category name
public bool DeleteCategory(string category)
{
bool success = false;
try
{
this.connectDS.GenericNonQuery("DELETE FROM ShopList WHERE
Category='"+category+"'");
success = true;
}
catch (Exception ex)
{
throw ex;
}
return success;
}
4. GetItemByCategory() – to retrieve all category items by category name
public IEnumerable<ShopListItem> GetItemsByCategory(string cat)
{
List<ShopListItem> items = null;
DataTable dt = this.connectDS.GenericQuery("SELECT * FROM ShopList WHERE
Category='" + cat + "'");
#region populated list of items with LINQ collapsed
return items;
}
19
5. SaveItem() – to update an item’s data if this item id is greater than zero, otherwise
insert an item to the table
public int SaveItem(ShopListItem item)
{
DataTable dt = null;
if(item.ID > 0)
this.connectDS.GenericNonQuery("UPDATE ShopList SET " +
"Name = '" + item.Name + "', "+
"Notes='" + item.Notes + "', "+
"Category='" + item.Category + "', " +
"Price=" + item.Price + ", " +
"Done= " + ((item.Done) ? '1' : '0') +
", "+ "DateModified='" +
DateTime.Now.ToString() + "' WHERE ID=" + item.ID);
else
dt = this.connectDS.GenericQuery("INSERT INTO ShopList " +
"(Name, Notes, Category, Price, Done, DateAdded, DateModified)" +
" Values "+
" ('" + item.Name + "', '" + item.Notes + "', '" + item.Category + "',
" + item.Price + ", " + ((item.Done) ? '1' : '0') + ", '" +
DateTime.Now.ToString() + "', '"
+ ((item.Done) ? DateTime.Now.ToString() : string.Empty ) + "' )"
+ " SELECT @@IDENTITY"
);
if (dt != null && dt.Rows.Count > 0)
{
int id = item.ID;
int.TryParse(dt.Rows[0][0].ToString(), out id);
item.ID = id;
}
return item.ID;
}
6. DeleteItem() – to delete an item from a table by item id
public int DeleteItem(int id)
{
this.connectDS.GenericNonQuery(" DELETE FROM ShopList WHERE ID="+id);
return id;
}
7. GetReport() – to retrieve all items from the database that were purchased during a
specified date range. If group by category parameter is set to true, I utilized LINQ
to group found items by category and accumulate the grouped items’ total.
20
public IEnumerable<ShopListItem> GetReport(DateTime start, DateTime end,
string done)
{
List<ShopListItem> items = null;
string sql = string.Empty;
sql = "SELECT * FROM ShopList WHERE DateModified >= '" + start + "' ";
sql += " AND DateModified <= '" + end + "' AND Done = '1' ORDER BY
Category";
DataTable dt = this.connectDS.GenericQuery(sql);
#region populate items from dt collapsed
if (done != null && done.ToUpper() == "TRUE")
{
List<ShopListItem> categories =
(
from p in items
group p by p.Category into g
select new ShopListItem
{
Category = string.Empty,
Price = g.Sum(p => p.Price),
Name = g.Key,
Notes = string.Empty,
ID = -1,
Done = true,
DateModified = g.Max(p=>p.DateModified)
}
).ToList();
items = categories;
}
}
return items;
}
DataSourceConnection class opens the connection to the database, executes all dynamic
queries built in the DataAccess class and closes the connection to the database. Any
“SELECT” statements are executed with the GenericQuery() method that takes a SQL
statement as a parameter in.
public DataTable GenericQuery(string sql)
{
DataTable dt = new DataTable();
21
using (SqlConnection m_Connection = new SqlConnection(connectionString))
{
m_Connection.Open();
using (SqlCommand comm = new SqlCommand(sql, m_Connection))
{
using (SqlDataAdapter data = new SqlDataAdapter())
{
data.SelectCommand = comm;
data.Fill(dt);
m_Connection.Close();
}
}
}
return dt;
}
Any “NON-SELECT” SQL statements are executed with the help of the
GenericNonQuery() method that takes a SQL statement to be executed as a parameter in.
In the Expense Management app, this method is used for an item and a category
insertion or deletion.
public void GenericNonQuery(string sql)
{
DataTable dt = new DataTable();
using (SqlConnection m_Connection = new SqlConnection(connectionString))
{
m_Connection.Open();
using (SqlCommand comm = new SqlCommand(sql, m_Connection))
{
comm.ExecuteNonQuery();
m_Connection.Close();
}
}
}
The ExpenseServiceWCFRole project exposes the core functionality implemented in the
DataService project to the client. The ShopListService class implements the
IShopListService
interface which is designed for interactions with a client.
22
[ServiceContract]
public interface IShopListService
{
[OperationContract]
IEnumerable<ShopListItem> GetItemsByCategory(string category);
[OperationContract]
ShopListItem GetItem(int id);
[OperationContract]
int SaveItem(ShopListItem item);
[OperationContract]
int DeleteItem(int id);
[OperationContract]
IEnumerable<string> GetCategories();
[OperationContract]
bool DeleteCategory(string cat);
}
The interface is annotated with the ServiceContract to define the service contract and
each method of this interface with the OperationContract - to be included as a service
operation in the WSDL document. ShopListService class implements this interface and
calls the Data Service’s core functionality methods.
public class ShopListService : IShopListService
{
private DataAccess DA = new DataAccess();
public ShopListItem GetItem(int id)
{
return DA.GetItem(id);
}
public int SaveItem(ShopListItem item)
{
return DA.SaveItem(item);
}
public int DeleteItem(int id)
{
return DA.DeleteItem(id);
}
public IEnumerable<ShopListItem> GetItemsByCategory(string category)
23
{
return DA.GetItemsByCategory(category);
}
public IEnumerable<string> GetCategories()
{
return DA.GetCategories();
}
public bool DeleteCategory(string cat)
{
return DA.DeleteCategory(cat);
}
I have chosen the Azure cloud as a host for the database and service due to the simple
navigation in the Azure portal and convenient deployment of the service to a cloud.
In order to implement this cloud application, Azure SDK is required, which can be found
at http://www.windowsazure.com/en-us/develop/overview/?campaign=getstarted.
When WCF Data Service (ExpenseServiceWCFRole) implementation was completed, I
generated a cloud deployment project with the following steps:
1. Select the ShopList.DataService project in Visual Studio 2010 solution
2. Right–click the project and select Add Windows Azure Deployment Project from
the context menu to create a deployment project. A newly created project was
ready to deploy to the cloud.
3.7.2 Application Layer Implementation
The Expense Management AL implementation is shared between platforms; the same
source classes are linked or added as existing classes to platform specific projects. The
sharing of AL is accomplished by adhering MVC pattern with Separated Interface and
24
utilizing MonoCross framework - all controller classes are derived from
MXContoller<T> abstract class.
The separation between View and Controller in the MonoCross pattern facilitates the
separation of the platform specific presentation layer from the cross-platform application
shared code [1]. This separation enabled my building of customized views for each
platform without regard to how they will be bound to the model and rendered in the
application.
Figure 3.7.2.1 Traditional MVC (left) vs. MonoCross MVC Pattern (right) [1]
The only requirement for a view was the Separated Interface implementation in order for
it to be processed and appropriately rendered by a controller.
The Expense Management AL has two main functions: first - interacting with cloud Data
Service on behalf of the presentation layer; second – implementation of the MVC pattern
controllers.
3.7.2.1 Connecting to Azure Cloud
When data services are hosted and activated in the cloud, they are ready to be consumed
by mobile clients. To establish this communication between clients’ AL and the cloud, I
used slsvcutil to generate a client proxy. The steps to generate this proxy are:
1. Open a Visual Studio 2010 Command Prompt
25
2. Navigate through the command prompt to a directory where SLSvcUtil.exe
resides, in my case it was C:\Program Files (x86)\Microsoft
SDKs\Silverlight\v4.0\Tools\
3. Run slsvcutil.exe http://shoplist.cloudapp.net/ShopListService.svc
/out:C:\MyProxy\ShopListProxy.cs to generate a proxy class in MyProxy
directory on drive C:\, where http://shoplist.cloudapp.net/ is the Data Service host
4. Add ShopListProxy.cs file to the shared AL code
After adding the proxy class to the application layer the ShopListServiceClient becomes
recognized and can be used for establishing communication with the Data Service.
ShopListServiceClient client = new ShopListServiceClient(
new BasicHttpBinding(),
new EndpointAddress("http://shoplist.cloudapp.net/ShopListService.svc"));
It is important to mention that a service call is asynchronous as all Silverlight
technologies are, and any Data Service method call should be implemented in the
following format:
ShopListServiceClient client = new ShopListServiceClient(
new BasicHttpBinding(),
new EndpointAddress("http://shoplist.cloudapp.net/ShopListService.svc"));
client.SaveItemCompleted += ((sender, e) =>
{
// populate model for PR
});
client.SaveItemAsync(item);
3.7.2.2 Controller Implementation
In the MVC patter, the controller populates the model with data and decides which view
should be rendered with the populated model. The Expense Management AL consists of
six controllers derived from MXController<T> class: CategoryController,
26
CategoryListController, ItemController, ItemListController, ReportController,
ReportCriteriaController. The generic type of MXController class – T is a model type.
Each of these controllers inherits a base class model.
MXController<T> is the MonoCross framework class that implements IMXController
interface with methods, properties and events necessary for the framework to trigger the
rendering of a platform specific view [1].
The requirements for any controller implementation of Expense Management AL:
1. Derived from MXController<T>, where T is a view model
2. Implement Load() method to populate or process model data
3. Implement as many as necessary private methods to successfully execute the
Load()
27
Examples of each controller implementation in the Expanse Management app.
1. CategoryListController is derived from MXController base class that sets a list of
strings as a model.
The Load() method takes a dictionary of strings as a parameter in, which in a
particular case is empty since it is a default view. The goal of the Load() method
is to populated a model with data, which is accomplished by calling a private
GetCategories() method. Since the call to the Data Services is asynchronous, I
enforced a delay before returning from the Load() method to ensure that the
model is populated. The last line in the Load() method – return value, defines
which view should be used for rendering model data. Since on application start of
PR this returned value is initialized with CategoryListView as shown below, the
CategoryListView is loaded with the model data.
28
2. CategoryController is derived from MXController base class and inherits
ShopListItem view model as a model for this controller. The overridden Load()
method takes a dictionary of strings as a parameter in with two members: Action
and CategoryName. Action value defines a category insertion or deletion event
performed on CategoryName value. If action is “GET” and CategoryName equals
“NEW”, then load an empty view by returning a value from the Load() method
that is initilized with a default CategoryView
To support Load() execution this controller has two private methods
3. ItemListController class is inherited from MXController that sets CategoryItems
view model as a model for this controller. The overridden Load() method finds a
category value for which items should be retrieved from a dictionary of strings – a
parameter in. The Data Service call is initiated through the private method
GetItems() to populate the model with the category items. When model is
populated, on exit from the Load(), the return value defines the view to be loaded
next, in a particular case it is ItemListView class due to the following
initialization.
29
The ItemListController class implementation:
4. ItemController class is inherited from the same base class as all the AL controllers
and operates on ShopListItem view model. The Load( ) method finds the
parameters’ values from the dictionary of parameters that are necessary to process
a user request. The most important parameter values are an action value that
defines the action to take and the updated model data. If action value is “NEW”,
the model is initialized with a new ShopListItem in the selected category and
ItemView is loaded -
30
due to the following initialization
If the action value is “GET” or “EDIT”, the model data is populated by calling the
private GetItem() method that invokes the Data Service method call to get an
item’s data. When data is returned, the controller model is populated and
ItemView is loaded.
If the action value is “DELETE”, the private method DeleteItem() call invokes the
Data Service method that removes an item from the database and redirects to the
updated category items list - ItemListView.
The redirection is done from the DeleteItem() on DeleteItemCompleted event
31
MXContainer.Instance.Redirect("Items/" + category);
The remaining two actions – “CREATE” and “UPDATE” - both execute by
calling the private UpdateItem() method on the modified model with a difference
in item id: “CREATE” - 0, “UPDATE” – a real item id. After the successful
execution of a model data update, a redirection to ItemListView takes place.
The private method that supports Load() activities:
The redirection to the next view from this controller is accomplished by returning
the string value from the Load() in some cases, and by calling Redirect() method
of the base class.
32
In order for this redirection to be enabled, the URI string that is used as a
parameter in to Redirect() method should be added to the navigation mapping on
application start under AL project.
5. ReportCriteriaController is derived from MXController<ReportFilters> with
ReportFilters view model.
The overridden Load() method creates a new instance of the model and
assigns it to be the controller’s model. When a new instance of
ReportFilters is created, the default values are assinged – the report date range
takes one month value and group by category is set to false.
The returned value from the Load() defines the ReportCriteriaView as the next
view to be loaded due to the following registration:
6. ReportController is derived from MXController<CategoryItem> base class which
defines CategoryItem view model as a model for this controller. The overridden
Load() method retrieves the parameters’ values set on previous view: start date,
end date, and group by. These values are used as parameters in, while invoking
33
the Data Service method call through the private GetReport() method to generate
the report.
When data is returned from the data service call, the post processing of returned data
takes place to prepare a model for the view by populating this view model’s
properties - Items, Header, and TotalToString - as shown above in the GetReport()
method. When model is populated the returned value from the Load() determines that
ReportView should be loaded next due to the following initialization.
34
The navigation between the Expense Management views is accomplished with URI –
based navigation from the MonoCross framework. This navigation is based on RESTful
routing principles. Each controller in the application is associated with one or more URI
endpoints that uniquely identify its place in the application workflow. Each action in the
application, whether it is selecting a category item to view this item’s details or saving a
category, is represented as navigation to one of these controller’s endpoints. To utilize
MonoCross navigation, all Expense Management controllers are registered on the AL
application start and App class inherits from the abstract MXApplicaion class.
35
3.7.3 Presentation Layer Implementation
A view presents a model‘s data to a user and is specific per platform. The data
presentation varies due to platform control differences but the main common part is that
each view implements the Separated Interface and overrides base class Render() method.
The separation between views and controllers is accomplished with IMXView interface
of MonoCross framework, which is built of methods, properties and events necessary for
the MonoCross framework to initialize the rendering of a view from a controller [1].
3.7.3.1 Platform Specific Views
The Expense Management views have the same functionality across all platforms, the
same navigation structure and the same layout. These were not hard to achieve during my
original implementation, even without sharing the AL. However, switching between
platforms was not convenient due to each platform UI control specifics, navigations, and
solutions organization which wasn’t even close to the figure below - the latest
presentation project structure.
36
Figure 3.7.3.1.1 Presentation Layer Project for iOS, Android, and Windows Phone 7
The application layer sharing is achieved by MonoCross navigation structure between
views and controllers and their derivation from the MonoCross framework base classes
which not only made the solutions organized but also set a structure for any view class
among platforms.
The requirements for any view class while utilizing MonoCross framework:
1. Derived from a MonoCross platform specific container that sets the model type
for each view: MXPhonePage<T> (WP7), MXTouchTableViewController<T>
(iPhone) or MXListActivityView<T> (Android), where T is a model type for a
view
2. Implement Render() method; the model set by a controller should be displayed in
the corresponding view through this method
3. Implement any additional private classes or methods needed to render the model
data in a view
37
4. Implement navigation between screens, the button icons can be different but the
activity flow should adhere to Figure 3.3.1
5. Implement event handlers necessary to support the activity flow
The Expense Management presentation layer consists of six views: CategoryListView,
CategoryView, ItemListView, ItemView, ReportCriteriaView, and ReportView. I’ll use
the example of building ItemListView for each platform to highlight the specifics of view
implementation that meets the five requirements above.
3.7.3.2 iOS View Implementation
Expense Management app for iOS is initiated through a static Main function that calls
another static function on UIApplication class to create the application control.
public class Application
{
static void Main (string[] args)
{
UIApplication.Main (args, null, "AppDelegate");
}
}
The application delegate, AppDelegate class, handles the app initialization and
registration of the platform specific views. The views need to be added to the model-view
mapping under a platform specific container the same way the AL controllers are
registered on the app start. This takes place in the overridden FinshedLaunching() method
of AppDelegate class.
38
MXTouchContainer is specific to iOS platform container from MonoCross framework.
An example of view implementation for iOS:
ItemListView is derived from MXTouchDialogView<CategoryItems> base class, which
in turn is derived from DialogViewController. CategoryItems is inherited from the base
class as a mode for this view. The overridden Render() method assigns a delegate class
and a data source to populate UI controls with data:
The delegate, TableViewDelegate class, is implemented within the view to handle an
item record selection through RowSelected event that redirects to a new view for editing
39
item and an item record hold event through a table edit mode activation that sets and item
deletion style.
The data source, TableViewDataSource class, is a private member of this view that
assigns model data to the cells which the table view uses to display the items as a user
scrolls through the list of items. In addition, the data source class assigns the total cost of
checked items to the table footer.
40
The table cells in this list view are formatted inside the overridden GetCell() method. If
an item is checked a checkbox will appear at the end of this item record, achieved by
setting the table cell accessory to a checkmark.
The item deletion on hold record event is accomplished by enabling a table editing mode,
following with the action to take when table edit mode set by a delegate is delete
41
The event handlers are implemented with a call of Navigate() method on the base class to
a controller associated with the specified URI and a set of parameters necessary to
complete the request, which in this particular case is a category name.
When a view is loaded, a new item button with its event handler is added to the
navigation bar by overriding ViewDidLoad()
A click on the add new button will invoke a controller registered for this particular URI
that defines which view to load to enable a new item entry for a user.
42
3.7.3.3 Android View Implementation
The Android application consists of one or more activities, and any activity can be an
entry point for the application by setting MainLauncher property to true. For Expense
Management application I set SplashScreenActivity class as an app entry point.
The initialization of all PR views for Android is done in the overridden OnCreate() of
SplashScreenActivity class.
An example of view implementation for Android:
ItemListView class is derived from MXListActivityView <CategoryItems> class which
in turn is derived from ActivityList - a class suitable for a list of items display.
CategoryItems is set as a view mode for this view within the base class. The overridden
43
Render() method finds the control layout between the Android resources to display the
checked items total cost and populates it with a model corresponding value. Additionally,
it assigns an adapter on base class list view and subscribes an item record long click event
handler for an item deletion.
The model data items are assigned to the view by a custom adapter class implemented
locally within a view. This adapter finds a list control defined in the resource layout and
populates the control with items data. The list layout declaration is below and follows
with the adapter implementation:
44
In addition to viewing items in the list and total cost display, the menu buttons - add new
and back - are added to the view within overridden OnCReateOptionsMenu() method.
This method finds a resource where these buttons are defined.
The resource item_list_menu.xml is built from a list of buttons to be included in the
navigation bar or menu.
45
When one of the menu options is selected, the ItemListView class invokes the
overriden method OnOptionItemSelected() that implements the navigation flow
An item deletion event handler is subscribed on the base list view within the Render()
method. Since an item deletion is permanent, before proceeding the AlertDialog checks
that the intended activity is valid and lets the flow continue on confirmation.
46
3.7.3.4 Windows Phone View Implementation
Windows Phone handles application initialization and the application events via App
class. The Expense Management views registration takes place in the constructor of this
class, where MXPhoneContainer is a platform specific container.
An example of view implementation for Windows Phone 7:
ItemListView class is inherited from MXPhonePage<CategoryItems> class with a
CategoryItems as a model for the derived class.
47
The overridden Render() method of this view assigns a model to this class DataContext
by taking advantage of built in data binding properties.
The assignment of the model to the class data context is not sufficient. The bindings of
the model members to the UI controls also need to be defined in the xaml file, and the
xaml file root tag should take a class name inherited from the same MXPhonePage BaseItemListView
<local:BaseItemListView>
<ListBox Name="lstItems" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Hold="Item_Delete" >
<TextBlock Text="{Binding Name}" />
<CheckBox IsChecked="{Binding Done}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</local:BaseItemListView>
The activity flow navigation is added to the ItemListView in the view constructor with
the InitAppBar() method.
48
The navigation control event handlers are implemented by navigation to the controllers
defined by the URI by invoking the base class Navigate() method.
The other event handlers on item select and on item hold are specified in xaml file of the
data grid control which is a parent control for a list box item.
To be consistent with other platfroms, before the selected item is deleted, a confirmation
to proceed with the current activity is enabled using MessageBoxResult popup.
49
The item selection event handler implementation is as follows where the selected item’s
category is retreived from the item‘s parent control.
The Expense Management PR code is more organized and has a clearly defined structure
of projects and classes with MonoCross framework. Switching between platforms is very
convenient and fast. Platform specifics become visible when a developer dives inside the
view class Render() method or runs the app. Even though there is a reduction in the lines
of written code, when I mentioned the tremendous reduction in effort and time earlier, it
was due to a clearly defined class structure with which the platform specifics become
50
insignificant. When I completed the implementation for one platform I could predict that
adding a presentation layer to a new platform would be a matter of hours and not days for
this simple app.
The main components of developing cross-platform applications with the MonoCross
MVC pattern are controllers that are shared between platforms, platform specific views
placed in their corresponding containers and URI and perspective-based navigation. The
base of platform specific implementation is the platform specific container, which is
responsible for implementing the navigation structure and creating and loading a model
via controller.
3.8 Solution Organization
Figure 3.8.1 Solution Organization for Windows Phone 7, Android, and iOS
The code organization becomes important during development of multi-platform
solutions. When the number of classes and projects grows, it becomes harder to navigate
through the code base. To address this issue I organized the solution identically in each
platform specific IDE, and this organization resembles the application architecture.
51
1. PR with views - (ShopList.WP7, ShopList.Droid, ShopList.iOS)
2. AL – controllers, shared between platforms
3. Framework – MonoCross containers and navigation classes consumed by AL and
PR
4. CommonLibrary – model classes, used throughout application
5. Data Service (Figure 3.7.1.1) – a separate solution for data processing in the cloud
52
CHAPTER 4
CONCLUSION AND FUTURE WORK
Throughout this project, I explored techniques for writing cross-platform mobile
applications. Some of them are new like storing WCF data service in a cloud or
MonoCross framework with MonoCross MVC pattern, and some of them are well
known, like SOA, WCF and C# programming language. MonoCross Framework enabled
me to implement a cross-platform mobile application for Android, iPhone and Windows
Phone 7 with maximum code reuse and high-quality native experience using a single
programming language – C#. Xamarin’s MonoTouch and Mono for Android provided me
with the ability to implement native user interface specifically for each of these
platforms. I will definitely apply these techniques to any future mobile development. My
suggestion for those who are looking for a cross-platforms solution is:
1. Use C# - code written in C# can be easily ported to iOS and Android.
2. Utilize the MonoCross MVC pattern – the application should be architected with
clearly defined Models/Views/Controllers and a separation between Models and
the rest.
3. Build native UIs – MonoTouch for iOS, Mono for Android for Android phone to
provide high–quality native UIs.
Future work with open source MonoCross framework can be extended to sharing
between platforms some component of the views that have the same functionality across
platforms, for example - menu control.
53
The application I developed in this project is not ready for production since there are
some enhancements that should be done before the release. The most important
enhancement is authenticating a user that will enable the items display per user or
multiple clients under the same use name. Another optional enhancement is storing data
locally on a device and synchronizing this data with the cloud data on application start or
end if internet connection is available. An interesting approach would be to extend this
application to be a hybrid application – when internet connection is available it performs
as a web application, when it is not available – as a native client.
54
References
1. Olson, Scott, John Hunter, Ben Horgen, and Kenny Goers. Professional CrossPlatform Mobile Development in C#. Indianapolis: John Wiley & Sons, Inc.,
2012.
2. Xamarin Documentation. [Online]. Available: http://docs.xamarin.com/
3. Cibraro, Pablo, Kurt Claeys, Fabio Cozzolino, and Johann Grabner. Professional
WCF 4 Windows Communication Foundation with .NET 4. Indianapolis: Wiley
Publishing, Inc., 2010.
Download