Simplify your iOS/Mac analytics

Overview

ARAnalytics v4 Build Status

ARAnalytics is to iOS what Analytical is to ruby, or Analytics.js is to javascript.

ARAnalytics is an analytics abstraction library offering a sane API for tracking events and user data. It currently supports on iOS: Mixpanel, Localytics, Flurry, GoogleAnalytics, KISSmetrics, Crittercism, Crashlytics, Fabric, Bugsnag, Countly, Helpshift, Tapstream, NewRelic, Amplitude, HockeyApp, HockeyAppLib, ParseAnalytics, HeapAnalytics, Chartbeat, UMengAnalytics, Librato, Segmentio, Swrve, YandexMobileMetrica, Adjust, AppsFlyer, Branch, Snowplow, Sentry, Intercom, Keen, Adobe and MobileAppTracker/Tune. And for OS X: KISSmetrics, Mixpanel and HockeyApp.

It does this by using CocoaPods subspecs to let you decide which libraries you'd like to use. You are free to also use the official API for any provider too. Also, it comes with an amazing DSL to clear up your methods.

Changelog

Integration

You shouldn't just use: pod "ARAnalytics". Since CocoaPods 0.36+ you should do something like:

  pod "ARAnalytics", :subspecs => ["Mixpanel", "Segmentio", "HockeyApp"]

Usage

Setup

Once you've pod installed'd the libraries you can either use the individual (for example) [ARAnalytics setupTestFlightWithTeamToken:@"TOKEN"] methods to start up each individual analytics platform or use the generic setupWithAnalytics with our constants.

  [ARAnalytics setupWithAnalytics:@{
      ARCrittercismAppID : @"KEY",
      ARKISSMetricsAPIKey : @"KEY",
      ARGoogleAnalyticsID : @"KEY"
   }];

Logging

Submit a console log that is stored online, for crash reporting this provides a great way to provide breadcrumbs. ARLog(@"Looked at Artwork (%@)", _artwork.name);

extern void ARLog (NSString *format, ...);

Event Tracking

/// Submit user events
+ (void)event:(NSString *)event;
+ (void)event:(NSString *)event withProperties:(NSDictionary *)properties;

// Add extra properties to get sent along with every event
+ (void)addEventSuperProperties:(NSDictionary *)superProperties;


/// Let ARAnalytics deal with the timing of an event
+ (void)startTimingEvent:(NSString *)event;
+ (void)finishTimingEvent:(NSString *)event;

Error Tracking

/// Submit errors to providers
+ (void)error:(NSError *)error;
+ (void)error:(NSError *)error withMessage:(NSString *)message;

User Properties

/// Set a per user property
+ (void)identifyUserWithID:(NSString *)userID andEmailAddress:(NSString *)email;
+ (void)setUserProperty:(NSString *)property toValue:(NSString *)value;
+ (void)incrementUserProperty:(NSString*)counterName byInt:(int)amount;

Page View Tracking

/// Monitor Navigation changes as page view
+ (void)pageView:(NSString *)pageTitle;
+ (void)monitorNavigationViewController:(UINavigationController *)controller;

On top of this you get access to use the original SDK. ARAnalytics provides a common API between lots of providers, so it will try to map most of the functionality between providers, but if you're doing complex things, expect to also use your provider's SDK.

Aspect-Oriented DSL

There is also a DSL-like setup constructor in the ARAnalytics/DSL subspec that lets you do all of your analytics setup at once. Example usage:

[ARAnalytics setupWithAnalytics: @{ /* keys */ } configuration: @{
   ARAnalyticsTrackedScreens: @[ @{
      ARAnalyticsClass: UIViewController.class,
      ARAnalyticsDetails: @[ @{
          ARAnalyticsPageNameKeyPath: @"title",
      }]
  }],
   ARAnalyticsTrackedEvents: @[@{
      ARAnalyticsClass: MyViewController.class,
      ARAnalyticsDetails: @[ @{
          ARAnalyticsEventName: @"button pressed",
          ARAnalyticsSelectorName: NSStringFromSelector(@selector(buttonPressed:)),
      },
      @{
          ARAnalyticsEventName: @"switch switched",
          ARAnalyticsSelectorName: NSStringFromSelector(@selector(switchSwitched:)),
      }]
   },
   ...

The above configuration specifies that the "button pressed" event be sent whenever the selector buttonPressed: is invoked on any instance of MyViewController. Additionally, every view controller will send a page view with its title as the page name whenever viewDidAppear: is called. There are also advanced uses using blocks in the DSL to selectively disable certain events, provide custom page/event property dictionaries, or to provide dynamic page/event names.

[ARAnalytics setupWithAnalytics: @{ /* keys */ } configuration: @{
   ARAnalyticsTrackedScreens: @[ @{
      ARAnalyticsClass: UIViewController.class,
      ARAnalyticsDetails: @[ @{
          ARAnalyticsProperties: ^NSDictionary*(MyViewController *controller, NSArray *parameters) {
            return @{ /* Custom screen view properties */ };
          }, 
          ARAnalyticsPageNameBlock:  ^NSDictionary*(MyViewController *controller, NSArray *parameters, NSDictionary *customProperties) {
            return [NSString stringWithFormat:@"%@:%@:%@",controller.a, controller.b, controller.c];
          }
      }]
  }],
  ARAnalyticsTrackedEvents: @[ @{
    ARAnalyticsClass: MyViewController.class,
    ARAnalyticsDetails: @[ 
      @{
        ARAnalyticsSelectorName: NSStringFromSelector(@selector(buttonPressed:)),
        ARAnalyticsShouldFire: ^BOOL(MyViewController *controller, NSArray *parameters) {
          return /* some condition */;
        },
        ARAnalyticsProperties: ^NSDictionary*(MyViewController *controller, NSArray *parameters) {
          return @{ /* Custom properties */ };
        },
        ARAnalyticsEventNameBlock:  ^NSDictionary*(MyViewController *controller, NSArray *parameters, NSDictionary *customProperties) {
          return [NSString stringWithFormat:@"%@ pressed", [(UIButton*)parameters[0] titleLabel].text];
        }
      },
      /* more events for this class */
    ]
  },
  ...

Note that when using page tracking on UIViewControllers, all instances must have a non-nil value for their title property. If your app uses nested view controllers, that may not be the case. In this instance, use the ARAnalyticsShouldFire block to disable these view controllers from firing analytics events.

ARAnalyticsShouldFire: ^BOOL(MyViewController *controller, NSArray *parameters) {
  return controller.title != nil;
},

HockeyApp

Starting with HockeyApp version 3.7.0, the HockeyApp provider will automatically keep logs of events and include those in crash reports, thus adding ‘breadcrumbs’ to your report and hopefully providing helpful context for your crash reports. Any messages logged with ARLog() will also get included in the report.

Note, however, that on iOS syslogd will not keep logs around for a long time, as such you should only expect logs of people that re-start the application immediately after the application crashing.

Full list of subspecs

iOS: Mixpanel, Localytics, Flurry, GoogleAnalytics, Firebase, KISSmetrics, Crittercism, Countly, Bugsnag, Helpshift, Tapstream, NewRelic, Amplitude, HockeyApp, HockeyAppLib, ParseAnalytics, HeapAnalytics, Chartbeat, UMengAnalytics, Segmentio, Swrve, YandexMobileMetrica, Adjust, Intercom, Librato, Crashlytics, Fabric, AppsFlyer, Branch, Snowplow, Sentry, Keen, Adobe, MobileAppTracker, Leanplum & Appboy.

OSX: KISSmetricsOSX, HockeyAppOSX, MixpanelOSX & ParseAnalyticsOSX.

Contributing, or adding a new analytics provider

See Contributing

Comments
  • Chained progressive tracking

    Chained progressive tracking

    Using the responder chain to progressively adding properties to an event. Events can be sent down the chain by calling -trackEvent:withProperties: on any UIResponder subclass. UIApplication will find these events and send it to ARAnalytics. Any UIResponder subclass can override that method to add properties for themselves. This allows adding context to an event without having to have it promptly where the event if initially fired.

    opened by banaslee 19
  • @orta => DSL subspec for analytics

    @orta => DSL subspec for analytics

    • [x] Figure out some CocoaPods craziness
    • [x] First Pass
    • [x] Completing implementation for screens
    • [x] Events
    • [x] Testing
    • [x] OS X Support

    Reference: http://albertodebortoli.github.io/blog/2014/03/25/an-aspect-oriented-approach-programming-to-ios-analytics/

    Closes #73.

    opened by ashfurrow 18
  • Increased deployment target for Localytics and Intercom.

    Increased deployment target for Localytics and Intercom.

    This is a smaller change to achieve https://github.com/orta/ARAnalytics/pull/282, fixes https://github.com/orta/ARAnalytics/issues/283. When building with a lower deployment target, the user will get an error.

    opened by BenchR267 17
  • [WIP] Add breadcrumb logging to HockeyApp

    [WIP] Add breadcrumb logging to HockeyApp

    This will log events and ARLog to the Apple System Logging facility and use those to then add context to HockeyApp crash reports.

    • [x] Document in README
    • [x] Wait till HockeyApp change is released: https://github.com/bitstadium/HockeySDK-iOS/pull/153
    • [x] ~~Set minimum HockeyApp version in ARAnalytics pod spec~~
    opened by alloy 15
  • NSInternalInconsistencyException when adding page tracking hook

    NSInternalInconsistencyException when adding page tracking hook

    I am using page tracking with the DSL feature in an iOS 8.3 simulator. I configure page tracking with the following configuration:

    @{
      ARAnalyticsTrackedScreens : @[@{
        ARAnalyticsClass : UIViewController.class,
        ARAnalyticsDetails : @[@{
          ARAnalyticsPageNameKeyPath : @"title",
        }],
        ARAnalyticsShouldFire : ^BOOL(UIViewController *controller, NSArray *parameters) {
          return controller.title != nil;
        }}]
    

    But I am always getting the following error:

    2015-04-17 11:48:41.938 Shoik[63892:872919] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Value for Key on _title returned nil.' *** First throw call stack: ( 0 CoreFoundation 0x000000010abe5c65 exceptionPreprocess + 165 1 libobjc.A.dylib 0x000000010a87ebb7 objc_exception_throw + 45 2 CoreFoundation 0x000000010abe5aca +[NSException raise:format:arguments:] + 106 3 Foundation 0x00000001083d798f -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195 4 Shoik 0x0000000106c2aeeb __53+[ARAnalytics(DSL) addScreenMonitoringAnalyticsHook:]_block_invoke_4 + 427 5 Shoik 0x0000000106d8455f -[RACSubscriber sendNext:] + 239 6 Shoik 0x0000000106d4659c -[RACPassthroughSubscriber sendNext:] + 444 7 Shoik 0x0000000106d83574 __23-[RACSubject sendNext:]_block_invoke + 68 8 Shoik 0x0000000106d83373 -[RACSubject enumerateSubscribersUsingBlock:] + 595 9 Shoik 0x0000000106d83507 -[RACSubject sendNext:] + 151 10 Shoik 0x0000000106d2d69b RACForwardInvocation + 347 11 Shoik 0x0000000106d2d47c __RACSwizzleForwardInvocation_block_invoke + 92 12 CoreFoundation 0x000000010ab42f4f __forwarding + 495 13 CoreFoundation 0x000000010ab42cd8 _CF_forwarding_prep_0 + 120 14 UIKit 0x0000000109305ff1 -[UIViewController _setViewAppearState:isAnimating:] + 567 15 UIKit 0x0000000109306b3b -[UIViewController _executeAfterAppearanceBlock] + 52 16 UIKit 0x00000001091f562c _applyBlockToCFArrayCopiedToStack + 314 17 UIKit 0x00000001091f54c5 _afterCACommitHandler + 564 18 CoreFoundation 0x000000010ab18ca7 CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION + 23 19 CoreFoundation 0x000000010ab18c00 __CFRunLoopDoObservers + 368 20 CoreFoundation 0x000000010ab0ea33 __CFRunLoopRun + 1123 21 CoreFoundation 0x000000010ab0e366 CFRunLoopRunSpecific + 470 22 GraphicsServices 0x000000010b689a3e GSEventRunModal + 161 23 UIKit 0x00000001091d1900 UIApplicationMain + 1282 24 Shoik 0x0000000106b7016f main + 111 25 libdyld.dylib 0x000000010b10e145 start + 1

    Am I doing something wrong?

    opened by beloso 12
  • Tracking UIViewController ancestors fails via DSL

    Tracking UIViewController ancestors fails via DSL

    Hi! I'm using sample code from your article.

    [ARAnalytics setupWithAnalytics:@{
      /* keys */
    } configuration:
    @{
      ARAnalyticsTrackedScreens: @[
          @{
              ARAnalyticsClass: UIViewController.class,
              ARAnalyticsDetails: @[ // default selector on iOS is viewDidAppear:
                  @{
                      ARAnalyticsPageNameKeyPath: @"title"
                  }
              ]
          }
      ]
    }];
    

    However it fails on NSAssert'ing title property in UINavigationController, UITabBarController, even some UIInputWindowController.

    Am I doing something wrong or just ignore asserts in DEBUG configuration?

    opened by ikovalisko 12
  • @ashfurrow => Dsl refactor

    @ashfurrow => Dsl refactor

    Hello there, decided to devote some time to cleanup & tests since you've now done all the hard work.

    Switched to @steipete's Aspect library, ( /cc Pete, found it a bit odd that the API for removal of aspects is a class method, yet theres a different API for classes and instances. ) which changed the block params to be an NSArray of the arguments. This is a breaking change for the Artsy stuff you've been doing I imagine :wink: :wine_glass:

    I found it a bit hard to write some more of the tests, as state would leak between tests. so I added a way to add / remove / remove all to the public API.

    I also tightened up the example JSON, I like the idea of being super specific with the tabbing, but for examples I'd rather it be more readable. One day I'll make a ruby script to tab these things, doing it in Xcode is a massive hassle.

    ( there's also a bunch of cleanup around the project in here too to make it fancier )

    opened by orta 10
  • Adobe provider screen views with props

    Adobe provider screen views with props

    In our Omniture implementation, all screen views have custom properties associated with them. This PR overrides -didShowNewPageView:withProperties: to call -trackState:data: for page views that have custom context data. Without this PR, ARAnalytics triggers an event (-trackAction:data:). Is this something that would be useful to other developers? or is this too specific to our implementation? Thanks

    opened by arifken 9
  • DSL trackedScreens not tracking pages in Google Analytcs

    DSL trackedScreens not tracking pages in Google Analytcs

    Hi, Google Analytics is not tracking pagenames in content and no live content is showed. This is the configuration that I used, which is copied from the doc. Any of you could help? thanks!

    [ARAnalytics setupWithAnalytics:@{
                                          ARLocalyticsAppKey    : @"x",
                                          ARCrashlyticsAPIKey   : @"y",
                                          ARGoogleAnalyticsID   : @"z",}
                          configuration: @{
                                           ARAnalyticsTrackedScreens: @[ @{
                                                                             ARAnalyticsClass: UIViewController.class,
                                                                             ARAnalyticsDetails: @[ @{
                                                                                                        ARAnalyticsPageNameKeyPath: @"title",
                                                                                                        }]
                                                                             }]}
    
         ];
    
    opened by elioscordo 9
  • Integrating with CocoaPods triggers warning in Xcode 6 Beta

    Integrating with CocoaPods triggers warning in Xcode 6 Beta

    When ARAnalytics is installed with CocoaPods, 2 warnings are generated in Xcode by default.

    Pods/Pods.xcodeproj Update to recommended settings
    - Target 'Pods-ARAnalytics' - Remove Duplicate References in Build Phase
    The Compile Sources build phase contains duplicate references for one or more files. This will remove the duplicate file references.
    - Target 'Pods-ARAnalytics' - Remove Duplicate References in Build Phase
    The Compile Sources build phase contains duplicate references for one or more files. This will remove the duplicate file references.
    

    Apparently few files get included multiple times into compile sources, which are:

    • ARAnalyticalProvider.m
    • ARAnalytics.m
    • ARNavigationControllerDelegateProxy.m

    Xcode will fix this for us, but having this fixed would be even better. I am assuming this happens only when two subspecs of Analytics are included, for example in my case:

    pod 'ARAnalytics/Crashlytics'
    pod 'ARAnalytics/GoogleAnalytics'
    pod 'ARAnalytics/DSL'
    
    opened by Legoless 9
  • Remove TestFlight events

    Remove TestFlight events

    TestFlight have removed FlightPath analytics since Apple bought them, there is no where on the website to view the analytics so I think it's time they are removed from ARAnalytics.

    Do we want to remove TestFlight completely from ARAnalytics? Or just remove the events being sent (so you can still [TestFlight takeOff:identifier]).

    opened by kylef 9
  • Move subspec dependency to ReactiveObjC

    Move subspec dependency to ReactiveObjC

    The RAC 2.x Objective-C APIs have been moved to their own repo so that the main ReactiveCocoa repo can focus on Cocoa bindings. We should update our DSL subspec to point to the new repo.

    opened by ashfurrow 1
  • Problems using ARAnalytics for Firebase in a swift 3 project using cocoapods

    Problems using ARAnalytics for Firebase in a swift 3 project using cocoapods

    After installing pods i am getting following compilation error

    In file included from ~/TestProject/Pods/ARAnalytics/Providers/FirebaseProvider.m:3: ~/TestProject/Pods/Headers/Private/Firebase/Firebase.h:1:9: fatal error: 'FirebaseAnalytics/FirebaseAnalytics.h' file not found #import <FirebaseAnalytics/FirebaseAnalytics.h>

    My podfile looks like this -

    # platform :ios, '9.0'
    target 'TestProject' do 
    source 'https://github.com/CocoaPods/Specs.git'
    use_frameworks!
    pod 'ARAnalytics/Firebase'
    end
    
    opened by ankitaporwal 2
  • When logging NSErrors, include domain and code

    When logging NSErrors, include domain and code

    Currently, it seems that localizedFailureReason, localizedDescription, localizedRecoverySuggestion and localizedRecoveryOptions are being logged. Curiously, error domain and error code aren't logged. Often, this is the most pertinent information.

    Case in point: I have some logged errors which only contains the description "The operation couldn't be completed", and no other information. This makes them hard to track.

    opened by jksk 0
  • Expose super properties as currentSuperProperties

    Expose super properties as currentSuperProperties

    I had my own category for ARAnalytics to extend it for my project but was limited by not having access to superProperties (since sharedInstance is not exposed either). For now, I'm using this fork in my Podfile, but thought this could go in the main project.

    opened by tettoffensive 4
  • setupWithAnalytics missing support for Firebase

    setupWithAnalytics missing support for Firebase

    setupWithAnalytics missing support for Firebase (ARAnalytics 4.0.0)

    Perhaps: ARFIRAnalyticsKey

    + (void)setupWithAnalytics:(NSDictionary *)analyticsDictionary {
    // ...
        if (analyticsDictionary[ARFIRAnalyticsKey]) {
            [self setupFirebaseAnalytics]; // :analyticsDictionary[ARFIRAnalyticsKey]];
        }
    
    
    opened by ScottYelich 3
Owner
Orta Therox
I help people build dev ecosystems. Current: TypeScript. Contributed to: Shiki, Shiki Twoslash, Danger, CocoaPods, Jest, GraphQL, RxSwift & Svelte.
Orta Therox
Analytics for my apps. Currently using Telemetry as the provider

RRAnalyticsKit Analytics for my apps. Currently using Telemetry as the provider Usage For example, I've a method evaluate() in MainViewModel that acts

rryam 2 Jan 26, 2022
Matomo iOS, tvOS and macOS SDK: a Matomo tracker written in Swift

MatomoTracker (former PiwikTracker) iOS SDK The MatomoTracker is an iOS, tvOS and macOS SDK for sending app analytics to a Matomo server. MatomoTracke

Matomo Analytics 367 Dec 17, 2022
Simplify your iOS/Mac analytics

ARAnalytics v4 ARAnalytics is to iOS what Analytical is to ruby, or Analytics.js is to javascript. ARAnalytics is an analytics abstraction library off

Orta Therox 1.8k Dec 29, 2022
Google Analytics tracker for Apple tvOS provides an easy integration of Google Analytics’ measurement protocol for Apple TV.

Google Analytics tracker for Apple tvOS by Adswerve About Google Analytics tracker for Apple tvOS provides an easy integration of Google Analytics’ me

Adswerve 81 Nov 13, 2022
Analytics layer abstraction, abstract analytics reporters and collect domain-driven analytic events.

?? Tentacles Current State: Work in Progress Documentation & Tests(100% completed, but needs refactoring and structuring) started but not done yet, im

Patrick 3 Dec 2, 2022
LibAuthentication will simplify your code when if you want to use FaceID/TouchID in your tweaks.

LibAuthentication will simplify your code when if you want to use FaceID/TouchID in your tweaks.

Maximehip 6 Oct 3, 2022
An iBeacon Manager library was created to simplify your interactions with iBeacons.

JMCiBeaconManager iBeacon is a name of technology that is enabling new location awareness possibilities for apps. "Leveraging Bluetooth Low Energy (BL

Izotx 146 Dec 17, 2022
TLIndexPathTools is a small set of classes that can greatly simplify your table and collection views.

TLIndexPathTools TLIndexPathTools is a small set of classes that can greatly simplify your table and collection views. Here are some of the awesome th

SwiftKick Mobile 347 Sep 21, 2022
The hassle-free way to add Segment analytics to your Swift app (iOS/tvOS/watchOS/macOS/Linux).

Analytics-Swift The hassle-free way to add Segment analytics to your Swift app (iOS/tvOS/watchOS/macOS/Linux/iPadOS). Analytics helps you measure your

Segment 53 Dec 16, 2022
A library to simplify iOS animations in Swift.

Updated for Swift 4.2 Requires Xcode 10 and Swift 4.2. Installation Drop in the Spring folder to your Xcode project (make sure to enable "Copy items i

Meng To 14k Jan 3, 2023
A collection of operators and utilities that simplify iOS layout code.

Anchorage A lightweight collection of intuitive operators and utilities that simplify Auto Layout code. Anchorage is built directly on top of the NSLa

Rightpoint 620 Jan 3, 2023
KolodaView is a class designed to simplify the implementation of Tinder like cards on iOS.

KolodaView Check this article on our blog. Purpose KolodaView is a class designed to simplify the implementation of Tinder like cards on iOS. It adds

Yalantis 5.2k Jan 2, 2023
Promises simplify asynchronous programming, freeing you up to focus on the more important things

Promises simplify asynchronous programming, freeing you up to focus on the more important things. They are easy to learn, easy to master and result in

Max Howell 14k Jan 5, 2023
Mockingbird was designed to simplify software testing, by easily mocking any system using HTTP/HTTPS

Mockingbird Mockingbird was designed to simplify software testing, by easily mocking any system using HTTP/HTTPS, allowing a team to test and develop

FARFETCH 183 Dec 24, 2022
An UITextField subclass to simplify country code's picking. Swift 5.0

Preview Installation NKVPhonePicker is available through CocoaPods. To install it, simply add the following line to your Podfile: pod 'NKVPhonePicker'

Nike Kov 140 Nov 23, 2022
CompositionalLayoutDSL, library to simplify the creation of UICollectionViewCompositionalLayout. It wraps the UIKit API and makes the code shorter and easier to read.

CompositionalLayoutDSL CompositionalLayoutDSL is a Swift library. It makes easier to create compositional layout for collection view. Requirements Doc

FABERNOVEL 44 Dec 27, 2022
A set of UIKit helpers that simplify the usage of UIKit view's and controller's in SwiftUI.

A set of UIKit helpers that simplify the usage of UIKit view's and controller's in SwiftUI. Many of these helpers are useful even in a pure UIKit project.

SwiftUI+ 6 Oct 28, 2022
LineSimplifier - Polyline simplification. Port of simplify.js

LineSimplifier LineSimplifier is a small Swift Package to simplify lines. A line

Andre 1 Aug 29, 2022
🥷 High-performance polyline simplification library - port of simplify.js

High-performance polyline simplification library SwiftSimplify is a tiny high-performance Swift polyline simplification library ported from Javascript

Daniele Margutti 272 Dec 15, 2022
The hassle-free way to integrate analytics into any iOS application.

Developer Feedback Requested: Analytics-Swift Pilot A pilot release of the new Analytics-Swift library is available at the Analytics-Swift repository.

Segment 383 Dec 14, 2022