BlueRiverInteractive / robovm-ios-bindings

[Deprecated] New bindings: https://github.com/robovm/robovm-robopods. A collection of third party bindings for RoboVM iOS
Apache License 2.0
162 stars 101 forks source link

Google Analytics missing sample & possibly not working #48

Closed jpancik closed 9 years ago

jpancik commented 10 years ago

Hello,

I have a problem with google analytics. My tracking code is not sending any data (tested with realtime and also checked on the next day). It worked in previous versions and I have updated my libs properly.

As there is no sample to check against, I will post my code here and if I'm doing something wrong please point it out. Maybe somebody could share their working tracking code?

Thanks.

public class IOSAnalyticsClient implements GoogleAnalyticsClient {
    private String id;

    private GAIDefaultTracker tracker;

    public IOSAnalyticsClient(String id) {
        this.id = id;
    }

    @Override
    public void startSession() {
        GAI.getSharedInstance().setDryRun(false);
        GAI.getSharedInstance().setDispatchInterval(20.0);

        tracker = GAI.getSharedInstance().getTracker(id);
    }

    @Override
    public void stopSession() {
        try {
            tracker.dispose();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    @Override
    public void trackEvent(String category, String action, String label, long value) {
        tracker.send(GAIDictionaryBuilder.createEvent(category, action, label, NSNumber.valueOf(value)).build());
    }

    @Override
    public void trackPageView(String name) {
        tracker.set("kGAIScreenName", name);
        tracker.send(GAIDictionaryBuilder.createAppView().build());
    }

    @Override
    public void trackTiming(String category, long timeInMilliseconds, String name, String label) {
        tracker.send(GAIDictionaryBuilder.createTiming(category, NSNumber.valueOf(timeInMilliseconds), name, label).build());
    }

    @Override
    public void trackException(String description, Throwable t, boolean fatal) {
        tracker.send(GAIDictionaryBuilder.createException(description, fatal).build());
    }

    @Override
    public void dispatch() {
        //System.out.println("dispatching");
        GAI.getSharedInstance().dispatch();
    }
}
milos1290 commented 10 years ago

Yeah, i trying everything also, and its not working. Last version i've used was working correctly.

BlueRiverInteractive commented 10 years ago

@milos1290 @jpancik I have never used this binding myself but could you check the content of each NSMutableDictionary you are sending? Just call System.out.println(GAIDictionaryBuilder.createAppView().build()); or similar. I assume during conversion to the new bindings something went wrong and maybe these dictionaries are empty now.

jpancik commented 10 years ago

Okey, I've tried in my tracking event code

System.out.println(GAIDictionaryBuilder.createEvent(category, action, label, NSNumber.valueOf(value)).build());

It printed things like:

{
    "&ea" = Debris;
    "&ec" = Experience;
    "&el" = Vase;
    "&ev" = 0;
    "&t" = event;
} 

so I guess this works properly?

BlueRiverInteractive commented 10 years ago

Ok this is interesting. You are also sure that GAI.getSharedInstance().dispatch(); gets called? Otherwise it seems like the binding is working as expected. Maybe it's a problem that dispatch is called from the wrong thread? The facebook binding don't really work, if we don't make the calls from the main thread. You could try to wrap your Analytics calling code inside this:

NSOperationQueue.getMainQueue().addOperation(new Runnable() {
    @Override
    public void run () {
        // your analytics code like dispatch()...
    }
});
jpancik commented 10 years ago

I've tried this:

@Override
public void trackEvent(String category, String action, String label, long value) {
    NSOperationQueue.getMainQueue().addOperation(new Runnable() {
        @Override
        public void run () {
            tracker.send(GAIDictionaryBuilder.createEvent(category, action, label, NSNumber.valueOf(value)).build());
            GAI.getSharedInstance().dispatch();
        }
    });
}

but still no go. Any further things I can try?

StevenGlrz commented 10 years ago

I simply do this and everything works fine

in the main method

    GAI.getSharedInstance().setDispatchInterval(20);
    GAI.getSharedInstance().setDefaultTracker(GAI.getSharedInstance().getTracker("trackingidhere"));

and in method where I initiate UI things

        UIWindow trackWindow = new UIWindow(new CGRect(0, 0, 0, 0));
        GAITrackedViewController trackedViewController = new GAITrackedViewController();
        trackedViewController.setScreenName("Game");

        trackWindow.setRootViewController(trackedViewController);
        trackWindow.makeKeyAndVisible();

Tell me if this works for you

jpancik commented 10 years ago

Please tell me more about the UI part.

rootViewController = UIApplication.getSharedApplication().getKeyWindow().getRootViewController();

this is how I acquire root view controller from libgdx, replacing it with GAITrackedViewController would not work I think.

this is my whole didFinishLaunching code for libgdx game:

@Override
    public boolean didFinishLaunching(UIApplication application, NSDictionary<NSString, ?> launchOptions) {
        boolean result = super.didFinishLaunching(application, launchOptions); 

        rootViewController = UIApplication.getSharedApplication().getKeyWindow().getRootViewController();

        /* here I removed some code where I create some banner ads */   

        rootViewController.getView().addSubview(banner1);
        rootViewController.getView().addSubview(banner2);

        return result;
    }
StevenGlrz commented 10 years ago

I create the view controller when create() is called in the LibGDX application listener. You don't have to modify the view controller that LibGDX has, just create a new one as I posted. I'm not sure if that leads to any issues, but I haven't ran into anything so far.

jpancik commented 10 years ago

I'm sorry, I don't follow. Could you possibly post code of the whole function? You can ofc remove parts that are irrelevant.

StevenGlrz commented 10 years ago

The code I posted that creates the GAITrackedViewController is created in the create() method that LibGDX calls when the app first starts. Sorry if I'm not being clear enough, but if you're using LibGDX, then you should know where create() is being called at.

jpancik commented 10 years ago

Well, the thing I don't understand is this - in create() method I can't call any iOS platform specific code, unless I implement a method in my interface which calls platform specific code. So I'm supposed to do that?

animvs commented 10 years ago

Hello guys. I'm suffering from this exactly problem. I've also tried this code after initializing my tracker:

    UIWindow trackWindow = new UIWindow(new CGRect(0, 0, 0, 0));
    GAITrackedViewController trackedViewController = new GAITrackedViewController();
    trackedViewController.setScreenName("Game");

    trackWindow.setRootViewController(trackedViewController);
    trackWindow.makeKeyAndVisible();

No data being received although. I'm using the ROBOVM's last version.

Any ideas ? Thanks!

StevenGlrz commented 10 years ago

Hmm, that's odd. Try running it on the main thread using the code that BlueRiverInteractive posted earlier in this post.

zino78 commented 10 years ago

Hi!

For me isnt working analytics for me too :(

I dont understand how bindings work exactly, but i see something, what i dont understand.

The GAIDefaultTracker class has an empty send method. I think this method dont call the native ios method. In the earlier version the gaitrackerimpl class send method call the native method.

Maybe that is the problem?

My program work fine, but dont send any data to analytics.

Thanks for help!

Z.

animvs commented 10 years ago

Ok, here is the output from builder.build():

{
    "&t" = appview;
    "LEVEL 1-1" = "&cd";
}
BlueRiverInteractive commented 10 years ago

@zino78 You could be onto something. I just pushed a basic implementation of the GAIDefaultTracker. I'm not sure if this does anything (haven't used this binding myself yet) but can you please try if this works for you? Maybe you need to explicitly use the GAIDefaultTracker class via setDefaultTracker().

zino78 commented 10 years ago

Thanks a lot! I try it in this eveneing! After it, i write the result. :)

animvs commented 10 years ago

OK, i got this exception from the new build:

Exception in thread "main" java.lang.UnsatisfiedLinkError: @Bridge method      org/robovm/bindings/googleanalytics/GAIDefaultTracker.$m$send$(Lorg/robovm/bindings/googleanalytics/GAIDefaultTracker;Lorg/robovm/objc/Selector;Lorg/robovm/apple/foundation/NSDictionary;)V not bound
    at org.robovm.bindings.googleanalytics.GAIDefaultTracker.$m$send$(Native Method)
    at org.robovm.bindings.googleanalytics.GAIDefaultTracker.objc_send(GAIDefaultTracker.java)
    at org.robovm.bindings.googleanalytics.GAIDefaultTracker.send(GAIDefaultTracker.java)
zino78 commented 10 years ago

Hi! I haven't yesterday time to try the new code, but today i try it!

animvs commented 10 years ago

@zino78 , have youe been able to test it yet ?

zino78 commented 10 years ago

Sorry, i don't have time, but today i try it. It make a class castexcpetion, but i don't know why.

java.lang.ClassCastException: org.robovm.bindings.googleanalytics.GAIDefaultLogger cannot be cast to org.robovm.objc.ObjCObject

I try to understand it :)

