☂️ Analytics abstraction layer for Swift

Overview

☂️ Umbrella

Swift CocoaPods CI Codecov

Analytics abstraction layer for Swift. Inspired by Moya.

Table of Contents

Why?

There are many tools for mobile app analytics such as Firebase, Google Analytics, Fabric Answers, Flurry, Mixpanel, etc. You might use one or more of those in your application. But most of those SDKs have some problems: if you use multiple analytics tools, your code will be messed up. And the SDKs take event name as a string and parameters as a dictionary which is not guaranteed by Swift compiler. It means that if you change the event definition, you should find all related code by your hand. It has an opportunity that cause a human error. Umbrella uses Swift enums and the associated values to solve these problems.

Features

  • 💪 Taking advantages of Swift compiler by using an enum and associated values.
  • 🎯 Logging events to multiple analytics providers at once.
  • 🎨 Creating custom analytics providers.

At a Glance

Before 🤢

FIRAnalytics.logEvent(withName: kFIREventEcommercePurchase, parameters: [
  kFIRParameterCurrency: "USD" as NSObject,
  kFIRParameterValue: 9.99 as NSNumber,
  kFIRParameterTransactionID: "20170709123456" as NSObject,
])
Flurry.logEvent("purchase", withParameters: [
  "Currency": "USD",
  "Price": 9.99,
  "Transaction ID": "20170709123456"
])
MyCustomAnalytics.logEvent("purchase", withParameters: [
  "currency": "USD",
  "price": 9.99,
  "transaction_id": "20170709123456"
])

After 😊

let analytics = Analytics<MyAppEvent>()
analytics.register(provider: FirebaseProvider())
analytics.register(provider: FlurryProvider())
analytics.register(provider: MyCustomProvider())
analytics.log(.purchase(currency: "USD", price: 9.99, transactionID: "20170709123456"))

Getting Started

Defining Events

First of all, you should define all of your events in a single enum. Let's assume that we have three events that have associated parameters.

enum MyAppEvent {
  case signup(username: String)
  case viewContent(productID: Int)
  case purchase(productID: Int, price: Float)
}

Then make the enum to conform the protocol EventType. It requires two functions: name(for:) and parameters(for:).

extension MyAppEvent: EventType {
  /// An event name to be logged
  func name(for provider: ProviderType) -> String? {
    switch self {
    case .signup: return "signup"
    case .viewContent: return "view_content"
    case .purchase: return "purchase"
    }
  }

  /// Parameters to be logged
  func parameters(for provider: ProviderType) -> [String: Any]? {
    switch self {
    case let .signup(username):
      return ["username": username]
    case let .viewContent(productID):
      return ["product_id": productID]
    case let .purchase(productID, price):
      return ["product_id": productID, "price": price]
    }
  }
}

You can even provide different event names and parameters by providers.

Using Analytics

You can define an Analytics instance anywhere but it's recommended to define at a global scope.

let analytics = Analytics<MyAppEvent>()

Then you should register providers. A prodiver is a wrapper for an actual analytics service such as Firebase and Fabric Answers. It's recommended to register providers in application(_:didFinishLaunchingWithOptions:).

analytics.register(provider: AnswersProvider())
analytics.register(provider: FirebaseProvider())
analytics.register(provider: FlurryProvider())
analytics.register(provider: MyAwesomeProvider())

If you finished those steps, you can now log the events 🎉

analytics.log(.signup(username: "devxoul"))

Built-in Providers

There are several built-in providers.

If there's no provider you're looking for, you can create an issue or create custom providers. It's also welcomed to create a pull request for missing services 🎉

Creating Custom Providers

If there's no built-in provider for the serivce you're using, you can also create your own. It's easy to create a provider: just create a class and conform to the protocol ProviderType.

final class MyAwesomeProvider: ProviderType {
  func log(_ eventName: String, parameters: [String: Any]?) {
    AwesomeAnalytics.logEvent(withName: eventName, parameters: parameters)
  }
}

Installation

Umbrella currently support CocoaPods only.

pod 'Umbrella'
pod 'Umbrella/Firebase' # using with built-in FirebaseProvider
pod 'Umbrella/...'

Contributing

Any discussions and pull requests are welcomed 💖

Generating Xcode Workspace

$ make project

