SlideShare uma empresa Scribd logo
1 de 53
How We Built a Mobile Electronic Health Record App
Using Xamarin, Angular, and Web API
About Matt Spradley
• Sr. Product Manager at Aprima
• Co-founded 3 software companies
• Used to write code
• Tinkers every now and then
• linkedin.com/in/mattspradley
• mattspradley.com
• matt.spradley@gmail.com
• 214-403-6749
How Should we Build a Cross Platform Mobile
App?
http://imgs.xkcd.com/comics/efficiency.png
Requirements
• Tablet 90% functional parity with desktop
EHR
• Work on iOS and Android phones and
tablets
• Integrate with on-premise servers
• No control over network (DNS, Firewall, etc.)
• Multiple versions of REST API
Test (POC) Don’t Guess
…And the Results
Score 66 64 63 53
Factor Weight HTML/Steroids HTML/Titanium Native/Xamarin Native
UX 3 2 2 3 3
Code Reuse 3 3 3 2 1
Special UI 1 1 2 3 3
Control 1 2 2 3 3
Effort 3 3 2 2 1
Maintenance 3 2 2 3 2
Cloud Reuse 1 3 3 1 1
OS Integration 2 2 2 3 3
Deployment Options 1 3 3 1 1
Existing Dev Skills 1 2 2 3 1
Hiring 2 2 2 3 2
Vendor Stability 3 2 2 2 3
UTDesign Decision 1 2 2 1 1
UI Testability 3 3 3 1 1
Winner???
Web UI with Angular Is Easy
<ul id="appointments" class="list-group list-group-fixed-height“
collapse="tileState.isCollapsed">
<li class="list-group-item" ng-show="!loading && appointments.length == 0">
<div class="col-xs-12 text-center-vert text-center">
<span translate>No appointments</span>
</div>
</li>
<li ng-repeat="appt in appointments | orderBy:'date'"
data-transition-to="{ appRoute: 'patientDashboard',
opts: {id: appt.PatientId}}"
class="list-group-item"
ng-class="{'active': (!!appt.clicked)}">
<ap-appointment-list-item
data-appt="appt"
data-context-menu-id="appt-context-menu-{{$index}}">
</ap-appointment-list-item>
</li>
</ul>
<div class="panel-body panel-flush" collapse="tileState.isCollapsed"
ng-if="!loading && !httpError">
<table class="table table-striped ap-table">
<thead>
<tr>
<th translate>Name</th>
<th ng-repeat="column in vitals.Columns | limitTo:observationLimit">
<ap-date-formatter date="{{column.ObservationDateTime}}“
format="short-date"></ap-date-formatter>
</th>
</tr>
</thead>
<tbody>
<tr ng-show="vitalsExist" ng-repeat="observations in vitals.Rows |
filter:hasValueForColumns">
<td>{{observations.Name}}</td>
<td ng-repeat="observation in observations.Observations |
limitTo:observationLimit"
ng-class="{danger: !observation.IsInRange && observation.Value}"
class="vital-value">
{{observation.Value}}
</td>
</tr>
<tr ng-if="!vitalsExist">
<td>
<span id="no-vital-results" translate>
No known vitals.
</span>
</td>
</tr>
</tbody>
</table>
</div>
Web UI with Angular Is Easy, Really
Code and Build
• Web UI
• Code in HTML, Less, AngularJS
• Build
• Grunt
• Less
• Template process
• JsHint
• Uglify
• Unit Tests w/ Jasmine and Karma
• Deploy
• Translate
• Images to Less
Chocolate and Peanut Butter
Our Customers LOVE Aprima NOW
Go Native with Xamarin for Hard Stuff
• For
• Taking Pictures
• Image Annotation
• PDF Viewer
• Why
• Flexibility
• C#
• Performance
• Custom UI
• Look and Feel
• Services
• Hiring
Xamarin Forms
Demo
Aprima NOW Hybrid Architecture
Javascript/HTML JS <--> Xamarin(C#) Bridge Xamarin(C#)
AngularJS App JS Bridge
Common
(portable class
library)
Xamarin.Android
Xamarin.iOS
Fire Event
Subscribe
SubscribeHandle Events
Handle Events
Fire Event or Subscribe
Invoke Callback from Subscription
AppServer
Javascript Bridge
Angular Service,
Ctrl etc
iOS JS Bridge
Android JS
Bridge
WinForms JS
Bridge
Fire Events to C#.
Subscribe to Events from C#
iOS C# Bridge
Android C#
Bridge
WinForms C#
Bridge
XHR to app:// window.AndrApp.Event(eventData); window.external.HandleEvent(eventData)
C# Objects
Fire Events to JS
Subscribe to Events from JS
webview.EvaluateJavascript(jsToFireEvent); Webview.LoadUrl( javascript:{jsToFireEvent} );
Webview.Document.InvokeScript( eval , jsToFireEvent );
Handle events from C#
Handle events from JS
Jsbridge.js
• JS object provides bridging capabilities to JS code
• Fire events to C#
• Add event handlers in JS to be called when event is fired from C#
• Bridge implementations for iOS, Android, and WinForms
• Normalizes event structure for consistency:
app://{module}/fireEvent?data={jsEventDataJson}&_={random}
C# -> JS event Firing
• To fire an event, call the following. BridgeContext is a bridge which is scoped to the UI WebView
component (iOS: UIWebView; Android: WebView; WinForms: Form/Control/etc)
this.BridgeContext.FireEvent(eventName, data);
• Which calls the following within the BridgeContext instance and actually dispatches the event to
javascript. ExecuteScript is implemented differently by each platform.
ExecuteScript(string.Format("bridge.app._dispatchEvent('{0}', {1});",
eventName, json));
iOS Jsbridge.js
• To send an event from JS to C#, iOS uses a custom NSUrlProtocol implementation
which listens for XHR traffic on a custom protocol (“app://”).
• To send event from JS to C#, an XHR request is made to custom protocol with
event data in the url.
function (url) {
var x1 = new bridge.app.CustomXhr();
x1.onerror = function (e) {
console.log('XHR error:' + JSON.stringify(e));
};
x1.open('GET', url);
x1.send();
}
iOS C# Bridge
• Registers global NSUrlProtocol handler, takes an instance of
UIWebView and bind global events to specific UIWebViews.
• To send event from C# to JS, executes dynamically generated JS which
calls into jsbridge.js component.
public override void ExecuteScript(string javascript)
{
webView.BeginInvokeOnMainThread(() => _webView.EvaluateJavascript(javascript));
}
iOS JavaScript Bridge Demo
Android jsbridge.js
• To send an event from JS to C#, Android uses a Java object which is made
accessible as a JavaScript object by adding the object instance to the Webview as
a JavaScript Interface.
• To send event from JS to C#, a method on the Java object instance is invoked from
JavaScript.
function (url){
var result = window.AndrApp.Event(url);
result = JSON.parse(result);
if (!result.Success) {
console.log('Android bridge error: ' + JSON.stringify(result));
}
}
Android C# bridge
• Instantiates and adds java object with [Export] or [JavascriptInterface] members. Members are
accessible from javascript.
webView.AddJavascriptInterface(new JsBridgeExports(this), "AndrApp");
• To execute a script, it loads a url which contains javascript to be executed:
public override void ExecuteScript(string javascript)
{
activity.RunOnUiThread(() => _webView.LoadUrl(string.Format("javascript: {0}", javascript)));
}
WinForms jsbridge.js
• To send an event from JS to C#, WinForms uses a C# object which is made accessible as a
Javascript object by adding the object instance to the WebView as the ObjectForScripting.
• To send event from JS to C#, a method on the C# object instance is invoked from javascript.
function (url) {
var result = window.external.HandleEvent(url);
result = JSON.parse(result);
if (!result.Success) {
console.log('PRM bridge error: ' + JSON.stringify(result));
}
}
WinForms C# bridge
• Instantiates and adds C# object to the WebBrowser instance as the ObjectForScripting.
ObjectForScripting must be have[ComVisible(true)]
this._browser.ObjectForScripting = new JsBridgeWindowExternalHandler(this);
To fire event from C# to JS, eval function is invoked from C# with a IIFE (Immediately Invoked Function Expression)
public override void ExecuteScript(string javascript)
{
_browser.Invoke(new Action(() =>
{
if (_browser.Document != null)
{
var script = string.Format("(function() {{ {0}; }})();", javascript);
_browser.Document.InvokeScript("eval", new object[] { script });
}
}));
}
JS Code to fire and listen for events
angular.module('amodule').controller('SomeCtrl',
['$scope', 'Bridge', function ($scope, Bridge){
//fire event
Bridge.navigate('aRoute', { id : 0 });
//listen for event
Bridge.on('someEvent', function (data) {
$scope.data = data;
});
}]
);
C# code to fire and listen for events
//Fire Event
this.BridgeContext.FireEvent("navigate", new { id = 0});
//listen to event
this.BridgeContext.AddEventListener("someEvent", (SomeType data) =>
{
//do something with data
});
Notes
• Bridge lifetimes vary by platform.
• iOS has a singleton bridge because NSProtocolHandler is added for an entire
application instead of for a specific UIWebView. iOS bridge has logic to broker
events to the correct bridge context which isassociated with a specific
UIWebView.
• Android bridges are instantiated per WebView instances
• WinForms bridges are instantiated per WebBrowser instance
• Native components must tell JS bridge which native implementation
is used. This can happen AFTER events have already been fired from
JS. This required queuing of events until the bridge was finished being
setup.
Notes
• Majority of code is in a PCL library and reused by all platforms
• Dll exists for each platform that contains platform specific code
• Very little platform specific code
• Bridge behavior consistent across the platforms
Frontend Tech Stack
• Xamarin
• Angular
• Bootstrap
• lodash
• Less
• Hammer.JS
Testing
http://www.idyllic-software.com/blog/category/ruby-on-rails/page/5/
Web UI is Easy to Test and Debug
Grunt Jasmine Protractor Webdriver E2E
Device Testing with Xamarin Test Cloud
Xamarin Test Cloud
Testing [Test]
public void PinchToZoom()
{
LoginPage.Login(app);
app.WaitForElement(x => x.Css("#dashboard"));
app.Screenshot("Then I am logged in at my home screen");
app.GoToPatients();
QuicksearchPage.SearchForPatient(app, "Anderson");
QuicksearchPage.SelectPatient(app, "e2ab0790-f271-471a-bdc2-e6bca0889dad");
app.WaitForElement(x => x.Css("#patient-widgets"), "Timed out waiting for patient
dashboard to load", new TimeSpan(0, 0, 3));
app.Screenshot("Then I see Jeff's profile");
PatientDashboardPage.ExpandWidget(app, PatientDashboardWidget.ObservationResults);
PatientDashboardPage.TapObservationResult(app, "3f39a0fa-99e9-494b-a234-170f3ff824ba");
Thread.Sleep(5000);
app.Screenshot("Now I should see the images");
//Scroll down to view first image
app.ScrollDownEnough(x => x.WebView().Css(".image-viewer"));
var rect = app.Query(x => x.WebView().Css(".image-viewer"))[0].Rect;
app.Zoom(rect.CenterX, rect.CenterY, 100);
app.Screenshot("Now I zoom in on the image");
}
Not All Web Browsers are Equal
iOS and Android Webview Update Differences
Inertial Scroll or EasyScroller
• Safari: Fixed DIVs Bad
• https://github.com/zynga/scroller
Xamarin Issues
• Constant updates
• Things break
• Universal API kerfuffle
• IDE lockups
• They’re still awesome and smart
http://www.doomsteaddiner.net/blog/wp-content/uploads/2013/04/wheels-off-hummer.png
Backend
• Web API
• OWIN
• Azure Relay
• SQL Server
• Feature List for Versions
• NEO (home brew ORM)
REST
Facade
App
Server
UI 1
UI 2
DBEF
Other
Aprima Mobile Application Architecture
Decoupled deployment from Aprima Main
On-Premise Server
Azure Relay WebHttpBinding
A Developer’s Guide to Service Bus in Windows Azure Platform
Service Bus Relay Web API Host
https://pfelix.wordpress.com/tag/asp-net-web-api/
Relay Demo
• By pass on-premise issues
• … and pesky IT road blocks
http://imgs.xkcd.com/comics/security.png
Azure Relay Performance
-100
0
100
200
300
400
500
600
700
800
Azure Ping1
(ms)
Relay Ping1
(ms)
Azure Ping2
(m2)
Relay Ping2
(m2)
Azure 5K (ms) Relay 5K (ms) Azure 10k
(ms)
Relay 10k
(ms)
Azure 50K
(ms)
Relay 50K
(ms)
Azure 500K
(ms)
Relay 500K
(ms)Average
Code Metrics
• Backend ≈ 50K lines
• 87% C#
• 10% Build scripts
• 3% Other
• Frontend ≈ 100K lines
• 59% JavaScript
• 30% HTML (HTML, CSS, Less)
• 8% C# (90% in common PCL)
• 3% Build scripts
It Works
Thanks to a Great Team
• Mobile Team
• Ryan Cady
• Kenneth Crawford
• Mike Duran
• Jeff Lott
• Contributors
• Doug Jost
• Chris Mojica
• Karl Shearer
• Design
• More Simple
Top Ten Rules of Software Development
1. Order the T-shirts for the Development team
2. Announce availability
3. Write the code
4. Write the manual
5. Hire a Product Manager
6. Spec the software (writing the specs after the code helps to ensure that
the software meets the specifications)
7. Ship
8. Test (the customers are a big help here)
9. Identify bugs as potential enhancements
10. Announce the upgrade program
http://www.nullskull.com/a/722/the-top-ten-rules-of-software-development.aspx
Links
• http://xamarin.com/
• https://angularjs.org/
• https://github.com/crdeutsch/MonoTouch-JsBridge
• http://zynga.github.io/scroller/
• https://pfelix.wordpress.com/tag/asp-net-web-api/
• Designing Evolvable Web APIs with ASP.NET
• https://github.com/pmhsfelix/WebApi.Explorations.ServiceBusRel
ayHost
• www.moresimple.com

Mais conteúdo relacionado

Mais procurados

Cross platform development
Cross platform developmentCross platform development
Cross platform development
dftaiwo
 
Building hybrid apps with Xamarin, Ryan Paul
Building hybrid apps with Xamarin, Ryan PaulBuilding hybrid apps with Xamarin, Ryan Paul
Building hybrid apps with Xamarin, Ryan Paul
Xamarin
 
PhoneGap Introduction
PhoneGap IntroductionPhoneGap Introduction
PhoneGap Introduction
Wen-Kai Huang
 

Mais procurados (20)

C# everywhere - Building Cross-Platform Apps with Xamarin and MvvmCross
C# everywhere - Building Cross-Platform Apps with Xamarin and MvvmCrossC# everywhere - Building Cross-Platform Apps with Xamarin and MvvmCross
C# everywhere - Building Cross-Platform Apps with Xamarin and MvvmCross
 
Xamarin microsoft graph
Xamarin microsoft graphXamarin microsoft graph
Xamarin microsoft graph
 
Cross Platform Development with Xamarin
Cross Platform Development with XamarinCross Platform Development with Xamarin
Cross Platform Development with Xamarin
 
MS Experiences 17 - Xamarin: Future of Mobile Development
MS Experiences 17 - Xamarin: Future of Mobile DevelopmentMS Experiences 17 - Xamarin: Future of Mobile Development
MS Experiences 17 - Xamarin: Future of Mobile Development
 
AnDevCon - Android and iOS Apps in C# with Xamarin
AnDevCon - Android and iOS Apps in C# with XamarinAnDevCon - Android and iOS Apps in C# with Xamarin
AnDevCon - Android and iOS Apps in C# with Xamarin
 
Introduction to CocosSharp
Introduction to CocosSharpIntroduction to CocosSharp
Introduction to CocosSharp
 
Xamarin DevOps
Xamarin DevOpsXamarin DevOps
Xamarin DevOps
 
Azure mobile services
Azure mobile servicesAzure mobile services
Azure mobile services
 
C# everywhere: Xamarin and cross platform development
C# everywhere: Xamarin and cross platform developmentC# everywhere: Xamarin and cross platform development
C# everywhere: Xamarin and cross platform development
 
Cross platform development
Cross platform developmentCross platform development
Cross platform development
 
Xamarin.forms Shell + Navigation
Xamarin.forms Shell + NavigationXamarin.forms Shell + Navigation
Xamarin.forms Shell + Navigation
 
Native Mobile Apps, Xamarin, and PhoneGap
Native Mobile Apps, Xamarin, and PhoneGapNative Mobile Apps, Xamarin, and PhoneGap
Native Mobile Apps, Xamarin, and PhoneGap
 
Xamarin Cross-Platform with Xamarin.Form, MvvmCross
Xamarin Cross-Platform with Xamarin.Form, MvvmCrossXamarin Cross-Platform with Xamarin.Form, MvvmCross
Xamarin Cross-Platform with Xamarin.Form, MvvmCross
 
COMAQA Conf #2. Никита Мещаненко. Xamarin test cloud
COMAQA Conf #2. Никита Мещаненко. Xamarin test cloudCOMAQA Conf #2. Никита Мещаненко. Xamarin test cloud
COMAQA Conf #2. Никита Мещаненко. Xamarin test cloud
 
Hybrid Mobile Development
Hybrid Mobile DevelopmentHybrid Mobile Development
Hybrid Mobile Development
 
.Net Standard Libraries and Xamarin
.Net Standard Libraries and Xamarin.Net Standard Libraries and Xamarin
.Net Standard Libraries and Xamarin
 
Building hybrid apps with Xamarin, Ryan Paul
Building hybrid apps with Xamarin, Ryan PaulBuilding hybrid apps with Xamarin, Ryan Paul
Building hybrid apps with Xamarin, Ryan Paul
 
Mobile development with xamarin
Mobile development with xamarinMobile development with xamarin
Mobile development with xamarin
 
PhoneGap Introduction
PhoneGap IntroductionPhoneGap Introduction
PhoneGap Introduction
 
Developing for the GeoWeb: Notes From The Field Dev Summit 2009
Developing for the GeoWeb: Notes From The Field Dev Summit 2009Developing for the GeoWeb: Notes From The Field Dev Summit 2009
Developing for the GeoWeb: Notes From The Field Dev Summit 2009
 

Destaque

Paul Mueller_Resume
Paul Mueller_ResumePaul Mueller_Resume
Paul Mueller_Resume
Paul Mueller
 
Qui és qui?
Qui és qui?Qui és qui?
Qui és qui?
Victoria
 
Final FaceView Mask Presentation
Final FaceView Mask PresentationFinal FaceView Mask Presentation
Final FaceView Mask Presentation
Alison Lillie
 

Destaque (20)

Custom HTML5-Native Bridge for Android
Custom HTML5-Native Bridge for AndroidCustom HTML5-Native Bridge for Android
Custom HTML5-Native Bridge for Android
 
Xamarin.Forms or Write Once, Run Anywhere
Xamarin.Forms or Write Once, Run AnywhereXamarin.Forms or Write Once, Run Anywhere
Xamarin.Forms or Write Once, Run Anywhere
 
салтыков
салтыковсалтыков
салтыков
 
Almacenamiento de Gas Natural
Almacenamiento de Gas NaturalAlmacenamiento de Gas Natural
Almacenamiento de Gas Natural
 
2010 NZJEL Appreciative Inquiry In Action
2010 NZJEL Appreciative Inquiry In Action2010 NZJEL Appreciative Inquiry In Action
2010 NZJEL Appreciative Inquiry In Action
 
Elizabeth calleja cuadro
Elizabeth calleja cuadroElizabeth calleja cuadro
Elizabeth calleja cuadro
 
Paul Mueller_Resume
Paul Mueller_ResumePaul Mueller_Resume
Paul Mueller_Resume
 
PTA Resume
PTA ResumePTA Resume
PTA Resume
 
Qui és qui?
Qui és qui?Qui és qui?
Qui és qui?
 
Aprima For Physicians
Aprima For PhysiciansAprima For Physicians
Aprima For Physicians
 
Bryly - projekt eukacyjny
Bryly - projekt eukacyjnyBryly - projekt eukacyjny
Bryly - projekt eukacyjny
 
Final FaceView Mask Presentation
Final FaceView Mask PresentationFinal FaceView Mask Presentation
Final FaceView Mask Presentation
 
The State of Email and Marketing Automation in South-East Asia
The State of Email and Marketing Automation in South-East AsiaThe State of Email and Marketing Automation in South-East Asia
The State of Email and Marketing Automation in South-East Asia
 
MA_RUIDO
MA_RUIDOMA_RUIDO
MA_RUIDO
 
Estaciones de flujo
Estaciones de flujoEstaciones de flujo
Estaciones de flujo
 
Meaningful Use of Electronic Health Records (October 16, 2016)
Meaningful Use of Electronic Health Records (October 16, 2016)Meaningful Use of Electronic Health Records (October 16, 2016)
Meaningful Use of Electronic Health Records (October 16, 2016)
 
BlueButton on FHIR at HIMSS'17 HL7 API Symposium
BlueButton on FHIR at HIMSS'17 HL7 API SymposiumBlueButton on FHIR at HIMSS'17 HL7 API Symposium
BlueButton on FHIR at HIMSS'17 HL7 API Symposium
 
Getting started with FHIR by Ewout Kramer
Getting started with FHIR by Ewout KramerGetting started with FHIR by Ewout Kramer
Getting started with FHIR by Ewout Kramer
 
Ch07ath
Ch07athCh07ath
Ch07ath
 
Operating System Chapter 3
Operating System Chapter 3Operating System Chapter 3
Operating System Chapter 3
 

Semelhante a How We Built a Mobile Electronic Health Record App Using Xamarin, Angular, and Web API

125 고성능 web view-deview 2013 발표 자료_공유용
125 고성능 web view-deview 2013 발표 자료_공유용125 고성능 web view-deview 2013 발표 자료_공유용
125 고성능 web view-deview 2013 발표 자료_공유용
NAVER D2
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
Mahmoud Hamed Mahmoud
 
Test strategy for web development
Test strategy for web developmentTest strategy for web development
Test strategy for web development
alice yang
 
Codestrong 2012 breakout session building your own custom cloud services
Codestrong 2012 breakout session   building your own custom cloud servicesCodestrong 2012 breakout session   building your own custom cloud services
Codestrong 2012 breakout session building your own custom cloud services
Axway Appcelerator
 

Semelhante a How We Built a Mobile Electronic Health Record App Using Xamarin, Angular, and Web API (20)

125 고성능 web view-deview 2013 발표 자료_공유용
125 고성능 web view-deview 2013 발표 자료_공유용125 고성능 web view-deview 2013 발표 자료_공유용
125 고성능 web view-deview 2013 발표 자료_공유용
 
iOS and Android apps automation
iOS and Android apps automationiOS and Android apps automation
iOS and Android apps automation
 
[Serverless Meetup Tokyo #3] Serverless in Azure (Azure Functionsのアップデート、事例、デ...
[Serverless Meetup Tokyo #3] Serverless in Azure (Azure Functionsのアップデート、事例、デ...[Serverless Meetup Tokyo #3] Serverless in Azure (Azure Functionsのアップデート、事例、デ...
[Serverless Meetup Tokyo #3] Serverless in Azure (Azure Functionsのアップデート、事例、デ...
 
e-KTP Information Extraction with Google Cloud Function & Google Cloud Vision
e-KTP Information Extraction with Google Cloud Function & Google Cloud Visione-KTP Information Extraction with Google Cloud Function & Google Cloud Vision
e-KTP Information Extraction with Google Cloud Function & Google Cloud Vision
 
Kraken Front-Trends
Kraken Front-TrendsKraken Front-Trends
Kraken Front-Trends
 
Event-driven IO server-side JavaScript environment based on V8 Engine
Event-driven IO server-side JavaScript environment based on V8 EngineEvent-driven IO server-side JavaScript environment based on V8 Engine
Event-driven IO server-side JavaScript environment based on V8 Engine
 
Ibm xamarin gtruty
Ibm xamarin gtrutyIbm xamarin gtruty
Ibm xamarin gtruty
 
Into to Node.js: Building Fast, Scaleable Network Applications
Into to Node.js: Building Fast, Scaleable Network ApplicationsInto to Node.js: Building Fast, Scaleable Network Applications
Into to Node.js: Building Fast, Scaleable Network Applications
 
Gdg dev fest hybrid apps your own mini-cordova
Gdg dev fest hybrid apps  your own mini-cordovaGdg dev fest hybrid apps  your own mini-cordova
Gdg dev fest hybrid apps your own mini-cordova
 
Intro To webOS
Intro To webOSIntro To webOS
Intro To webOS
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
 
Android Wear: A Developer's Perspective
Android Wear: A Developer's PerspectiveAndroid Wear: A Developer's Perspective
Android Wear: A Developer's Perspective
 
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 -  Fullstack end-to-end Test Automation with node.jsForwardJS 2017 -  Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
 
Test strategy for web development
Test strategy for web developmentTest strategy for web development
Test strategy for web development
 
The MEAN stack
The MEAN stack The MEAN stack
The MEAN stack
 
Hybrid apps - Your own mini Cordova
Hybrid apps - Your own mini CordovaHybrid apps - Your own mini Cordova
Hybrid apps - Your own mini Cordova
 
Night Watch with QA
Night Watch with QANight Watch with QA
Night Watch with QA
 
Codestrong 2012 breakout session building your own custom cloud services
Codestrong 2012 breakout session   building your own custom cloud servicesCodestrong 2012 breakout session   building your own custom cloud services
Codestrong 2012 breakout session building your own custom cloud services
 
Node azure
Node azureNode azure
Node azure
 
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
 

Último

introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 

Último (20)

Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 

How We Built a Mobile Electronic Health Record App Using Xamarin, Angular, and Web API

  • 1. How We Built a Mobile Electronic Health Record App Using Xamarin, Angular, and Web API
  • 2. About Matt Spradley • Sr. Product Manager at Aprima • Co-founded 3 software companies • Used to write code • Tinkers every now and then • linkedin.com/in/mattspradley • mattspradley.com • matt.spradley@gmail.com • 214-403-6749
  • 3.
  • 4.
  • 5. How Should we Build a Cross Platform Mobile App? http://imgs.xkcd.com/comics/efficiency.png
  • 6. Requirements • Tablet 90% functional parity with desktop EHR • Work on iOS and Android phones and tablets • Integrate with on-premise servers • No control over network (DNS, Firewall, etc.) • Multiple versions of REST API
  • 8.
  • 9. …And the Results Score 66 64 63 53 Factor Weight HTML/Steroids HTML/Titanium Native/Xamarin Native UX 3 2 2 3 3 Code Reuse 3 3 3 2 1 Special UI 1 1 2 3 3 Control 1 2 2 3 3 Effort 3 3 2 2 1 Maintenance 3 2 2 3 2 Cloud Reuse 1 3 3 1 1 OS Integration 2 2 2 3 3 Deployment Options 1 3 3 1 1 Existing Dev Skills 1 2 2 3 1 Hiring 2 2 2 3 2 Vendor Stability 3 2 2 2 3 UTDesign Decision 1 2 2 1 1 UI Testability 3 3 3 1 1 Winner???
  • 10. Web UI with Angular Is Easy <ul id="appointments" class="list-group list-group-fixed-height“ collapse="tileState.isCollapsed"> <li class="list-group-item" ng-show="!loading && appointments.length == 0"> <div class="col-xs-12 text-center-vert text-center"> <span translate>No appointments</span> </div> </li> <li ng-repeat="appt in appointments | orderBy:'date'" data-transition-to="{ appRoute: 'patientDashboard', opts: {id: appt.PatientId}}" class="list-group-item" ng-class="{'active': (!!appt.clicked)}"> <ap-appointment-list-item data-appt="appt" data-context-menu-id="appt-context-menu-{{$index}}"> </ap-appointment-list-item> </li> </ul>
  • 11. <div class="panel-body panel-flush" collapse="tileState.isCollapsed" ng-if="!loading && !httpError"> <table class="table table-striped ap-table"> <thead> <tr> <th translate>Name</th> <th ng-repeat="column in vitals.Columns | limitTo:observationLimit"> <ap-date-formatter date="{{column.ObservationDateTime}}“ format="short-date"></ap-date-formatter> </th> </tr> </thead> <tbody> <tr ng-show="vitalsExist" ng-repeat="observations in vitals.Rows | filter:hasValueForColumns"> <td>{{observations.Name}}</td> <td ng-repeat="observation in observations.Observations | limitTo:observationLimit" ng-class="{danger: !observation.IsInRange && observation.Value}" class="vital-value"> {{observation.Value}} </td> </tr> <tr ng-if="!vitalsExist"> <td> <span id="no-vital-results" translate> No known vitals. </span> </td> </tr> </tbody> </table> </div> Web UI with Angular Is Easy, Really
  • 12. Code and Build • Web UI • Code in HTML, Less, AngularJS • Build • Grunt • Less • Template process • JsHint • Uglify • Unit Tests w/ Jasmine and Karma • Deploy • Translate • Images to Less
  • 13. Chocolate and Peanut Butter Our Customers LOVE Aprima NOW
  • 14. Go Native with Xamarin for Hard Stuff • For • Taking Pictures • Image Annotation • PDF Viewer • Why • Flexibility • C# • Performance • Custom UI • Look and Feel • Services • Hiring
  • 16. Aprima NOW Hybrid Architecture Javascript/HTML JS <--> Xamarin(C#) Bridge Xamarin(C#) AngularJS App JS Bridge Common (portable class library) Xamarin.Android Xamarin.iOS Fire Event Subscribe SubscribeHandle Events Handle Events Fire Event or Subscribe Invoke Callback from Subscription AppServer
  • 17.
  • 18. Javascript Bridge Angular Service, Ctrl etc iOS JS Bridge Android JS Bridge WinForms JS Bridge Fire Events to C#. Subscribe to Events from C# iOS C# Bridge Android C# Bridge WinForms C# Bridge XHR to app:// window.AndrApp.Event(eventData); window.external.HandleEvent(eventData) C# Objects Fire Events to JS Subscribe to Events from JS webview.EvaluateJavascript(jsToFireEvent); Webview.LoadUrl( javascript:{jsToFireEvent} ); Webview.Document.InvokeScript( eval , jsToFireEvent ); Handle events from C# Handle events from JS
  • 19.
  • 20. Jsbridge.js • JS object provides bridging capabilities to JS code • Fire events to C# • Add event handlers in JS to be called when event is fired from C# • Bridge implementations for iOS, Android, and WinForms • Normalizes event structure for consistency: app://{module}/fireEvent?data={jsEventDataJson}&_={random}
  • 21. C# -> JS event Firing • To fire an event, call the following. BridgeContext is a bridge which is scoped to the UI WebView component (iOS: UIWebView; Android: WebView; WinForms: Form/Control/etc) this.BridgeContext.FireEvent(eventName, data); • Which calls the following within the BridgeContext instance and actually dispatches the event to javascript. ExecuteScript is implemented differently by each platform. ExecuteScript(string.Format("bridge.app._dispatchEvent('{0}', {1});", eventName, json));
  • 22. iOS Jsbridge.js • To send an event from JS to C#, iOS uses a custom NSUrlProtocol implementation which listens for XHR traffic on a custom protocol (“app://”). • To send event from JS to C#, an XHR request is made to custom protocol with event data in the url. function (url) { var x1 = new bridge.app.CustomXhr(); x1.onerror = function (e) { console.log('XHR error:' + JSON.stringify(e)); }; x1.open('GET', url); x1.send(); }
  • 23. iOS C# Bridge • Registers global NSUrlProtocol handler, takes an instance of UIWebView and bind global events to specific UIWebViews. • To send event from C# to JS, executes dynamically generated JS which calls into jsbridge.js component. public override void ExecuteScript(string javascript) { webView.BeginInvokeOnMainThread(() => _webView.EvaluateJavascript(javascript)); }
  • 25. Android jsbridge.js • To send an event from JS to C#, Android uses a Java object which is made accessible as a JavaScript object by adding the object instance to the Webview as a JavaScript Interface. • To send event from JS to C#, a method on the Java object instance is invoked from JavaScript. function (url){ var result = window.AndrApp.Event(url); result = JSON.parse(result); if (!result.Success) { console.log('Android bridge error: ' + JSON.stringify(result)); } }
  • 26. Android C# bridge • Instantiates and adds java object with [Export] or [JavascriptInterface] members. Members are accessible from javascript. webView.AddJavascriptInterface(new JsBridgeExports(this), "AndrApp"); • To execute a script, it loads a url which contains javascript to be executed: public override void ExecuteScript(string javascript) { activity.RunOnUiThread(() => _webView.LoadUrl(string.Format("javascript: {0}", javascript))); }
  • 27. WinForms jsbridge.js • To send an event from JS to C#, WinForms uses a C# object which is made accessible as a Javascript object by adding the object instance to the WebView as the ObjectForScripting. • To send event from JS to C#, a method on the C# object instance is invoked from javascript. function (url) { var result = window.external.HandleEvent(url); result = JSON.parse(result); if (!result.Success) { console.log('PRM bridge error: ' + JSON.stringify(result)); } }
  • 28. WinForms C# bridge • Instantiates and adds C# object to the WebBrowser instance as the ObjectForScripting. ObjectForScripting must be have[ComVisible(true)] this._browser.ObjectForScripting = new JsBridgeWindowExternalHandler(this); To fire event from C# to JS, eval function is invoked from C# with a IIFE (Immediately Invoked Function Expression) public override void ExecuteScript(string javascript) { _browser.Invoke(new Action(() => { if (_browser.Document != null) { var script = string.Format("(function() {{ {0}; }})();", javascript); _browser.Document.InvokeScript("eval", new object[] { script }); } })); }
  • 29. JS Code to fire and listen for events angular.module('amodule').controller('SomeCtrl', ['$scope', 'Bridge', function ($scope, Bridge){ //fire event Bridge.navigate('aRoute', { id : 0 }); //listen for event Bridge.on('someEvent', function (data) { $scope.data = data; }); }] );
  • 30. C# code to fire and listen for events //Fire Event this.BridgeContext.FireEvent("navigate", new { id = 0}); //listen to event this.BridgeContext.AddEventListener("someEvent", (SomeType data) => { //do something with data });
  • 31. Notes • Bridge lifetimes vary by platform. • iOS has a singleton bridge because NSProtocolHandler is added for an entire application instead of for a specific UIWebView. iOS bridge has logic to broker events to the correct bridge context which isassociated with a specific UIWebView. • Android bridges are instantiated per WebView instances • WinForms bridges are instantiated per WebBrowser instance • Native components must tell JS bridge which native implementation is used. This can happen AFTER events have already been fired from JS. This required queuing of events until the bridge was finished being setup.
  • 32. Notes • Majority of code is in a PCL library and reused by all platforms • Dll exists for each platform that contains platform specific code • Very little platform specific code • Bridge behavior consistent across the platforms
  • 33. Frontend Tech Stack • Xamarin • Angular • Bootstrap • lodash • Less • Hammer.JS
  • 35. Web UI is Easy to Test and Debug Grunt Jasmine Protractor Webdriver E2E
  • 36. Device Testing with Xamarin Test Cloud
  • 37. Xamarin Test Cloud Testing [Test] public void PinchToZoom() { LoginPage.Login(app); app.WaitForElement(x => x.Css("#dashboard")); app.Screenshot("Then I am logged in at my home screen"); app.GoToPatients(); QuicksearchPage.SearchForPatient(app, "Anderson"); QuicksearchPage.SelectPatient(app, "e2ab0790-f271-471a-bdc2-e6bca0889dad"); app.WaitForElement(x => x.Css("#patient-widgets"), "Timed out waiting for patient dashboard to load", new TimeSpan(0, 0, 3)); app.Screenshot("Then I see Jeff's profile"); PatientDashboardPage.ExpandWidget(app, PatientDashboardWidget.ObservationResults); PatientDashboardPage.TapObservationResult(app, "3f39a0fa-99e9-494b-a234-170f3ff824ba"); Thread.Sleep(5000); app.Screenshot("Now I should see the images"); //Scroll down to view first image app.ScrollDownEnough(x => x.WebView().Css(".image-viewer")); var rect = app.Query(x => x.WebView().Css(".image-viewer"))[0].Rect; app.Zoom(rect.CenterX, rect.CenterY, 100); app.Screenshot("Now I zoom in on the image"); }
  • 38. Not All Web Browsers are Equal
  • 39. iOS and Android Webview Update Differences
  • 40. Inertial Scroll or EasyScroller • Safari: Fixed DIVs Bad • https://github.com/zynga/scroller
  • 41. Xamarin Issues • Constant updates • Things break • Universal API kerfuffle • IDE lockups • They’re still awesome and smart http://www.doomsteaddiner.net/blog/wp-content/uploads/2013/04/wheels-off-hummer.png
  • 42. Backend • Web API • OWIN • Azure Relay • SQL Server • Feature List for Versions • NEO (home brew ORM)
  • 43. REST Facade App Server UI 1 UI 2 DBEF Other Aprima Mobile Application Architecture Decoupled deployment from Aprima Main
  • 45. Azure Relay WebHttpBinding A Developer’s Guide to Service Bus in Windows Azure Platform
  • 46. Service Bus Relay Web API Host https://pfelix.wordpress.com/tag/asp-net-web-api/
  • 47. Relay Demo • By pass on-premise issues • … and pesky IT road blocks http://imgs.xkcd.com/comics/security.png
  • 48. Azure Relay Performance -100 0 100 200 300 400 500 600 700 800 Azure Ping1 (ms) Relay Ping1 (ms) Azure Ping2 (m2) Relay Ping2 (m2) Azure 5K (ms) Relay 5K (ms) Azure 10k (ms) Relay 10k (ms) Azure 50K (ms) Relay 50K (ms) Azure 500K (ms) Relay 500K (ms)Average
  • 49. Code Metrics • Backend ≈ 50K lines • 87% C# • 10% Build scripts • 3% Other • Frontend ≈ 100K lines • 59% JavaScript • 30% HTML (HTML, CSS, Less) • 8% C# (90% in common PCL) • 3% Build scripts
  • 51. Thanks to a Great Team • Mobile Team • Ryan Cady • Kenneth Crawford • Mike Duran • Jeff Lott • Contributors • Doug Jost • Chris Mojica • Karl Shearer • Design • More Simple
  • 52. Top Ten Rules of Software Development 1. Order the T-shirts for the Development team 2. Announce availability 3. Write the code 4. Write the manual 5. Hire a Product Manager 6. Spec the software (writing the specs after the code helps to ensure that the software meets the specifications) 7. Ship 8. Test (the customers are a big help here) 9. Identify bugs as potential enhancements 10. Announce the upgrade program http://www.nullskull.com/a/722/the-top-ten-rules-of-software-development.aspx
  • 53. Links • http://xamarin.com/ • https://angularjs.org/ • https://github.com/crdeutsch/MonoTouch-JsBridge • http://zynga.github.io/scroller/ • https://pfelix.wordpress.com/tag/asp-net-web-api/ • Designing Evolvable Web APIs with ASP.NET • https://github.com/pmhsfelix/WebApi.Explorations.ServiceBusRel ayHost • www.moresimple.com