├── .all-contributorsrc ├── .editorconfig ├── .github ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── test.yml ├── .gitignore ├── CapacitorCommunityFirebaseAnalytics.podspec ├── LICENSE ├── PLUGIN_AUTHOR_README.md ├── README.md ├── android ├── .npmignore ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── proguard-rules.pro ├── settings.gradle └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── getcapacitor │ │ │ └── community │ │ │ └── firebaseanalytics │ │ │ └── FirebaseAnalytics.java │ └── res │ │ ├── layout │ │ └── bridge_layout_main.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── getcapacitor │ └── community │ └── firebaseanalytics │ └── FirebaseAnalyticsTest.java ├── ios ├── .npmignore ├── Plugin.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Plugin.xcscheme ├── Plugin.xcworkspace │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Plugin │ ├── Info.plist │ ├── Plugin.h │ ├── Plugin.m │ └── Plugin.swift ├── PluginTests │ ├── Info.plist │ └── PluginTests.swift └── Podfile ├── package-lock.json ├── package.json ├── rollup.config.mjs ├── src ├── definitions.ts ├── index.ts └── web.ts └── tsconfig.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "brownoxford", 10 | "name": "Chris Abernethy", 11 | "avatar_url": "https://avatars.githubusercontent.com/u/755209?v=4", 12 | "profile": "https://github.com/brownoxford", 13 | "contributions": [ 14 | "maintenance" 15 | ] 16 | }, 17 | { 18 | "login": "priyankpat", 19 | "name": "Priyank Patel", 20 | "avatar_url": "https://avatars.githubusercontent.com/u/5585797?v=4", 21 | "profile": "http://priyankpatel.io", 22 | "contributions": [ 23 | "code" 24 | ] 25 | }, 26 | { 27 | "login": "stewwan", 28 | "name": "stewwan", 29 | "avatar_url": "https://avatars.githubusercontent.com/u/19799027?v=4", 30 | "profile": "http://github.com/stewones", 31 | "contributions": [ 32 | "code" 33 | ] 34 | }, 35 | { 36 | "login": "karm435", 37 | "name": "Karmjit Singh", 38 | "avatar_url": "https://avatars.githubusercontent.com/u/6672354?v=4", 39 | "profile": "https://www.codewithkarma.com/", 40 | "contributions": [ 41 | "test", 42 | "bug" 43 | ] 44 | }, 45 | { 46 | "login": "mRoca", 47 | "name": "Michel Roca", 48 | "avatar_url": "https://avatars.githubusercontent.com/u/4746261?v=4", 49 | "profile": "https://github.com/mRoca", 50 | "contributions": [ 51 | "bug" 52 | ] 53 | }, 54 | { 55 | "login": "slajar", 56 | "name": "Matthias", 57 | "avatar_url": "https://avatars.githubusercontent.com/u/1584274?v=4", 58 | "profile": "http://www.ultramixer.com", 59 | "contributions": [ 60 | "review" 61 | ] 62 | }, 63 | { 64 | "login": "tobium", 65 | "name": "Tobi", 66 | "avatar_url": "https://avatars.githubusercontent.com/u/2484805?v=4", 67 | "profile": "http://www.ultramixer.com", 68 | "contributions": [ 69 | "code" 70 | ] 71 | }, 72 | { 73 | "login": "salohcin714", 74 | "name": "Nicholas Norris", 75 | "avatar_url": "https://avatars.githubusercontent.com/u/41271531?v=4", 76 | "profile": "https://github.com/salohcin714", 77 | "contributions": [ 78 | "bug" 79 | ] 80 | }, 81 | { 82 | "login": "gabrielscarvalho", 83 | "name": "gabrielscarvalho", 84 | "avatar_url": "https://avatars.githubusercontent.com/u/1574205?v=4", 85 | "profile": "https://github.com/gabrielscarvalho", 86 | "contributions": [ 87 | "bug", 88 | "code" 89 | ] 90 | }, 91 | { 92 | "login": "ptmkenny", 93 | "name": "ptmkenny", 94 | "avatar_url": "https://avatars.githubusercontent.com/u/1451472?v=4", 95 | "profile": "https://github.com/ptmkenny", 96 | "contributions": [ 97 | "bug", 98 | "code", 99 | "doc" 100 | ] 101 | }, 102 | { 103 | "login": "vkyeswa", 104 | "name": "vkyeswa", 105 | "avatar_url": "https://avatars.githubusercontent.com/u/5016129?v=4", 106 | "profile": "https://github.com/vkyeswa", 107 | "contributions": [ 108 | "bug" 109 | ] 110 | }, 111 | { 112 | "login": "losciur", 113 | "name": "losciur", 114 | "avatar_url": "https://avatars.githubusercontent.com/u/62714342?v=4", 115 | "profile": "https://github.com/losciur", 116 | "contributions": [ 117 | "test", 118 | "bug" 119 | ] 120 | }, 121 | { 122 | "login": "wyattades", 123 | "name": "Wyatt Ades", 124 | "avatar_url": "https://avatars.githubusercontent.com/u/992076?v=4", 125 | "profile": "https://github.com/wyattades", 126 | "contributions": [ 127 | "code" 128 | ] 129 | }, 130 | { 131 | "login": "quqkuk", 132 | "name": "quq", 133 | "avatar_url": "https://avatars.githubusercontent.com/u/40238888?v=4", 134 | "profile": "https://github.com/quqkuk", 135 | "contributions": [ 136 | "code" 137 | ] 138 | } 139 | ], 140 | "contributorsPerLine": 7, 141 | "projectName": "firebase-analytics", 142 | "projectOwner": "capacitor-community", 143 | "repoType": "github", 144 | "repoHost": "https://github.com", 145 | "skipCi": true 146 | } 147 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = false 8 | insert_final_newline = false -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 2 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this Capacitor Community project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities. 4 | 5 | Communication through this repository must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 6 | 7 | We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to this Capacitor Community project to do the same. 8 | 9 | If any member of the community violates this code of conduct, the maintainers of this Capacitor Community and/or the Ionic project may take action, including but not limited to removing issues, comments, and PRs or blocking accounts as deemed appropriate. 10 | 11 | If you are subject to or witness unacceptable behavior, or have any other concerns, please contact the maintainer of this repository or email hi@ionicframework.com. 12 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributing to this project 3 | 4 | Describe the steps a developer should go through in order to contribute to this project 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [master] 4 | pull_request: 5 | branches: [master] 6 | workflow_dispatch: 7 | name: Plugin Unit Tests 8 | jobs: 9 | ios: 10 | name: iOS Unit Tests 11 | runs-on: macos-latest 12 | strategy: 13 | matrix: 14 | destination: 15 | - "platform=iOS Simulator,OS=18.1,name=iPhone 16" 16 | steps: 17 | - name: Checkout Code 18 | uses: actions/checkout@v3 19 | - name: Setup Node 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: "20" 23 | - name: Install NPM Dependencies 24 | run: npm ci 25 | - name: Build NPM Module 26 | run: npm run build 27 | - name: Install Cocoapods 28 | run: cd ios && pod install 29 | - name: Run iOS Tests 30 | run: cd ios && xcodebuild clean test -workspace Plugin.xcworkspace -scheme Plugin -destination "${destination}" 31 | env: 32 | destination: ${{ matrix.destination }} 33 | 34 | android: 35 | name: Android Unit Tests 36 | runs-on: ubuntu-latest 37 | steps: 38 | - name: Checkout Code 39 | uses: actions/checkout@v3 40 | - name: Setup Node 41 | uses: actions/setup-node@v4 42 | with: 43 | node-version: "20" 44 | - name: Setup JDK 21 45 | uses: actions/setup-java@v4 46 | with: 47 | distribution: "zulu" 48 | java-version: "21" 49 | - name: Install NPM Dependencies 50 | run: npm ci 51 | - name: Build NPM Module 52 | run: npm run build 53 | - name: Run Android Tests 54 | run: cd ./android && ./gradlew test --stacktrace 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | dist 3 | .sourcemaps 4 | xcuserdata/ 5 | node_modules/ 6 | cli/dist/commands/copy.js 7 | Pods/ 8 | test_project/ 9 | *.map 10 | .DS_Store 11 | Podfile.lock 12 | example/www/ 13 | example/electron/www/* 14 | example/electron/capacitor.config.json 15 | example/android/app/src/main/assets/public/* 16 | !example/android/app/src/main/assets/public/.gitkeep 17 | example/ios/IonicRunner/public/* 18 | !example/ios/IonicRunner/public/.gitkeep 19 | Build/* 20 | Index/ 21 | .*.sw* 22 | site/www 23 | android-template.iml 24 | !/build/.npmkeep 25 | lerna-debug.log 26 | capacitor-ios/ 27 | local.properties 28 | contents.xcworkspacedata 29 | .stencil/ 30 | android-template/.gradle/ 31 | android-template/app/app.iml 32 | /site/.env 33 | /site/.firebase 34 | .gradle/ 35 | .settings/ 36 | .project 37 | android/.gradle/ 38 | android/build/ 39 | android/*.iml 40 | android/android.iml 41 | android/.idea/workspace.xml 42 | android/.idea/tasks.xml 43 | android/.idea/gradle.xml 44 | android/.idea/assetWizardSettings.xml 45 | android/.idea/dictionaries 46 | android/.idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | android/.idea/caches 49 | android/.idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | android/.idea/navEditor.xml -------------------------------------------------------------------------------- /CapacitorCommunityFirebaseAnalytics.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | package = JSON.parse(File.read(File.join(File.dirname(__FILE__), 'package.json'))) 3 | 4 | s.name = 'CapacitorCommunityFirebaseAnalytics' 5 | s.version = package['version'] 6 | s.summary = package['description'] 7 | s.license = package['license'] 8 | s.homepage = package['homepage'] 9 | s.author = package['author'] 10 | s.source = { :git => 'https://github.com/capacitor-community/firebase-analytics', :tag => s.version.to_s } 11 | s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' 12 | s.ios.deployment_target = '13.0' 13 | s.static_framework = true 14 | s.dependency 'Capacitor' 15 | s.dependency 'FirebaseAnalytics' 16 | end 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 mesur.io 4 | Copyright (c) 2020 Priyank Patel 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /PLUGIN_AUTHOR_README.md: -------------------------------------------------------------------------------- 1 | # For authors of this plugin from the Capacitor core team 2 | 3 | This is a welcome message to all new plugin authors in the Capacitor Community organization. After reading and acting on this feel free to delete it from the repo. 4 | 5 | First of all, welcome! We look forward to having your awesome plugin and contributions in this organization and are available for help if need be (easiest way is to ping one of us on Twitter). 6 | 7 | ## Registring with the Capacitor team 8 | 9 | Before following any of the steps below, make sure you have been granted access to the `capacitor-community` GitHub org and `@capacitor-community` npm scope. 10 | 11 | ## Project Setup 12 | 13 | One of the goals of the Capacitor Community initiative is to have a set of github repos that follow a set of conventions around READMES, package naming 14 | 15 | ### Getting Started 16 | 17 | When starting a new repo in the `capacitor-community` org, make sure to select using the `capacitor-community/.github` template repo for your new project. This will pre-populate your project with a set of ready to go housekeeping items. 18 | 19 | ### License 20 | 21 | We _strongly_ encourage your project use the MIT license. Apache 2 is also acceptable. Any other license must be approved with the Capacitor core team in advance to avoid licensing surprises. 22 | 23 | Your next step after creating the project should be to update the `LICENSE` file and fill in the correct year and copyright holder information. 24 | 25 | ### README format 26 | 27 | ### Package Naming 28 | 29 | Packages should be named as simply as possible, without any `capacitor` or `plugin` words in the package name itself. Packages must be published in the `@capacitor-community` npm scope. 30 | 31 | For example, a Google Maps plugin would be published under `@capacitor-community/google-maps`. 32 | 33 | ### Publishing 34 | 35 | Projects should use the `np` package for publishing which will correctly update tags and manage the entire publish process. 36 | 37 | ### Changelogs 38 | 39 | Projects should follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) process (more info soon) 40 | 41 | ### Recognizing Contributors 42 | 43 | Recognizing contributors is important. Every project in the `capacitor-community` GitHub org is automatically set up to use [All Contributors](https://allcontributors.org/) and maintainers should recognize any community members that contribute by following the [All Contributors usage guide](https://allcontributors.org/docs/en/bot/usage). 44 | 45 | ### Code Formatting 46 | 47 | Capacitor uses a slightly less conventional code style for iOS and Android. The main differences are using two spaces and curly braces opening on the same line. Please adjust your editor settings or use a code formatter. In the future we will distribute a prettier config to make this easier. 48 | 49 | ### Where to get help 50 | 51 | While the Capacitor Community organization is a community-driven environment, it is facilitated by the core Capacitor team at Ionic. If you are ever in need of help, don't hesitate to tweet at one of us or send us an email, especially to Max (Ionic CEO): [@maxlynch on Twitter](https://twitter.com/maxlynch). 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |


2 |

Firebase Analytics

3 |

@capacitor-community/firebase-analytics

4 |

5 | Capacitor community plugin for native Firebase Analytics. 6 |

7 | 8 |

9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 |

19 | 20 | ## ❗❗ Breaking changes when updating to ✏️v7.0.0✏️❗❗ 21 | 22 | ✏️✏️ This plugin now supports Capacitor 7 only. For Capacitor 6, 5 and 4 please use version listed below ✏️✏️ 23 | 24 | ## Plugin versions 25 | 26 | | Capacitor version | Plugin version | 27 | | ----------------- | -------------- | 28 | | 7.x | 7.x | 29 | | 6.x | 6.x | 30 | | 5.x | 5.0.1 | 31 | | 4.x | 1.0.1 | 32 | 33 | ## Maintainers 34 | 35 | | Maintainer | GitHub | Social | 36 | | ---------- | --------------------------------------- | ----------------------------------------- | 37 | | mesur.io | [mesur-io](https://github.com/mesur-io) | [@mesur_io](https://twitter.com/mesur_io) | 38 | 39 | ## Installation 40 | 41 | Using npm: 42 | 43 | ```bash 44 | npm install @capacitor-community/firebase-analytics@latest 45 | ``` 46 | 47 | Using yarn: 48 | 49 | ```bash 50 | yarn add @capacitor-community/firebase-analytics@latest 51 | ``` 52 | 53 | Sync native files: 54 | 55 | ```bash 56 | # Update the native plugins and dependencies referenced in package.json 57 | npx cap sync 58 | ``` 59 | 60 | > **Note:** You may also need to run **File > Sync Project with Gradle Files** in order for Android Studio to recognize the import. 61 | 62 | ## Configuration 63 | 64 | No configuration is required for this plugin. 65 | 66 | ## Examples 67 | 68 | [Click here](https://github.com/jcesarmobile/capacitor-firebase-analytics-example) for an example on how to implement this plugin. 69 | 70 | You can also clone the repository: 71 | 72 | ```bash 73 | git clone https://github.com/jcesarmobile/capacitor-firebase-analytics-example 74 | ``` 75 | 76 | ## Supported methods 77 | 78 | | Name | Android | iOS | Web | 79 | | :------------------------ | :------ | :-- | :-- | 80 | | setUserId | ✅ | ✅ | ✅ | 81 | | setUserProperty | ✅ | ✅ | ✅ | 82 | | getAppInstanceId | ✅ | ✅ | ❌ | 83 | | setScreenName | ✅ | ✅ | ❌ | 84 | | reset | ✅ | ✅ | ❌ | 85 | | logEvent | ✅ | ✅ | ✅ | 86 | | setCollectionEnabled | ✅ | ✅ | ✅ | 87 | | setSessionTimeoutDuration | ✅ | ✅ | ✅ | 88 | | enable | ✅ | ✅ | ✅ | 89 | | disable | ✅ | ✅ | ✅ | 90 | 91 | ## Usage 92 | 93 | ```typescript 94 | import { FirebaseAnalytics } from "@capacitor-community/firebase-analytics"; 95 | 96 | /** 97 | * Platform: Web 98 | * Configure and initialize the firebase app. 99 | * @param options - firebase web app configuration options 100 | * */ 101 | FirebaseAnalytics.initializeFirebase({ 102 | apiKey: "...", 103 | authDomain: "...", 104 | databaseURL: "...", 105 | projectId: "...", 106 | storageBucket: "...", 107 | messagingSenderId: "...", 108 | appId: "...", 109 | measurementId: "...", 110 | }); 111 | 112 | /** 113 | * Platform: Web/Android/iOS 114 | * Sets the user ID property. 115 | * @param userId - unique identifier of a user 116 | * @returns void 117 | * https://firebase.google.com/docs/analytics/userid 118 | */ 119 | FirebaseAnalytics.setUserId({ 120 | userId: "john_doe_123", 121 | }); 122 | 123 | /** 124 | * Platform: Web/Android/iOS 125 | * Sets a user property to a given value. 126 | * @param options - property name and value to set 127 | * @returns void 128 | * https://firebase.google.com/docs/analytics/user-properties 129 | */ 130 | FirebaseAnalytics.setUserProperty({ 131 | name: "favorite_food", 132 | value: "pizza", 133 | }); 134 | 135 | /** 136 | * Platform: Android/iOS 137 | * Retrieves the app instance id from the service. 138 | * @param none 139 | * @returns instanceId - individual instance id value 140 | * https://firebase.google.com/docs/analytics/user-properties 141 | */ 142 | FirebaseAnalytics.getAppInstanceId(); 143 | 144 | /** 145 | * Platform: Android/iOS 146 | * Sets the current screen name, which specifies the current visual context in your app. 147 | * @param screenName - name of the current screen to track 148 | * nameOverride - name of the screen class to override 149 | * @returns instanceId - individual instance id value 150 | * https://firebase.google.com/docs/analytics/screenviews 151 | */ 152 | FirebaseAnalytics.setScreenName({ 153 | screenName: "login", 154 | nameOverride: "LoginScreen", 155 | }); 156 | 157 | /** 158 | * Platform: Web/Android/iOS 159 | * Clears all analytics data for this app from the device and resets the app instance id. 160 | * @param none 161 | * @returns void 162 | */ 163 | FirebaseAnalytics.reset(); 164 | 165 | /** 166 | * Platform: Web/Android/iOS 167 | * Logs an app event. 168 | * @param name - name of the event to log 169 | * params - key/value pairs of properties (25 maximum per event) 170 | * @returns void 171 | */ 172 | FirebaseAnalytics.logEvent({ 173 | name: "select_content", 174 | params: { 175 | content_type: "image", 176 | content_id: "P12453", 177 | items: [{ name: "Kittens" }], 178 | }, 179 | }); 180 | 181 | /** 182 | * Platform: Web/Android/iOS 183 | * Sets whether analytics collection is enabled for this app on this device. 184 | * @param name - enabled - boolean true/false 185 | * @returns void 186 | */ 187 | FirebaseAnalytics.setCollectionEnabled({ 188 | enabled: false, 189 | }); 190 | 191 | /** 192 | * Platform: Web/Android/iOS 193 | * Deprecated - use setCollectionEnabled() instead 194 | * Enable analytics collection for this app on this device. 195 | * @param none 196 | * @returns void 197 | */ 198 | FirebaseAnalytics.enable(); 199 | 200 | /** 201 | * Platform: Web/Android/iOS 202 | * Deprecated - use setCollectionEnabled() instead 203 | * Disable analytics collection for this app on this device. 204 | * @param none 205 | * @returns void 206 | */ 207 | FirebaseAnalytics.disable(); 208 | 209 | /** 210 | * Platform: Web/Android/iOS 211 | * Sets the duration of inactivity that terminates the current session. 212 | * @param duration - duration in seconds (default - 18000) 213 | * @returns void 214 | */ 215 | FirebaseAnalytics.setSessionTimeoutDuration({ 216 | duration: 10000, 217 | }); 218 | ``` 219 | 220 | ## Setup 221 | 222 | Navigate to the project settings page for your app on Firebase. 223 | 224 | ### iOS 225 | 226 | Download the `GoogleService-Info.plist` file. In Xcode right-click on the yellow folder named "App" and select the `Add files to "App"`. 227 | 228 | > Tip: if you drag and drop your file to this location, Xcode may not be able to find it. 229 | 230 | ### Android 231 | 232 | Download the `google-services.json` file and copy it to `android/app/` directory of your capacitor project. 233 | 234 | #### Variables 235 | 236 | This plugin will use the following project variables (defined in your app’s `variables.gradle` file): 237 | 238 | - `$firebaseAnalyticsVersion` version of `com.google.firebase:firebase-analytics` (default: `21.2.2`) 239 | 240 | ## iOS setup 241 | 242 | - `ionic start my-cap-app --capacitor` 243 | - `cd my-cap-app` 244 | - `npm install --save @capacitor-community/firebase-analytics` 245 | - `mkdir www && touch www/index.html` 246 | - `sudo gem install cocoapods` (only once) 247 | - `npx cap add ios` 248 | - `npx cap sync ios` (every time you run `npm install`) 249 | - `npx cap open ios` 250 | - sign your app at xcode (general tab) 251 | - add `GoogleService-Info.plist` to the app folder in xcode 252 | 253 | ### Enable debug view 254 | 255 | 1. In Xcode, select Product > Scheme > Edit scheme 256 | 2. Select Run from the left menu 257 | 3. Select the Arguments tab 258 | 4. In the Arguments Passed On Launch section, add `-FIRAnalyticsDebugEnabled` 259 | 260 | > Tip: every time you change a native code you may need to clean up the cache (Product > Clean build folder) and then run the app again. 261 | 262 | ## Android setup 263 | 264 | - `ionic start my-cap-app --capacitor` 265 | - `cd my-cap-app` 266 | - `npm install --save @capacitor-community/firebase-analytics` 267 | - `mkdir www && touch www/index.html` 268 | - `npx cap add android` 269 | - `npx cap sync android` (every time you run `npm install`) 270 | - `npx cap open android` 271 | - add `google-services.json` to your `android/app` folder 272 | 273 | Now you should be set to go. Try to run your client using `ionic cap run android --livereload --address=0.0.0.0`. 274 | 275 | > Tip: every time you change a native code you may need to clean up the cache (Build > Clean Project | Build > Rebuild Project) and then run the app again. 276 | 277 | ## Updating 278 | 279 | For existing projects you can upgrade all capacitor related packages (including this plugin) with this single command 280 | 281 | `npx npm-upgrade '*capacitor*' && npm install` 282 | 283 | ## Migration 284 | 285 | If you were previously using the `capacitor-analytics` package from npm 286 | 287 | 1. Update NPM package: 288 | 289 | ```bash 290 | npm uninstall --save capacitor-analytics 291 | npm install --save-prod @capacitor-community/firebase-analytics@latest 292 | ``` 293 | 294 | 1. Update the plugin initialization in Android's _MainActivity.java_ 295 | 296 | Remove the old plugin import: 297 | 298 | ```diff 299 | -import io.stewan.capacitor.analytics.AnalyticsPlugin; 300 | ``` 301 | 302 | Update the `init()` call to remove the old plugin import. You may be able to remove the entire `init()` call if there is nothing else in there. 303 | 304 | ```diff 305 | // Initializes the Bridge 306 | this.init(savedInstanceState, new ArrayList>() {{ 307 | // Additional plugins you've installed go here 308 | // Ex: add(TotallyAwesomePlugin.class); 309 | - add(AnalyticsPlugin.class); 310 | }}); 311 | ``` 312 | 313 | 1. Public API changes: 314 | - `instance()` has been renamed to `getAppInstanceId()` 315 | - `setScreen()` has been renamed to `setScreenName()` 316 | - `setUserID()` has been renamed to `setUserId()` 317 | - `setUserProp()` has been renamed to `setUserProperty()` 318 | - `enable()` has been deprecated in favor of `setCollectionEnabled()` 319 | - `disable()` has been deprecated in favor of `setCollectionEnabled()` 320 | 321 | ## Further info 322 | 323 | - [Android](https://firebase.google.com/docs/android/setup) 324 | - [iOS](https://firebase.google.com/docs/analytics/get-started?platform=ios) 325 | - [Web](https://firebase.google.com/docs/analytics/get-started?platform=web) 326 | 327 | ## Contributors ✨ 328 | 329 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 |