This will automatically generate Umbrella.xcworkspace and perform pod install.

Creating New Provider

For example, imagine that we are going to create a new provider for an analytics service 'Raincoat'.

  1. Add a library and a target definition in Package.swift.

      let package = Package(
        name: "Umbrella",
        products: [
          .library(name: "Umbrella", targets: ["Umbrella"]),
          .library(name: "UmbrellaFirebase", targets: ["UmbrellaFirebase"]),
          .library(name: "UmbrellaMixpanel", targets: ["UmbrellaMixpanel"]),
    +     .library(name: "UmbrellaRaincoat", targets: ["UmbrellaRaincoat"]),
        ],
        targets: [
          .target(name: "Umbrella"),
          .target(name: "UmbrellaFirebase", dependencies: ["Umbrella"]),
          .target(name: "UmbrellaMixpanel", dependencies: ["Umbrella"]),
    +     .target(name: "UmbrellaRaincoat", dependencies: ["Umbrella"]),
          .testTarget(name: "UmbrellaTests", dependencies: ["Umbrella"]),
          .testTarget(name: "UmbrellaFirebaseTests", dependencies: ["UmbrellaFirebase"]),
          .testTarget(name: "UmbrellaMixpanelTests", dependencies: ["UmbrellaMixpanel"]),
    +     .testTarget(name: "UmbrellaRaincoat", dependencies: ["UmbrellaRaincoat"]),
        ]
      )
  2. Add a source file and a test file.

      ...
      ├── Sources
      │   ├── UmbrellaFirebase
      │   │   └── FirebaseProvider.swift
      │   ├── UmbrellaMixpanel
      │   │   └── MixpanelProvider.swift
    + │   ├── UmbrellaRaincoat
    + │   │   └── RaincoatProvider.swift
      |   ...
      ├── Tests
      │   ├── UmbrellaFirebaseTests
      │   │   └── FirebaseProviderTests.swift
      │   ├── UmbrellaMixpanelTests
      │   │   └── MixpanelProviderTests.swift
    + │   ├── UmbrellaRaincoatTests
    + │   │   └── RaincoatProviderTests.swift
      ... ...
  3. Add a CocoaPods dependency in Podfile.

     target 'UmbrellaFirebaseTests' do
       platform :ios, '8.0'
       pod 'Firebase/Analytics'
     end
    
     target 'UmbrellaMixpanelTests' do
       platform :ios, '8.0'
       pod 'Mixpanel'
     end
    
    + target 'UmbrellaRaincoatTests' do
    +   platform :ios, '8.0'
    +   pod 'Raincoat'
    + end
  4. Add a CocoaPods subspec in Umbrella.podspec.

      s.subspec "Firebase" do |ss|
        ss.source_files = "Sources/UmbrellaFirebase/*.swift"
        ss.dependency "Umbrella/Core"
      end
    
      s.subspec "Mixpanel" do |ss|
        ss.source_files = "Sources/UmbrellaMixpanel/*.swift"
        ss.dependency "Umbrella/Core"
      end
    
    + s.subspec "Raincoat" do |ss|
    +   ss.source_files = "Sources/UmbrellaRaincoat/*.swift"
    +   ss.dependency "Umbrella/Core"
    + end
  5. Create a Xcode workspace and run tests. Don't forget to check the code coverage to ensure that tests can cover the new provider.

    $ make project

License

Umbrella is under MIT license. See the LICENSE file for more info.

You might also like...
Simple proxy in Swift for converting between HTTP and API Gateway Lambda payloads

SwiftLambdaProxy A simple proxy that can convert HTTP requests to Lambda API Gat

JustTrivia - Trivia Application Created in Swift
JustTrivia - Trivia Application Created in Swift

JustTrivia - Trivia Application Created in Swift Usage Please use a small number

Task-Manager - Task Manager App With Swift
Task-Manager - Task Manager App With Swift

Task-Manager It's typical task manager where user can assign the importance, def

📲 The curated list of iOS Developer interview questions and answers, Swift & Objective-C
📲 The curated list of iOS Developer interview questions and answers, Swift & Objective-C

Awesome iOS interview questions and answers 🔛 Get started by picking interview's language and start preparing right now Install the app Prepare for t

A very simple way to implement Backbone.js style custom event listeners and triggering in Swift for iOS development.

