Saturday, February 29, 2020

Sync Office 365 calendar with Google Calendar

If your company is using Office 365 and you want to see your work calendar on your private phone you have a few choices:

  • Send an invitation link to your private email address to import it into your default calendar app (e.g. Google Calendar). This feature is disabled for some companies.
  • Install the Outlook app and use that to check your work calendar separately - meh. I want all my calendars in one place!
  • Add Exchange integration to your phone. That way your work-related appointments should show up in your default calendar app. However, some companies disable this feature, too.
Since all these solutions were inconvenient or blocked in my case, I had to come up with something else. I ended up using Microsoft Flow (something you should get for free as part of your Office 365 account anyway) to automate a workflow that copies calendar entries to a separate Google Calendar. Here's what the flow looks like:

("Calendar ID" removed for privacy reasons)

The code for "Start time" and "End time" is as follows:
  • convertToUtc(triggerOutputs()?['body/start'], 'GMT Standard Time')
  • convertToUtc(triggerOutputs()?['body/end'], 'GMT Standard Time')
Now authorize Microsoft Flow to access both your Office 365 as well as your Google Calendar and you are good to go! This workflow is very minimalistic and comes with obvious defects like not honoring updates to existing events. Supporting that would require significantly more effort and is not worth it in my opinion. I'd be happy to chat about possible solutions if anyone is interested in actually making this work though!

Monday, December 9, 2019

Developing in the cloud: List of web apps to use for common tasks

Since the rise of Chromebooks I loved the idea of ditching installed apps for equivalent web apps. Years later there's so many web apps focussed on getting a very specific and simple job done as fast as possible. Below I'm collecting a list of those web apps I come across for future reference:

  • OnPaste - offers a few options to edit or markup images. I used it to highlight a specific area of an image.
  • SQLite Viewer - upload an SQLite database and browse it.
  • Zip Viewer - upload a ZIP file and browse it.
  • croppola - crop an image to predefined or custom ratios.

Let me know if you come across any other web apps that make your everyday tasks easier. Someone else did what needed to be done: create a compilation of such web apps.

Friday, August 23, 2019

Publishing an Android app in China

Thinking about publishing your Android app in China? Just add half a dozen of questionable permissions and you're good to go!

For the last five months I've been trying to work with a service called AppTutti to publish my Android app in China. Due to some very unique approach of the Chinese government, developers are not (easily) able to publish their app for the Chinese market themselves. Instead you can work with third-party services to get your app published. I chose AppTutti for the reason that it seemed more or less legit and offered to do at least the basics without paying any money upfront (instead they would take a cut in revenue). That approach seemed appropriate for my situation, as I was not sure if there is a big market for my niche in China anyway.

The good

The good news is that AppTutti translated my app to Chinese for no charge. As far as I can tell the quality of the translation is decent.

The bad

As mentioned before, the basic service provided is free of charge due to revenue sharing. In order to generate any revenue at all, you have to add monetization libraries to your app that are specialized for the Chinese market. So far so good, but you don't receive any information about what those libraries do exactly. Worse, those libraries seem to be a data mining hell come true:
  • WRITE_EXTERNAL_STORAGE to read all your local data? Hm...
  • ACCESS_FINE_LOCATION to get your exact position? Of course!
  • GET_TASKS to get other apps running on your phone? Hell yeah.
There's also some code that is meant to download *something* in the background. You can find all necessary changes here:

Despite a good amount of skepticism I went ahead to see what comes next. Integration was fairly easy since most of the code just had to be copy-pasted into my project. However, for some reason the integration did not work despite doing exactly what the provided documentation (given in form of a docx) suggested. Overall it took their support 1-2 months to figure out what went wrong. Eventually I did not have to make any changes on my side, so it must have been something on their side.

Finally, Chinese market here we come!? No. "Your App File has been found at local Chinese Stores! Please provide your Authorisation Letter and ORDER our IP Certificate Services to upgrade to RSPP Plus service for Reclaiming Process (from the stores).".

... 🤔

Turns out a very old version of my app was published without authorization before. The only way to reclaim ownership was to pay 200$ to AppTutti so they can start the process to reclaim the app. Admittedly, 200$ is not so bad, but it has a bitter taste if you ask me: free service, but since some companies seem to publish apps in China without permission you have to pay anyway. :)

If one window closes another one opens - or so - and I figured it's not worth spending any more time on publishing my app in China anyway. The rogue copy of my app that is already available there only accumulated a few thousand installs so far! Not worth the hours I have wasted on this odyssey so far and not worth another hour for sure.

TLDR; check download stats of similar apps before attempting to publish your app in China.

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 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).