Building HackerWeb for iOS

Mockup of HackerWeb iOS app

HackerWeb is one of my most favorite side projects.

It's yet another mobile-friendly minimalistic client for Hacker News. It's a web-only client for the past few years, and now I've built an iOS client, which turns out to be my first ever iOS app publicly available on the App Store! 🚀

The backstory

On June 2011, I made a statement:

Making a web app feels (exactly) like a native app sure takes effort. Still, it's doable.

On October 2011, I was playing around with -webkit-overflow-scrolling: touch, introduced with the release of iOS 5.

On Feb 2012, I released HackerWeb (known as "HNmobile" at that time). I tried to coin the phrase "Looks and feels like a native iOS app" for the web app. I believe that HackerWeb is the first ever web app that tries to ambitiously cross the boundary between native and web.

Screenshot of HNMobile landing page on Mobile Safari

On March 2012, I wrote an article on how I built it. It got submitted to Hacker News and to my surprise, appeared on the front page.

Screenshot of HNmobile frontpage showing 'How I built the Hacker News mobile web app' article listed at the top

Feedback has been remarkable.

Behold @cheeaun 's very native looking Hacker News mobile web app.

SengMin Tan (@sengming)

HN mobile web app … #hnmobile Now you tell me that a mobile web app can do everything a native app does... as easily!

Sebastien Arbogast (@sarbogast)

Holy shit. A webapp that is better than a lot of native apps:

Mitchell (@mitchell209)

Really impressed by @cheeaun's Hacker News mobile web app. Much better than any native clients/the full site on iOS.

Nathan Clark (@nthnclrk)

This is quite possibly the best iOS web app I've ever used, it's almost perfect in every way I can think of…

Philip (@philo23)

This web app feels snappier than every native HN app I've tried. You should give it a try

Romain Ruetschi (@_romac)

This is THE BEST and ONLY useful way to read Hacker News on an iPhone or iPad. Bookmark.

Scott Hanselman (@shanselman)

Time goes by as I continue improving the app bit by bit.

Since it's a web app, it auto-updates itself quietly and doesn't need uh... much announcements.

Okay, more tweet reviews:

I use HackerWeb every day, best thing ever.

Mario Ricalde (@mario_ricalde)

HackerWeb A simply readable Hacker News web app to bookmark on your mobile phone - and it's open source :)

Jacob Shea (@JacobShea)

Have you guys seen HackerWeb? HackerNews reading pleasure (mobile included)

Hugo Bessa (@hugoBessaa)

just discovered #hackerweb today, best mobile experience I've seen so far

Vince Mi (@v_mi)

Ever since HackerWeb is launched, there's been a few relevant articles and JavaScript libraries popping up on the Internet:

...and probably a few more which I've missed.

Obviously at this point, it's clear to say that I'm quite obsessed with "native".

When React Native is announced on January 2015, I was super excited and a little sceptical at same time. I gave it a quick try and wasn't really satisfied with it. Perhaps it was too new for me and I didn't get it yet.

After attending ReactEurope on July 2015, I become inspired again to try React Native. It took me few weeks and finally, the iOS project comes alive.

Accepting the challenge

Previously, I have to make a web app that looks and feels like a native app. It was really difficult especially the time when I start doing this with the iOS 5 skeuomorphic design. I totally wouldn't recommend trying this for production web sites at all.

This time, I have to make a native app that looks and feels like the original web app. I personally find this ironic because it actually comes full circle. I have a feeling that I need to prove that it can be done the other way around.

I set a few requirements for my "Minimum Viable Product":

  • New logo. I've never been satisfied with the old logo. This app needs a new one.

  • No new features. It needs to be exactly the same as the current web app. There were a lot of new ideas during the building phase, but I manage to get a hold of myself and stick to the end goal 😎

  • Must use Safari View Controller. Technically it's a much better built-in browser or in-app web view. It has all the power of Safari, so it shares the same cookies and session as Safari app itself. It's more secure and convenient for users at the same time. The only caveats are the minimum iOS 9 requirement and users who prefer other 3rd-party browsers like Chrome.

  • Great performance. With React Native, I find no difficulty at all to make the app feels fast. My concern is a pretty classic problem with every app out there: super long list of items on the screen. The threaded comments interface is pretty challenging especially for Hacker News where the length of a comment text can fill up the whole screen and the nested levels of threads can be quite deep. "Who is hiring?" posts become a different kind of thread where all comments are on the root level and the count can go up to 600 or more.