Swift Custom Events A very simple way to implement Backbone.js style custom event listeners and triggering in Swift for iOS development. This provides

MpesaSDK - Swift SDK for the M-Pesa API (Mozambique)
MpesaSDK - Swift SDK for the M-Pesa API (Mozambique)

M-Pesa SDK Swift package for M-Pesa API (Mozambique) Ready Methods/APIs C2B B2B

GoraInterviewTask - Gora Interview Task with swift
GoraInterviewTask - Gora Interview Task with swift

goraInterviewTask Implements some endpoints from https://jsonplaceholder.typicod

Swiftcord - Swift wrapper for Discord's API. Maintained fork of Azoy's Sword
Swiftcord - Swift wrapper for Discord's API. Maintained fork of Azoy's Sword

Swiftcord - A Discord Library for Swift Requirements macOS, Linux, iOS, watchOS,

MetaWear-Swift-Combine-SDK - Build iOS and macOS apps controlling MetaWear Bluetooth Low Energy wearables without C++ or CoreBluetooth expertise
Comments
  • Drop iOS8 support to get rid of SPM warning

    Drop iOS8 support to get rid of SPM warning

    Any version of Xcode > 12 with dropped iOS 8 support will issue this warning.

    "The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 15.5.99."

    Alternatively, we may be able to just remove the entire platforms definition - but this should be enough.

    opened by rodrigordc 1
  • Bump tzinfo from 1.2.7 to 1.2.10

    Bump tzinfo from 1.2.7 to 1.2.10

    Bumps tzinfo from 1.2.7 to 1.2.10.

    Release notes

    Sourced from tzinfo's releases.

    v1.2.10

    TZInfo v1.2.10 on RubyGems.org

    v1.2.9

    • Fixed an incorrect InvalidTimezoneIdentifier exception raised when loading a zoneinfo file that includes rules specifying an additional transition to the final defined offset (for example, Africa/Casablanca in version 2018e of the Time Zone Database). #123.

    TZInfo v1.2.9 on RubyGems.org

    v1.2.8

    • Added support for handling "slim" format zoneinfo files that are produced by default by zic version 2020b and later. The POSIX-style TZ string is now used calculate DST transition times after the final defined transition in the file. The 64-bit section is now always used regardless of whether Time has support for 64-bit times. #120.
    • Rubinius is no longer supported.

    TZInfo v1.2.8 on RubyGems.org

    Changelog

    Sourced from tzinfo's changelog.

    Version 1.2.10 - 19-Jul-2022

    Version 1.2.9 - 16-Dec-2020

    • Fixed an incorrect InvalidTimezoneIdentifier exception raised when loading a zoneinfo file that includes rules specifying an additional transition to the final defined offset (for example, Africa/Casablanca in version 2018e of the Time Zone Database). #123.

    Version 1.2.8 - 8-Nov-2020

    • Added support for handling "slim" format zoneinfo files that are produced by default by zic version 2020b and later. The POSIX-style TZ string is now used calculate DST transition times after the final defined transition in the file. The 64-bit section is now always used regardless of whether Time has support for 64-bit times. #120.
    • Rubinius is no longer supported.
    Commits
    • 0814dcd Fix the release date.
    • fd05e2a Preparing v1.2.10.
    • b98c32e Merge branch 'fix-directory-traversal-1.2' into 1.2
    • ac3ee68 Remove unnecessary escaping of + within regex character classes.
    • 9d49bf9 Fix relative path loading tests.
    • 394c381 Remove private_constant for consistency and compatibility.
    • 5e9f990 Exclude Arch Linux's SECURITY file from the time zone index.
    • 17fc9e1 Workaround for 'Permission denied - NUL' errors with JRuby on Windows.
    • 6bd7a51 Update copyright years.
    • 9905ca9 Fix directory traversal in Timezone.get when using Ruby data source
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump cocoapods-downloader from 1.4.0 to 1.6.3

    Bump cocoapods-downloader from 1.4.0 to 1.6.3

    Bumps cocoapods-downloader from 1.4.0 to 1.6.3.

    Release notes

    Sourced from cocoapods-downloader's releases.

    1.6.3

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.2

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.1

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.0

    Enhancements
    • None.
    Bug Fixes
    • Adds a check for command injections in the input for hg and git.
      orta #124

    1.5.1

    Enhancements
    • None.
    Bug Fixes
    • Fix "can't modify frozen string" errors when pods are integrated using the branch option
      buju77 #10920

    1.5.0

    ... (truncated)

    Changelog

    Sourced from cocoapods-downloader's changelog.

    1.6.3 (2022-04-01)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.2 (2022-03-28)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.1 (2022-03-23)

    Enhancements
    • None.
    Bug Fixes
    • None.

    1.6.0 (2022-03-22)

    Enhancements
    • None.
    Bug Fixes
    • Adds a check for command injections in the input for hg and git.
      orta #124

    1.5.1 (2021-09-07)

    Enhancements
    • None.

    ... (truncated)

    Commits
    • c03e2ed Release 1.6.3
    • f75bccc Disable Bazaar tests due to macOS 12.3 not including python2
    • 52a0d54 Merge pull request #128 from CocoaPods/validate_before_dl
    • d27c983 Ensure that the git pre-processor doesn't accidentally bail also
    • 3adfe1f [CHANGELOG] Add empty Master section
    • 591167a Release 1.6.2
    • d2564c3 Merge pull request #127 from CocoaPods/validate_before_dl
    • 99fec61 Switches where we check for invalid input, to move it inside the download fun...
    • 96679f2 [CHANGELOG] Add empty Master section
    • 3a7c54b Release 1.6.1
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Could you raise the supported deployment target versions for SPM?

    Could you raise the supported deployment target versions for SPM?

    */SourcePackages/checkouts/Umbrella/Package.swift The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.5.99.

    opened by Desmuz 0
