Setting up analytics for your React Native app

React Native Analytics

When I finally got my iOS app (Sprinkles) to a good point and wanted to start testing it on real devices, I did a bunch of research and looked at things like TestFlight but eventually decided on Fabric because of the added analytics support and the idea of cross-platform support if I decided to also use it for Android as well (and this was also around the time React Native rolled out support for Android). Another positive for Fabric was the installation process. Once you created an account, you install Fabric and it walks you through how to add Fabric to your existing projects. They made it pretty simple and the instructions were really easy to follow. And once installed, I could then build the app and distribute it to people by email and it also tracked some basic analytics like number of active users, number of session and average session length. And it also tracked exceptions/errors and provides a stack-trace if available. For example:

Thread : Crashed: com.twitter.crashlytics.ios.exception
0 Sprinkles 0x10013a0c0 CLSProcessRecordAllThreads + 4296466624
1 Sprinkles 0x10013a0c0 CLSProcessRecordAllThreads + 4296466624
2 Sprinkles 0x10013a4e0 CLSProcessRecordAllThreads + 4296467680
3 Sprinkles 0x10012b42c CLSHandler + 4296406060
4 Sprinkles 0x100138a00 __CLSExceptionRecord_block_invoke + 4296460800
5 libdispatch.dylib 0x197d516a8 _dispatch_client_callout + 16
6 libdispatch.dylib 0x197d5c954 _dispatch_barrier_sync_f_invoke + 100
7 Sprinkles 0x1001384ac CLSExceptionRecord + 4296459436
8 Sprinkles 0x1001382e8 CLSExceptionRecordNSException + 4296458984
9 Sprinkles 0x100137f48 CLSTerminateHandler() + 4296458056
10 libc++abi.dylib 0x196bd6f44 std::__terminate(void (*)()) + 16
11 libc++abi.dylib 0x196bd685c __cxxabiv1::exception_cleanup_func(_Unwind_Reason_Code, _Unwind_Exception*) + 134
12 libobjc.A.dylib 0x197534094 _objc_exception_destructor(void*) + 330
13 Sprinkles 0x1000e0f4c -[RCTBatchedBridge _handleRequestNumber:moduleID:methodID:params:] + 4296101708
14 Sprinkles 0x1000e0930 __33-[RCTBatchedBridge handleBuffer:]_block_invoke + 4296100144
15 libdispatch.dylib 0x197d516e8 _dispatch_call_block_and_release + 24
16 libdispatch.dylib 0x197d516a8 _dispatch_client_callout + 16
17 libdispatch.dylib 0x197d5d6ec _dispatch_queue_drain + 864
18 libdispatch.dylib 0x197d551ac _dispatch_queue_invoke + 464
19 libdispatch.dylib 0x197d5f5bc _dispatch_root_queue_drain + 728
20 libdispatch.dylib 0x197d5f2dc _dispatch_worker_thread3 + 112
21 libsystem_pthread.dylib 0x197f65470 _pthread_wqthread + 1092
22 libsystem_pthread.dylib 0x197f65020 start_wqthread + 4

Fabric also emails you each day with some basic stats with analytics and number of crashes if any. Unfortunately, my app doesn’t really have that many users, but I imagine if I had 100s of beta users, I would be able to see how many use the app daily and if there were any problems/errors.

Now Fabric isn’t the only solution, doing some searching, I stumbled upon the following StackOverflow article:

How to set up analytics on React Native for iOS

The interesting answer included a link to a react-native-mixpanel project on GitHub. For my next project, I might have to give this a try as I’ve used Mixpanel for web projects and really liked it.

And another interesting project worth looking at is the react-native-fabric project on GitHub. I haven’t given it a try yet, but I might start using it to track specific user events. I have been meaning to actually try building something like this since Fabric provides the the calls to make from XCode but a bridge needed to be created so you could call it from the JS. I still might try implementing this myself since I haven’t tried using RCTBridgeModule yet.

Warning: possible EventEmitter memory leak detected. 11 change listeners added.

Got an interesting node.js warning on the server while rendering React components. After a little research and this helpful Stack Overflow Question that described the problem being due to adding event listeners in the componentWillMount rather than the componentDidMount. I didn’t realize the distinction that componentWillMount will run while rendering on the server. In any case, this is pretty useful and interesting information that helps me understand how to use componentWillMount and componentDidMount when building components that get rendered on the server. I hope this helps someone out there.

Getting noscript when trying to do server-side/universal rendering

