{"id":10101,"date":"2013-11-20T13:01:05","date_gmt":"2013-11-20T12:01:05","guid":{"rendered":"https:\/\/blog.trifork.com\/?p=10101"},"modified":"2013-11-20T13:01:05","modified_gmt":"2013-11-20T12:01:05","slug":"cordova-from-the-trenches-write-once-run-debug-everywhere","status":"publish","type":"post","link":"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/","title":{"rendered":"Cordova from the Trenches: Write Once, Run &#038; Debug Everywhere!"},"content":{"rendered":"<p dir=\"ltr\" id=\"docs-internal-guid-3877dc9a-567a-8560-8c94-adc8b21d70dc\"><em>Co-written by Gian Luca Ortelli and Ashkan Roshanayi.<\/em><\/p>\n<p><a href=\"https:\/\/trifork.nl\/articles\/wp-content\/uploads\/sites\/3\/2013\/11\/apple-touch-icon-iphone.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-10106\" style=\"float: left;margin-right: 15px\" alt=\"CrisisApp\" src=\"https:\/\/trifork.nl\/articles\/wp-content\/uploads\/sites\/3\/2013\/11\/apple-touch-icon-iphone.png\" width=\"76\" height=\"76\" \/><\/a>Trifork was asked to develop a mobile app for crisis management in a \u201cGRIP 1\u201d crisis situation for Dutch municipalities.The users of the app are municipal employees involved during a crisis situation. The app was designed in co-creation with the involved municipal employees. But what is a crisis?<\/p>\n<p><!--more--><\/p>\n<h2>Welcome to the world of crisis!<\/h2>\n<p dir=\"ltr\">Your mileage may vary but according to Dutch government there are different levels of crisis. Our project was targeted at situation \u201cGRIP 1\u201d meaning serious, but not too vital situation that requires the involvement of municipal employees besides other assistance crew like the police, ambulance and firemen.<\/p>\n<p dir=\"ltr\">Imagine there is a fire in a building. When someone calls 112, the police, fire brigade, ambulance crew and a person from the municipality (OvD-BZ) will be informed. The role of the municipal employee is to inform, assist and support people i.e. responsible for closing down the street, arrange that people have a place to stay, inform the mayor, etc. So this municipal employee has to make lots of phone calls, has to make notice of the situation and log all his actions, all according to a protocol.<\/p>\n<p dir=\"ltr\">So this was not about developing a mobile app for relaxed users sitting on their couch at home, but users in stressful situations that just want to get things done. They are not looking for the latest, most amazing UI transitions that are available in iOS 7.0.3 or Android 4.x.y. They needed focus and simplicity.<\/p>\n<h2>Other requirements, limitations, policies (you name it)&#8230;<\/h2>\n<p dir=\"ltr\">It may sounds relieving to design an app that doesn\u2019t need that much UI gymnastic but there were other requirements that shaped our decisions as the development team:<\/p>\n<ul>\n<li>the budget of the project was limited (which project has unlimited budget!?) and<\/li>\n<li>the desired target platform for the app was determined to be both iOS and Android<\/li>\n<\/ul>\n<p>So the first obvious solution was going by a platform independent technology stack (e.g. HTML5). In general the app did not need specific services offered by the phone except for one small thing: we should be able to store files on the phone. However, as you probably know, storing files can not be done by using &#8220;pure&#8221; HTML5 because you need to be authorized properly. Therefore&#8230;<\/p>\n<h2>Add a wrapper framework to toppings!<\/h2>\n<p dir=\"ltr\">After evaluating a few frameworks, we finally decided to use <a href=\"http:\/\/cordova.apache.org\/\" target=\"_blank\" rel=\"noopener\">Cordova<\/a> to build, package and deploy a &#8220;native-like&#8221; app. Cordova offers some nice abstractions on top of native phone functionality like <a title=\"Cordova File API\" href=\"http:\/\/cordova.apache.org\/docs\/en\/3.0.0\/cordova_file_file.md.html#File\" target=\"_blank\" rel=\"noopener\">file API<\/a> that could be used to store files on device.<\/p>\n<p dir=\"ltr\">The promise of Cordova (and similar frameworks) is simple: developers who are good at html\/css\/javascript can leverage their knowledge to quickly develop mobile apps while staying within their comfort zone.<\/p>\n<p dir=\"ltr\">Obviously there are many other similar frameworks out there, but because of its good fit we decided to go for Cordova. However this doesn\u2019t stop us from mentioning how much room still is available for technologies like <a title=\"Apportable\" href=\"http:\/\/www.apportable.com\/\" target=\"_blank\" rel=\"noopener\">Apportable<\/a> (read our <a title=\"Apportable (a much better alternative to Phonegap) and AFNetworking 2.0\" href=\"https:\/\/blog.trifork.com\/2013\/10\/22\/apportable-a-much-better-alternative-to-phonegap-and-afnetworking-2-0\/\" target=\"_blank\" rel=\"noopener\">other blog post<\/a> on this). To cut a long story short our technology \/ framework stack was:<\/p>\n<ul>\n<li>HTML 5<\/li>\n<li>jQuery Mobile for styling &amp; themes<\/li>\n<li>WebStorage for storing data (SQLite)<\/li>\n<li>Cordova for accessing native functionality<\/li>\n<li>Dropbox.js SDK, a client lib for Dropbox API<\/li>\n<li>Cordova plugins: File API, InAppBrowser and <a title=\"CDVPDFViewer\" href=\"https:\/\/github.com\/RandyMcMillan\/CDVPDFViewer\" target=\"_blank\" rel=\"noopener\">CDVPDFViewer<\/a><\/li>\n<li>Mustache.js<\/li>\n<li><a title=\"add2home\" href=\"http:\/\/cubiq.org\/add-to-home-screen\" target=\"_blank\" rel=\"noopener\">add2home.js<\/a><\/li>\n<li>TestFlight for easy beta testing distribution<\/li>\n<\/ul>\n<h2>The challenges<\/h2>\n<p dir=\"ltr\">Despite our good take off especially with webstorage, challenges were waiting for us:<\/p>\n<ul>\n<li>Event handling &#8211; Webstorage uses asynchronous callback functions, that you can use to update listviews. Aligning this with JQuery Mobile events is quite challenging.<\/li>\n<li>Dropbox integration. For the integration we used a <a title=\"Dropbox\" href=\"http:\/\/cdnjs.com\/libraries\/dropbox.js\/\" target=\"_blank\" rel=\"noopener\">Dropbox.js SDK<\/a>. In general this worked fine, but we had to tweak some parts to make it work smooth. We ended up using the default \u201c<a title=\"Dropbox\" href=\"https:\/\/github.com\/dropbox\/dropbox-js\/blob\/stable\/guides\/builtin_drivers.md\" target=\"_blank\" rel=\"noopener\">Redirect driver<\/a>\u201d, which is not the nicest solution but at least works on all devices.<\/li>\n<li>Cordova development in team:\u00a0 the development environment of Cordova\u00a0 is platform dependent. This makes the usage of the <a title=\"Cordova CLI\" href=\"http:\/\/cordova.apache.org\/docs\/en\/edge\/guide_cli_index.md.html#The%20Command-line%20Interface\" target=\"_blank\" rel=\"noopener\">Cordova CLI<\/a> (which is the preferred way from version 3) not very easy when working on different environments. The behavior of \u201ccordova build android\u201d and generated artifacts could be very different for developer on windows and linux. This is not rocket science neither unsolvable but it takes time and attention to setup your environment, put things in a SCM, ignore some other from SCM and get confident with your individual and team workflow.<\/li>\n<li>90% shared &#8211; 10% separated code between iOS and Android. Obviously we hoped to be able to write the entire application staying platform independent, but that didn\u2019t work out. In particular the Dropbox integration and some inter-app communication (being able to open a PDF file from the application) required to spend time on iOS or Android specific tweaks. Android required less effort (not even 20 lines of code) but iOS required much more specific tweaking. At the end the time spent on platform specific issues, especially on iOS, took more than was expected.<\/li>\n<li>Tooling for cordova projects can be improved. This can be a minor issue but if you are using e.g. Xcode for building and emulating a project then you will miss the power of a true html\/css\/javascript tool that can be handy in a cordova project. So if you need defacto features like refactoring in javascript you will find yourself hopping back and forth between Xcode and Textmate\/SublimText\/\u2026 it looks like java development in notepad 8 years ago!<\/li>\n<\/ul>\n<h2>Lessons we learned on the way\u2026<\/h2>\n<ul>\n<li>Test and debug everywhere. Especially for iOS we were confronted with the fact that some of the Cordova builds didn\u2019t run on certain devices, \u00a0and some builds did. The build configuration settings were identical. This is probably due to some build configuration setting \u201cunder the hood\u201d of Cordova. Unfortunately we didn\u2019t have the time to investigate this yet\u2026<\/li>\n<li>Cordova is designed from start to be extensible using a <a title=\"Cordova plugin architecture\" href=\"http:\/\/cordova.apache.org\/docs\/en\/edge\/guide_hybrid_plugins_index.md.html#Plugin%20Development%20Guide\" target=\"_blank\" rel=\"noopener\">plugin architecture<\/a>. It means that if you need a specific functionality that is not provided by off-the-shelf plugins, you can develop it and in theory plug it in &amp; play. There are already quite some plugins available for Cordova, but we needed a proper PDF viewer on the iOS which was not available off-the-shelf. Writing a plugin is not as easy as it seems as the supporting documentation is quite limited.<\/li>\n<li>Use one platform for development and deployment. Developing on OSX makes it possible to deploy on iOS and Android. So make sure you all have macs\u2026<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Co-written by Gian Luca Ortelli and Ashkan Roshanayi. Trifork was asked to develop a mobile app for crisis management in a \u201cGRIP 1\u201d crisis situation for Dutch municipalities.The users of the app are municipal employees involved during a crisis situation. The app was designed in co-creation with the involved municipal employees. But what is a [&hellip;]<\/p>\n","protected":false},"author":85,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":""},"categories":[87,55,10],"tags":[25,42,358,359,59],"class_list":["post-10101","post","type-post","status-publish","format-standard","hentry","category-html5-mobile","category-mobile","category-development","tag-android","tag-apache","tag-apache-cordova","tag-cordova","tag-ios"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Cordova from the Trenches: Write Once, Run &#038; Debug Everywhere! - Trifork Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Cordova from the Trenches: Write Once, Run &#038; Debug Everywhere! - Trifork Blog\" \/>\n<meta property=\"og:description\" content=\"Co-written by Gian Luca Ortelli and Ashkan Roshanayi. Trifork was asked to develop a mobile app for crisis management in a \u201cGRIP 1\u201d crisis situation for Dutch municipalities.The users of the app are municipal employees involved during a crisis situation. The app was designed in co-creation with the involved municipal employees. But what is a [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/\" \/>\n<meta property=\"og:site_name\" content=\"Trifork Blog\" \/>\n<meta property=\"article:published_time\" content=\"2013-11-20T12:01:05+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/trifork.nl\/articles\/wp-content\/uploads\/sites\/3\/2013\/11\/apple-touch-icon-iphone.png\" \/>\n<meta name=\"author\" content=\"Monique Dewanchand\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Monique Dewanchand\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/\",\"url\":\"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/\",\"name\":\"Cordova from the Trenches: Write Once, Run &#038; Debug Everywhere! - Trifork Blog\",\"isPartOf\":{\"@id\":\"https:\/\/trifork.nl\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/trifork.nl\/articles\/wp-content\/uploads\/sites\/3\/2013\/11\/apple-touch-icon-iphone.png\",\"datePublished\":\"2013-11-20T12:01:05+00:00\",\"author\":{\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/12c42e68a093abbf30458205e82538e2\"},\"breadcrumb\":{\"@id\":\"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/#primaryimage\",\"url\":\"https:\/\/trifork.nl\/articles\/wp-content\/uploads\/sites\/3\/2013\/11\/apple-touch-icon-iphone.png\",\"contentUrl\":\"https:\/\/trifork.nl\/articles\/wp-content\/uploads\/sites\/3\/2013\/11\/apple-touch-icon-iphone.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/trifork.nl\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Cordova from the Trenches: Write Once, Run &#038; Debug Everywhere!\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/trifork.nl\/blog\/#website\",\"url\":\"https:\/\/trifork.nl\/blog\/\",\"name\":\"Trifork Blog\",\"description\":\"Keep updated on the technical solutions Trifork is working on!\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/trifork.nl\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/12c42e68a093abbf30458205e82538e2\",\"name\":\"Monique Dewanchand\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/081e68cb1b09eea5fa6cd7aeaaf446a1?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/081e68cb1b09eea5fa6cd7aeaaf446a1?s=96&d=mm&r=g\",\"caption\":\"Monique Dewanchand\"},\"url\":\"https:\/\/trifork.nl\/blog\/author\/moniqued\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Cordova from the Trenches: Write Once, Run &#038; Debug Everywhere! - Trifork Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/","og_locale":"en_US","og_type":"article","og_title":"Cordova from the Trenches: Write Once, Run &#038; Debug Everywhere! - Trifork Blog","og_description":"Co-written by Gian Luca Ortelli and Ashkan Roshanayi. Trifork was asked to develop a mobile app for crisis management in a \u201cGRIP 1\u201d crisis situation for Dutch municipalities.The users of the app are municipal employees involved during a crisis situation. The app was designed in co-creation with the involved municipal employees. But what is a [&hellip;]","og_url":"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/","og_site_name":"Trifork Blog","article_published_time":"2013-11-20T12:01:05+00:00","og_image":[{"url":"https:\/\/trifork.nl\/articles\/wp-content\/uploads\/sites\/3\/2013\/11\/apple-touch-icon-iphone.png","type":"","width":"","height":""}],"author":"Monique Dewanchand","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Monique Dewanchand","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/","url":"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/","name":"Cordova from the Trenches: Write Once, Run &#038; Debug Everywhere! - Trifork Blog","isPartOf":{"@id":"https:\/\/trifork.nl\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/#primaryimage"},"image":{"@id":"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/#primaryimage"},"thumbnailUrl":"https:\/\/trifork.nl\/articles\/wp-content\/uploads\/sites\/3\/2013\/11\/apple-touch-icon-iphone.png","datePublished":"2013-11-20T12:01:05+00:00","author":{"@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/12c42e68a093abbf30458205e82538e2"},"breadcrumb":{"@id":"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/#primaryimage","url":"https:\/\/trifork.nl\/articles\/wp-content\/uploads\/sites\/3\/2013\/11\/apple-touch-icon-iphone.png","contentUrl":"https:\/\/trifork.nl\/articles\/wp-content\/uploads\/sites\/3\/2013\/11\/apple-touch-icon-iphone.png"},{"@type":"BreadcrumbList","@id":"https:\/\/trifork.nl\/blog\/cordova-from-the-trenches-write-once-run-debug-everywhere\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/trifork.nl\/blog\/"},{"@type":"ListItem","position":2,"name":"Cordova from the Trenches: Write Once, Run &#038; Debug Everywhere!"}]},{"@type":"WebSite","@id":"https:\/\/trifork.nl\/blog\/#website","url":"https:\/\/trifork.nl\/blog\/","name":"Trifork Blog","description":"Keep updated on the technical solutions Trifork is working on!","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/trifork.nl\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/12c42e68a093abbf30458205e82538e2","name":"Monique Dewanchand","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/081e68cb1b09eea5fa6cd7aeaaf446a1?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/081e68cb1b09eea5fa6cd7aeaaf446a1?s=96&d=mm&r=g","caption":"Monique Dewanchand"},"url":"https:\/\/trifork.nl\/blog\/author\/moniqued\/"}]}},"_links":{"self":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts\/10101","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/users\/85"}],"replies":[{"embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/comments?post=10101"}],"version-history":[{"count":0,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts\/10101\/revisions"}],"wp:attachment":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/media?parent=10101"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/categories?post=10101"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/tags?post=10101"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}