Releases(0.12.0)
Owner
Suyeol Jeon
A lazy developer 😴 I write many code to write less code.
Suyeol Jeon
This is swift project example to connect VNPTSmartCA SDK using Swift Language.

Example source code to integrate with VNPTSmartCA iOS SDK To run the example project, clone repository, and run pod install Requirements Installation

null 1 Feb 14, 2022
Home-assistant-swift-sdk - Used to integrate the Home Assistant APIs with your Swift-based apps.

home-assistant-swift-sdk This open-source library allows you to interact with a Home Assistant instance in your Swift-based (e.g., iOS, macOS, etc.) a

Alexander Golden 0 Dec 31, 2021
Azure Functions in Swift! Purely in Swift!

Azure Functions for Swift ⚡️ Write Azure Functions in Swift. This framework supports the new Azure Functions Custom Handlers (starting from 0.6.0) in

Saleh Albuga 87 Jan 3, 2023
Official Appwrite Swift SDK 🦅🍎

Appwrite Swift SDK This SDK is compatible with Appwrite server version 0.11.x. For older versions, please check previous releases. This is the Swift S

Appwrite 27 Dec 25, 2022
Swift SDK for Blockfrost.io API

Swift5 API client for Blockfrost Swift 5 SDK for Blockfrost.io API. Installation • Usage • API Endpoints Installation Swift package manager dependenci

blockfrost.io 10 Dec 24, 2022
WalletConnect Swift SDK v2

Wallet Connect v.2 - Swift Swift implementation of WalletConnect v.2 protocol for native iOS applications. Requirements iOS 13 XCode 13 Swift 5 Usage

WalletConnect Labs 16 Mar 30, 2022
Swift framework for authenticating with the Spotify API

SpotifyLogin SpotifyLogin is a Swift 5 Framework for authenticating with the Spotify API. Usage of this framework is bound under the Developer Terms o

Spotify 344 Jan 4, 2023
⚡️ A fully-featured and blazing-fast Swift API client to interact with Algolia.

The perfect starting point to integrate Algolia within your Swift project Documentation • Community Forum • Stack Overflow • Report a bug • FAQ • Supp

Algolia 192 Dec 23, 2022
A library for creating Stream Deck plugins in Swift.

StreamDeck A library for creating Stream Deck plugins in Swift. Usage Your plugin class should inherit from StreamDeckPlugin, which handles the WebSoc

Emory Dunn 15 Jan 2, 2023
iOS Mobile Automation With Swift

ios-mobile-automation Since I could hardly find any resources on iOS automation

Ahmethan G. 0 Dec 19, 2021