Now this was a pretty frustrating problem that cost me at least 3 days of debugging, investigation and trial/error testing. But basically, this was due to none of the routes matching on the server. Funny thing is that the route did match when running in the browser and it rendered just fine. And just for the record, I’m using Babel 6, React-Router, Redux, and Redux-Simple-Router which is probably why you’re reading this. So I spent a lot of time debugging this code which I got from the examples:

import { renderToString } from 'react-dom/server'
import { match, RouterContext } from 'react-router'
import routes from './routes'

serve((req, res) => {
  // Note that req.url here should be the full URL path from
  // the original request, including the query string.
  match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
    if (error) {
      res.status(500).send(error.message)
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search)
    } else if (renderProps) {
      // You can also check renderProps.components or renderProps.routes for
      // your "not found" component or route respectively, and send a 404 as
      // below, if you're using a catch-all route.
      res.status(200).send(renderToString(<RouterContext {...renderProps} />))
    } else {
      res.status(404).send('Not found')
    }
  })
})

Stepping through the code above, renderProps was always undefined. Running other samples, I saw that renderProps should contain the route that will be rendered. So for whatever reason, the URL wasn’t wasn’t matching any of the routes specified. So the reason the routes weren’t matching on the server is because my routes were being included like this:

var routes = "./routes"

And here is how I defined the routes:

module.exports = () => {
 var routes = (
   <Route path={ baseUri } component={ Container }>
     <IndexRoute component={ Home } />
     <Route path='*' component={ NotFound } />
   </Route>
 )
 return routes
}

And again, this setup works perfectly fine when running in the browser. After some trial and error, I decided to try copying the syntax from the example and changed my routes definition to:

export default (
 <Route path="/" component={ Container }>
 <IndexRoute component={ Home } />
 <Route path="*" component={ NotFound } />
 </Route>
)

And guess what, it worked. I’m not sure if  I know why it worked, but for whatever reason, this was the missing piece of the puzzle that got server-side rendering to work. My renderProps was no longer undefined and everything was rendering correctly.

And that’s all folks, hope this helps someone.

React Native: cmd+R not working

So I was super excited to start using React Native, it’s been a while since I tried building an iOS app and because I haven’t used Objective-C in a while, I really haven’t had any motivation to build any of the ideas I have had. Then enter React Native and the dream that all the speed and ease of building React apps on the web would be ported to building mobile iOS apps. So as soon as I had free time (which is rare) I started going through the Getting Started guide. Even the Getting Started guide was fast and easy. Got everything downloaded and everything seemed to be working, I was able to create a new project and open it up in Xcode and it built perfectly. But then I made some text changes – my personal favorite is always to add “Hello World” to any app – and then I tried the reload feature by clicking cmd+R in the simulator… wait… nothing… try again… still nothing. That’s weird, everything up until now has been easy and just worked. So I closed the simulator, and tried to rebuild… still not showing my changes… okay, maybe something isn’t being build, I’ll just close down Xcode… bring back Xcode… rebuild.. still nothing… okay, maybe there was something weird with my project, let me blow it away and recreate it… okay, now rebuild… still nothing… getting a little frustrated… let’s just say I decided to walk away and came back a while later… and looking through the GitHub issues for React Native, I found the following:

Cmd-R not refreshing?

Everything loads up fine, example are are running smoothly, but if I make a change in the JS file and hit Cmd-R in the simulator, nothing happens. Did I forget something?

And after going through the thread and trying a few things suggested, I noticed a terminal window that was running in the background:

I also notice that there was a problem with the packager and it wasn’t could initialize. So I kill the process and try again… still nothing… so I decide to try the good old Windows solution and reboot my machine… wait for it… it worked (thanks Microsoft for conditioning me to always do this). So it seems Watchman was in a weird state and wouldn’t actually run, so I had to reboot the machine to get it un-weird. There was probably a way to do it without rebooting my machine, but rebooting was quick and worked. Anyways, I hope this helps someone out there – good luck and happy hacking with React Native.

Great List of Open Source Projects for Web Projects

Great list of open source projects – focused on front-end projects (which are really the only ones I use). I also like how he broke up the projects into fairly logical/useful categories so I can just jump to the section that I’m interested in. For example, right now, I’m interested in charting libraries and have only really used nvd3, so I’m now interested in trying out a bunch of the other charting libraries listed. Anyways, great list of resources, definitely check it out if you’re looking for UI frameworks, charts, maps, text, video, audio, tables, lazy loading, scrolling, animations, UI elements, templating, HTTP requests, dates (probably not the kind of dates you’re really looking for), events, icons, colors, databases, social. If you find anything good, be sure to star the project and give a shout-out to the author.