animvs commented 10 years ago

Thats because GAIDefaultLogger should inherit from NSObject class. You can either change GAIDefaultLogger by yourself (make it extends NSObject) or just don't use it since it is not a required class

windlord0408 commented 10 years ago

After updarage code, i got this error: java.lang.UnsatisfiedLinkError: @Bridge method org/robovm/bindings/googleanalytics/GAIDefaultTracker.$m$send$(Lorg/robovm/bindings/googleanalytics/GAIDefaultTracker;Lorg/robovm/objc/Selector;Lorg/robovm/apple/foundation/NSDictionary;)V not bound at org.robovm.bindings.googleanalytics.GAIDefaultTracker.$m$send$(Native Method) at org.robovm.bindings.googleanalytics.GAIDefaultTracker.objc_send(GAIDefaultTracker.java) at org.robovm.bindings.googleanalytics.GAIDefaultTracker.send(GAIDefaultTracker.java) Please help me to fix it. Thanks alot

animvs commented 10 years ago

Same here... Anyone got any clue on this ?

BlueRiverInteractive commented 10 years ago

I'm trying to fix this but I need some help.

  1. Did it work with the first binding version long time ago? 1.1 If so, can you point me to the commit where it still did work?
  2. How is the Google Analytics binding supposed to be used? 2.1 Can you provide me a really basic sample code?
