1) The document describes how the author built a mobile electronic health record app using Xamarin, Angular, and Web API.
2) They used Angular for the web UI and Xamarin for native platform capabilities. A JavaScript bridge was used to connect the two.
3) Azure Service Bus Relay was employed to allow communication with on-premise servers despite network restrictions. This demonstrated good performance.
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
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
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
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
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");
}
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)
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