Mixpanel integrated in iOS SDK is not sending events - ios

​I have an iOS SDK project with lots of modules (in Objective-C).
I want to start tracking events to see how my clients use our SDK but I can't see anything in the insights tab. What am I doing wrong?
 
In the point of entry to the SDK I have added this (just following the docs):
[Mixpanel sharedInstanceWithToken:#"myTOKEN"];
self.mixpanel.serverURL = #"https://api-eu.mixpanel.com";
[self.mixpanel track:#"Video play" properties:#{
#"genre": #"hip-hop",
#"duration in seconds": #42,
}];
I can see with breakpoints that the code it’s executed, however my insights are completely empty.
I also tried adding events with the codeless tracking, and while it looks like it’s working and I can connect to the app, the events aren’t appearing in the insights tab.
 
​

I think you need to assign the shared instance to your local property if that hasn't been done outside of the code you've posted.
[Mixpanel sharedInstanceWithToken:#"myTOKEN"];
self.mixpanel = [Mixpanel sharedInstance]; // assign here
self.mixpanel.serverURL = #"https://api-eu.mixpanel.com";
[self.mixpanel track:#"Video play" properties:#{
#"genre": #"hip-hop",
#"duration in seconds": #42,
}];

Related

iOS 11.4 not asking Privacy Usage ( Privacy - Motion Usage Description has been set )

I'm stumped, iOS 11.4 ( 15F79 ), iPhone 6. Cannot get the App to Ask for Motion Data. info.plist has been set via the editor and double checked via the info.plist open in textWrangler, Also deleted key and saved via textWrangler.
<key>NSMotionUsageDescription</key>
<string>This app needs your Phones motion manager to update when the phone is tilted. Please allow this App to use your phones tilt devices</string>
I have deleted then reinstalled the app about 10 times. I have restared the phone 5 times. I have checked through settings and my app does NOT show up in Privacy-Motion and Fitness or anywhere else in settings. I am using a free developer account, maybe that has something to do with it?
I created a new Xcode game template and changed nothing apart from importing CoreMotion and this code
**** Edited, sorry I forgot to say I had started the instance, just forgot to put it here, just in case someone thinks that's the problem ************
let motionManager = CMMotionManager()
override func didMove(to view: SKView) {
motionManager.startDeviceMotionUpdates()
if motionManager.isDeviceMotionActive == true {
motionManager.accelerometerUpdateInterval = 0.2
motionManager.startAccelerometerUpdates(to: OperationQueue.current!, withHandler: {
(accelerometerData: CMAccelerometerData!, error: NSError!) in
let acceleration = accelerometerData.acceleration
print(accelerometerData)
} as! CMAccelerometerHandler)
}else{
print(CMMotionActivityManager.authorizationStatus().rawValue)
}
which prints a 0 ( an Enum - case not determined ) to the console.
In my actual app it was a 3 ( same Enum - case Denied ).
As I've said, I have uninstalled, reinstalled, edited plist via Xcode and text wrangler ( a code editor ) , tried different versions of the code above, tried the code in different places ( in did move to view, in class )tried code off apple docs. etc.... I haven't been asked the NSUsage question and the App keeps crashing.
I have looked for ways to get the Alert fired up, As in CLLocationManager.requestWhenInUseAuthorization() but I cannot find a comparable CMMotion version ( I don't think there is one. ) I have created a new swift file , imported Foundation and CMMotion and just put that code there, But still no Alert asking for Motion Data.
I tried a single view app template instead of a game template thinking that might be the issue, Nope.
What do I do?
Any help Appreciated. Thanks
You are confusing two related but different classes.
CMMotionManager gives access to accelerometer, magnetometer and gyroscope data. It does not require any user permission as this information is not considered privacy related.
In your else clause you are checking the authorisation status of CMMotionActivityManager. This object reports the device motion type (walking, running, driving). This information is considered privacy related and when you create an instance of this class and request data from it, the permissions alert is displayed.
The reason your else is being triggered is because you are checking isDeviceMotionActive; this will be false until you call startDeviceMotionUpdates, which you never do. Even if you used isAccelerometerActive you would have a problem because you call startAccelerometerUpdates in the if clause which will never be reached.
You probably meant to check isAccelerometerAvailable. If this returns false then there isn't much you can do; the device doesn't have an accelerometer.
Update
It doesn't make sense to check isDeviceMotionActive immediately after calling startDeviceMotion:
You know it's active; you just started it
I imagine the start up takes some time, so you could expect to get false if you check immediately.
Apple recommends that you do not have more than one observer in place for each motion device type, so the purpose of check the is...Active to ensure you don't call start... again if you have already done so.
If you only want gyroscope data then you don't need to call startDeviceMotionUpdates at all.

Skobbler background mode without SKTNavigationManager

I'm developing an IOS app in swift language with the Skobbler navigation SDK.
I try to allow the user to use navigation while in background mode (IPhone locked).
I have question stated below :
1) Is it possible to do so without using the SDKTools and the SKTNavigationManager ? We only use SKMaps.frameworks functions.
With this configuration, I can't use the allowBackgroundNavigation
property of SKTNavigationConfiguration like in the demo.
I set
SKPositionerService.sharedInstance().worksInBackground = true
and allowed the "location Update in BackgroundMode" to the info.plist. Unfortunately the updateCurrentLocation doesn't triggered in background and navigation doesn't works neither.
Thank you very much in advance :-) !!
P.S. : I succeeded to run a short code in background with the official library CCLocationManager. So my app seems correctly configured...
The hotfix for this issue can be downloaded from here:
ObjC: https://www.dropbox.com/s/ruk6at2fju0rdd7/SKMaps_2_5_1.zip?dl=0
Swift: https://www.dropbox.com/s/lgbdherhqzudy2a/SKMapsSwift_2_5_1.zip?dl=0
Sorry..this is not an answer, but a "Same Problem". updatedCurrentLocation is not called when the app is in the background.
Thought I add some more code to give more info and perhaps find the cause:
My code:
SKPositionerService.sharedInstance().delegate = self
SKPositionerService.sharedInstance().worksInBackground = true
SKPositionerService.sharedInstance().automaticLocationUpdatePause = false
SKPositionerService.sharedInstance().startLocationUpdate()
Also tried putting SKPositionerService.sharedInstance().startLocationUpdate() as first line. No luck.
When I run a CLLocationManager alongside the SKPositionerService like so:
locManager = CLLocationManager()
locManager.desiredAccuracy = 10000
locManager.distanceFilter = 10000
locManager.allowsBackgroundLocationUpdates = true
locManager.pausesLocationUpdatesAutomatically = false
locManager.startUpdatingLocation()
updatedCurrentLocation IS being called while in background.
I used this when I was running 2.5.0 as that version was not yet iOS9 ready, but I thought that 2.5.1 would be. This of course is a horrible workaround as a 2nd locationmanager eats battery.
Could it be that, in the SKPositionerService implementation, you are not setting CLLocationManager().allowsBackgroundLocationUpdates to true when SKPositionerService.sharedInstance().worksInBackground is set to true?
btw I'm running the 2.5.1 hot fix posted here.
btw2: This can not be tested in the simulator. The simulator will call updatedCurrentLocation even when the app is 'backgrounded'. I'm guessing because the simulator doesn't really have a 'background' mode.
btw3: I would be very surprised if background mode works for the SDKTools Navigation Manager... with this 2.5.1. hot fix)

