Tuesday, August 13, 2019

Measuring the success of your app ad campaign using Firebase

We recently launched an iOS version of an app that was fairly popular on Android due to organic growth (that app being the first of its kind a few years ago). Now - better late than never - we figured it's worth a try on iOS too.

Problem is that there are a few similar apps available on iOS by now, so organic growth - while still working - is too slow for us to see if the app is worth spending more effort on. That's where we started looking at paid ads.

For starters, there are two main providers for promoting your app: Google (AdSense) and Apple Search Ads. Not having done this before we simply started throwing money at the problem and started getting conversions at 30 cent each (that's Euro). Of course, those users were mostly based in countries like India, Brazil, etc. Targeting countries like US or Germany would cost much more. However, our app is not location-dependent so whatever kind of user we get is fine for us :)

So users started to trickle in - at least Google and Apple told us so and happily requested more and more money from us. However, we had no clue what those users were doing in our app, i.e. did they use the core functionality? And more importantly, did they generate revenue via In-App purchases or clicking ads displayed inside the app?

Please welcome our next guest, Firebase Analytics: by default, you do not see how a user was acquired in Firebase for an iOS app (you do on Android). For some reason this is nowhere promoted as prominently as it should, but in order to attribute the source of your users properly on iOS you have to add the iAd framework to your app. The documentation mentions it here shortly among a bunch of other text: "You must add the iAd framework to the Xcode project file for your app in order to track Apple Search Ads." Doing so also changes the answers you have to provide during app submission in the App Store in regards to user privacy.

But that leads us to our next problem: Firebase can do so much, but some things it only does *after* you specifically told it to do so. By now you might have the information available how each user was acquired, however, you are not able to see analytics specifically for that group of users. Usually you would use an "audience" in Firebase to show statistics only for a specific group of users, but audiences only grow after creating them. Meaning: although you might see in the Firebase dashboard that you acquired 1000 users via Google ads, you have no clue what these users did after getting acquired. So go ahead and make sure you create a few audiences: I created one for users acquired via Apple and Google specifically, and another one for all paid acquisitions. That way you can quickly drill down if one of those two providers generates more active or "useful" users for you.

For us it turned out that for every thousand dollar or so spent on ads we earn 10 dollars back via ads shown in our app - oh well!

Thursday, May 2, 2019

How to include a CMake project in a Xcode project

For an iOS app I'm working on I needed to include a C++ project, have it build according to the current scheme (debug / release) and be able to debug it. I don't know much about C++, but I know that CMake is a popular build tool and for the project I was trying to import it was the preferred way to build it anyway. Turns out there are not a lot of people doing this as most of the information you'll find is either outdated (no, I'm not using Xcode 5 anymore) or requires a lot of background knowledge about both Xcode and CMake - which I'm both lacking.

To save myself and others some time in the future, I'd like to walk through an example of how you can build a CMake project for iOS in Xcode:

1. Create iOS Xcode project

Doh! Assuming you don't have one already. There is nothing specific to do here.

2. Clone the C++ project you'd like to include in your project

I'll be using glog for the purpose of this tutorial. Please note that some projects do not build out of the box on iOS for different reasons. I have created a fork of some projects that I needed on iOS, maybe you are lucky and the one you are looking for is among them:

3. CMake, meet Xcode.

First you need to clone a toolchain for iOS to teach CMake how to compile for iOS. Please note: I was not able to use the latest version at the time of writing this article. Instead, I used a specific commit.
Next, run the following one-liner inside your project folder in the terminal:
mkdir build/ && cd build/ && cmake -G "Xcode" -DCMAKE_TOOLCHAIN_FILE=../ios-cmake/ios.toolchain.cmake ../glog.ios/ && cd ../
I usually place that in a file called build.sh as you will need to rerun this whenever the C++ project changes (i.e. new files added).

The above commands will take a while to complete, but at the end you should see something along the lines of:
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/tom/workspace/cmake-sample.ios/build
Please note that you might have to install CMake first and the Xcode command line tools.

4. Xcode, meet CMake!