Designing the logo

History of all previous logos for HackerWeb

The first logo/icon was designed in 2011. The first 3 iterations feature the letter 'Y' because it matches Hacker News's favicon, which is actually the logo of Ycombinator. This 'Y' logo was never meant to be a logo for Hacker News.

Paul Graham mentioned this before:

The YC logo on HN is not the site's logo; it's a very small banner ad.

However, for the sake of familiarity, most Hacker News apps use 'Y' even though there's no letter 'Y' in the name of the site at all.

So in the 4th iteration, I decided to change the letter to 'H' while rebranding the app as 'HackerWeb'. It's a very simple logo until someone mentioned to me that it looked too similar to Harvest's logo. I admit that I didn't put much effort at all in this design iteration and the similarity is purely coincidental.

In the 5th iteration, it's still 'H' with a flatter design, but contains a hidden 'Y' in the orange background (Not sure anyone notice?).

I've done a lot of sketches.

Hand-drawn sketches of HackerWeb logos

I really like this one as it was inspired by the Monument Valley game.

HackerWeb logo, inspired by Monument Valley game

And then I moved on to this:

HackerWeb logo, almost final iteration

This design really caught my eye because I was focusing on combining the letter 'H' and 'W' into one. The 'H' is "folded" to form a hidden 'W'. It's both 2D and 3D at the same time depending on how a person look at it. The blue side of the logo looks like a tilted lowercased 'y', which I think is a nice touch.

The colors somehow look a bit "off" so I played around with colors and gradients.

Multiple iterations of the HackerWeb logo

I choose orange and blue. Orange symbolises the web app while blue is for the native app. Right in the middle, it blends together signifying the boundary between web and native. Finally I got to replace the orange background with a white background, which I think is more complementary to the cleanliness and undistracting nature of the app.

The final winner is this:

HackerWeb logo, the final winner

Building with React Native

React Native is simply amazing.

Few notes:

  • As I'm already familiar with React, it's surprisingly easy to get started with React Native. Everything is still about components, JSX, states and props.
  • CSS in JS. Yes, it takes a while to get used to it. In React Native, there's a limited set of CSS properties available for styling. Flexbox is definitely your best friend.
  • There's still no one true answer for the navigation system in React Native. There is an experimental implementation coming soon. However I prefer using NavigatorIOS because it feels more native on iOS despite its limited API and occasional bugs.
  • Linking native libraries used to be quite troublesome but it's easier now with rnpm (React Native Package Manager).
  • Even though I can require or import modules, React Native doesn't run in the Node environment. For some modules, I'll have to compile them into standalone modules with Browserify.
  • I use Alt for managing data and states.
  • ListView unfortunately doesn't work like iOS's UITableView. It's slightly worse in performance when rendering huge lists and doesn't render the rest of the rows until it's scrolled.
  • 3D Touch support landed in version 0.20.0 but I haven't figure out how to integrate it with Safari View Controller, for example when 3D-touching a link.
  • There's no display: inline-block in React Native. But it's possible to simulate it with some flexbox magic.
  • Not quite relevant to React Native or React, but I got to say, spread operators and JSX spread attributes are pretty darn cool.
  • LayoutAnimation is simply magical. It's unbelievable to see how a one-liner code can do so much to animate almost anything on the screen.

Overall, I'm very impressed with React Native. There were a few small issues once in a while but usually they are fixed in just few days.

I built a few of my own custom components, put together in the same repository:

When I have the time, I plan to separate them out into individual modules and repositories.

Web and native

On 28 September 2015, I posted a comparison screenshot between the web app and the iOS app:

Comparison screenshot of HackerWeb web app and HackerWeb iOS app

It's beautiful.

It's a moment when I couldn't even differentiate both of them.

