models to go: how we built a dsl for mobile apps with tools from the eclipse modeling project
DESCRIPTION
Thanks to the advent of almost ubiquitous mobile internet and fueled by thousands of add-on applications, smartphones enjoy an increasing popularity. Companies who want to reach their customers with mobile devices need to consider implementing their solutions for an ever increasing plethora of devices and platforms. Given the costs for multi-platform development, the million-dollar question is, can we build multi-platform applications which address the individual characteristics of the respective platforms without sacrificing stability and slick UIs? In this talk, we will explain how we built APPLause, a DSL for mobile apps, using model-driven approaches to enable us to target multiple platforms at once. We will show how we developed the language along the concepts of the supported platforms, while at the same time making sure the generated application can be extended manually where needed. The DSL we describe has been used to build the conference app for ESE (available for iPhone and Android) and is available as open source.TRANSCRIPT
Models To GoPeter Friese, itemis
Heiko Behrens, itemis
@peterfriese | @HBehrens@itemismobile
http://mobile.itemis.de
(c) 2010 Heiko Behrens & Peter FrieseMore info: http://www.heikobehrens.net / http://www.peterfriese.de / http://mobile.itemis.com
mobile is sexy
mobile is challenging
diversity of platforms
94 App Stores
two categories
countless devices
How can we address this diversity?
You can write amazing web apps that look exactly and behave exactly like apps on the iPhone
Steve Jobs, WWDC 2007
MOBILE WEB
server-side web
Device
Web Browser
Backend
Web Serverexecutes application
logic
Files Database
client-side web
Device
Web Browser
Backend
DatabaseFiles
JavaScriptexecutes application logic
hybrid app
Device
Native App
Browserexecutes JavaScript
JavaScript Bridge
Request Interceptor
Interpreter
Backend
interpreted app
Device
Native App
Application Script
interpreter
Backend
Files
Database
Generator Input
Device
Native App
Logic
Backend
Files
Database
Logic
Files
Database
DatabaseFiles
Modeldescribes logic andcomplete system
Generator
generated app
gain speed through restrictions
Lists Details Custom
http://www.flickr.com/photos/minifig/3174009125/
analyzing the problem
Anatomyof these apps
Cells
View
Navigation
NameImage
Speaker
TitleLocation
Session
Entity
Data Provider
demo
getting real
tabbarApplication itemisApp { button { title= "Tuesday" icon= "calendar.png" view= SessionList( SessionsByDay("0") ) }
button { title= "Wednesday" icon= "calendar.png" view= SessionList( SessionsByDay("1") ) } button { title= "Thursday" icon= "calendar.png" view= SessionList( SessionsByDay("2") ) } button { title= "Speakers" icon= "person.png" view= SpeakersList( AllSpeakers() ) }}
tabbarApplication itemisApp { button { title= "Tuesday" icon= "calendar.png" view= SessionList( SessionsByDay("0") ) }
button { title= "Wednesday" icon= "calendar.png" view= SessionList( SessionsByDay("1") ) } button { title= "Thursday" icon= "calendar.png" view= SessionList( SessionsByDay("2") ) } button { title= "Speakers" icon= "person.png" view= SpeakersList( AllSpeakers() ) }}
-(UIViewController*)createController {! itemisAppProviders *providers = [[[itemisAppProviders alloc] init] autorelease];! UITabBarController *result = [[UITabBarController alloc] init];! NSMutableArray *controllers = [NSMutableArray array];!! UIViewController<IPUIView> *controller;! UINavigationController *navController;! IPContentProvider *contentProvider;
! // controller for @"Tuesday"! contentProvider = [providers providerForSessionsByDay: @"0"];!! controller = [[SessionListViewController alloc] init];! [controller setContentProvider: contentProvider];! controller.tabBarItem.title = @"Tuesday";! controller.tabBarItem.image = [UIImage imageNamed:@"calendar.png"];! navController = [[UINavigationController alloc] initWithRootViewController:controller];! [controllers addObject: navController];! [controller release];! [navController release];
!! // controller for @"Wednesday"! contentProvider = [providers providerForSessionsByDay: @"1"];!! controller = [[SessionListViewController alloc] init];! [controller setContentProvider: contentProvider];! controller.tabBarItem.title = @"Wednesday";! controller.tabBarItem.image = [UIImage imageNamed:@"calendar.png"];! navController = [[UINavigationController alloc] initWithRootViewController:controller];! [controllers addObject: navController];! [controller release];! [navController release];
!! // controller for @"Thursday"! contentProvider = [providers providerForSessionsByDay: @"2"];!! controller = [[SessionListViewController alloc] init];! [controller setContentProvider: contentProvider];! controller.tabBarItem.title = @"Thursday";! controller.tabBarItem.image = [UIImage imageNamed:@"calendar.png"];! navController = [[UINavigationController alloc] initWithRootViewController:controller];! [controllers addObject: navController];! [controller release];! [navController release];
!! // controller for @"Speakers"! contentProvider = [providers providerForAllSpeakers];!! controller = [[SpeakersListViewController alloc] init];! [controller setContentProvider: contentProvider];! controller.tabBarItem.title = @"Speakers";! controller.tabBarItem.image = [UIImage imageNamed:@"person.png"];! navController = [[UINavigationController alloc] initWithRootViewController:controller];! [controllers addObject: navController];! [controller release];! [navController release];
! result.viewControllers = controllers;! return result;}
-(UIViewController*)createController {! itemisAppProviders *providers = [[[itemisAppProviders alloc] init] autorelease];! UITabBarController *result = [[UITabBarController alloc] init];! NSMutableArray *controllers = [NSMutableArray array];!! UIViewController<IPUIView> *controller;! UINavigationController *navController;! IPContentProvider *contentProvider;
! // controller for @"Tuesday"! contentProvider = [providers providerForSessionsByDay: @"0"];!! controller = [[SessionListViewController alloc] init];! [controller setContentProvider: contentProvider];! controller.tabBarItem.title = @"Tuesday";! controller.tabBarItem.image = [UIImage imageNamed:@"calendar.png"];! navController = [[UINavigationController alloc] initWithRootViewController:controller];! [controllers addObject: navController];! [controller release];! [navController release];
!! // controller for @"Wednesday"! contentProvider = [providers providerForSessionsByDay: @"1"];!! controller = [[SessionListViewController alloc] init];! [controller setContentProvider: contentProvider];! controller.tabBarItem.title = @"Wednesday";! controller.tabBarItem.image = [UIImage imageNamed:@"calendar.png"];! navController = [[UINavigationController alloc] initWithRootViewController:controller];! [controllers addObject: navController];! [controller release];! [navController release];
!! // controller for @"Thursday"! contentProvider = [providers providerForSessionsByDay: @"2"];!! controller = [[SessionListViewController alloc] init];! [controller setContentProvider: contentProvider];! controller.tabBarItem.title = @"Thursday";! controller.tabBarItem.image = [UIImage imageNamed:@"calendar.png"];! navController = [[UINavigationController alloc] initWithRootViewController:controller];! [controllers addObject: navController];! [controller release];! [navController release];
!! // controller for @"Speakers"! contentProvider = [providers providerForAllSpeakers];!! controller = [[SpeakersListViewController alloc] init];! [controller setContentProvider: contentProvider];! controller.tabBarItem.title = @"Speakers";! controller.tabBarItem.image = [UIImage imageNamed:@"person.png"];! navController = [[UINavigationController alloc] initWithRootViewController:controller];! [controllers addObject: navController];! [controller release];! [navController release];
! result.viewControllers = controllers;! return result;}
«Xpand»
«DEFINE moduleFile FOR Application»«FILE filenameApplicationDelegateModule()»#import "«filenameApplicationDelegateHeader()»"#import "IPUIView.h"#import "«filenameCentralProvidersHeader()»"
«EXPAND importStatements-»
@implementation «applicationDelegateClassname()»
@synthesize window, rootController;
-(UIViewController*)createController { «centralProvidersClassName()» *providers = [[[«centralProvidersClassName()» alloc] init] autorelease]; UITabBarController *result = [[UITabBarController alloc] init]; NSMutableArray *controllers = [NSMutableArray array]; UIViewController<IPUIView> *controller; UINavigationController *navController; IPContentProvider *contentProvider;
«EXPAND barControllerInstance FOREACH buttons»
result.viewControllers = controllers; return result;}
- (void)applicationDidFinishLaunching:(UIApplication *)application { self.rootController = [self createController]; [window addSubview: [self.rootController view]]; [window makeKeyAndVisible];}
- (void)dealloc { self.rootController = nil; [window release]; [super dealloc];}
@end«ENDFILE»«ENDDEFINE»
«DEFINE moduleFile FOR Application»«FILE filenameApplicationDelegateModule()»#import "«filenameApplicationDelegateHeader()»"#import "IPUIView.h"#import "«filenameCentralProvidersHeader()»"
«EXPAND importStatements-»
@implementation «applicationDelegateClassname()»
@synthesize window, rootController;
-(UIViewController*)createController { «centralProvidersClassName()» *providers = [[[«centralProvidersClassName()» alloc] init] autorelease]; UITabBarController *result = [[UITabBarController alloc] init]; NSMutableArray *controllers = [NSMutableArray array]; UIViewController<IPUIView> *controller; UINavigationController *navController; IPContentProvider *contentProvider;
«EXPAND barControllerInstance FOREACH buttons»
result.viewControllers = controllers; return result;}
- (void)applicationDidFinishLaunching:(UIApplication *)application { self.rootController = [self createController]; [window addSubview: [self.rootController view]]; [window makeKeyAndVisible];}
- (void)dealloc { self.rootController = nil; [window release]; [super dealloc];}
@end«ENDFILE»«ENDDEFINE»
«DEFINE barControllerInstance FOR TabbarButton» «IF view.provider != null» // controller for «this.title.expression('', '')» contentProvider = «view.provider.contentProvider('providers', '', '')»; «ENDIF» controller = [[«view.view.className()» alloc] init]; [controller setContentProvider: contentProvider]; controller.tabBarItem.title = «title.expression('', '')»; controller.tabBarItem.image = [UIImage imageNamed:«this.icon.expression('','')»]; navController = [[UINavigationController alloc] initWithRootViewController:controller]; [controllers addObject: navController]; [controller release]; [navController release];«ENDDEFINE»
tool integration
demo 2
Objective-C
Simulator
Device
Java
Device
Simulator
DSLdescribes application
developer’s point of view
Grammardescribes DSL
«Xpand»Parser
Editor
TemplatesiPhone
TemplatesAndroid
EMF MM
toolsmith’s point of view
Objective-C
Simulator
Device
Java
Device
Simulator
DSLdescribes application
Grammardescribes DSL
«Xpand»Parser
Editor
TemplatesiPhone
TemplatesAndroid
EMF MM
applauseAPPlause
http://code.google.com/p/applause/
http://mobile.itemis.de
@peterfriese | http://peterfriese.de@hbehrens |!http://heikobehrens.net