If the previous step succeeded and did not report any errors in the last three lines you are already halfway there! Hang tight. You should see a new .xcodeproj-file now in a folder called "build" if you look at your project using the file explorer. In my case it's called glog.xcodeproj. Drag this file into the file panel (on the left) of your Xcode project to link them. It doesn't really matter where exactly you drag it to as the file structure of a Xcode project is purely virtual.
Files created by CMake after running the above commands
This is what your Xcode project might look like after dragging the project created by CMake into it

A few more things left to click-click configure in Xcode: go to your project file and under "General" click the Add-button for "Linked Frameworks and Libraries". In the dialog that pops up you should see your C++ project show up. Add it!
Linking the framework generated by CMake

In the same file under "Build Phases" add your C++ project to "Target dependencies" (note: there are lots of targets showing up here. It's usually the one with a grey house-like icon and the exact same name as your C++ project). If you don't do this, Xcode won't automatically rebuild your C++ project if necessary.
Adding the framework as a build dependency

Last but definitely not least you have to tell Xcode where to find the headers of the C++ project. Again in the project file, under "Build Settings" search for a setting called "Header Search Paths", add the path to the header files and make it "recursive" (should work with "non-recursive" too if you put the correct folder there). One would expect this setting to change automatically, but unfortunately you'll have to do this for each C++ dependency you add.
Specifying path to lo

5. Wrap C++ with Objective-C to use it in Swift

As of now Swift does not support calling C++ directly. Instead you have to call Objective-C, which can call C++. There's a lot of stuff about this online already, so give it a go. Feel free to leave a comment if you can't get it to work.

(A few tips and tricks to fix common quirks)

  • If your project doesn't build and you are completely out of ideas what went wrong, try removing the build-folder, rerunning the commands to create it and restart Xcode (yes, that does help sometimes).
  • Sometimes, cleaning the project twice makes a difference. I swear I'm not kidding.
  • All of this is very unstable in my experience, so it could be that it stops working with the next Mac / Xcode update. CMake versions do matter too (I'm using 3.14.0).

Wednesday, May 1, 2019

Ways to legitimately improve your rating on Google Play Store

User ratings on Google Play Store are... hard to read sometimes. It really hurts to see how people seemingly did not care to understand what your app actually does and then complain about it by leaving a bad rating. However, there is a big opportunity for you as developer to turn some of those heart-breaking-swear-ratings into something that does not drag down your average rating shown to future users.

By replying to reviews in a very polite way you can turn at least some of those - 50% in my case into something that is at least a little more positive. I had cases where people (accidentally?) rated the app with one star, but turned it into the full five stars after I had replied to their rating.

Again, it's important to not let your feelings take over and reply in a mean or emotional way. Stay professional, stay classy 😎. My opening phrase is usually "Thanks for your feedback" - even if the feedback was non-existent or not constructive at all. This is how you make some people aware of how stupid their review was in the first place. Next, I ask along the lines of "what exactly went wrong" or "how can we improve the app" to get a discussion going. Last but not least I often end with "contact me via email at [email protected]" in order to make it obvious for less technically versed people how to continue the discussion (if I'm not mistaken, there is a big button saying "REPLY" in the email that Google is sending to users, but still...).

Long story short: Keep an eye on your reviews, reply to them in a polite and professional manner and give the user concrete actions to take.

If your problem is not receiving enough ratings in the first place, I highly suggest to include a dialog that asks users to review your app. If you do this in a way that does not annoy users you'll see many more reviews for your app soon. In my case the conversion rate is very low - only 2% of users asked to leave a rating agree to do so.

Thursday, April 25, 2019

Create a simple landing page for your app in just a few clicks - for free

After redesigning one of my apps from scratch recently I decided it’s time to upgrade the accompanying website for it too. Previously it was hosted on a hidden subpage of my Blogger blog and I hardly ever updated it. Still, it received quite some traffic via the Google Play Store…

So a new website, right? Shouldn’t be that hard since I was looking for something simple: title, a short description, the logo and a few screenshots. Oh, a link to the app stores would be nice too of course. However I could not find any useful template / services to create a minimalist app landing page without designing it myself (my CSS is rusty to say the least). There are a gazillion templates that promise to deliver app landing pages, but most of them were bloated with unnecessary features or design elements. Shortly before giving up - and considering to refresh my CSS skills - I found LaunchKit. One of their tools allows you to create a website from the information available on the App Store (screenshot, logo, description, etc) - for free! Unfortunately they shut down their services after getting acquired by Google, but all of their code is open-source now and you can host it yourself: https://github.com/launchkit/launchkit/

Here’s a sneak peek of what I created:

Not too shabby, right? I even added some custom JavaScript to show a live chat for customers to ask questions (not shown on the screenshot). Here is the live version of it: opendocument.app

There is a few different ways how you can get something similar for your app too now that LaunchKit is not live anymore:

1. Host it yourself

LaunchKit released everything you need to host their services yourself. However, that means you’ll need a server to run it on - which costs a few bucks per month. Worth it, but definitely not the easiest solution if you keep in mind that you have to fix it yourself if the server goes down one night. Also, scalability? Nope. If you go down this route I would suggest to take a look at a fork that makes use of Docker: https://github.com/victorkifer/LaunchKitDocker/pull/1

2. Have someone else host it for you

Some people were smart enough to take the code that was published and host it so that others can use it. The only one I found so far is apptoolkit.io - it offers most of the features for free but some of them are paid (at an unreasonably high monthly rate).

3. Generate the website and export it as a static website

If you put in some extra effort you get the best of both worlds: create a website for free, host it for free and also have someone else worry about your servers. PLUS this scales infinitely (theoretically). And who else to use for hosting than good old Google? More specifically, we’ll use Firebase Hosting.

First generate a website using either a hosted or self-hosted version (localhost is enough) of LaunchKit. Afterwards export it as a static website using some bash magic: https://gist.github.com/mikecrittenden/fe02c59fed1aeebd0a9697cf7e9f5c0c

Last but not least you upload the “exported” website to Firebase by leveraging their Hosting service: https://firebase.google.com/docs/hosting/deploying

I won’t go into details here, but the steps provided above give you an idea of how the process works. The website you end up with is scalable (please mind the limitations of the free Firebase plan), fast, customizable and even supports connecting to a custom domain. If you link this up with Cloudflare now you are pretty good to go. One less thing to worry about if your app becomes the next big thing over night. ;)

