Adding Firebase Analytis to a Robovm iOS app

We have developed several apps in Kotlin, that are used on both Android and iOS.

For iOS, we use Robovm or Multi-OS Engine

We need to have Firebase Analytics in an iOS app made with Robovm.

Update 31 aug 2017: Firebase Robovm bindings now available in RoboPods

Some Firebase bindings are now available in Robopods. Check out Firebase bindings for RoboPods.

Approaches

We have tried two approaches:

  • Using Cacoapods. Downloading Firebase and all its dependencies from there. Some some of the dependencies are not packaged as Cacoa Touch framework, but contain the source files instead. This approach does not work with Robovm approach, as it requires frameworks. It seems to be not capable of compiling dependencies at build-time.
  • Downloading the libraries from Firebase iOS setup page. This approach worked for us.

Adding libraries to Robovm project

Project structure

The project has the following structure:

  • gradle module ios-common (has libs directory)
  • gradle module app-1 (has robovm.xml, builds ipa for app-1)
  • gradle module app-2 (has robovm.mxml, builds ipa for app-2)

Adding the libraries

Download the libraries from Firebase iOS setup page.

Extract firebase-4.0.x.zip. As we need Analytics pick the libraries in the Analytics folder, and copy them to ios-common/libs. The contents of our ios-common/libs directory after copying the libraries:

ios-common/libs contents

Now update robovm.xml to refer to the new libraries:

<config>
    <frameworkPaths>
      <path>../ios-common/libs</path>
    </frameworkPaths>
    <frameworks>
      <framework>FirebaseAnalytics</framework>
      <framework>FirebaseCore</framework>
      <framework>FirebaseCoreDiagnostics</framework>
      <framework>FirebaseInstanceID</framework>
      <framework>FirebaseNanoPB</framework>
      <framework>GoogleToolboxForMac</framework>
      <framework>nanopb</framework>
    </frameworks>
  </config>

Verify that gradlew createIPA still succeeds.

Creating bindings

To call the native Firebase libraries, Java bindings are needed. Create these bindings manually or add Firebase bindings for RoboPods as Gradle dependency.

Below instructions to create bindings manually. We need to be able to make the following calls to Firebase libraries:

  • [FIRApp configure]; (initializes Firebase, to be called from IOSApplication.Delegate.didFinishLaunching)
  • [FIRAnalytics setScreenName] (to log screen switches)
  • [FirAnalytics logEventWithName] (to log events)

Each Objective-C class has its own Java representative:

FIRApp.java

 package com.company.ios.common.analytics.firebase.bindings;
 
 import org.robovm.apple.foundation.NSObject;
 import org.robovm.objc.ObjCRuntime;
 import org.robovm.objc.annotation.Method;
 import org.robovm.objc.annotation.NativeClass;
 import org.robovm.rt.bro.annotation.Library;
 import org.robovm.rt.bro.ptr.Ptr;
 
 @Library(Library.INTERNAL)
 @NativeClass("FIRApp")
 public class FIRApp extends NSObject {
 
     public static class FIRAppPtr extends Ptr<FIRApp, FIRAppPtr> {}
     static { ObjCRuntime.bind(FIRApp.class); }
 
     public FIRApp() {}
     protected FIRApp(long handle) { super(handle); }
     protected FIRApp(SkipInit skipInit) { super(skipInit); }
 
     @Method(selector = "configure")
     public static native void configure();
 
 }

FIRAnalytics.java

package com.company.ios.common.analytics.firebase.bindings;

import org.robovm.apple.foundation.NSDictionary;
import org.robovm.apple.foundation.NSObject;
import org.robovm.apple.foundation.NSString;
import org.robovm.objc.ObjCRuntime;
import org.robovm.objc.annotation.Method;
import org.robovm.objc.annotation.NativeClass;
import org.robovm.rt.bro.annotation.Library;
import org.robovm.rt.bro.ptr.Ptr;


@Library(Library.INTERNAL)
@NativeClass("FIRAnalytics")
public class FIRAnalytics extends NSObject {

    public static class FIRAnalyticsPtr extends Ptr<FIRAnalytics, FIRAnalyticsPtr> {
    }

    static {
        ObjCRuntime.bind(FIRAnalytics.class);
    }

    public FIRAnalytics() {
    }

    protected FIRAnalytics(long handle) {
        super(handle);
    }

    protected FIRAnalytics(SkipInit skipInit) {
        super(skipInit);
    }

    @Method(selector = "setScreenName:screenClass:")
    public static native void setScreenName(String screenName, String screenClassOverride);

    /**
     * @param customAttributes use {@link org.robovm.apple.foundation.NSMutableDictionary}
     */
    @Method(selector="logEventWithName:parameters:")
    public static native void logEventWithName(String name, NSDictionary<NSString, ? extends NSObject> customAttributes);
}

Also download the GoogleService-Info.plist and put it in the data-directory of the Robovm app.

Implement calls to use the bindings

Use gradlew launchIOSDevice to launch the app

In the Firebase Console, Open the STREAMVIEW screen and click ‘USER SNAPSHOT’ to get insights in events being logged.