animvs commented 10 years ago

@BlueRiverInteractive , thanks for your time.

  1. I had not used the bindings before; when i got to it, it was [apparently] not working; it does compiles before the last commit, but did not send any data.
  2. Im not sure i got your point here, but this is how the analytics SDK should be implemented on iOS: https://developers.google.com/analytics/devguides/collection/ios/v3/

2.1 Ok, im building a simple prototype, will send it to you tomorrow.

windlord0408 commented 10 years ago

Hi @BlueRiverInteractive, thanks for your answer. I have some information:

  1. My project worked fine with older binding version. 1.1 Here's the old version I mentioned above: https://github.com/BlueRiverInteractive/robovm-ios-bindings/tree/ceee584865bfb6db7f2436e5034d22c47eb7a930/google-analytics/src/org/robovm/bindings/googleanalytics 2.2 This's simple class use to call Google Analytics binding:

public class RobovmGoogleAnalytics extends GoogleAnalytics {

private static RobovmGoogleAnalytics instance;

public static RobovmGoogleAnalytics getInstance() {
    if (instance == null) {
        instance = new RobovmGoogleAnalytics();
    }
    return instance;
}

GAIDefaultTracker tracker;

private RobovmGoogleAnalytics() {
    GAI.getSharedInstance().setTrackUncaughtExceptions(true);
    GAI.getSharedInstance().setDispatchInterval(20);
    tracker = GAI.getSharedInstance().getTracker("UA-9999999-9");
}

@Override
public void sendView(String appScreen) {
    tracker.set(GAIFields.kGAIScreenName, appScreen);
    tracker.send(GAIDictionaryBuilder.createAppView().build());
}

@Override
public void sendEvent(String category, String action, String label,
        Long value) {
    tracker.send(GAIDictionaryBuilder.createEvent(category, action, label,
            NSNumber.valueOf(value)).build());
}

@Override
public void sendException(String description, boolean fatal) {
    tracker.send(GAIDictionaryBuilder.createException(description, fatal)
            .build());
}

@Override
public void sendSocial(String network, String action, String target) {
    tracker.send(GAIDictionaryBuilder.createSocial(network, action, target)
            .build());
}

@Override
public void sendTiming(String category, long intervalInMilliseconds,
        String name, String label) {
    tracker.send(GAIDictionaryBuilder.createTiming(category,
            NSNumber.valueOf(intervalInMilliseconds), name, label).build());
}

}

