{
  "attachments": [],
  "title": "Adding Android to a multi-platform React app",
  "tags": [
    "webdev",
    "native",
    "react",
    "reactnative",
    "android",
    "ios",
    "mobile",
    "mozilla"
  ],
  "year": "2015",
  "month": "09",
  "day": "21",
  "isDir": false,
  "slug": "react-native-android",
  "type": "entry",
  "date": "2015-09-21T19:00:00.000Z",
  "postName": "2015-09-21-react-native-android",
  "html": "<nav role=\"navigation\" class=\"table-of-contents\"></nav>\n\n<p>TL;DR: A couple of months back, <a href=\"http://blog.lmorchard.com/2015/07/22/react-multiplatform/\">I wrote about a TODO app built using React\nfor web and React Native for iOS</a>. </p>\n<p>Last week, the team at Facebook \n<a href=\"https://code.facebook.com/posts/1189117404435352/\">released React Native for Android</a>. So, I circled back to add\nAndroid support and revisit how code sharing looks now.</p>\n<h2 id=\"getting-up-to-speed\">Getting up to speed</h2>\n<p>With this <a href=\"https://code.facebook.com/posts/1189117404435352/\">new release of React Native</a>, I was able to add support\nfor Android to <a href=\"https://github.com/lmorchard/react-multiplatform\">my little TODO app</a>.</p>\n<p>The first task was to <a href=\"https://github.com/lmorchard/react-multiplatform/commit/38fb7afe67f8c339b8d51c69a1f515a5a91e97c7\">shuffle directories &amp; files around and add the base\nAndroid support</a>. In general, the project layout is now cleaner.\nAssets for each platform now live in separate sub-directories.</p>\n<p>Next, to start iterating &amp; experimenting, I copied the code from the iOS app\ninto Android-specific directories. I <a href=\"https://github.com/lmorchard/react-multiplatform/commit/fd80e9859400744ac5fcffc8f7d75d6703a3856d\">only needed to make some small\ntweaks</a> to account for differences in native component sets. That got my\nbase app functionality working.</p>\n<p>Then, <a href=\"https://github.com/lmorchard/react-multiplatform/commit/dd8b6b307c31b67fde23c6b090e7b1f1d8b0f579\">I squashed the iOS &amp; Android models together</a> when I realized that\ncode was identical between the React Native platforms. That could change in\nthe future, but there's no need for a difference right now.</p>\n<p>After sleeping on it, <a href=\"https://github.com/lmorchard/react-multiplatform/commit/ea7abb421b7e0486b2d3de42001724343f832901\">I refactored some common mixins</a> to take advantage of\nadditional sharing opportunities I found between iOS &amp; Android views. That\nhelped to further shrink the lines of duplicated code.</p>\n<p>This added what amounts to a new category of code sharing in my project. So,\n<a href=\"https://github.com/lmorchard/react-multiplatform/commit/cdbbff72cb941fac75f68c1c91279fa780997b26\">I separated that code into its own module</a> to make the distinction easier\nto see &amp; measure.  Now, I have code shared between web and native in general,\nand code shared between the iOS and Android native platforms.</p>\n<p>Finally, in an attempt to start automating my code metrics, <a href=\"https://github.com/lmorchard/react-multiplatform/commit/d5149768e116571d0a1a059d1ff16e1cfc45fcfd\">I added\n<code>loc-metrics.sh</code></a>.</p>\n<h2 id=\"visualizing-the-code-metrics\">Visualizing the code metrics</h2>\n<p>So, I tried drawing some Venn diagrams in my notebook. But, I'm terrible at\ndrawing. That's when I remembered that SVG is a thing where I can draw by\nwriting code. So, <a href=\"https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial\">I spent an afternoon teaching myself some SVG</a>\nand <a href=\"https://github.com/lmorchard/react-multiplatform/commit/0014232c9858e082414e094be021170fda19aab0\">reworked my metrics shell script</a>.</p>\n<p>I'm not going to bother trying to make the areas actually proportional to the\nlines of code. But, here's a rough picture of code sharing:</p>\n<img style=\"width: 240px\" src=\"/uploads/2015/react-native-android/shared-overall.svg\" width=\"\" height=\"\">\n<img style=\"width: 240px\" src=\"/uploads/2015/react-native-android/shared-models.svg\" width=\"\" height=\"\">\n<img style=\"width: 240px\" src=\"/uploads/2015/react-native-android/shared-views.svg\" width=\"\" height=\"\">\n\n<p>If you can't see those images, then you'll need to find a browser that understands\nSVG until I can be bothered to convert to PNG. (Pull requests welcome!)</p>\n<h2 id=\"conclusions-revisited\">Conclusions revisited</h2>\n<p>As before, most of the models code is shared between web and both native\nplatforms. What's unique is mostly boilerplate wrapping <a href=\"http://blog.lmorchard.com/2015/07/22/react-multiplatform/#forking-sharing-model-code-for-persistence\">the localStorage /\nasyncStorage split between web and native</a>.</p>\n<p>On the view side, however, things are a bit more spread out. In a nutshell,\nReact patterns in general allow a decent chunk of code to be shared between\nweb and native. And even more code can be shared between the iOS and Android\nplatforms.</p>\n<p>But, unique concerns in each platform - web, iOS, and Android - call for\nunique code for each case. This is not actually a failing, though: Varying the\nUX between web &amp; iOS &amp; Android is a flexibility you'll probably appreciate. </p>\n<p>In other words, use components &amp; conventions unique to each\nplatform without your app suffering from the lowest-common-denominator UX\nproblem historically found in a lot of multi-platform apps. In the case of this\nTODO app, that just boils down to trivialities like checkboxes &amp; switches &amp;\nsegmented controls. In a larger app, I'd expect this concern to grow.</p>\n<p>I'm being lazy and not coding up the math in percentages. This approach shared\nabout half the code from the web app, and even more than that for each of the\nnative apps. I think that's a significant advantage over writing separate\napps.</p>\n<p>Of course, <a href=\"http://blog.lmorchard.com/2015/07/22/react-multiplatform/#conclusion\">all my caveats from the first go\naround</a> still apply: This is a very simple app. The code devoted to\ndoing interesting things versus React boilerplate is probably not at a good\nratio. Also, as more view components arise, further overlap might be found.\nAnd, hopefully, common logic would remain the primary area of growth on the\nmodel site.</p>\n<p>I think this approach toward building apps remains interesting &amp; promising. </p>\n<!-- vim: set wrap wm=5 syntax=markdown textwidth=78: -->\n",
  "body": "<nav role=\"navigation\" class=\"table-of-contents\"></nav>\n\nTL;DR: A couple of months back, [I wrote about a TODO app built using React\nfor web and React Native for iOS][rnpart1]. \n\nLast week, the team at Facebook \n[released React Native for Android][rnandroid]. So, I circled back to add\nAndroid support and revisit how code sharing looks now.\n\n[rnandroid]: https://code.facebook.com/posts/1189117404435352/\n[rnpart1]: http://blog.lmorchard.com/2015/07/22/react-multiplatform/\n[reactmultiplatform]: https://github.com/lmorchard/react-multiplatform\n\n## Getting up to speed\n\nWith this [new release of React Native][rnandroid], I was able to add support\nfor Android to [my little TODO app][reactmultiplatform].\n  \nThe first task was to [shuffle directories & files around and add the base\nAndroid support][c1]. In general, the project layout is now cleaner.\nAssets for each platform now live in separate sub-directories.\n\n[c1]: https://github.com/lmorchard/react-multiplatform/commit/38fb7afe67f8c339b8d51c69a1f515a5a91e97c7\n\nNext, to start iterating & experimenting, I copied the code from the iOS app\ninto Android-specific directories. I [only needed to make some small\ntweaks][c2] to account for differences in native component sets. That got my\nbase app functionality working.\n\n[c2]: https://github.com/lmorchard/react-multiplatform/commit/fd80e9859400744ac5fcffc8f7d75d6703a3856d\n\nThen, [I squashed the iOS & Android models together][c3] when I realized that\ncode was identical between the React Native platforms. That could change in\nthe future, but there's no need for a difference right now.\n\n[c3]: https://github.com/lmorchard/react-multiplatform/commit/dd8b6b307c31b67fde23c6b090e7b1f1d8b0f579\n\nAfter sleeping on it, [I refactored some common mixins][c4] to take advantage of\nadditional sharing opportunities I found between iOS & Android views. That\nhelped to further shrink the lines of duplicated code.\n\n[c4]: https://github.com/lmorchard/react-multiplatform/commit/ea7abb421b7e0486b2d3de42001724343f832901\n\nThis added what amounts to a new category of code sharing in my project. So,\n[I separated that code into its own module][c5] to make the distinction easier\nto see & measure.  Now, I have code shared between web and native in general,\nand code shared between the iOS and Android native platforms.\n\n[c5]: https://github.com/lmorchard/react-multiplatform/commit/cdbbff72cb941fac75f68c1c91279fa780997b26\n\nFinally, in an attempt to start automating my code metrics, [I added\n`loc-metrics.sh`][c6].\n\n[c6]: https://github.com/lmorchard/react-multiplatform/commit/d5149768e116571d0a1a059d1ff16e1cfc45fcfd\n\n## Visualizing the code metrics\n\nSo, I tried drawing some Venn diagrams in my notebook. But, I'm terrible at\ndrawing. That's when I remembered that SVG is a thing where I can draw by\nwriting code. So, [I spent an afternoon teaching myself some SVG][svgtutorial]\nand [reworked my metrics shell script][c7].\n\n[c7]: https://github.com/lmorchard/react-multiplatform/commit/0014232c9858e082414e094be021170fda19aab0\n[svgtutorial]: https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial\n\nI'm not going to bother trying to make the areas actually proportional to the\nlines of code. But, here's a rough picture of code sharing:\n\n<img style=\"width: 240px\" src=\"/uploads/2015/react-native-android/shared-overall.svg\">\n<img style=\"width: 240px\" src=\"/uploads/2015/react-native-android/shared-models.svg\">\n<img style=\"width: 240px\" src=\"/uploads/2015/react-native-android/shared-views.svg\">\n\nIf you can't see those images, then you'll need to find a browser that understands\nSVG until I can be bothered to convert to PNG. (Pull requests welcome!)\n\n## Conclusions revisited\n\nAs before, most of the models code is shared between web and both native\nplatforms. What's unique is mostly boilerplate wrapping [the localStorage /\nasyncStorage split between web and native][storagesplit].\n\n[storagesplit]: http://blog.lmorchard.com/2015/07/22/react-multiplatform/#forking-sharing-model-code-for-persistence\n\nOn the view side, however, things are a bit more spread out. In a nutshell,\nReact patterns in general allow a decent chunk of code to be shared between\nweb and native. And even more code can be shared between the iOS and Android\nplatforms.\n\nBut, unique concerns in each platform - web, iOS, and Android - call for\nunique code for each case. This is not actually a failing, though: Varying the\nUX between web & iOS & Android is a flexibility you'll probably appreciate. \n\nIn other words, use components & conventions unique to each\nplatform without your app suffering from the lowest-common-denominator UX\nproblem historically found in a lot of multi-platform apps. In the case of this\nTODO app, that just boils down to trivialities like checkboxes & switches &\nsegmented controls. In a larger app, I'd expect this concern to grow.\n\nI'm being lazy and not coding up the math in percentages. This approach shared\nabout half the code from the web app, and even more than that for each of the\nnative apps. I think that's a significant advantage over writing separate\napps.\n\nOf course, [all my caveats from the first go\naround][caveats] still apply: This is a very simple app. The code devoted to\ndoing interesting things versus React boilerplate is probably not at a good\nratio. Also, as more view components arise, further overlap might be found.\nAnd, hopefully, common logic would remain the primary area of growth on the\nmodel site.\n\n[caveats]: http://blog.lmorchard.com/2015/07/22/react-multiplatform/#conclusion\n\nI think this approach toward building apps remains interesting & promising. \n\n<!-- vim: set wrap wm=5 syntax=markdown textwidth=78: -->\n",
  "parentPath": "./content/posts/archives/2015",
  "path": "2015/09/21/react-native-android",
  "thumbnail": "/uploads/2015/react-native-android/shared-overall.svg",
  "needsBuild": true,
  "prevPostPath": "2015/08/07/web-awesome",
  "prevPostTitle": "The web is awesome",
  "nextPostPath": "2015/09/21/blocked",
  "nextPostTitle": "The day the web shrugged?"
}