Along the way, I've made a few tiny changes and decisions:

  • The comment icon used to be vertically centered in each individual row. I moved it to the top mainly because I couldn't make it work on React Native 😜. I gave up and fix the icon placement on the web app instead for consistency sake.

  • On the web app, if a user long-press on a story link in the list, it will show the iOS Share sheet menu. It's a browser feature. However, I realise that this gesture is not common at all on iOS native apps. I thought of removing this feature but decided to keep it and increase the long-press activation delay instead.

  • Visited story links on the web app are grayed out. Basically, it's just a styling for :visited CSS pseudo-class. As a web developer, I've never thought of it as a "feature" and kind of take it for granted. On the iOS app, I have to manually implement this feature and simulate browser history in a very simplified way. If only I could use a hidden Safari View Controller to check visited links somehow 🤔

  • On the iOS app, I decided to linkify the commentator username pointing to the profile page on Hacker News, for example, my profile page. It simply opens up the Safari View Controller. I've thought of creating a nicer interface for it but feels like over-designing it and perhaps over-engineering it because will need to fetch another API call, etc. After implementing this, I back-ported the change to the web app.

  • In the comments view of the iOS app, I added a 'Share' button in the navigation bar. This is not needed on the web app because everything shareable can be triggered by long-pressing. Since long-press gesture is not common for native apps, I add the 'Share' button there.

  • For both web and iOS app, there's no pull-to-refresh. Technically it's not hard to implement it with React Native, yet it's not a natural gesture on web sites. I choose not to implement it because there's no reason to do it. Hacker News is not Twitter or Facebook. There's no real-time stories sliding in from the top. I purposedly make it difficult to reload the stories. Even if the reload button is tapped, it will fetch from the cache most of the time which will expire in few minutes. It's a bit like I'm helping readers to be less obsessive in an unusual way, thus also explains why I limit the number of stories to 60. No more, no less. Done with the stories? Go back to your life 😉

  • As of now, there is no visible "integration" between the iOS app and the web app. No Universal links. No jumping from the web app to the iOS app. If the user shares a story from the Share sheet, the URL points to Hacker News website, not the web app. From my point of view, there is no need to pull users away from the web app or trying to get more active users on my iOS app. I just don't care about the platform differences.

Launching on the App Store

On 19 February 2016, I gave out a few TestFlight invites to a number of people, so that I could gather feedback and flesh out the bugs. Surprisingly, most of the feedback are positive and there were no serious bugs.

I really need to launch the app on the App Store soon because I've been taking a break since October and stalling the progress for few months. I accidentally diverted my attention to my other side projects and fortunately manage to refocus back on this project on 31 January.

I think hard about the pricing of my app. Usually I would make my apps free, but this time, I need to offset the Apple Developer Program membership cost, not to mention all the money I've spent maintaining my (unofficial) Hacker News API since the 2012 debut. Gratipay (previously known as Gittip) doesn't work for me at all. PayPal.Me doesn't work in Singapore or even any parts of Asia.

I did some research on the pricing of other Hacker News apps and finally decided to just go for minimum pricing (99 cents at this point), judging from the complexity of the app and the fact that it looks exactly the same as the current web app now. I don't have to implement a "trial phase" thing or any similar strategies because users can try it on the web app itself before purchasing.

In the end, this is more like a small donation to me, not really a source of revenue or profit.

On 25 February 2016, I submitted the app to the App Store.

I know that the review process would take roughly a week so while waiting, I focus on revamping the landing page. I took this chance to rethink of everything on the page, like removing all the unnecessary marketing nonsense, removing GitHub links, and just go straight to the point. homepage redesign

Super minimalistic. The preview "image" on the right side is actually the live web app itself contained inside an iframe. And I've also included an easter egg 😁

On 1 March, the review status changed to "In Review". I was thrilled. Then the status changed to "Pending Contract" and I have to sign some contracts. Stan Chang helped me a lot in figuring out all the confusing documents and legalities. After that, it changed to "Ready for Sale" and my first impression was like "Wait, really?". Honestly I was expecting the app to be rejected after hearing those horror stories from other iOS developers, but I guess I got lucky(?)

Officially I announce the release of my first iOS app on Twitter and Facebook 🚀

HackerWeb on the App Store; the iTunes Preview page

So this is it. HackerWeb for iOS. Since 2011.

I am deeply grateful to all my long-time loyal users, beta testers, and my friends who supported me. I really appreciate Paul Irish's compliment and everyone else's because positive feedback is always the reason that kept me going and continue building things. It has always been worth more than any number of downloads or likes or whatever.

I’ll be continuing to work on my project in my spare time and further improve things along the way. Follow me on Twitter or @hackerwebapp for updates.

Update 2 May 2016: Continue to Part 2, Building HackerWeb for Android.