Chris Abernethy

🚧

Priyank Patel

💻

stewwan

💻

Karmjit Singh

⚠️ 🐛

Michel Roca

🐛

Matthias

👀

Tobi

💻

Nicholas Norris

🐛

gabrielscarvalho

🐛 💻

ptmkenny

🐛 💻 📖

vkyeswa

🐛

losciur

⚠️ 🐛

wyattades

💻

losciur

💻
354 | 355 | 356 | 357 | 358 | 359 | 360 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 361 | -------------------------------------------------------------------------------- /android/.npmignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build 3 | local.properties -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' 3 | androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0' 4 | androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1' 5 | androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1' 6 | firebaseAnalyticsVersion = project.hasProperty('firebaseAnalyticsVersion') ? rootProject.ext.firebaseAnalyticsVersion : '21.2.2' 7 | } 8 | 9 | buildscript { 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath 'com.github.bjoernq:unmockplugin:0.7.8' 16 | 17 | classpath 'com.android.tools.build:gradle:8.7.2' 18 | 19 | classpath 'com.google.gms:google-services:4.4.2' 20 | } 21 | } 22 | 23 | apply plugin: 'com.android.library' 24 | 25 | apply plugin: 'de.mobilej.unmock' 26 | unMock { 27 | keep "android.os.Bundle" 28 | keepStartingWith "org.json." 29 | } 30 | 31 | android { 32 | namespace "com.getcapacitor.community.firebaseanalytics" 33 | compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35 34 | defaultConfig { 35 | minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23 36 | targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35 37 | versionCode 1 38 | versionName "1.0" 39 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 40 | } 41 | buildTypes { 42 | release { 43 | minifyEnabled false 44 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 45 | } 46 | } 47 | lintOptions { 48 | abortOnError false 49 | } 50 | compileOptions { 51 | sourceCompatibility JavaVersion.VERSION_21 52 | targetCompatibility JavaVersion.VERSION_21 53 | } 54 | } 55 | 56 | repositories { 57 | google() 58 | mavenCentral() 59 | } 60 | 61 | 62 | dependencies { 63 | implementation fileTree(dir: 'libs', include: ['*.jar']) 64 | implementation project(':capacitor-android') 65 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" 66 | testImplementation "junit:junit:$junitVersion" 67 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" 68 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" 69 | implementation "com.google.firebase:firebase-analytics:$firebaseAnalyticsVersion" 70 | } 71 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | # Supports AndroidX 20 | android.useAndroidX=true 21 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capacitor-community/firebase-analytics/25160d7e50aaf0840794f1f62ff3903165e8fa5f/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | if ! command -v java >/dev/null 2>&1 134 | then 135 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 136 | 137 | Please set the JAVA_HOME variable in your environment to match the 138 | location of your Java installation." 139 | fi 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | 201 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 202 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 203 | 204 | # Collect all arguments for the java command; 205 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 206 | # shell script including quotes and variable substitutions, so put them in 207 | # double quotes to make sure that they get re-expanded; and 208 | # * put everything else in single quotes, so that it's not re-expanded. 209 | 210 | set -- \ 211 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 212 | -classpath "$CLASSPATH" \ 213 | org.gradle.wrapper.GradleWrapperMain \ 214 | "$@" 215 | 216 | # Stop when "xargs" is not available. 217 | if ! command -v xargs >/dev/null 2>&1 218 | then 219 | die "xargs is not available" 220 | fi 221 | 222 | # Use "xargs" to parse quoted args. 223 | # 224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 | # 226 | # In Bash we could simply go: 227 | # 228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 | # set -- "${ARGS[@]}" "$@" 230 | # 231 | # but POSIX shell has neither arrays nor command substitution, so instead we 232 | # post-process each arg (as a line of input to sed) to backslash-escape any 233 | # character that might be a shell metacharacter, then use eval to reverse 234 | # that process (while maintaining the separation between arguments), and wrap 235 | # the whole thing up as a single "set" statement. 236 | # 237 | # This will of course break if any of these variables contains a newline or 238 | # an unmatched quote. 239 | # 240 | 241 | eval "set -- $( 242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 | xargs -n1 | 244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 | tr '\n' ' ' 246 | )" '"$@"' 247 | 248 | exec "$JAVACMD" "$@" 249 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /android/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':capacitor-android' 2 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/src/main/java/com/getcapacitor/community/firebaseanalytics/FirebaseAnalytics.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.firebaseanalytics; 2 | 3 | import android.Manifest; 4 | import android.os.Bundle; 5 | import androidx.annotation.NonNull; 6 | import com.getcapacitor.JSObject; 7 | import com.getcapacitor.Plugin; 8 | import com.getcapacitor.PluginCall; 9 | import com.getcapacitor.PluginMethod; 10 | import com.getcapacitor.annotation.CapacitorPlugin; 11 | import com.getcapacitor.annotation.Permission; 12 | import com.google.android.gms.tasks.OnCompleteListener; 13 | import com.google.android.gms.tasks.Task; 14 | import java.util.Iterator; 15 | import org.json.JSONArray; 16 | import org.json.JSONException; 17 | import org.json.JSONObject; 18 | 19 | @CapacitorPlugin( 20 | name = "FirebaseAnalytics", 21 | permissions = { 22 | @Permission( 23 | strings = { Manifest.permission.ACCESS_NETWORK_STATE }, 24 | alias = "network" 25 | ), 26 | @Permission(strings = { Manifest.permission.INTERNET }, alias = "internet"), 27 | @Permission( 28 | strings = { Manifest.permission.WAKE_LOCK }, 29 | alias = "wakelock" 30 | ), 31 | } 32 | ) 33 | public class FirebaseAnalytics extends Plugin { 34 | private com.google.firebase.analytics.FirebaseAnalytics mFirebaseAnalytics; 35 | 36 | private final String MISSING_REF_MSSG = 37 | "Firebase analytics is not initialized"; 38 | 39 | @Override 40 | public void load() { 41 | super.load(); 42 | 43 | // Obtain the FirebaseAnalytics instance. 44 | mFirebaseAnalytics = 45 | com.google.firebase.analytics.FirebaseAnalytics.getInstance( 46 | bridge.getActivity() 47 | ); 48 | } 49 | 50 | /** 51 | * Sets the user ID property. 52 | * @param call - userId: unique identifier of the user to log 53 | */ 54 | @PluginMethod 55 | public void setUserId(PluginCall call) { 56 | try { 57 | if (mFirebaseAnalytics == null) { 58 | call.reject(MISSING_REF_MSSG); 59 | return; 60 | } 61 | 62 | if (!call.hasOption("userId")) { 63 | call.reject("userId property is missing"); 64 | return; 65 | } 66 | 67 | String userId = call.getString("userId"); 68 | mFirebaseAnalytics.setUserId(userId); 69 | call.resolve(); 70 | } catch (Exception ex) { 71 | call.reject(ex.getLocalizedMessage()); 72 | } 73 | } 74 | 75 | /** 76 | * Sets a user property to a given value. 77 | * @param call - name: The name of the user property to set. 78 | * value: The value of the user property. 79 | */ 80 | @PluginMethod 81 | public void setUserProperty(PluginCall call) { 82 | try { 83 | if (mFirebaseAnalytics == null) { 84 | call.reject(MISSING_REF_MSSG); 85 | return; 86 | } 87 | 88 | if (!call.hasOption("name")) { 89 | call.reject("name property is missing"); 90 | return; 91 | } 92 | 93 | if (!call.hasOption("value")) { 94 | call.reject("value property is missing"); 95 | return; 96 | } 97 | 98 | String name = call.getString("name"); 99 | String value = call.getString("value"); 100 | 101 | mFirebaseAnalytics.setUserProperty(name, value); 102 | call.resolve(); 103 | } catch (Exception ex) { 104 | call.reject(ex.getLocalizedMessage()); 105 | } 106 | } 107 | 108 | /** 109 | * Retrieves the app instance id from the service. 110 | * @param call - instanceId: current instance if of the app 111 | */ 112 | @PluginMethod 113 | public void getAppInstanceId(final PluginCall call) { 114 | if (mFirebaseAnalytics == null) { 115 | call.reject(MISSING_REF_MSSG); 116 | return; 117 | } 118 | Task task = mFirebaseAnalytics.getAppInstanceId(); 119 | task.addOnCompleteListener(new OnCompleteListener() { 120 | @Override 121 | public void onComplete(@NonNull Task task) { 122 | if (task.isSuccessful()) { 123 | String instanceId = task.getResult(); 124 | if (instanceId != null && instanceId.isEmpty()) { 125 | call.reject("failed to obtain app instance id"); 126 | } else { 127 | JSObject result = new JSObject(); 128 | result.put("instanceId", instanceId); 129 | call.resolve(result); 130 | } 131 | } else { 132 | Exception exception = task.getException(); 133 | call.reject(exception.getLocalizedMessage()); 134 | } 135 | } 136 | }); 137 | } 138 | 139 | /** 140 | * Sets the current screen name, which specifies the current visual context in your app. 141 | * @param call - screenName: the activity to which the screen name and class name apply. 142 | * nameOverride: the name of the current screen. Set to null to clear the current screen name. 143 | */ 144 | @PluginMethod 145 | public void setScreenName(final PluginCall call) { 146 | try { 147 | if (mFirebaseAnalytics == null) { 148 | call.reject(MISSING_REF_MSSG); 149 | return; 150 | } 151 | 152 | if (!call.hasOption("screenName")) { 153 | call.reject("screenName property is missing"); 154 | return; 155 | } 156 | 157 | final String screenName = call.getString("screenName"); 158 | final String nameOverride = call.getString("nameOverride", null); 159 | 160 | bridge 161 | .getActivity() 162 | .runOnUiThread( 163 | new Runnable() { 164 | 165 | @Override 166 | public void run() { 167 | Bundle bundle = new Bundle(); 168 | bundle.putString( 169 | com.google.firebase.analytics.FirebaseAnalytics.Param.SCREEN_NAME, 170 | screenName 171 | ); 172 | bundle.putString( 173 | com.google.firebase.analytics.FirebaseAnalytics.Param.SCREEN_CLASS, 174 | nameOverride 175 | ); 176 | mFirebaseAnalytics.logEvent( 177 | com.google.firebase.analytics.FirebaseAnalytics.Event.SCREEN_VIEW, 178 | bundle 179 | ); 180 | call.resolve(); 181 | } 182 | } 183 | ); 184 | } catch (Exception ex) { 185 | call.reject(ex.getLocalizedMessage()); 186 | } 187 | } 188 | 189 | /** 190 | * Clears all analytics data for this app from the device and resets the app instance id. 191 | * @param call 192 | */ 193 | @PluginMethod 194 | public void reset(PluginCall call) { 195 | try { 196 | if (mFirebaseAnalytics == null) { 197 | call.reject(MISSING_REF_MSSG); 198 | return; 199 | } 200 | 201 | mFirebaseAnalytics.resetAnalyticsData(); 202 | call.resolve(); 203 | } catch (Exception ex) { 204 | call.reject(ex.getLocalizedMessage()); 205 | } 206 | } 207 | 208 | /** 209 | * Logs an app event. 210 | * @param call - name: unique name of the event 211 | * params: the map of event parameters. 212 | */ 213 | @PluginMethod 214 | public void logEvent(PluginCall call) { 215 | try { 216 | if (mFirebaseAnalytics == null) { 217 | call.reject(MISSING_REF_MSSG); 218 | return; 219 | } 220 | 221 | if (!call.hasOption("name")) { 222 | call.reject("name property is missing"); 223 | return; 224 | } 225 | 226 | String name = call.getString("name"); 227 | JSONObject params = call.getData().getJSObject("params"); 228 | mFirebaseAnalytics.logEvent(name, params != null ? FirebaseAnalytics.convertJsonToBundle(params) : null); 229 | call.resolve(); 230 | } catch (Exception ex) { 231 | call.reject(ex.getLocalizedMessage()); 232 | } 233 | } 234 | 235 | /** 236 | * Sets whether analytics collection is enabled for this app on this device. 237 | * @param call - enabled: boolean true/false to enable/disable logging 238 | */ 239 | @PluginMethod 240 | public void setCollectionEnabled(PluginCall call) { 241 | if (mFirebaseAnalytics == null) { 242 | call.reject(MISSING_REF_MSSG); 243 | return; 244 | } 245 | 246 | boolean enabled = call.getBoolean("enabled", false); 247 | 248 | mFirebaseAnalytics.setAnalyticsCollectionEnabled(enabled); 249 | call.resolve(); 250 | } 251 | 252 | /** 253 | * Deprecated: use setCollectionEnabled() instead 254 | * Enable analytics collection for this app on this device. 255 | * @param call - enabled: boolean true/false to enable/disable logging 256 | */ 257 | @Deprecated 258 | @PluginMethod 259 | public void enable(PluginCall call) { 260 | if (mFirebaseAnalytics == null) { 261 | call.reject(MISSING_REF_MSSG); 262 | return; 263 | } 264 | 265 | mFirebaseAnalytics.setAnalyticsCollectionEnabled(true); 266 | call.resolve(); 267 | } 268 | 269 | /** 270 | * Deprecated: use setCollectionEnabled() instead 271 | * Disable analytics collection for this app on this device. 272 | * @param call 273 | */ 274 | @Deprecated 275 | @PluginMethod 276 | public void disable(PluginCall call) { 277 | if (mFirebaseAnalytics == null) { 278 | call.reject(MISSING_REF_MSSG); 279 | return; 280 | } 281 | 282 | mFirebaseAnalytics.setAnalyticsCollectionEnabled(false); 283 | call.resolve(); 284 | } 285 | 286 | /** 287 | * Sets the duration of inactivity that terminates the current session. 288 | * @param call: options - duration: duration of inactivity 289 | */ 290 | @PluginMethod 291 | public void setSessionTimeoutDuration(PluginCall call) { 292 | if (mFirebaseAnalytics == null) { 293 | call.reject(MISSING_REF_MSSG); 294 | return; 295 | } 296 | 297 | int duration = call.getInt("duration", 1800); 298 | 299 | mFirebaseAnalytics.setSessionTimeoutDuration(duration); 300 | call.resolve(); 301 | } 302 | 303 | public static Bundle convertJsonToBundle(JSONObject json) { 304 | Bundle bundle = new Bundle(); 305 | if (json == null || json.length() == 0) return bundle; 306 | 307 | Iterator iterator = json.keys(); 308 | while (iterator.hasNext()) { 309 | String key = (String) iterator.next(); 310 | try { 311 | Object value = json.get(key); 312 | if (value == null); 313 | else if (value instanceof String) bundle.putString(key, (String) value); 314 | else if (value instanceof Boolean) bundle.putBoolean(key, (Boolean) value); 315 | else if (value instanceof Integer) bundle.putInt(key, (Integer) value); 316 | else if (value instanceof Long) bundle.putLong(key, (Long) value); 317 | else if (value instanceof Float) bundle.putFloat(key, (Float) value); 318 | else if (value instanceof Double) bundle.putDouble(key, (Double) value); 319 | else if (value instanceof JSONObject) bundle.putBundle(key, FirebaseAnalytics.convertJsonToBundle((JSONObject) value)); 320 | else if (value instanceof JSONArray) { 321 | JSONArray array = (JSONArray) value; 322 | Object first = array.length() == 0 ? null : (Object) array.get(0); 323 | if (first == null); 324 | else if (first instanceof JSONObject) { 325 | Bundle[] items = new Bundle[array.length()]; 326 | for (int i = 0; i < array.length(); i++) items[i] = FirebaseAnalytics.convertJsonToBundle(array.getJSONObject(i)); 327 | bundle.putParcelableArray(key, items); 328 | } else if (first instanceof String) { 329 | String[] items = new String[array.length()]; 330 | for (int i = 0; i < array.length(); i++) items[i] = array.getString(i); 331 | bundle.putStringArray(key, items); 332 | } else if (first instanceof Integer || first instanceof Float || first instanceof Double) { 333 | float[] items = new float[array.length()]; 334 | for (int i = 0; i < array.length(); i++) { 335 | items[i] = ((Number) array.get(i)).floatValue(); 336 | } 337 | bundle.putFloatArray(key, items); 338 | } 339 | } 340 | } catch (ClassCastException | JSONException e) { 341 | e.printStackTrace(); 342 | } 343 | } 344 | 345 | return bundle; 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /android/src/main/res/layout/bridge_layout_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Just a simple string 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/test/java/com/getcapacitor/community/firebaseanalytics/FirebaseAnalyticsTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.community.firebaseanalytics; 2 | 3 | import android.os.Bundle; 4 | 5 | import org.json.JSONObject; 6 | 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.*; 10 | 11 | import java.util.Arrays; 12 | 13 | public class FirebaseAnalyticsTest { 14 | 15 | private Bundle toBundle(String json) throws Exception { 16 | return FirebaseAnalytics.convertJsonToBundle(new JSONObject(json)); 17 | } 18 | 19 | private void assertBundle(String json, String bundleStr) throws Exception { 20 | assertEquals(bundleStr, toBundle(json).toString()); 21 | } 22 | 23 | @Test 24 | public void convertJsonToBundle() throws Exception { 25 | // basic fields 26 | assertBundle("{}", "Bundle[{}]"); 27 | assertBundle("{ \"hello\": \"world\" }", "Bundle[{hello=world}]"); 28 | assertBundle("{ \"foo\": 123.456 }", "Bundle[{foo=123.456}]"); 29 | assertBundle("{ \"foo\": null }", "Bundle[{}]"); 30 | 31 | // nested objects 32 | assertBundle("{ \"foo\": { \"bar\": 123 } }", "Bundle[{foo=Bundle[{bar=123}]}]"); 33 | assertBundle("{ \"foo\": {} }", "Bundle[{foo=Bundle[{}]}]"); 34 | 35 | // don't allow mismatched array elements 36 | assertBundle("{ \"foo\": [{ \"bar\": 123 }, 456.789], \"fizz\": 123 }", "Bundle[{fizz=123}]"); 37 | 38 | // array of bundles 39 | assertArrayEquals( 40 | new String[]{"Bundle[{bar=123}]", "Bundle[{fizz=456}]"}, 41 | Arrays.stream(toBundle("{ \"foo\": [{ \"bar\": 123 }, { \"fizz\": 456 }] }").getParcelableArray("foo")).map(p -> p.toString()).toArray() 42 | ); 43 | 44 | // any combination of number types in array should be fine 45 | assertArrayEquals( 46 | new float[]{123, 456}, 47 | toBundle("{ \"foo\": [123, 456] }").getFloatArray("foo"), 48 | 0 49 | ); 50 | assertArrayEquals( 51 | new float[]{123, 456.789f}, 52 | toBundle("{ \"foo\": [123, 456.789] }").getFloatArray("foo"), 53 | 0 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ios/.npmignore: -------------------------------------------------------------------------------- 1 | Pods/ 2 | Podfile.lock 3 | contents.xcworkspacedata 4 | xcuserdata/ -------------------------------------------------------------------------------- /ios/Plugin.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 50ADFF92201F53D600D50D53 /* FBAnalytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFF88201F53D600D50D53 /* FBAnalytics.framework */; }; 11 | 50ADFF97201F53D600D50D53 /* PluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFF96201F53D600D50D53 /* PluginTests.swift */; }; 12 | 50ADFF99201F53D600D50D53 /* Plugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 50ADFF8B201F53D600D50D53 /* Plugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ADFFA52020D75100D50D53 /* Capacitor.framework */; }; 14 | 50ADFFA82020EE4F00D50D53 /* Plugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ADFFA72020EE4F00D50D53 /* Plugin.m */; }; 15 | 50E1A94820377CB70090CE1A /* Plugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E1A94720377CB70090CE1A /* Plugin.swift */; }; 16 | 514C07B99E19497CDDC5B493 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27959E58207F713EC0CC0E55 /* Pods_PluginTests.framework */; }; 17 | 7D88EB682EAD87CCEAA045D7 /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A58FC96B15FCC9C6F670EF81 /* Pods_Plugin.framework */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | 50ADFF93201F53D600D50D53 /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = 50ADFF7F201F53D600D50D53 /* Project object */; 24 | proxyType = 1; 25 | remoteGlobalIDString = 50ADFF87201F53D600D50D53; 26 | remoteInfo = Plugin; 27 | }; 28 | /* End PBXContainerItemProxy section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 0F9355E366F06F9B469B2DA1 /* Pods-PluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.release.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig"; sourceTree = ""; }; 32 | 27959E58207F713EC0CC0E55 /* Pods_PluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 3486FE8CBADD42C9317B9C19 /* Pods-PluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PluginTests.debug.xcconfig"; path = "Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig"; sourceTree = ""; }; 34 | 50ADFF88201F53D600D50D53 /* FBAnalytics.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FBAnalytics.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | 50ADFF8B201F53D600D50D53 /* Plugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Plugin.h; sourceTree = ""; }; 36 | 50ADFF8C201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 37 | 50ADFF91201F53D600D50D53 /* PluginTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PluginTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 50ADFF96201F53D600D50D53 /* PluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginTests.swift; sourceTree = ""; }; 39 | 50ADFF98201F53D600D50D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | 50ADFFA52020D75100D50D53 /* Capacitor.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Capacitor.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 50ADFFA72020EE4F00D50D53 /* Plugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Plugin.m; sourceTree = ""; }; 42 | 50E1A94720377CB70090CE1A /* Plugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Plugin.swift; sourceTree = ""; }; 43 | 6E675A98AAA3127288C969DB /* Pods-Plugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.debug.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig"; sourceTree = ""; }; 44 | 86A0AFE27CEDCE9BC8390294 /* Pods-Plugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Plugin.release.xcconfig"; path = "Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig"; sourceTree = ""; }; 45 | A58FC96B15FCC9C6F670EF81 /* Pods_Plugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Plugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | /* End PBXFileReference section */ 47 | 48 | /* Begin PBXFrameworksBuildPhase section */ 49 | 50ADFF84201F53D600D50D53 /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | 50ADFFA42020D75100D50D53 /* Capacitor.framework in Frameworks */, 54 | 7D88EB682EAD87CCEAA045D7 /* Pods_Plugin.framework in Frameworks */, 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | 50ADFF8E201F53D600D50D53 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | 50ADFF92201F53D600D50D53 /* FBAnalytics.framework in Frameworks */, 63 | 514C07B99E19497CDDC5B493 /* Pods_PluginTests.framework in Frameworks */, 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXFrameworksBuildPhase section */ 68 | 69 | /* Begin PBXGroup section */ 70 | 50ADFF7E201F53D600D50D53 = { 71 | isa = PBXGroup; 72 | children = ( 73 | 50ADFF8A201F53D600D50D53 /* Plugin */, 74 | 50ADFF95201F53D600D50D53 /* PluginTests */, 75 | 50ADFF89201F53D600D50D53 /* Products */, 76 | A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */, 77 | 5A5C76EB557399FD4094496E /* Pods */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | 50ADFF89201F53D600D50D53 /* Products */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 50ADFF88201F53D600D50D53 /* FBAnalytics.framework */, 85 | 50ADFF91201F53D600D50D53 /* PluginTests.xctest */, 86 | ); 87 | name = Products; 88 | sourceTree = ""; 89 | }; 90 | 50ADFF8A201F53D600D50D53 /* Plugin */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 50E1A94720377CB70090CE1A /* Plugin.swift */, 94 | 50ADFF8B201F53D600D50D53 /* Plugin.h */, 95 | 50ADFFA72020EE4F00D50D53 /* Plugin.m */, 96 | 50ADFF8C201F53D600D50D53 /* Info.plist */, 97 | ); 98 | path = Plugin; 99 | sourceTree = ""; 100 | }; 101 | 50ADFF95201F53D600D50D53 /* PluginTests */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 50ADFF96201F53D600D50D53 /* PluginTests.swift */, 105 | 50ADFF98201F53D600D50D53 /* Info.plist */, 106 | ); 107 | path = PluginTests; 108 | sourceTree = ""; 109 | }; 110 | 5A5C76EB557399FD4094496E /* Pods */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 6E675A98AAA3127288C969DB /* Pods-Plugin.debug.xcconfig */, 114 | 86A0AFE27CEDCE9BC8390294 /* Pods-Plugin.release.xcconfig */, 115 | 3486FE8CBADD42C9317B9C19 /* Pods-PluginTests.debug.xcconfig */, 116 | 0F9355E366F06F9B469B2DA1 /* Pods-PluginTests.release.xcconfig */, 117 | ); 118 | path = Pods; 119 | sourceTree = ""; 120 | }; 121 | A797B9EFA3DCEFEA1FBB66A9 /* Frameworks */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 50ADFFA52020D75100D50D53 /* Capacitor.framework */, 125 | A58FC96B15FCC9C6F670EF81 /* Pods_Plugin.framework */, 126 | 27959E58207F713EC0CC0E55 /* Pods_PluginTests.framework */, 127 | ); 128 | name = Frameworks; 129 | sourceTree = ""; 130 | }; 131 | /* End PBXGroup section */ 132 | 133 | /* Begin PBXHeadersBuildPhase section */ 134 | 50ADFF85201F53D600D50D53 /* Headers */ = { 135 | isa = PBXHeadersBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | 50ADFF99201F53D600D50D53 /* Plugin.h in Headers */, 139 | ); 140 | runOnlyForDeploymentPostprocessing = 0; 141 | }; 142 | /* End PBXHeadersBuildPhase section */ 143 | 144 | /* Begin PBXNativeTarget section */ 145 | 50ADFF87201F53D600D50D53 /* Plugin */ = { 146 | isa = PBXNativeTarget; 147 | buildConfigurationList = 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */; 148 | buildPhases = ( 149 | B8FB7BDBBF19462780ED4629 /* [CP] Check Pods Manifest.lock */, 150 | 50ADFF83201F53D600D50D53 /* Sources */, 151 | 50ADFF84201F53D600D50D53 /* Frameworks */, 152 | 50ADFF85201F53D600D50D53 /* Headers */, 153 | 50ADFF86201F53D600D50D53 /* Resources */, 154 | ); 155 | buildRules = ( 156 | ); 157 | dependencies = ( 158 | ); 159 | name = Plugin; 160 | productName = Plugin; 161 | productReference = 50ADFF88201F53D600D50D53 /* FBAnalytics.framework */; 162 | productType = "com.apple.product-type.framework"; 163 | }; 164 | 50ADFF90201F53D600D50D53 /* PluginTests */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */; 167 | buildPhases = ( 168 | 0B09C91B7EF8C88C7CD73DC7 /* [CP] Check Pods Manifest.lock */, 169 | 50ADFF8D201F53D600D50D53 /* Sources */, 170 | 50ADFF8E201F53D600D50D53 /* Frameworks */, 171 | 50ADFF8F201F53D600D50D53 /* Resources */, 172 | 0B5D6F563581022CCDC45B4A /* [CP] Embed Pods Frameworks */, 173 | ); 174 | buildRules = ( 175 | ); 176 | dependencies = ( 177 | 50ADFF94201F53D600D50D53 /* PBXTargetDependency */, 178 | ); 179 | name = PluginTests; 180 | productName = PluginTests; 181 | productReference = 50ADFF91201F53D600D50D53 /* PluginTests.xctest */; 182 | productType = "com.apple.product-type.bundle.unit-test"; 183 | }; 184 | /* End PBXNativeTarget section */ 185 | 186 | /* Begin PBXProject section */ 187 | 50ADFF7F201F53D600D50D53 /* Project object */ = { 188 | isa = PBXProject; 189 | attributes = { 190 | LastSwiftUpdateCheck = 0920; 191 | LastUpgradeCheck = 0920; 192 | ORGANIZATIONNAME = "Max Lynch"; 193 | TargetAttributes = { 194 | 50ADFF87201F53D600D50D53 = { 195 | CreatedOnToolsVersion = 9.2; 196 | LastSwiftMigration = 1100; 197 | ProvisioningStyle = Automatic; 198 | }; 199 | 50ADFF90201F53D600D50D53 = { 200 | CreatedOnToolsVersion = 9.2; 201 | LastSwiftMigration = 1100; 202 | ProvisioningStyle = Manual; 203 | }; 204 | }; 205 | }; 206 | buildConfigurationList = 50ADFF82201F53D600D50D53 /* Build configuration list for PBXProject "Plugin" */; 207 | compatibilityVersion = "Xcode 8.0"; 208 | developmentRegion = en; 209 | hasScannedForEncodings = 0; 210 | knownRegions = ( 211 | en, 212 | ); 213 | mainGroup = 50ADFF7E201F53D600D50D53; 214 | productRefGroup = 50ADFF89201F53D600D50D53 /* Products */; 215 | projectDirPath = ""; 216 | projectRoot = ""; 217 | targets = ( 218 | 50ADFF87201F53D600D50D53 /* Plugin */, 219 | 50ADFF90201F53D600D50D53 /* PluginTests */, 220 | ); 221 | }; 222 | /* End PBXProject section */ 223 | 224 | /* Begin PBXResourcesBuildPhase section */ 225 | 50ADFF86201F53D600D50D53 /* Resources */ = { 226 | isa = PBXResourcesBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | ); 230 | runOnlyForDeploymentPostprocessing = 0; 231 | }; 232 | 50ADFF8F201F53D600D50D53 /* Resources */ = { 233 | isa = PBXResourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | }; 239 | /* End PBXResourcesBuildPhase section */ 240 | 241 | /* Begin PBXShellScriptBuildPhase section */ 242 | 0B09C91B7EF8C88C7CD73DC7 /* [CP] Check Pods Manifest.lock */ = { 243 | isa = PBXShellScriptBuildPhase; 244 | buildActionMask = 2147483647; 245 | files = ( 246 | ); 247 | inputFileListPaths = ( 248 | ); 249 | inputPaths = ( 250 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 251 | "${PODS_ROOT}/Manifest.lock", 252 | ); 253 | name = "[CP] Check Pods Manifest.lock"; 254 | outputFileListPaths = ( 255 | ); 256 | outputPaths = ( 257 | "$(DERIVED_FILE_DIR)/Pods-PluginTests-checkManifestLockResult.txt", 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | shellPath = /bin/sh; 261 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 262 | showEnvVarsInLog = 0; 263 | }; 264 | 0B5D6F563581022CCDC45B4A /* [CP] Embed Pods Frameworks */ = { 265 | isa = PBXShellScriptBuildPhase; 266 | buildActionMask = 2147483647; 267 | files = ( 268 | ); 269 | inputPaths = ( 270 | "${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh", 271 | "${BUILT_PRODUCTS_DIR}/Capacitor/Capacitor.framework", 272 | "${BUILT_PRODUCTS_DIR}/CapacitorCordova/Cordova.framework", 273 | "${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework", 274 | "${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework", 275 | "${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework", 276 | "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", 277 | "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", 278 | "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", 279 | ); 280 | name = "[CP] Embed Pods Frameworks"; 281 | outputPaths = ( 282 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Capacitor.framework", 283 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cordova.framework", 284 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework", 285 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework", 286 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework", 287 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", 288 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework", 289 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | shellPath = /bin/sh; 293 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh\"\n"; 294 | showEnvVarsInLog = 0; 295 | }; 296 | B8FB7BDBBF19462780ED4629 /* [CP] Check Pods Manifest.lock */ = { 297 | isa = PBXShellScriptBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | ); 301 | inputFileListPaths = ( 302 | ); 303 | inputPaths = ( 304 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 305 | "${PODS_ROOT}/Manifest.lock", 306 | ); 307 | name = "[CP] Check Pods Manifest.lock"; 308 | outputFileListPaths = ( 309 | ); 310 | outputPaths = ( 311 | "$(DERIVED_FILE_DIR)/Pods-Plugin-checkManifestLockResult.txt", 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | shellPath = /bin/sh; 315 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 316 | showEnvVarsInLog = 0; 317 | }; 318 | /* End PBXShellScriptBuildPhase section */ 319 | 320 | /* Begin PBXSourcesBuildPhase section */ 321 | 50ADFF83201F53D600D50D53 /* Sources */ = { 322 | isa = PBXSourcesBuildPhase; 323 | buildActionMask = 2147483647; 324 | files = ( 325 | 50E1A94820377CB70090CE1A /* Plugin.swift in Sources */, 326 | 50ADFFA82020EE4F00D50D53 /* Plugin.m in Sources */, 327 | ); 328 | runOnlyForDeploymentPostprocessing = 0; 329 | }; 330 | 50ADFF8D201F53D600D50D53 /* Sources */ = { 331 | isa = PBXSourcesBuildPhase; 332 | buildActionMask = 2147483647; 333 | files = ( 334 | 50ADFF97201F53D600D50D53 /* PluginTests.swift in Sources */, 335 | ); 336 | runOnlyForDeploymentPostprocessing = 0; 337 | }; 338 | /* End PBXSourcesBuildPhase section */ 339 | 340 | /* Begin PBXTargetDependency section */ 341 | 50ADFF94201F53D600D50D53 /* PBXTargetDependency */ = { 342 | isa = PBXTargetDependency; 343 | target = 50ADFF87201F53D600D50D53 /* Plugin */; 344 | targetProxy = 50ADFF93201F53D600D50D53 /* PBXContainerItemProxy */; 345 | }; 346 | /* End PBXTargetDependency section */ 347 | 348 | /* Begin XCBuildConfiguration section */ 349 | 50ADFF9A201F53D600D50D53 /* Debug */ = { 350 | isa = XCBuildConfiguration; 351 | buildSettings = { 352 | ALWAYS_SEARCH_USER_PATHS = NO; 353 | CLANG_ANALYZER_NONNULL = YES; 354 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 355 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 356 | CLANG_CXX_LIBRARY = "libc++"; 357 | CLANG_ENABLE_MODULES = YES; 358 | CLANG_ENABLE_OBJC_ARC = YES; 359 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 360 | CLANG_WARN_BOOL_CONVERSION = YES; 361 | CLANG_WARN_COMMA = YES; 362 | CLANG_WARN_CONSTANT_CONVERSION = YES; 363 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 364 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 365 | CLANG_WARN_EMPTY_BODY = YES; 366 | CLANG_WARN_ENUM_CONVERSION = YES; 367 | CLANG_WARN_INFINITE_RECURSION = YES; 368 | CLANG_WARN_INT_CONVERSION = YES; 369 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 370 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 371 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 372 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 373 | CLANG_WARN_STRICT_PROTOTYPES = YES; 374 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 375 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 376 | CLANG_WARN_UNREACHABLE_CODE = YES; 377 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 378 | CODE_SIGN_IDENTITY = "iPhone Developer"; 379 | COPY_PHASE_STRIP = NO; 380 | CURRENT_PROJECT_VERSION = 1; 381 | DEBUG_INFORMATION_FORMAT = dwarf; 382 | ENABLE_STRICT_OBJC_MSGSEND = YES; 383 | ENABLE_TESTABILITY = YES; 384 | GCC_C_LANGUAGE_STANDARD = gnu11; 385 | GCC_DYNAMIC_NO_PIC = NO; 386 | GCC_NO_COMMON_BLOCKS = YES; 387 | GCC_OPTIMIZATION_LEVEL = 0; 388 | GCC_PREPROCESSOR_DEFINITIONS = ( 389 | "DEBUG=1", 390 | "$(inherited)", 391 | ); 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 399 | MTL_ENABLE_DEBUG_INFO = YES; 400 | ONLY_ACTIVE_ARCH = YES; 401 | OTHER_LDFLAGS = "-objC"; 402 | SDKROOT = iphoneos; 403 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 404 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 405 | VERSIONING_SYSTEM = "apple-generic"; 406 | VERSION_INFO_PREFIX = ""; 407 | }; 408 | name = Debug; 409 | }; 410 | 50ADFF9B201F53D600D50D53 /* Release */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | ALWAYS_SEARCH_USER_PATHS = NO; 414 | CLANG_ANALYZER_NONNULL = YES; 415 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 416 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 417 | CLANG_CXX_LIBRARY = "libc++"; 418 | CLANG_ENABLE_MODULES = YES; 419 | CLANG_ENABLE_OBJC_ARC = YES; 420 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 421 | CLANG_WARN_BOOL_CONVERSION = YES; 422 | CLANG_WARN_COMMA = YES; 423 | CLANG_WARN_CONSTANT_CONVERSION = YES; 424 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 425 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 426 | CLANG_WARN_EMPTY_BODY = YES; 427 | CLANG_WARN_ENUM_CONVERSION = YES; 428 | CLANG_WARN_INFINITE_RECURSION = YES; 429 | CLANG_WARN_INT_CONVERSION = YES; 430 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 431 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 432 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 433 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 434 | CLANG_WARN_STRICT_PROTOTYPES = YES; 435 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 436 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 437 | CLANG_WARN_UNREACHABLE_CODE = YES; 438 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 439 | CODE_SIGN_IDENTITY = "iPhone Developer"; 440 | COPY_PHASE_STRIP = NO; 441 | CURRENT_PROJECT_VERSION = 1; 442 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 443 | ENABLE_NS_ASSERTIONS = NO; 444 | ENABLE_STRICT_OBJC_MSGSEND = YES; 445 | GCC_C_LANGUAGE_STANDARD = gnu11; 446 | GCC_NO_COMMON_BLOCKS = YES; 447 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 448 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 449 | GCC_WARN_UNDECLARED_SELECTOR = YES; 450 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 451 | GCC_WARN_UNUSED_FUNCTION = YES; 452 | GCC_WARN_UNUSED_VARIABLE = YES; 453 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 454 | MTL_ENABLE_DEBUG_INFO = NO; 455 | OTHER_LDFLAGS = "-objC"; 456 | SDKROOT = iphoneos; 457 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 458 | VALIDATE_PRODUCT = YES; 459 | VERSIONING_SYSTEM = "apple-generic"; 460 | VERSION_INFO_PREFIX = ""; 461 | }; 462 | name = Release; 463 | }; 464 | 50ADFF9D201F53D600D50D53 /* Debug */ = { 465 | isa = XCBuildConfiguration; 466 | baseConfigurationReference = 6E675A98AAA3127288C969DB /* Pods-Plugin.debug.xcconfig */; 467 | buildSettings = { 468 | CLANG_ENABLE_MODULES = YES; 469 | CODE_SIGN_IDENTITY = ""; 470 | CODE_SIGN_STYLE = Automatic; 471 | DEFINES_MODULE = YES; 472 | DYLIB_COMPATIBILITY_VERSION = 1; 473 | DYLIB_CURRENT_VERSION = 1; 474 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 475 | INFOPLIST_FILE = Plugin/Info.plist; 476 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 477 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 478 | "IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.0; 479 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)\n$(FRAMEWORK_SEARCH_PATHS)"; 480 | MARKETING_VERSION = 0.1; 481 | ONLY_ACTIVE_ARCH = YES; 482 | PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.community.firebaseanalytics; 483 | PRODUCT_NAME = FBAnalytics; 484 | SKIP_INSTALL = YES; 485 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 486 | SWIFT_VERSION = 5.0; 487 | TARGETED_DEVICE_FAMILY = "1,2"; 488 | }; 489 | name = Debug; 490 | }; 491 | 50ADFF9E201F53D600D50D53 /* Release */ = { 492 | isa = XCBuildConfiguration; 493 | baseConfigurationReference = 86A0AFE27CEDCE9BC8390294 /* Pods-Plugin.release.xcconfig */; 494 | buildSettings = { 495 | CLANG_ENABLE_MODULES = YES; 496 | CODE_SIGN_IDENTITY = ""; 497 | CODE_SIGN_STYLE = Automatic; 498 | DEFINES_MODULE = YES; 499 | DYLIB_COMPATIBILITY_VERSION = 1; 500 | DYLIB_CURRENT_VERSION = 1; 501 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 502 | INFOPLIST_FILE = Plugin/Info.plist; 503 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 504 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 505 | "IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.0; 506 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; 507 | MARKETING_VERSION = 0.1; 508 | ONLY_ACTIVE_ARCH = NO; 509 | PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.community.firebaseanalytics; 510 | PRODUCT_NAME = FBAnalytics; 511 | SKIP_INSTALL = YES; 512 | SWIFT_VERSION = 5.0; 513 | TARGETED_DEVICE_FAMILY = "1,2"; 514 | }; 515 | name = Release; 516 | }; 517 | 50ADFFA0201F53D600D50D53 /* Debug */ = { 518 | isa = XCBuildConfiguration; 519 | baseConfigurationReference = 3486FE8CBADD42C9317B9C19 /* Pods-PluginTests.debug.xcconfig */; 520 | buildSettings = { 521 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 522 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; 523 | CODE_SIGN_STYLE = Manual; 524 | DEVELOPMENT_TEAM = ""; 525 | INFOPLIST_FILE = PluginTests/Info.plist; 526 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 527 | PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.PluginTests; 528 | PRODUCT_NAME = "$(TARGET_NAME)"; 529 | PROVISIONING_PROFILE_SPECIFIER = ""; 530 | SWIFT_VERSION = 5.0; 531 | TARGETED_DEVICE_FAMILY = "1,2"; 532 | }; 533 | name = Debug; 534 | }; 535 | 50ADFFA1201F53D600D50D53 /* Release */ = { 536 | isa = XCBuildConfiguration; 537 | baseConfigurationReference = 0F9355E366F06F9B469B2DA1 /* Pods-PluginTests.release.xcconfig */; 538 | buildSettings = { 539 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 540 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; 541 | CODE_SIGN_STYLE = Manual; 542 | DEVELOPMENT_TEAM = ""; 543 | INFOPLIST_FILE = PluginTests/Info.plist; 544 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 545 | PRODUCT_BUNDLE_IDENTIFIER = com.getcapacitor.PluginTests; 546 | PRODUCT_NAME = "$(TARGET_NAME)"; 547 | PROVISIONING_PROFILE_SPECIFIER = ""; 548 | SWIFT_VERSION = 5.0; 549 | TARGETED_DEVICE_FAMILY = "1,2"; 550 | }; 551 | name = Release; 552 | }; 553 | /* End XCBuildConfiguration section */ 554 | 555 | /* Begin XCConfigurationList section */ 556 | 50ADFF82201F53D600D50D53 /* Build configuration list for PBXProject "Plugin" */ = { 557 | isa = XCConfigurationList; 558 | buildConfigurations = ( 559 | 50ADFF9A201F53D600D50D53 /* Debug */, 560 | 50ADFF9B201F53D600D50D53 /* Release */, 561 | ); 562 | defaultConfigurationIsVisible = 0; 563 | defaultConfigurationName = Release; 564 | }; 565 | 50ADFF9C201F53D600D50D53 /* Build configuration list for PBXNativeTarget "Plugin" */ = { 566 | isa = XCConfigurationList; 567 | buildConfigurations = ( 568 | 50ADFF9D201F53D600D50D53 /* Debug */, 569 | 50ADFF9E201F53D600D50D53 /* Release */, 570 | ); 571 | defaultConfigurationIsVisible = 0; 572 | defaultConfigurationName = Release; 573 | }; 574 | 50ADFF9F201F53D600D50D53 /* Build configuration list for PBXNativeTarget "PluginTests" */ = { 575 | isa = XCConfigurationList; 576 | buildConfigurations = ( 577 | 50ADFFA0201F53D600D50D53 /* Debug */, 578 | 50ADFFA1201F53D600D50D53 /* Release */, 579 | ); 580 | defaultConfigurationIsVisible = 0; 581 | defaultConfigurationName = Release; 582 | }; 583 | /* End XCConfigurationList section */ 584 | }; 585 | rootObject = 50ADFF7F201F53D600D50D53 /* Project object */; 586 | } 587 | -------------------------------------------------------------------------------- /ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 54 | 57 | 58 | 59 | 60 | 66 | 67 | 73 | 74 | 75 | 76 | 78 | 79 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Plugin/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/Plugin/Plugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | //! Project version number for Plugin. 4 | FOUNDATION_EXPORT double PluginVersionNumber; 5 | 6 | //! Project version string for Plugin. 7 | FOUNDATION_EXPORT const unsigned char PluginVersionString[]; 8 | 9 | // In this header, you should import all the public headers of your framework using statements like #import 10 | 11 | -------------------------------------------------------------------------------- /ios/Plugin/Plugin.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | CAP_PLUGIN(FirebaseAnalytics, "FirebaseAnalytics", 5 | CAP_PLUGIN_METHOD(setUserId, CAPPluginReturnPromise); 6 | CAP_PLUGIN_METHOD(setUserProperty, CAPPluginReturnPromise); 7 | CAP_PLUGIN_METHOD(getAppInstanceId, CAPPluginReturnPromise); 8 | CAP_PLUGIN_METHOD(setScreenName, CAPPluginReturnPromise); 9 | CAP_PLUGIN_METHOD(reset, CAPPluginReturnPromise); 10 | CAP_PLUGIN_METHOD(logEvent, CAPPluginReturnPromise); 11 | CAP_PLUGIN_METHOD(setCollectionEnabled, CAPPluginReturnPromise); 12 | CAP_PLUGIN_METHOD(setSessionTimeoutDuration, CAPPluginReturnPromise); 13 | CAP_PLUGIN_METHOD(enable, CAPPluginReturnPromise); 14 | CAP_PLUGIN_METHOD(disable, CAPPluginReturnPromise); 15 | ) 16 | -------------------------------------------------------------------------------- /ios/Plugin/Plugin.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Capacitor 3 | import FirebaseCore 4 | import FirebaseAnalytics 5 | 6 | @objc(FirebaseAnalytics) 7 | public class FirebaseAnalytics: CAPPlugin { 8 | 9 | public override func load() { 10 | if FirebaseApp.app() == nil { 11 | FirebaseApp.configure() 12 | } 13 | } 14 | 15 | /// Sets the user ID property. 16 | /// - Parameter call: userId - unique identifier of the user to log 17 | @objc func setUserId(_ call: CAPPluginCall) { 18 | if let userId = call.getString("userId") { 19 | Analytics.setUserID(userId) 20 | call.resolve() 21 | } else { 22 | call.reject("userId property is missing") 23 | } 24 | } 25 | 26 | /// Sets a user property to a given value. 27 | /// - Parameter call: name - The name of the user property to set. 28 | /// value - The value of the user property. 29 | @objc func setUserProperty(_ call: CAPPluginCall) { 30 | if let name = call.getString("name"), let value = call.getString("value") { 31 | Analytics.setUserProperty(value, forName: name) 32 | call.resolve() 33 | } else { 34 | if call.getString("name") != nil { 35 | call.reject("value property is missing") 36 | } else { 37 | call.reject("name property is missing"); 38 | } 39 | } 40 | } 41 | 42 | /// Retrieves the app instance id from the service. 43 | /// - Parameter call: instanceId - current instance if of the app 44 | @objc func getAppInstanceId(_ call: CAPPluginCall) { 45 | let instanceId = Analytics.appInstanceID() 46 | call.resolve([ 47 | "instanceId": instanceId 48 | ]) 49 | } 50 | 51 | /// Sets the current screen name, which specifies the current visual context in your app. 52 | /// - Parameter call: screenName - the activity to which the screen name and class name apply. 53 | /// nameOverride - the name of the current screen. Set to null to clear the current screen name. 54 | @objc func setScreenName(_ call: CAPPluginCall) { 55 | if let screenName = call.getString("screenName") { 56 | let nameOverride = call.getString("nameOverride") ?? nil 57 | DispatchQueue.main.async { 58 | Analytics.logEvent(AnalyticsEventScreenView, 59 | parameters: [AnalyticsParameterScreenName: screenName, 60 | AnalyticsParameterScreenClass: nameOverride]) 61 | } 62 | call.resolve() 63 | } else { 64 | call.reject("screenName property is missing") 65 | } 66 | } 67 | 68 | 69 | /// Clears all analytics data for this app from the device and resets the app instance id. 70 | @objc func reset(_ call: CAPPluginCall) { 71 | Analytics.resetAnalyticsData() 72 | call.resolve() 73 | } 74 | 75 | 76 | /// Logs an app event. 77 | /// - Parameter call: name - unique name of the event 78 | /// params - the map of event parameters. 79 | @objc func logEvent(_ call: CAPPluginCall) { 80 | 81 | /// Name is a required argument to logEvent() 82 | guard let name = call.getString("name"), !name.isEmpty else { 83 | call.reject("Event name is required and can't be empty") 84 | return 85 | } 86 | 87 | /// logEvent() expects `nil` when there are no parameters 88 | guard var params = call.getObject("params"), !params.isEmpty else { 89 | Analytics.logEvent(name, parameters: nil) 90 | call.resolve() 91 | return 92 | } 93 | 94 | /// FirebaseAnalytics silently converts any item quantity that is not an 95 | /// integer to zero, this includes any NSNumber or string value passed 96 | /// as an option to CAPPluginCall. 97 | if var items = params["items"] as? NSArray as? [[String:Any]] { 98 | for (idx, item) in items.enumerated() { 99 | if let quantity = item["quantity"] { 100 | guard let intVal = quantity as? Int else { 101 | call.reject("Item quantity must be specified as an integer value") 102 | return 103 | } 104 | items[idx]["quantity"] = intVal 105 | } 106 | } 107 | params["items"] = items 108 | } 109 | 110 | Analytics.logEvent(name, parameters: params) 111 | call.resolve() 112 | } 113 | 114 | 115 | /// Sets whether analytics collection is enabled for this app on this device. 116 | /// - Parameter call: enabled - boolean true/false to enable/disable logging 117 | @objc func setCollectionEnabled(_ call: CAPPluginCall) { 118 | if let enabled = call.getBool("enabled") { 119 | Analytics.setAnalyticsCollectionEnabled(enabled) 120 | } else { 121 | Analytics.setAnalyticsCollectionEnabled(false) 122 | } 123 | call.resolve() 124 | } 125 | 126 | 127 | /// Sets the duration of inactivity that terminates the current session. 128 | /// - Parameter call: duration - duration of inactivity 129 | @objc func setSessionTimeoutDuration(_ call: CAPPluginCall) { 130 | let duration = call.getInt("duration") ?? 1800 131 | 132 | Analytics.setSessionTimeoutInterval(TimeInterval(duration)) 133 | call.resolve() 134 | } 135 | 136 | /// Deprecated - use setCollectionEnabled instead 137 | /// Enable analytics collection for this app on this device. 138 | /// - Parameter call 139 | @available(*, deprecated, renamed: "setCollectionEnabled") 140 | @objc func enable(_ call: CAPPluginCall) { 141 | Analytics.setAnalyticsCollectionEnabled(true) 142 | call.resolve() 143 | } 144 | 145 | /// Deprecated - use setCollectionEnabled instead 146 | /// Disable analytics collection for this app on this device. 147 | /// - Parameter call 148 | @available(*, deprecated, renamed: "setCollectionEnabled") 149 | @objc func disable(_ call: CAPPluginCall) { 150 | Analytics.setAnalyticsCollectionEnabled(false) 151 | call.resolve() 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /ios/PluginTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/PluginTests/PluginTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Capacitor 3 | @testable import FBAnalytics 4 | 5 | class PluginTests: XCTestCase { 6 | 7 | override func setUp() { 8 | super.setUp() 9 | // Put setup code here. This method is called before the invocation of each test method in the class. 10 | } 11 | 12 | override func tearDown() { 13 | // Put teardown code here. This method is called after the invocation of each test method in the class. 14 | super.tearDown() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '14.0' 2 | 3 | def capacitor_pods 4 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 5 | use_frameworks! 6 | pod 'Capacitor', :path => '../node_modules/@capacitor/ios' 7 | pod 'CapacitorCordova', :path => '../node_modules/@capacitor/ios' 8 | end 9 | 10 | target 'Plugin' do 11 | capacitor_pods 12 | pod 'FirebaseAnalytics' 13 | end 14 | 15 | target 'PluginTests' do 16 | capacitor_pods 17 | end 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@capacitor-community/firebase-analytics", 3 | "version": "7.0.0", 4 | "description": "A native plugin for firebase analytics.", 5 | "homepage": "https://github.com/capacitor-community/firebase-analytics", 6 | "main": "dist/plugin.cjs.js", 7 | "module": "dist/esm/index.js", 8 | "types": "dist/esm/index.d.ts", 9 | "unpkg": "dist/plugin.js", 10 | "scripts": { 11 | "build": "npm run clean && tsc && rollup -c rollup.config.mjs", 12 | "clean": "rimraf ./dist", 13 | "watch": "tsc --watch", 14 | "prepublishOnly": "npm run build", 15 | "release": "np", 16 | "test": "echo \"No test specified\"" 17 | }, 18 | "author": "mesur.io ", 19 | "license": "MIT", 20 | "devDependencies": { 21 | "@capacitor/android": "^7.0.0", 22 | "@capacitor/core": "^7.0.0", 23 | "@capacitor/ios": "^7.0.0", 24 | "husky": "^4.2.5", 25 | "np": "^7.6.2", 26 | "prettier": "^3.4.2", 27 | "prettier-plugin-java": "^2.6.7", 28 | "pretty-quick": "^4.0.0", 29 | "rimraf": "^6.0.1", 30 | "rollup": "^4.30.1", 31 | "typescript": "^4.2.3" 32 | }, 33 | "peerDependencies": { 34 | "@capacitor/core": "^7.0.0" 35 | }, 36 | "husky": { 37 | "hooks": { 38 | "pre-commit": "pretty-quick --staged" 39 | } 40 | }, 41 | "files": [ 42 | "android/src/main/", 43 | "android/build.gradle", 44 | "dist/", 45 | "ios/Plugin/", 46 | "CapacitorCommunityFirebaseAnalytics.podspec" 47 | ], 48 | "keywords": [ 49 | "capacitor", 50 | "plugin", 51 | "native" 52 | ], 53 | "capacitor": { 54 | "ios": { 55 | "src": "ios" 56 | }, 57 | "android": { 58 | "src": "android" 59 | } 60 | }, 61 | "repository": { 62 | "type": "git", 63 | "url": "https://github.com/capacitor-community/firebase-analytics" 64 | }, 65 | "bugs": { 66 | "url": "https://github.com/capacitor-community/firebase-analytics/issues" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | input: "dist/esm/index.js", 3 | output: [ 4 | { 5 | file: "dist/plugin.js", 6 | format: "iife", 7 | name: "capacitorPlugin", 8 | globals: { 9 | "@capacitor/core": "capacitorExports", 10 | }, 11 | sourcemap: true, 12 | inlineDynamicImports: true, 13 | }, 14 | { 15 | file: "dist/plugin.cjs.js", 16 | format: "cjs", 17 | sourcemap: true, 18 | inlineDynamicImports: true, 19 | }, 20 | ], 21 | external: ["@capacitor/core"], 22 | }; 23 | -------------------------------------------------------------------------------- /src/definitions.ts: -------------------------------------------------------------------------------- 1 | export interface FirebaseAnalyticsPlugin { 2 | initializeFirebase(options: FirebaseInitOptions): Promise; 3 | setUserId(options: { userId: string }): Promise; 4 | setUserProperty(options: { name: string; value: string }): Promise; 5 | getAppInstanceId(): Promise<{ instanceId: string | null }>; 6 | setScreenName(options: { 7 | screenName: string; 8 | nameOverride?: string; 9 | }): Promise; 10 | reset(): Promise; 11 | logEvent(options: { name: string; params: object }): Promise; 12 | setCollectionEnabled(options: { enabled: boolean }): Promise; 13 | setSessionTimeoutDuration(options: { duration: number }): Promise; 14 | enable(): Promise; 15 | disable(): Promise; 16 | } 17 | 18 | export interface FirebaseInitOptions { 19 | apiKey: string; 20 | authDomain: string; 21 | databaseURL?: string; 22 | projectId: string; 23 | storageBucket: string; 24 | messagingSenderId: string; 25 | appId: string; 26 | measurementId: string; 27 | } 28 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { registerPlugin } from "@capacitor/core"; 2 | import type { FirebaseAnalyticsPlugin } from "./definitions"; 3 | 4 | const FirebaseAnalytics = registerPlugin( 5 | "FirebaseAnalytics", 6 | { 7 | web: () => import("./web").then((m) => new m.FirebaseAnalyticsWeb()), 8 | } 9 | ); 10 | 11 | export * from "./definitions"; 12 | export { FirebaseAnalytics }; 13 | -------------------------------------------------------------------------------- /src/web.ts: -------------------------------------------------------------------------------- 1 | import { WebPlugin } from "@capacitor/core"; 2 | 3 | import { FirebaseAnalyticsPlugin, FirebaseInitOptions } from "./definitions"; 4 | 5 | declare var window: any; 6 | 7 | export class FirebaseAnalyticsWeb 8 | extends WebPlugin 9 | implements FirebaseAnalyticsPlugin { 10 | private not_supported_mssg = "This method is not supported"; 11 | private options_missing_mssg = "Firebase options are missing"; 12 | private duplicate_app_mssg = "Firebase app already exists"; 13 | private analytics_missing_mssg = 14 | "Firebase analytics is not initialized. Make sure initializeFirebase() is called once"; 15 | 16 | public readonly ready: Promise; 17 | private readyResolver: Function; 18 | private analyticsRef: any; 19 | 20 | private scripts = [ 21 | { 22 | key: "firebase-app", 23 | src: "https://www.gstatic.com/firebasejs/8.2.3/firebase-app.js", 24 | }, 25 | { 26 | key: "firebase-ac", 27 | src: "https://www.gstatic.com/firebasejs/8.2.3/firebase-analytics.js", 28 | }, 29 | ]; 30 | 31 | constructor() { 32 | super(); 33 | this.ready = new Promise((resolve) => (this.readyResolver = resolve)); 34 | this.configure(); 35 | } 36 | 37 | /** 38 | * Configure and Initialize FirebaseApp if not present 39 | * @param options - web app's Firebase configuration 40 | * @returns firebase analytics object reference 41 | * Platform: Web 42 | */ 43 | initializeFirebase(options: FirebaseInitOptions): Promise { 44 | return new Promise(async (resolve, reject) => { 45 | await this.ready; 46 | 47 | if (this.hasFirebaseInitialized()) { 48 | reject(this.duplicate_app_mssg); 49 | return; 50 | } 51 | 52 | if (!options) { 53 | reject(this.options_missing_mssg); 54 | return; 55 | } 56 | 57 | const app = window.firebase.initializeApp(options); 58 | this.analyticsRef = app.analytics(); 59 | resolve(this.analyticsRef); 60 | }); 61 | } 62 | 63 | /** 64 | * Sets the user ID property. 65 | * @param options - userId: unique identifier of the user to log 66 | * Platform: Web/Android/iOS 67 | */ 68 | setUserId(options: { userId: string }): Promise { 69 | return new Promise(async (resolve, reject) => { 70 | await this.ready; 71 | 72 | if (!this.analyticsRef) { 73 | reject(this.analytics_missing_mssg); 74 | return; 75 | } 76 | 77 | const { userId } = options || { userId: undefined }; 78 | 79 | if (!userId) { 80 | reject("userId property is missing"); 81 | return; 82 | } 83 | 84 | this.analyticsRef.setUserId(userId); 85 | resolve(); 86 | }); 87 | } 88 | 89 | /** 90 | * Sets a user property to a given value. 91 | * @param options - name: The name of the user property to set. 92 | * value: The value of the user property. 93 | * Platform: Web/Android/iOS 94 | */ 95 | setUserProperty(options: { name: string; value: string }): Promise { 96 | return new Promise(async (resolve, reject) => { 97 | await this.ready; 98 | 99 | if (!this.analyticsRef) { 100 | reject(this.analytics_missing_mssg); 101 | return; 102 | } 103 | 104 | const { name, value } = options || { name: undefined, value: undefined }; 105 | 106 | if (!name) { 107 | reject("name property is missing"); 108 | return; 109 | } 110 | 111 | if (!value) { 112 | reject("value property is missing"); 113 | return; 114 | } 115 | 116 | let property: any = {}; 117 | property[name] = value; 118 | this.analyticsRef.setUserProperties(property); 119 | resolve(); 120 | }); 121 | } 122 | 123 | /** 124 | * Retrieves the app instance id from the service. 125 | * @returns - instanceId: current instance if of the app 126 | * Platform: Web/Android/iOS 127 | */ 128 | getAppInstanceId(): Promise<{ instanceId: string }> { 129 | return new Promise((resolve, _reject) => resolve); 130 | } 131 | 132 | /** 133 | * Sets the current screen name, which specifies the current visual context in your app. 134 | * @param options - screenName: the activity to which the screen name and class name apply. 135 | * nameOverride: the name of the current screen. Set to null to clear the current screen name. 136 | * Platform: Android/iOS 137 | */ 138 | setScreenName(_options: { 139 | screenName: string; 140 | nameOverride: string; 141 | }): Promise { 142 | return new Promise((resolve, _reject) => resolve); 143 | } 144 | 145 | /** 146 | * Clears all analytics data for this app from the device and resets the app instance id. 147 | * Platform: Android/iOS 148 | */ 149 | reset(): Promise { 150 | return new Promise((resolve, _reject) => resolve); 151 | } 152 | 153 | /** 154 | * Logs an app event. 155 | * @param options - name: unique name of the event 156 | * params: the map of event parameters. 157 | * Platform: Web/Android/iOS 158 | */ 159 | logEvent(options: { name: string; params: object }): Promise { 160 | return new Promise(async (resolve, reject) => { 161 | await this.ready; 162 | 163 | if (!this.analyticsRef) { 164 | reject(this.analytics_missing_mssg); 165 | return; 166 | } 167 | 168 | const { name, params } = options || { 169 | name: undefined, 170 | params: undefined, 171 | }; 172 | 173 | if (!name) { 174 | reject("name property is missing"); 175 | return; 176 | } 177 | 178 | this.analyticsRef.logEvent(name, params); 179 | resolve(); 180 | }); 181 | } 182 | 183 | /** 184 | * Sets whether analytics collection is enabled for this app on this device. 185 | * @param options - enabled: boolean true/false to enable/disable logging 186 | * Platform: Web/Android/iOS 187 | */ 188 | setCollectionEnabled(options: { enabled: boolean }): Promise { 189 | return new Promise(async (resolve, reject) => { 190 | await this.ready; 191 | 192 | if (!this.analyticsRef) { 193 | reject(this.analytics_missing_mssg); 194 | return; 195 | } 196 | 197 | const { enabled } = options || { enabled: false }; 198 | this.analyticsRef.setAnalyticsCollectionEnabled(enabled); 199 | resolve(); 200 | }); 201 | } 202 | 203 | /** 204 | * Sets the duration of inactivity that terminates the current session. 205 | * @param options - duration: duration of inactivity 206 | * Platform: Android/iOS 207 | */ 208 | setSessionTimeoutDuration(_options: { duration: number }): Promise { 209 | return new Promise((_resolve, reject) => { 210 | reject(this.not_supported_mssg); 211 | }); 212 | } 213 | 214 | /** 215 | * Returns analytics reference object 216 | */ 217 | get remoteConfig() { 218 | return this.analyticsRef; 219 | } 220 | 221 | enable(): Promise { 222 | return new Promise(async (resolve, reject) => { 223 | await this.ready; 224 | 225 | if (!this.analyticsRef) { 226 | reject(this.analytics_missing_mssg); 227 | return; 228 | } 229 | 230 | this.analyticsRef.setAnalyticsCollectionEnabled(true); 231 | resolve(); 232 | }); 233 | } 234 | 235 | disable(): Promise { 236 | return new Promise(async (resolve, reject) => { 237 | await this.ready; 238 | 239 | if (!this.analyticsRef) { 240 | reject(this.analytics_missing_mssg); 241 | return; 242 | } 243 | 244 | this.analyticsRef.setAnalyticsCollectionEnabled(false); 245 | resolve(); 246 | }); 247 | } 248 | 249 | /** 250 | * Ready resolver to check and load firebase analytics 251 | */ 252 | private async configure() { 253 | try { 254 | await this.loadScripts(); 255 | 256 | if ( 257 | window.firebase && 258 | window.firebase.analytics && 259 | this.hasFirebaseInitialized() 260 | ) { 261 | this.analyticsRef = window.firebase.analytics(); 262 | } 263 | } catch (error) { 264 | throw error; 265 | } 266 | 267 | const interval = setInterval(() => { 268 | if (!window.firebase) { 269 | return; 270 | } 271 | clearInterval(interval); 272 | this.readyResolver(); 273 | }, 50); 274 | } 275 | 276 | /** 277 | * Check for existing loaded script and load new scripts 278 | */ 279 | private loadScripts() { 280 | const firebaseAppScript = this.scripts[0]; 281 | const firebaseAnalyticsScript = this.scripts[1]; 282 | 283 | return new Promise(async (resolve, _reject) => { 284 | const scripts = this.scripts.map((script) => script.key); 285 | if ( 286 | document.getElementById(scripts[0]) && 287 | document.getElementById(scripts[1]) 288 | ) { 289 | return resolve(null); 290 | } 291 | 292 | await this.loadScript(firebaseAppScript.key, firebaseAppScript.src); 293 | await this.loadScript( 294 | firebaseAnalyticsScript.key, 295 | firebaseAnalyticsScript.src 296 | ); 297 | resolve(null); 298 | }); 299 | } 300 | 301 | /** 302 | * Loaded single script with provided id and source 303 | * @param id - unique identifier of the script 304 | * @param src - source of the script 305 | */ 306 | private loadScript(id: string, src: string): Promise { 307 | return new Promise((resolve, reject) => { 308 | const file = document.createElement("script"); 309 | file.type = "text/javascript"; 310 | file.src = src; 311 | file.id = id; 312 | file.onload = resolve; 313 | file.onerror = reject; 314 | document.querySelector("head").appendChild(file); 315 | }); 316 | } 317 | 318 | /** 319 | * Returns true/false if firebase object reference exists inside window 320 | */ 321 | private hasFirebaseInitialized() { 322 | if (!window.firebase) { 323 | return false; 324 | } 325 | 326 | const firebaseApps = window.firebase.apps; 327 | if (firebaseApps && firebaseApps.length === 0) { 328 | return false; 329 | } 330 | 331 | return true; 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "declaration": true, 5 | "experimentalDecorators": true, 6 | "lib": ["dom", "es2017"], 7 | "module": "esnext", 8 | "moduleResolution": "node", 9 | "noImplicitAny": true, 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "outDir": "dist/esm", 13 | "sourceMap": true, 14 | "target": "es2017" 15 | }, 16 | "files": ["src/index.ts"] 17 | } 18 | --------------------------------------------------------------------------------