Hope you will fix it soon. Thank you very much.

BlueRiverInteractive commented 10 years ago

Thanks for your help! I've checked the old binding version and the current but couldn't find any real differences. I have now reverted GAITracker and GAIDefaultTracker. Can you please tell me if this changes anything?

BlueRiverInteractive commented 10 years ago

Ok I just found some difference. Seems like the creator of the initial version of the binding made GAITrackerImpl class and used it in several places in the GAI class. However, according to the obj-c header file, at these places the generic interface GAITracker should be used in these places. I just pushed another commit that removes the GAITrackerImpl (or GAIDefaultTracker as it is named now). I hope this fixes the issue finally.

windlord0408 commented 10 years ago

After update newest code and replace GAIDefaultTracker with GAITracker in RobovmGoogleAnalytics, I got this error:

java.lang.IncompatibleClassChangeError: Class org.robovm.apple.foundation.NSObject does not implement the requested interface org.robovm.bindings.googleanalytics.GAITracker at com.test.RobovmGoogleAnalytics.sendEvent(RobovmGoogleAnalytics.java)

Please help me to fix it. Thanks.

fechy commented 10 years ago

I'm getting the same issue. I get:

Exception in thread "main" java.lang.IncompatibleClassChangeError: 
Class org.robovm.apple.foundation.NSObject does not implement the 
requested interface org.robovm.bindings.googleanalytics.GAITracker

My code looks like:

@Override
public boolean didFinishLaunching (UIApplication application, NSDictionary<NSString, ?> launchOptions) {
        boolean b = super.didFinishLaunching(application, launchOptions);

        // Configure Google Analytics
        GAI.getSharedInstance().setTrackUncaughtExceptions(true);
        GAI.getSharedInstance().setDryRun(false);
        GAI.getSharedInstance().setDispatchInterval(20.0);

        // Get Google Analytics
        tracker = GAI.getSharedInstance().getTracker(Settings.ANALYTICS_TRACK_ID);

        // Track page view
        this.sendView("Game");

        return b;
}

private void sendView(String appScreen) {
     tracker.set(GAIFields.kGAIScreenName, appScreen);
     tracker.send(GAIDictionaryBuilder.createAppView().build());
}

Any thoughts? Thanks!

alessandro-lac commented 10 years ago

Any news?

we are getting the same issue as windlord0408 and fechy. Tried to mess around with the library without any luck :(

animvs commented 10 years ago

I got the same error:

Exception in thread "main" java.lang.IncompatibleClassChangeError: Class org.robovm.apple.foundation.NSObject does not implement the requested interface org.robovm.bindings.googleanalytics.GAITracker

jpancik commented 10 years ago

java.lang.IncompatibleClassChangeError: Class org.robovm.apple.foundation.NSObject does not implement the requested interface org.robovm.bindings.googleanalytics.GAITracker

got same error. Any update?

Thanks

animvs commented 10 years ago

@jpancik, Sadly no. I've been messing around this issue without success.. I guess we need someone with more knowledge about robovm bindings..

marcinjakubowski commented 10 years ago

This has worked for me: https://gist.github.com/marcinjakubowski/fcf7e7f81925a51c3203 :

  1. Create a new file GAITrackerImpl.java and copy the contents from the linked gist
  2. Modify GAI.java according to my gist (basically change all occurrences of GAITracker to GAITrackerImpl)

I won't submit this as a pull request because I have no idea what I'm doing, it's probably not the right way it should be done, but I have never written a line of Objective-C in my life and it's my second day working with RoboVM. But it works and Google Analytics gets the data correctly, so I don't really care. Hope this helps someone.

rotter commented 10 years ago

I can confirm that @marcinjakubowski 's solution WORKS (thanks a lot!). And also I have no clue what he's done, as I have also never written a line of ObjC code and I'm very very new to RoboVM, started today playing with bindings.

Just to be clear, this is what I did:

GAI.getSharedInstance().setTrackUncaughtExceptions(true);
GAI.getSharedInstance().setDispatchInterval(20);

GAITrackerImpl tracker = GAI.getSharedInstance().getTracker("UA-key-stuff");

GAI.getSharedInstance().setDefaultTracker(tracker);

tracker.set(GAIFields.kGAIScreenName, "MyGameName");
tracker.send(GAIDictionaryBuilder.createAppView().build());

The GAITrackerImpl class is new, copied from @marcinjakubowski 's link. The GAI class was also copied from his link (replacing the original one).

jpancik commented 10 years ago

@marcinjakubowski @rotter Thank you! I also confirm it works. Already submitting new version to iTunes app store.. @BlueRiverInteractive could you look at this? Why it works?

marcinjakubowski commented 10 years ago

@jpancik I can explain a bit why it works: it's because Google has an implementation of the interface GAITracker which is private: the GAITrackerImpl. I read somewhere that one of RoboVM's limitations is support for such private implementations. I found out the name of the private class by reading toString of the returned GAITracker object (returned GAITrackerImpl@....), and then took the idea on how to make it work from Google Play Game Services implementation of GPPShareBuilder. But I think it's done better there, somehow the methods return the interface and not the private implementation and RoboVM recognizes the returned object correctly. I could not make it work so that GAI getTracker returns GAITracker and RoboVM recognizes it's GAITrackerImpl underneath, so I just made it dirty and had getTracker return GAITrackerImpl. I'm hoping someone who knows what they're doing can do it "the right way" :)