Non-screenview events with Google Tag Manager on iOS

we're trying to use GTM on iOS to track non-screenview events using the data layer and cannot get this to work. First, here's our call to GTM:
NSLog(#"voted!");
NSLog(#"question: %#, answer: %#",self.question.question,selectedAnswer.answer);
[[ATITracking instance] trackEventWithTagManager:#"didVote" parameters:#{#"questionValue":self.question.question,#"voteValue":selectedAnswer.answer}];
We have 2 data layer variables set in GTM for the questionValue and the voteValue. See:
https://www.dropbox.com/s/jru5a06vs1bfmm3/variables.jpg?dl=0
And here's our trigger with the event set to didVote:
https://www.dropbox.com/s/0ydxml4yemji2f5/trigger.jpg?dl=0
And our event tag uses the trigger from above (cannot post link due to rep limit.)
Has anyone seen a non-screenview event tracked successfully in iOS using GTM? Thanks in advance.
Events are working for me with no problems. This is slightly modified code from the GTM iOS SDK example
-(void) logEvent:(NSString*) event withProperties:(NSDictionary*) properties {
NSMutableDictionary* eventProperties = [NSMutableDictionary dictionaryWithDictionary:#{#"event": #"customEvent",#"eventCategory":#"User action",#"eventName":event}];
if (properties) {
[eventProperties addEntriesFromDictionary:properties];
}
TAGDataLayer* dataLayer = self.tagManager.dataLayer;
[dataLayer push:eventProperties];
}
Based on GTM documentation https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#events event category and event action must not be empty. I didn't see any events in GA until I configured these parameters in my tag and started pushing them from the client.
Hope it helps.
Please see attached screenshot of my tag:

How does phoneGap (Cordova) work internally, iOS specific

I have started developing html applications for mutliple platforms. I recently heard about Cordova 2.0(PhoneGap) and ever since I have been curious to know how the bridge works.
After lot of code walking, i saw that the Exec.js is the code where call from JS -> Native happens
execXhr = execXhr || new XMLHttpRequest();
// Changeing this to a GET will make the XHR reach the URIProtocol on 4.2.
// For some reason it still doesn't work though...
execXhr.open('HEAD', "file:///!gap_exec", true);
execXhr.setRequestHeader('vc', cordova.iOSVCAddr);
if (shouldBundleCommandJson()) {
execXhr.setRequestHeader('cmds', nativecomm());
}
execXhr.send(null);
} else {
execIframe = execIframe || createExecIframe();
execIframe.src = "gap://ready";
But want to understand how that works, what is the concept here, what does file:///!gap_exec or gap://ready do? and how does the call propgate to the lower layers (native code layers)
thanks a bunch in advance.
The trick is easy:
There is a webview. This displays your app. The webview will handle all navigation events.
If the browser navigates to:
file:///!gap_exec
or
gap://
the webview will cancel the navigation. Everything behind these strings is re-used as an identifier, to get the concrete plugin/plugin-method and parameter:
pseudo-url example:
gap://echoplugin/echothistext?Hello World
This will cause phonegap to look for an echoplugin and call the echothistext method to send the text "Hello World" to the (native) plugin.
update
The way back from native to javascript is (or may be) loading a javascript: url into the webview.
The concrete implementation is a little bit more complex, because the javascript has to send a callback-id to native code. There could be more than one native call are running at the same time. But in fact this is no magic at all. Just a number to get the correct JSON to the right javascript-callback.
There are different ways to communicate between the platform and javascript. For Android there are three or four different bridges.
I am trying to figure this out in more detail, too. Basically there are 2 Methods on the iOS side that can help ...
- webView:shouldStartLoadWithRequest:navigationType: and
- stringByEvaluatingJavaScriptFromString:script
From the sources it seems cordova sends a "READY" message using webView:shouldStartLoadWithRequest:... and then picks up results with the second message, but I am not sure.
Cordova Sources iOSExec
There is much to learn there.

Restkit, Stop Logging?

I am wondering..
Restkit keeps showing reachability information, request information as i use it. Will this automatically stop in production version or do i need to do something to stop them from displaying like setting RKLog level?
thanks
To turn everything off add this to your app delegate.
RKLogConfigureByName("*", RKLogLevelOff);
Note: At least in RestKit v0.20.x you will still see a "RestKit logging initialized..." message in dev builds.
To suppress just the Reachability messages, use this:
RKLogConfigureByName("RestKit/Network/Reachability", RKLogLevelCritical);
Look in lcl_config_components.h for the complete list:
"restkit" "RestKit"
"restkit.network" "RestKit/Network"
"restkit.network.cache" "RestKit/Network/Cache"
"restkit.network.queue" "RestKit/Network/Queue"
"restkit.network.reachability" "RestKit/Network/Reachability"
"restkit.object_mapping" "RestKit/ObjectMapping"
"restkit.core_data" "RestKit/CoreData"
"restkit.core_data.cache" "RestKit/CoreData/Cache"
"restkit.core_data.search_engine" "RestKit/CoreData/SearchEngine"
"restkit.support" "RestKit/Support"
"restkit.support.parsers" "RestKit/Support/Parsers"
"restkit.three20" "RestKit/Three20"
"restkit.ui" "RestKit/UI"
"restkit.testing" "RestKit/Testing"
"app" "App"
The logging messages in a RestKit app are controlled by the RKLog calls. For example:
RKLogConfigureByName("RestKit", RKLogLevelWarning);
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
RKLog is implemented with Aren Harren's lcl_log (see http://0xc0.de/LibComponentLogging) library. I just briefly looked through the code for lcl and I didn't see any code that would prevent it from printing in a production version, so I would ensure that my RKLog code does not appear in production code.
RestKit is configured to show info messages and above in DEBUG builds. In non-DEBUG builds, only warnings, errors, and critical messages are logged. This is defined via RKLogLevelDefault in RKLog.h.
If you want to change the log level for one of RestKit's log components, you can call RKLogConfigureByName(component, level) with the component name and RKLogLevel log level. RKLogConfigureByName("*", RKLogLevelOff) can be used to disable logging for all components. Ensure that RKLogInitialize() was called before, because RKLogInitialize() overwrites the log level settings for RestKit's components on the first call.
If you want to remove all logging code from your production build, you can simply add the preprocessor define _LCL_NO_LOGGING to your build settings. See http://0xc0.de/LibComponentLogging for details.
Kyle's solution is correct. The Swift version is a little bit different:
RKlcl_configure_by_name("*", RKlcl_vOff.rawValue)

Resources