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.