Monday, December 24, 2018

Custom domain for Google MyBusiness websites

Unfortunately there is no way of setting a custom domain for websites created using the tools provided by Google MyBusiness, except ordering the domain via Google. That however is only possible in some countries at the moment, so it is not an option for some...

To solve that issue I created an app for CloudFlare, which makes your Google MyBusiness website appear under your own domain without confusing the user. You can find and install the app for free here. Read on to know why I think this is a good solution for a bad problem.

When looking at this problem I saw only two reasonable solutions: 1. forwarding your domain to the domain provided by Google (ending in . business.site) and 2. using an iFrame to load the website "within your website) without the user noticing. While the latter is not a perfect solution either, forwarding your domain creates a very bad user experience because the user starts his journey by typing in your domain but suddenly ends up on a possibly very different domain. This can cause confusion and a feeling that something went wrong for the user.

Implementing the iFrame-approach was more complicated than expected because it is not a commonly used solution. That's why I took the opportunity to learn more about CloudFlare apps and use them to solve my problem. The app automatically creates a DNS entry pointing to a server which hosts a very small HTML template. The CloudFlare app uses that to load the iFrame using the website of your choice (i.e. Google MyBusiness website).

There is an opportunity to get rid of the server, but that would require CloudFlare workers. Since they are not free I don't expect them to have a very big customer base so I decided not to limit my app unnecessarily.

Installing the app is literally as easy as clicking "Install" on CloudFlare and telling the app which website to redirect to. That of course requires your domain's DNS to be managed by CloudFlare, which I suggest anyway.