WillCalderwood commented 10 years ago

Does someone who's got this working want to push their fix? As no one else has suggested anything better in the last 6 months it's the best solution that we have.

dungelin commented 10 years ago

Below is code i used in my game, It work fine.

//Start Google Analytics
    GAI.getSharedInstance().setDispatchInterval(20);
    GAI.getSharedInstance().setTrackUncaughtExceptions(true);
    GAI.getSharedInstance().setDryRun(false);
    tracker = GAI.getSharedInstance().getTracker(gaID);
    //End Google Analytics      
           //send view
    tracker.send(GAIDictionaryBuilder.createEvent("Game Event", "Start Game", "Start Game",    NSNumber.valueOf(0)).build());
    // Track events with parameters.
    tracker.set(GAIFields.kGAIScreenName, "Game Screen");
           tracker.send(GAIDictionaryBuilder.createAppView().build())
WillCalderwood commented 10 years ago

Thanks @dungelin. I just did an exact copy/paste of your code and set my tracking id and I'm getting the error

java.lang.IncompatibleClassChangeError: Class org.robovm.apple.foundation.NSObject does not implement the requested interface org.robovm.bindings.googleanalytics.GAITracker

I guess there must be some issue with the way I'm importing the binding.

marcinjakubowski commented 10 years ago

@WillCalderwood have a look at the solution I posted here https://github.com/BlueRiverInteractive/robovm-ios-bindings/issues/48#issuecomment-48248092

WillCalderwood commented 10 years ago

@marcinjakubowski - if dungelin has got it working fine as is, then I might see if I can do the same first. I try to avoid hacking about with 3rd party libraries as then I just have a headache when they're updated which is why I suggested your solution should be pushed as the fix.

@marcinjakubowski & @dungelin What version of robovm are each of you using?

Thanks for the help

marcinjakubowski commented 10 years ago

I was on initially on 0.0.8 when my solution worked fine for me, updated to 0.0.10 and it was still working. I am now migrating to 1.0.0-alpha-04, but haven't finished yet so I'm not sure if it works correctly.

dungelin commented 10 years ago

@WillCalderwood i use latest robovm and Analytics here.

dungelin commented 10 years ago

@WillCalderwood I forgot, must include hack from @marcinjakubowski

WillCalderwood commented 10 years ago

Thanks, glad I didn't try without that. :-)

wolfgangpue commented 9 years ago

Does somebody have a link to the *.jar file of @marcinjakubowski fixed version? I use libgdx and don't want to compile the bindings by myself.

marcinjakubowski commented 9 years ago

You can just download the files and add them to your project directly, that's what I did. But maybe someone has a jar.