{"id":15293535,"url":"https://github.com/devxoul/umbrella","last_synced_at":"2025-04-04T12:10:07.639Z","repository":{"id":21715065,"uuid":"93848675","full_name":"devxoul/Umbrella","owner":"devxoul","description":"☂️ Analytics abstraction layer for Swift","archived":false,"fork":false,"pushed_at":"2022-09-25T21:08:00.000Z","size":97,"stargazers_count":614,"open_issues_count":18,"forks_count":48,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-04T12:10:04.356Z","etag":null,"topics":["analytics","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devxoul.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-09T10:38:22.000Z","updated_at":"2025-02-11T10:38:53.000Z","dependencies_parsed_at":"2022-07-25T02:02:16.589Z","dependency_job_id":null,"html_url":"https://github.com/devxoul/Umbrella","commit_stats":null,"previous_names":["devxoul/eventanalytics"],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devxoul%2FUmbrella","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devxoul%2FUmbrella/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devxoul%2FUmbrella/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devxoul%2FUmbrella/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devxoul","download_url":"https://codeload.github.com/devxoul/Umbrella/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247174456,"owners_count":20896078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analytics","swift"],"created_at":"2024-09-30T16:49:54.049Z","updated_at":"2025-04-04T12:10:07.621Z","avatar_url":"https://github.com/devxoul.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ☂️ Umbrella\n\n![Swift](https://img.shields.io/badge/Swift-5.0-orange.svg)\n[![CocoaPods](http://img.shields.io/cocoapods/v/Umbrella.svg)](https://cocoapods.org/pods/Umbrella)\n[![CI](https://github.com/devxoul/Umbrella/workflows/CI/badge.svg)](https://github.com/devxoul/Umbrella/actions)\n[![Codecov](https://img.shields.io/codecov/c/github/devxoul/Umbrella.svg)](https://codecov.io/gh/devxoul/Umbrella)\n\nAnalytics abstraction layer for Swift. Inspired by [Moya](https://github.com/Moya/Moya).\n\n## Table of Contents\n\n* [Why?](#why)\n* [Features](#features)\n* [At a Glance](#at-a-glance)\n* [Getting Started](#getting-started)\n    * [Defining Events](#defining-events)\n    * [Using Analytics](#using-analytics)\n    * [Built-in Providers](#built-in-providers)\n    * [Creating Custom Providers](#creating-custom-providers)\n* [Installation](#installation)\n* [Contributing](#contributing)\n    * [Generating Xcode Workspace](#generating-xcode-workspace)\n    * [Creating New Provider](#creating-new-provider)\n* [License](#license)\n\n## Why?\n\nThere 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.**\n\n## Features\n\n* 💪 Taking advantages of Swift compiler by using an enum and associated values.\n* 🎯 Logging events to multiple analytics providers at once.\n* 🎨 Creating custom analytics providers.\n\n## At a Glance\n\n**Before** 🤢\n\n```swift\nFIRAnalytics.logEvent(withName: kFIREventEcommercePurchase, parameters: [\n  kFIRParameterCurrency: \"USD\" as NSObject,\n  kFIRParameterValue: 9.99 as NSNumber,\n  kFIRParameterTransactionID: \"20170709123456\" as NSObject,\n])\nFlurry.logEvent(\"purchase\", withParameters: [\n  \"Currency\": \"USD\",\n  \"Price\": 9.99,\n  \"Transaction ID\": \"20170709123456\"\n])\nMyCustomAnalytics.logEvent(\"purchase\", withParameters: [\n  \"currency\": \"USD\",\n  \"price\": 9.99,\n  \"transaction_id\": \"20170709123456\"\n])\n```\n\n**After** 😊\n\n```swift\nlet analytics = Analytics\u003cMyAppEvent\u003e()\nanalytics.register(provider: FirebaseProvider())\nanalytics.register(provider: FlurryProvider())\nanalytics.register(provider: MyCustomProvider())\nanalytics.log(.purchase(currency: \"USD\", price: 9.99, transactionID: \"20170709123456\"))\n```\n\n## Getting Started\n\n### Defining Events\n\nFirst 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.\n\n```swift\nenum MyAppEvent {\n  case signup(username: String)\n  case viewContent(productID: Int)\n  case purchase(productID: Int, price: Float)\n}\n```\n\nThen make the enum to conform the protocol `EventType`. It requires two functions: `name(for:)` and `parameters(for:)`.\n\n```swift\nextension MyAppEvent: EventType {\n  /// An event name to be logged\n  func name(for provider: ProviderType) -\u003e String? {\n    switch self {\n    case .signup: return \"signup\"\n    case .viewContent: return \"view_content\"\n    case .purchase: return \"purchase\"\n    }\n  }\n\n  /// Parameters to be logged\n  func parameters(for provider: ProviderType) -\u003e [String: Any]? {\n    switch self {\n    case let .signup(username):\n      return [\"username\": username]\n    case let .viewContent(productID):\n      return [\"product_id\": productID]\n    case let .purchase(productID, price):\n      return [\"product_id\": productID, \"price\": price]\n    }\n  }\n}\n```\n\nYou can even provide different event names and parameters by `provider`s.\n\n### Using Analytics\n\nYou can define an `Analytics` instance anywhere but it's recommended to define at a global scope.\n\n```swift\nlet analytics = Analytics\u003cMyAppEvent\u003e()\n```\n\nThen 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:)`.\n\n```swift\nanalytics.register(provider: AnswersProvider())\nanalytics.register(provider: FirebaseProvider())\nanalytics.register(provider: FlurryProvider())\nanalytics.register(provider: MyAwesomeProvider())\n```\n\nIf you finished those steps, you can now log the events 🎉\n\n```swift\nanalytics.log(.signup(username: \"devxoul\"))\n```\n\n### Built-in Providers\n\nThere are several built-in providers.\n\n* AmplitudeProvider ([Amplitude-iOS](https://cocoapods.org/pods/Amplitude-iOS))\n* AnswersProvider ([Answers](https://cocoapods.org/pods/Answers))\n* AppboyProvider ([Appboy-iOS-SDK](http://cocoapods.org/pods/Appboy-iOS-SDK))\n* AppsFlyerProvider ([AppsFlyerFramework](http://cocoapods.org/pods/AppsFlyerFramework))\n* FacebookProvider ([FBSDKCoreKit](https://cocoapods.org/pods/FBSDKCoreKit))\n* FirebaseProvider ([Firebase/Analytics](https://cocoapods.org/pods/Firebase))\n* FlurryProvider ([Flurry-iOS-SDK/FabricSDK](https://cocoapods.org/pods/Flurry-iOS-SDK))\n* IntercomProvider ([Intercom](https://cocoapods.org/pods/Intercom))\n* LocalyticsProvider ([Localytics](https://cocoapods.org/pods/Localytics))\n* MixpanelProvider ([Mixpanel](https://cocoapods.org/pods/Mixpanel))\n* SegmentProvider ([Analytics](https://cocoapods.org/pods/Analytics))\n\nIf there's no provider you're looking for, you can [create an issue](https://github.com/devxoul/Umbrella/issues/new) or [create custom providers](#creating-custom-providers). It's also welcomed to create a pull request for missing services 🎉\n\n### Creating Custom Providers\n\nIf 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`.\n\n```swift\nfinal class MyAwesomeProvider: ProviderType {\n  func log(_ eventName: String, parameters: [String: Any]?) {\n    AwesomeAnalytics.logEvent(withName: eventName, parameters: parameters)\n  }\n}\n```\n\n## Installation\n\nUmbrella currently support [CocoaPods](https://cocoapods.org) only.\n\n```ruby\npod 'Umbrella'\npod 'Umbrella/Firebase' # using with built-in FirebaseProvider\npod 'Umbrella/...'\n```\n\n## Contributing\n\nAny discussions and pull requests are welcomed 💖\n\n### Generating Xcode Workspace\n\n```bash\n$ make project\n```\n\nThis will automatically generate **`Umbrella.xcworkspace`** and perform `pod install`.\n\n### Creating New Provider\n\nFor example, imagine that we are going to create a new provider for an analytics service 'Raincoat'.\n\n1. Add a library and a target definition in **`Package.swift`**.\n\n    ```diff\n      let package = Package(\n        name: \"Umbrella\",\n        products: [\n          .library(name: \"Umbrella\", targets: [\"Umbrella\"]),\n          .library(name: \"UmbrellaFirebase\", targets: [\"UmbrellaFirebase\"]),\n          .library(name: \"UmbrellaMixpanel\", targets: [\"UmbrellaMixpanel\"]),\n    +     .library(name: \"UmbrellaRaincoat\", targets: [\"UmbrellaRaincoat\"]),\n        ],\n        targets: [\n          .target(name: \"Umbrella\"),\n          .target(name: \"UmbrellaFirebase\", dependencies: [\"Umbrella\"]),\n          .target(name: \"UmbrellaMixpanel\", dependencies: [\"Umbrella\"]),\n    +     .target(name: \"UmbrellaRaincoat\", dependencies: [\"Umbrella\"]),\n          .testTarget(name: \"UmbrellaTests\", dependencies: [\"Umbrella\"]),\n          .testTarget(name: \"UmbrellaFirebaseTests\", dependencies: [\"UmbrellaFirebase\"]),\n          .testTarget(name: \"UmbrellaMixpanelTests\", dependencies: [\"UmbrellaMixpanel\"]),\n    +     .testTarget(name: \"UmbrellaRaincoat\", dependencies: [\"UmbrellaRaincoat\"]),\n        ]\n      )\n    ```\n\n2. Add a source file and a test file.\n\n    ```diff\n      ...\n      ├── Sources\n      │   ├── UmbrellaFirebase\n      │   │   └── FirebaseProvider.swift\n      │   ├── UmbrellaMixpanel\n      │   │   └── MixpanelProvider.swift\n    + │   ├── UmbrellaRaincoat\n    + │   │   └── RaincoatProvider.swift\n      |   ...\n      ├── Tests\n      │   ├── UmbrellaFirebaseTests\n      │   │   └── FirebaseProviderTests.swift\n      │   ├── UmbrellaMixpanelTests\n      │   │   └── MixpanelProviderTests.swift\n    + │   ├── UmbrellaRaincoatTests\n    + │   │   └── RaincoatProviderTests.swift\n      ... ...\n    ```\n\n3. Add a CocoaPods dependency in **`Podfile`**.\n\n    ```diff\n     target 'UmbrellaFirebaseTests' do\n       platform :ios, '8.0'\n       pod 'Firebase/Analytics'\n     end\n\n     target 'UmbrellaMixpanelTests' do\n       platform :ios, '8.0'\n       pod 'Mixpanel'\n     end\n\n    + target 'UmbrellaRaincoatTests' do\n    +   platform :ios, '8.0'\n    +   pod 'Raincoat'\n    + end\n    ```\n\n4. Add a CocoaPods subspec in **`Umbrella.podspec`**.\n\n    ```diff\n      s.subspec \"Firebase\" do |ss|\n        ss.source_files = \"Sources/UmbrellaFirebase/*.swift\"\n        ss.dependency \"Umbrella/Core\"\n      end\n\n      s.subspec \"Mixpanel\" do |ss|\n        ss.source_files = \"Sources/UmbrellaMixpanel/*.swift\"\n        ss.dependency \"Umbrella/Core\"\n      end\n\n    + s.subspec \"Raincoat\" do |ss|\n    +   ss.source_files = \"Sources/UmbrellaRaincoat/*.swift\"\n    +   ss.dependency \"Umbrella/Core\"\n    + end\n    ```\n\n5. Create a Xcode workspace and run tests. Don't forget to check the code coverage to ensure that tests can cover the new provider.\n\n    ```console\n    $ make project\n    ```\n\n## License\n\nUmbrella is under MIT license. See the [LICENSE](LICENSE) file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevxoul%2Fumbrella","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevxoul%2Fumbrella","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevxoul%2Fumbrella/lists"}