https://github.com/moklick/frontend-stuff

How to Calculate the Angle Between Two Points in Javascript

So it’s been a while since I’ve posted, so I thought I would post something that was both useful and nostalgic.  I haven’t had a need to do any form of trig since college, maybe even high school.  But for the hackathon last week, I was building an in-browser version of Missile Command that let you blow up the contents of the page.  To do this, I needed to animate missiles being fired and I need to know what the angle between the base and the target to rotate the missile sprite to look correctly.  So my first search yielded the following code snippet:

var angle = Math.atan2(y2 - y1, x2 - x1);

This seemed pretty simple and straightforward and to get the x2 and y2 values, I used the clientX and clientY values from the mouse click event and I used getBoundingClientRect() to get the top and left properties of the base which was a div element positioned at the bottom of the page.  So the final code to calculate the angle looked like this:

// e - mouse event
// base - div element
var baseRect = base.getBoundingCLientRect(),
    y2 = e.clientY,
    x2 = e.clientX,
    y1 = baseRect.top,
    x1 = baseRect.left + (baseRect.width/2),
    angle = Math.atan2(y2 - y1, x2 - x1);

So this made perfect sense and I was feeling pretty good (except for the flashbacks to high school and sitting in those uncomfortable chairs hoping the teacher wouldn’t notice I didn’t do my homework).  I then use the CSS Transform property to rotate my missile sprite like this:

transform:rotate(angle);
-ms-transform:rotate(angle); /* IE 9 */
-webkit-transform:rotate(angle); /* Opera, Chrome, and Safari */

And of course this is going to work on my first try, right? If you’ve read any of my other blog posts, you should know by now that nothing I do ever works on the first try.  So I click in the upper-right quadrant of the page and the missile rotates to point straight up.  At first, I think it’s because my sprite is actually pointing up and I need to offset the rotation.  Then I think there’s something wrong with how I was calculating the x and y coordinates.  So I debug all the values and they look okay.  Then I look at the calculated angle value and notice that it’s not even close to what it should be.  What could I have done wrong… that’s when I went back to the original equation and realized that angle was returned in radian and not degrees.  Well, first I had to remember what radians were and then I had to figure out how to convert it into degrees which turned out to be pretty simple:

var angleDegrees = angleRads * (180/Math.PI);

And then we go, now we have an angle in degrees that works.  Like I said at the beginning, this was a useful exercise in using something I learned in school and something that felt somewhat nostalgic.  Since I want to do more game development, I have a feeling this is only the beginning of my adventures of trying to remember trig basics.  Wish me luck…

Can’t Login to Synology DSM – “System is getting ready. Please log in later.”

Synology DS212

So I’m hoping this will help someone who encounters the same problem I did when I tried to login to my Synology DS212 tonight.  At first, I thought it was simply waking up from being asleep,but I kept checking every couple minutes and after like 15 minutes, when I kept getting:

System is getting ready. Please log in later.

I knew something was wrong.  So I did some searching on Google and of course, I wasn’t the only one having problems.  On Synology’s forum, I found a bunch of people having the same problem going back to March.  Skimming through the reports, it seems due to upgrading the version of DSM.  However, there were “official” reports from Synology saying it was due to the Synology box being compromised (aka hacked).  I don’t know if I completely believe this.  But rather than point fingers and play the blame game, let’s get to the solution (or solutions).  If you look at this post, you’ll see Synology suggests 3 possible solutions:

  1. Remove disks and use a spare disk to re-install DSM
  2. Manually install DSM
  3. Remove disks and boot (then contact Synology)

So I will jump to the answer and recommend going with Option 1.  That worked for me.  It was fairly pain-less to remove the hard-drives, insert a spare drive, turn it on, and use the Synology Assistant to find the box on my network and upgrade to the latest version of DSM.  Then I took out the spare hard-drive and put back my original hard-drives.  I then had to wait for it boot up again and use the Synology Assistant to install the latest version of DSM to be able to login to DSM via my web browser again (yes, I spent probably a hour or so to get back to the same functionality I had months ago – this is called technology).  Anyways, the other options didn’t seem so great and no one else seemed to have any success, so I would recommend going with Option 1 like I did.  And then hopefully you’ll have a working NAS again and you can continue backing up your cat videos.