From 51534dff9729c50165e7054da4a08f54d78573e2 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Tue, 17 Aug 2021 18:31:52 -0500 Subject: [PATCH 1/4] test(e2e): make sure all e2e tests are run even in sub-directories I tested to verify this does not stop running any existing tests (even if not in sub-directories), but there's no reason not to add the recursive glob in now just in case to future proof all tests --- tests/e2e/.mocharc.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/e2e/.mocharc.js b/tests/e2e/.mocharc.js index c15d4922b3..b3e23fe121 100644 --- a/tests/e2e/.mocharc.js +++ b/tests/e2e/.mocharc.js @@ -11,20 +11,20 @@ module.exports = { recursive: true, require: 'node_modules/jet/platform/node', spec: [ - '../packages/app/e2e/*.e2e.js', - '../packages/app-check/e2e/*.e2e.js', - '../packages/analytics/e2e/*.e2e.js', - '../packages/auth/e2e/*.e2e.js', - '../packages/crashlytics/e2e/*.e2e.js', + '../packages/app/e2e/**/*.e2e.js', + '../packages/app-check/e2e/**/*.e2e.js', + '../packages/analytics/e2e/**/*.e2e.js', + '../packages/auth/e2e/**/*.e2e.js', + '../packages/crashlytics/e2e/**/*.e2e.js', '../packages/database/e2e/**/*.e2e.js', - '../packages/dynamic-links/e2e/*.e2e.js', + '../packages/dynamic-links/e2e/**/*.e2e.js', '../packages/firestore/e2e/**/*.e2e.js', - '../packages/functions/e2e/*.e2e.js', - '../packages/perf/e2e/*.e2e.js', - '../packages/messaging/e2e/*.e2e.js', - '../packages/ml/e2e/*.e2e.js', - '../packages/in-app-messaging/e2e/*.e2e.js', - '../packages/remote-config/e2e/*.e2e.js', - '../packages/storage/e2e/*.e2e.js', + '../packages/functions/e2e/**/*.e2e.js', + '../packages/perf/e2e/**/*.e2e.js', + '../packages/messaging/e2e/**/*.e2e.js', + '../packages/ml/e2e/**/*.e2e.js', + '../packages/in-app-messaging/e2e/**/*.e2e.js', + '../packages/remote-config/e2e/**/*.e2e.js', + '../packages/storage/e2e/**/*.e2e.js', ], }; From 3900a5dedd28d1e9ea74753d45e1c9ff743e9f1c Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Tue, 17 Aug 2021 18:38:41 -0500 Subject: [PATCH 2/4] chore(template): groom new module template more this is the version used to generate the installations module boilerplate --- scripts/_TEMPLATE_/e2e/_template_.e2e.js | 1 - scripts/_TEMPLATE_/type-test.ts | 10 +++++----- scripts/create-firebase-module.js | 12 +++++++++++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/scripts/_TEMPLATE_/e2e/_template_.e2e.js b/scripts/_TEMPLATE_/e2e/_template_.e2e.js index d8bb85f380..e134dabc4f 100644 --- a/scripts/_TEMPLATE_/e2e/_template_.e2e.js +++ b/scripts/_TEMPLATE_/e2e/_template_.e2e.js @@ -16,7 +16,6 @@ */ describe('_template_()', function () { - describe('aMethod()', function () { // TODO }); diff --git a/scripts/_TEMPLATE_/type-test.ts b/scripts/_TEMPLATE_/type-test.ts index b08e556268..a02f58033c 100644 --- a/scripts/_TEMPLATE_/type-test.ts +++ b/scripts/_TEMPLATE_/type-test.ts @@ -1,14 +1,14 @@ import firebase from '@react-native-firebase/app'; -import defaultExport, { firebase as firebaseFromModule } from '@react-native-firebase/_Template_'; +import defaultExport, { firebase as firebaseFromModule } from '@react-native-firebase/_template_'; // checks module exists at root -console.log(firebase._Template_().app.name); +console.log(firebase._template_().app.name); // checks module exists at app level -console.log(firebase.app()._Template_().app.name); +console.log(firebase.app()._template_().app.name); // checks statics exist -console.log(firebase._Template_.SDK_VERSION); +console.log(firebase._template_.SDK_VERSION); // checks statics exist on defaultExport console.log(defaultExport.SDK_VERSION); @@ -20,7 +20,7 @@ console.log(firebase.SDK_VERSION); console.log(firebaseFromModule.SDK_VERSION); // checks multi-app support exists -console.log(firebase._Template_(firebase.app()).app.name); +console.log(firebase._template_(firebase.app()).app.name); // checks default export supports app arg console.log(defaultExport(firebase.app()).app.name); diff --git a/scripts/create-firebase-module.js b/scripts/create-firebase-module.js index ebf05fd196..45b7ecea6e 100644 --- a/scripts/create-firebase-module.js +++ b/scripts/create-firebase-module.js @@ -101,7 +101,12 @@ inquirer console.log('1) ADD IT TO `KNOWN_NAMESPACES` in packages/app/lib/internal/constants.js'); console.log(''); console.log('2) ADD IT TO THE docs:'); - console.log(' - in website/docs/sidebar.yaml'); + console.log(' - in docs//index.md and usage/index.md'); + console.log( + ' - in docs//... find the prev next links where you slice in and fix them', + ); + console.log(' - in docs/app/usage.md list of apps that are multi-app, if it is multi-app'); + console.log(' - in docs/sidebar.yaml'); console.log(' - in website/scripts/source-reference.js'); console.log(' - in website/src/templates/utils.ts'); console.log(''); @@ -109,5 +114,10 @@ inquirer console.log(' - package namespaces in java and package.json and index.d.ts'); console.log(' - the @firebase tag in index.d.ts (creates docs site reference API links)'); console.log(''); + console.log('4) Add the e2e tests:'); + console.log(' - tests/e2e/.mocharc.js'); + console.log(' - tests/package.json (and run yarn + yarn tests:pod:install)'); + console.log(' - tests/app.js'); + console.log(''); }) .catch(console.error); From 0eb412c0d0d6b21f484ae5abe755ddaee3a49f72 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Tue, 17 Aug 2021 18:40:50 -0500 Subject: [PATCH 3/4] feat(installations): implement Firebase Installations module In particular Installations.delete() is needed for GDPR compliance --- .spellcheck.dict.txt | 1 + docs/app/usage.md | 3 +- docs/in-app-messaging/usage/index.md | 2 +- docs/installations/usage/index.md | 37 ++ docs/ml/usage/index.md | 2 +- docs/sidebar.yaml | 4 + packages/app/lib/internal/constants.js | 1 + packages/installations/.npmignore | 65 ++++ packages/installations/LICENSE | 32 ++ packages/installations/README.md | 61 +++ .../installations/RNFBInstallations.podspec | 45 +++ .../__tests__/installations.test.ts | 21 ++ packages/installations/android/.editorconfig | 10 + packages/installations/android/build.gradle | 99 +++++ packages/installations/android/lint.xml | 5 + .../installations/android/settings.gradle | 1 + .../android/src/main/AndroidManifest.xml | 8 + ...eactNativeFirebaseInstallationsModule.java | 107 ++++++ ...actNativeFirebaseInstallationsPackage.java | 41 ++ .../installations/e2e/installations.e2e.js | 80 ++++ .../project.pbxproj | 349 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 5 + .../xcshareddata/IDETemplateMacros.plist | 24 ++ .../RNFBInstallationsModule.h | 24 ++ .../RNFBInstallationsModule.m | 125 +++++++ packages/installations/lib/index.d.ts | 160 ++++++++ packages/installations/lib/index.js | 79 ++++ packages/installations/package.json | 30 ++ packages/installations/type-test.ts | 26 ++ tests/app.js | 1 + tests/e2e/.mocharc.js | 1 + tests/ios/Podfile.lock | 99 ++--- tests/package.json | 1 + website/scripts/source-reference.js | 2 + website/src/templates/utils.ts | 2 + 37 files changed, 1521 insertions(+), 47 deletions(-) create mode 100644 docs/installations/usage/index.md create mode 100644 packages/installations/.npmignore create mode 100644 packages/installations/LICENSE create mode 100644 packages/installations/README.md create mode 100644 packages/installations/RNFBInstallations.podspec create mode 100644 packages/installations/__tests__/installations.test.ts create mode 100644 packages/installations/android/.editorconfig create mode 100644 packages/installations/android/build.gradle create mode 100644 packages/installations/android/lint.xml create mode 100644 packages/installations/android/settings.gradle create mode 100644 packages/installations/android/src/main/AndroidManifest.xml create mode 100644 packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsModule.java create mode 100644 packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsPackage.java create mode 100644 packages/installations/e2e/installations.e2e.js create mode 100644 packages/installations/ios/RNFBInstallations.xcodeproj/project.pbxproj create mode 100644 packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/installations/ios/RNFBInstallations.xcodeproj/xcshareddata/IDETemplateMacros.plist create mode 100644 packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.h create mode 100644 packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.m create mode 100644 packages/installations/lib/index.d.ts create mode 100644 packages/installations/lib/index.js create mode 100644 packages/installations/package.json create mode 100644 packages/installations/type-test.ts diff --git a/.spellcheck.dict.txt b/.spellcheck.dict.txt index 74087c8078..d7d2f40149 100644 --- a/.spellcheck.dict.txt +++ b/.spellcheck.dict.txt @@ -55,6 +55,7 @@ Fastlane FCM firebase Firebase +FirebaseApp firebase-ios-sdk Firestore getIdToken diff --git a/docs/app/usage.md b/docs/app/usage.md index 3cd0265396..e304c8b5e2 100644 --- a/docs/app/usage.md +++ b/docs/app/usage.md @@ -21,13 +21,14 @@ for manually initializing secondary Firebase app instances. Currently, the native Firebase SDKs only provide functionality for creating secondary apps on the following services: -- [AppCheck](/app-check/usage). +- [App Check](/app-check/usage). - [Authentication](/auth/usage). - [Realtime Database](/database/usage). - [Cloud Firestore](/firestore/usage). - [Cloud Functions](/functions/usage) - [Cloud Storage](/storage/usage). - [ML](/ml/usage). +- [Installations](/installations/usage), - [Remote Config](/remote-config/usage). ## Initializing secondary apps diff --git a/docs/in-app-messaging/usage/index.md b/docs/in-app-messaging/usage/index.md index 72358725d4..04ad034e8a 100644 --- a/docs/in-app-messaging/usage/index.md +++ b/docs/in-app-messaging/usage/index.md @@ -2,7 +2,7 @@ title: In App Messaging description: Installation and getting started with In App Messaging. icon: //static.invertase.io/assets/firebase/in-app-messaging.svg -next: /ml/usage +next: /installations/usage previous: /dynamic-links/usage --- diff --git a/docs/installations/usage/index.md b/docs/installations/usage/index.md new file mode 100644 index 0000000000..ed98d490ac --- /dev/null +++ b/docs/installations/usage/index.md @@ -0,0 +1,37 @@ +--- +title: Installations +description: Installation and getting started with Installations. +icon: //static.invertase.io/assets/social/firebase-logo.png +next: /ml/usage +previous: /in-app-messaging/usage +--- + +# Installation + +This module requires that the `@react-native-firebase/app` module is already setup and installed. To install the "app" +module, view the [Getting Started](/) documentation. + +```bash +# Install & setup the app module +yarn add @react-native-firebase/app + +# Install the installations module +yarn add @react-native-firebase/installations + +# If you're developing your app using iOS, run this command +cd ios/ && pod install +``` + +# What does it do + +The Firebase installations service: + +- provides a unique identifier for a Firebase installation +- provides an auth token for a Firebase installation +- provides an API to perform GDPR-compliant deletion of a Firebase installation. + +Each configured `FirebaseApp` has a corresponding single instance of Installations. An instance of the class provides access to the installation info for the FirebaseApp as well as the ability to delete it. A Firebase Installation is unique by `FirebaseApp.name` and `FirebaseApp.options.googleAppID` + +# Usage + +Please see the API Reference for detailed usage information on the available APIs diff --git a/docs/ml/usage/index.md b/docs/ml/usage/index.md index 8bb49c671b..3c48815c14 100644 --- a/docs/ml/usage/index.md +++ b/docs/ml/usage/index.md @@ -3,7 +3,7 @@ title: ML description: Installation and getting started with ML. icon: //static.invertase.io/assets/firebase/ml-kit.svg next: /remote-config/usage -previous: /in-app-messaging/usage +previous: /installations/usage --- # Installation diff --git a/docs/sidebar.yaml b/docs/sidebar.yaml index 51897590ca..86dd79753a 100644 --- a/docs/sidebar.yaml +++ b/docs/sidebar.yaml @@ -97,6 +97,10 @@ - - - Usage - '/in-app-messaging/usage' - '//static.invertase.io/assets/firebase/in-app-messaging.svg' +- - Installations + - - - Usage + - '/installations/usage' + - '//static.invertase.io/assets/social/firebase-logo.png' - - ML - - - Usage - '/ml/usage' diff --git a/packages/app/lib/internal/constants.js b/packages/app/lib/internal/constants.js index 4bc585ef6b..aae6cb3d62 100644 --- a/packages/app/lib/internal/constants.js +++ b/packages/app/lib/internal/constants.js @@ -27,6 +27,7 @@ export const KNOWN_NAMESPACES = [ 'crashlytics', 'database', 'inAppMessaging', + 'installations', 'firestore', 'functions', 'indexing', diff --git a/packages/installations/.npmignore b/packages/installations/.npmignore new file mode 100644 index 0000000000..d9fa30e5a5 --- /dev/null +++ b/packages/installations/.npmignore @@ -0,0 +1,65 @@ +# Built application files +android/*/build/ + +# Crashlytics configuations +android/com_crashlytics_export_strings.xml + +# Local configuration file (sdk path, etc) +android/local.properties + +# Gradle generated files +android/.gradle/ + +# Signing files +android/.signing/ + +# User-specific configurations +android/.idea/gradle.xml +android/.idea/libraries/ +android/.idea/workspace.xml +android/.idea/tasks.xml +android/.idea/.name +android/.idea/compiler.xml +android/.idea/copyright/profiles_settings.xml +android/.idea/encodings.xml +android/.idea/misc.xml +android/.idea/modules.xml +android/.idea/scopes/scope_settings.xml +android/.idea/vcs.xml +android/*.iml + +# Xcode +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 +*.xcuserstate +ios/Pods +ios/build +*project.xcworkspace* +*xcuserdata* + +# OS-specific files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.dbandroid/gradle +android/gradlew +android/build +android/gradlew.bat +android/gradle/ + +.idea +coverage +yarn.lock +e2e/ +.github +.vscode +.nyc_output +android/.settings +*.coverage.json +.circleci +.eslintignore diff --git a/packages/installations/LICENSE b/packages/installations/LICENSE new file mode 100644 index 0000000000..ef3ed44f06 --- /dev/null +++ b/packages/installations/LICENSE @@ -0,0 +1,32 @@ +Apache-2.0 License +------------------ + +Copyright (c) 2016-present Invertase Limited & Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this library except in compliance with the License. + +You may obtain a copy of the Apache-2.0 License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +Creative Commons Attribution 3.0 License +---------------------------------------- + +Copyright (c) 2016-present Invertase Limited & Contributors + +Documentation and other instructional materials provided for this project +(including on a separate documentation repository or it's documentation website) are +licensed under the Creative Commons Attribution 3.0 License. Code samples/blocks +contained therein are licensed under the Apache License, Version 2.0 (the "License"), as above. + +You may obtain a copy of the Creative Commons Attribution 3.0 License at + + https://creativecommons.org/licenses/by/3.0/ diff --git a/packages/installations/README.md b/packages/installations/README.md new file mode 100644 index 0000000000..b926f3ac08 --- /dev/null +++ b/packages/installations/README.md @@ -0,0 +1,61 @@ +

+ +
+
+

React Native Firebase - Installations

+

+ +

+ Coverage + NPM downloads + NPM version + License + Maintained with Lerna +

+ +

+ Chat on Discord + Follow on Twitter + Follow on Facebook +

+ +---- + +Entry point for Firebase installations. + +The Firebase installations service: + +- provides a unique identifier for a Firebase installation +- provides an auth token for a Firebase installation +- provides a API to perform GDPR-compliant deletion of a Firebase installation. + + +[> Learn More](https://firebase.google.com/docs/projects/manage-installations) + +## Installation + +Requires `@react-native-firebase/app` to be installed. + +```bash +yarn add @react-native-firebase/installations +``` + +## Documentation + + - [Guides](https://rnfirebase.io/installations/usage/) + - [Reference](https://rnfirebase.io/reference/installations) + +## License + +- See [LICENSE](/LICENSE) + +---- + +

+ +

+ Built and maintained with đź’› by Invertase. +

+

+ +---- diff --git a/packages/installations/RNFBInstallations.podspec b/packages/installations/RNFBInstallations.podspec new file mode 100644 index 0000000000..3a9aa1b4cd --- /dev/null +++ b/packages/installations/RNFBInstallations.podspec @@ -0,0 +1,45 @@ +require 'json' +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) +appPackage = JSON.parse(File.read(File.join('..', 'app', 'package.json'))) + +coreVersionDetected = appPackage['version'] +coreVersionRequired = package['peerDependencies'][appPackage['name']] +firebase_sdk_version = appPackage['sdkVersions']['ios']['firebase'] +if coreVersionDetected != coreVersionRequired + Pod::UI.warn "NPM package '#{package['name']}' depends on '#{appPackage['name']}' v#{coreVersionRequired} but found v#{coreVersionDetected}, this might cause build issues or runtime crashes." +end + +Pod::Spec.new do |s| + s.name = "RNFBInstallations" + s.version = package["version"] + s.description = package["description"] + s.summary = <<-DESC + A well tested feature rich Firebase implementation for React Native, supporting iOS & Android. + DESC + s.homepage = "http://invertase.io/oss/react-native-firebase" + s.license = package['license'] + s.authors = "Invertase Limited" + s.source = { :git => "https://github.com/invertase/react-native-firebase.git", :tag => "v#{s.version}" } + s.social_media_url = 'http://twitter.com/invertaseio' + s.ios.deployment_target = "10.0" + s.source_files = 'ios/**/*.{h,m}' + + # React Native dependencies + s.dependency 'React-Core' + s.dependency 'RNFBApp' + + if defined?($FirebaseSDKVersion) + Pod::UI.puts "#{s.name}: Using user specified Firebase SDK version '#{$FirebaseSDKVersion}'" + firebase_sdk_version = $FirebaseSDKVersion + end + + # Firebase dependencies + s.dependency 'Firebase/Installations', firebase_sdk_version + + if defined?($RNFirebaseAsStaticFramework) + Pod::UI.puts "#{s.name}: Using overridden static_framework value of '#{$RNFirebaseAsStaticFramework}'" + s.static_framework = $RNFirebaseAsStaticFramework + else + s.static_framework = false + end +end diff --git a/packages/installations/__tests__/installations.test.ts b/packages/installations/__tests__/installations.test.ts new file mode 100644 index 0000000000..c1a945bcad --- /dev/null +++ b/packages/installations/__tests__/installations.test.ts @@ -0,0 +1,21 @@ +import { firebase } from '../lib'; + +describe('installations()', function () { + describe('namespace', function () { + it('accessible from firebase.app()', function () { + const app = firebase.app(); + expect(app.installations).toBeDefined(); + expect(app.installations().app).toEqual(app); + }); + + it('supports multiple apps', async function () { + expect(firebase.installations().app.name).toEqual('[DEFAULT]'); + expect(firebase.installations(firebase.app('secondaryFromNative')).app.name).toEqual( + 'secondaryFromNative', + ); + expect(firebase.app('secondaryFromNative').installations().app.name).toEqual( + 'secondaryFromNative', + ); + }); + }); +}); diff --git a/packages/installations/android/.editorconfig b/packages/installations/android/.editorconfig new file mode 100644 index 0000000000..670398e990 --- /dev/null +++ b/packages/installations/android/.editorconfig @@ -0,0 +1,10 @@ +# editorconfig +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/packages/installations/android/build.gradle b/packages/installations/android/build.gradle new file mode 100644 index 0000000000..75788c2138 --- /dev/null +++ b/packages/installations/android/build.gradle @@ -0,0 +1,99 @@ +import io.invertase.gradle.common.PackageJson + +buildscript { + // The Android Gradle plugin is only required when opening the android folder stand-alone. + // This avoids unnecessary downloads and potential conflicts when the library is included as a + // module dependency in an application project. + if (project == rootProject) { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath("com.android.tools.build:gradle:7.0.0") + } + } +} + +plugins { + id "io.invertase.gradle.build" version "1.5" +} + +def appProject +if (findProject(':@react-native-firebase_app')) { + appProject = project(':@react-native-firebase_app') +} else if (findProject(':react-native-firebase_app')) { + appProject = project(':react-native-firebase_app') +} else { + throw new GradleException('Could not find the react-native-firebase/app package, have you installed it?') +} +def packageJson = PackageJson.getForProject(project) +def appPackageJson = PackageJson.getForProject(appProject) +def firebaseBomVersion = appPackageJson['sdkVersions']['android']['firebase'] +def jsonMinSdk = appPackageJson['sdkVersions']['android']['minSdk'] +def jsonTargetSdk = appPackageJson['sdkVersions']['android']['targetSdk'] +def jsonCompileSdk = appPackageJson['sdkVersions']['android']['compileSdk'] +def jsonBuildTools = appPackageJson['sdkVersions']['android']['buildTools'] +def coreVersionDetected = appPackageJson['version'] +def coreVersionRequired = packageJson['peerDependencies'][appPackageJson['name']] +// Only log after build completed so log warning appears at the end +if (coreVersionDetected != coreVersionRequired) { + gradle.buildFinished { + project.logger.warn("ReactNativeFirebase WARNING: NPM package '${packageJson['name']}' depends on '${appPackageJson['name']}' v${coreVersionRequired} but found v${coreVersionDetected}, this might cause build issues or runtime crashes.") + } +} + +project.ext { + set('react-native', [ + versions: [ + android : [ + minSdk : jsonMinSdk, + targetSdk : jsonTargetSdk, + compileSdk: jsonCompileSdk, + // optional as gradle.buildTools comes with one by default + // overriding here though to match the version RN uses + buildTools: jsonBuildTools + ], + + firebase: [ + bom: firebaseBomVersion, + ], + ], + ]) +} + +android { + defaultConfig { + multiDexEnabled true + } + lintOptions { + disable 'GradleCompatible' + abortOnError false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + sourceSets { + main { + java.srcDirs = ['src/main/java', 'src/reactnative/java'] + } + } +} + +repositories { + google() + mavenCentral() +} + +dependencies { + api appProject + implementation platform("com.google.firebase:firebase-bom:${ReactNative.ext.getVersion("firebase", "bom")}") + implementation "com.google.firebase:firebase-installations" +} + +ReactNative.shared.applyPackageVersion() +ReactNative.shared.applyDefaultExcludes() +ReactNative.module.applyAndroidVersions() +ReactNative.module.applyReactNativeDependency("api") diff --git a/packages/installations/android/lint.xml b/packages/installations/android/lint.xml new file mode 100644 index 0000000000..c3dd72aca0 --- /dev/null +++ b/packages/installations/android/lint.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/installations/android/settings.gradle b/packages/installations/android/settings.gradle new file mode 100644 index 0000000000..82e62bda0e --- /dev/null +++ b/packages/installations/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = '@react-native-firebase_installations' diff --git a/packages/installations/android/src/main/AndroidManifest.xml b/packages/installations/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..7790b94d21 --- /dev/null +++ b/packages/installations/android/src/main/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsModule.java b/packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsModule.java new file mode 100644 index 0000000000..eb40ad7a97 --- /dev/null +++ b/packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsModule.java @@ -0,0 +1,107 @@ +package io.invertase.firebase.installations; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import android.util.Log; +import com.facebook.react.bridge.*; +import com.google.android.gms.tasks.Tasks; +import com.google.firebase.FirebaseApp; +import com.google.firebase.installations.FirebaseInstallations; +import io.invertase.firebase.common.ReactNativeFirebaseModule; + +public class ReactNativeFirebaseInstallationsModule extends ReactNativeFirebaseModule { + private static final String TAG = "Installations"; + + ReactNativeFirebaseInstallationsModule(ReactApplicationContext reactContext) { + super(reactContext, TAG); + } + + @ReactMethod + public void getId(String appName, Promise promise) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + + Tasks.call( + getExecutor(), + () -> { + return Tasks.await(FirebaseInstallations.getInstance(firebaseApp).getId()); + }) + .addOnCompleteListener( + getExecutor(), + (task) -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + Log.e( + TAG, + "RNFB: Unknown error while fetching Installations ID " + + task.getException().getMessage()); + rejectPromiseWithCodeAndMessage( + promise, "id-error", task.getException().getMessage()); + } + }); + } + + @ReactMethod + public void getToken(String appName, boolean forceRefresh, Promise promise) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + Tasks.call( + getExecutor(), + () -> { + return Tasks.await( + FirebaseInstallations.getInstance(firebaseApp).getToken(forceRefresh)); + }) + .addOnCompleteListener( + getExecutor(), + (task) -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult().getToken()); + } else { + Log.e( + TAG, + "RNFB: Unknown error while fetching Installations token " + + task.getException().getMessage()); + rejectPromiseWithCodeAndMessage( + promise, "token-error", task.getException().getMessage()); + } + }); + } + + @ReactMethod + public void delete(String appName, Promise promise) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + Tasks.call( + getExecutor(), + () -> { + return Tasks.await(FirebaseInstallations.getInstance(firebaseApp).delete()); + }) + .addOnCompleteListener( + getExecutor(), + (task) -> { + if (task.isSuccessful()) { + promise.resolve(null); + } else { + Log.e( + TAG, + "RNFB: Unknown error while deleting Installations" + + task.getException().getMessage()); + rejectPromiseWithCodeAndMessage( + promise, "delete-error", task.getException().getMessage()); + } + }); + } +} diff --git a/packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsPackage.java b/packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsPackage.java new file mode 100644 index 0000000000..a845533203 --- /dev/null +++ b/packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsPackage.java @@ -0,0 +1,41 @@ +package io.invertase.firebase.installations; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@SuppressWarnings("unused") +public class ReactNativeFirebaseInstallationsPackage implements ReactPackage { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + modules.add(new ReactNativeFirebaseInstallationsModule(reactContext)); + return modules; + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} diff --git a/packages/installations/e2e/installations.e2e.js b/packages/installations/e2e/installations.e2e.js new file mode 100644 index 0000000000..41967e0ebd --- /dev/null +++ b/packages/installations/e2e/installations.e2e.js @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const jwt = require('jsonwebtoken'); + +const ID_LENGTH = 22; +const PROJECT_ID = 448618578101; // this is "magic", it's the react-native-firebase-testing project ID + +describe('installations()', function () { + describe('getId()', function () { + it('returns a valid installation id', async function () { + const id = await firebase.installations().getId(); + id.should.be.a.String(); + id.length.should.be.equals(ID_LENGTH); + }); + }); + + describe('getToken()', function () { + it('returns a valid auth token with no arguments', async function () { + const id = await firebase.installations().getId(); + const token = await firebase.installations().getToken(); + token.should.be.a.String(); + token.should.not.equal(''); + const decodedToken = jwt.decode(token); + decodedToken.fid.should.equal(id); // fid == firebase installations id + decodedToken.projectNumber.should.equal(PROJECT_ID); + if (decodedToken.exp < Date.now()) { + Promise.reject('Token already expired'); + } + + const token2 = await firebase.installations().getToken(true); + token2.should.be.a.String(); + token2.should.not.equal(''); + const decodedToken2 = jwt.decode(token2); + decodedToken2.fid.should.equal(id); + decodedToken2.projectNumber.should.equal(PROJECT_ID); + if (decodedToken2.exp < Date.now()) { + Promise.reject('Token already expired'); + } + (token === token2).should.be.false(); + }); + }); + + describe('delete()', function () { + it('successfully deletes', async function () { + const id = await firebase.installations().getId(); + id.should.be.a.String(); + id.length.should.be.equals(ID_LENGTH); + await firebase.installations().delete(); + + // New id should be different + const id2 = await firebase.installations().getId(); + id2.should.be.a.String(); + id2.length.should.be.equals(ID_LENGTH); + (id === id2).should.be.false(); + + const token = await firebase.installations().getToken(false); + const decodedToken = jwt.decode(token); + decodedToken.fid.should.equal(id2); // fid == firebase installations id + decodedToken.projectNumber.should.equal(PROJECT_ID); + if (decodedToken.exp < Date.now()) { + Promise.reject('Token already expired'); + } + }); + }); +}); diff --git a/packages/installations/ios/RNFBInstallations.xcodeproj/project.pbxproj b/packages/installations/ios/RNFBInstallations.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..d238d5a79d --- /dev/null +++ b/packages/installations/ios/RNFBInstallations.xcodeproj/project.pbxproj @@ -0,0 +1,349 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 2744B98621F45429004F8E3F /* RNFBInstallationsModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBInstallationsModule.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 2744B98021F45429004F8E3F /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 2744B98221F45429004F8E3F /* libRNFBInstallations.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBInstallations.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 2744B98421F45429004F8E3F /* RNFBInstallationsModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBInstallationsModule.h; path = RNFBInstallations/RNFBInstallationsModule.h; sourceTree = SOURCE_ROOT; }; + 2744B98521F45429004F8E3F /* RNFBInstallationsModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBInstallationsModule.m; path = RNFBInstallations/RNFBInstallationsModule.m; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 2744B97F21F45429004F8E3F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2744B97521F452B8004F8E3F /* Products */ = { + isa = PBXGroup; + children = ( + 2744B98221F45429004F8E3F /* libRNFBInstallations.a */, + ); + name = Products; + sourceTree = ""; + }; + 2744B98321F45429004F8E3F /* RNFBInstallations */ = { + isa = PBXGroup; + children = ( + 2744B9A121F48736004F8E3F /* converters */, + 2744B98C21F45C64004F8E3F /* common */, + 2744B98421F45429004F8E3F /* RNFBInstallationsModule.h */, + 2744B98521F45429004F8E3F /* RNFBInstallationsModule.m */, + ); + path = RNFBInstallations; + sourceTree = ""; + }; + 3323F52AAFE26B7384BE4DE3 = { + isa = PBXGroup; + children = ( + 2744B98321F45429004F8E3F /* RNFBInstallations */, + 2744B97521F452B8004F8E3F /* Products */, + ); + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 2744B98121F45429004F8E3F /* RNFBInstallations */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2744B98821F45429004F8E3F /* Build configuration list for PBXNativeTarget "RNFBInstallations" */; + buildPhases = ( + 2744B97E21F45429004F8E3F /* Sources */, + 2744B97F21F45429004F8E3F /* Frameworks */, + 2744B98021F45429004F8E3F /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RNFBInstallations; + productName = RNFBInstallations; + productReference = 2744B98221F45429004F8E3F /* libRNFBInstallations.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3323F95273A95DB34F55C6D7 /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = RNFBInstallations; + LastUpgradeCheck = 1010; + ORGANIZATIONNAME = Invertase; + TargetAttributes = { + 2744B98121F45429004F8E3F = { + CreatedOnToolsVersion = 10.1; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 3323F1C5716BA966BBBB95A4 /* Build configuration list for PBXProject "RNFBInstallations" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 3323F52AAFE26B7384BE4DE3; + productRefGroup = 2744B97521F452B8004F8E3F /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2744B98121F45429004F8E3F /* RNFBInstallations */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 2744B97E21F45429004F8E3F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2744B98621F45429004F8E3F /* RNFBInstallationsModule.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 2744B98921F45429004F8E3F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 2744B98A21F45429004F8E3F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 3323F77D701E1896E6D239CF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "${BUILT_PRODUCTS_DIR}/**", + "${SRCROOT}/../../../ios/Firebase/**", + "$(FIREBASE_SEARCH_PATH)/Firebase/**", + "$(SRCROOT)/../../../ios/Pods/FirebaseInstallations/Frameworks", + "$(SRCROOT)/../../../tests/ios/Pods/FirebaseInstallations/Frameworks", + ); + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(REACT_SEARCH_PATH)/React/**", + "$(SRCROOT)/../../react-native/React/**", + "$(SRCROOT)/../../react-native-firebase/ios/**", + "$(FIREBASE_SEARCH_PATH)/Firebase/**", + "${SRCROOT}/../../../ios/Firebase/**", + "${SRCROOT}/../../../ios/Pods/Headers/Public/**", + "${SRCROOT}/../../../tests/ios/Pods/Headers/Public/**", + "$(SRCROOT)/../../../node_modules/react-native/React/**", + "$(SRCROOT)/../../../node_modules/react-native-firebase/ios/**", + "$(SRCROOT)/../../../packages/app/ios/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + MACH_O_TYPE = staticlib; + OTHER_LDFLAGS = "$(inherited)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 3323F7E33E1559A2B9826720 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "${BUILT_PRODUCTS_DIR}/**", + "${SRCROOT}/../../../ios/Firebase/**", + "$(FIREBASE_SEARCH_PATH)/Firebase/**", + "$(SRCROOT)/../../../ios/Pods/FirebaseInstallations/Frameworks", + ); + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(REACT_SEARCH_PATH)/React/**", + "$(SRCROOT)/../../react-native/React/**", + "$(SRCROOT)/../../react-native-firebase/ios/**", + "$(FIREBASE_SEARCH_PATH)/Firebase/**", + "${SRCROOT}/../../../ios/Firebase/**", + "${SRCROOT}/../../../ios/Pods/Headers/Public/**", + "${SRCROOT}/../../../tests/ios/Pods/Headers/Public/**", + "$(SRCROOT)/../../../node_modules/react-native/React/**", + "$(SRCROOT)/../../../node_modules/react-native-firebase/ios/**", + "$(SRCROOT)/../../../packages/app/ios/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + MACH_O_TYPE = staticlib; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = "$(inherited)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2744B98821F45429004F8E3F /* Build configuration list for PBXNativeTarget "RNFBInstallations" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2744B98921F45429004F8E3F /* Debug */, + 2744B98A21F45429004F8E3F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3323F1C5716BA966BBBB95A4 /* Build configuration list for PBXProject "RNFBInstallations" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3323F7E33E1559A2B9826720 /* Debug */, + 3323F77D701E1896E6D239CF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3323F95273A95DB34F55C6D7 /* Project object */; +} diff --git a/packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..919434a625 --- /dev/null +++ b/packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..0c67376eba --- /dev/null +++ b/packages/installations/ios/RNFBInstallations.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/installations/ios/RNFBInstallations.xcodeproj/xcshareddata/IDETemplateMacros.plist b/packages/installations/ios/RNFBInstallations.xcodeproj/xcshareddata/IDETemplateMacros.plist new file mode 100644 index 0000000000..63f0a6e5dd --- /dev/null +++ b/packages/installations/ios/RNFBInstallations.xcodeproj/xcshareddata/IDETemplateMacros.plist @@ -0,0 +1,24 @@ + + + + + FILEHEADER + +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + diff --git a/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.h b/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.h new file mode 100644 index 0000000000..a734bb8f29 --- /dev/null +++ b/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +#import + +@interface RNFBInstallationsModule : NSObject + +@end diff --git a/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.m b/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.m new file mode 100644 index 0000000000..7b07b36a0b --- /dev/null +++ b/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.m @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import + +#import "RNFBApp/RNFBSharedUtils.h" +#import "RNFBInstallationsModule.h" + +#import "FirebaseInstallations/FIRInstallations.h" + +@implementation RNFBInstallationsModule +#pragma mark - +#pragma mark Module Setup + +RCT_EXPORT_MODULE(); + +- (dispatch_queue_t)methodQueue { + return dispatch_get_main_queue(); +} + +#pragma mark - +#pragma mark Firebase Installations Methods + +RCT_EXPORT_METHOD(delete + : (FIRApp *)firebaseApp + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) { + FIRInstallations *installations = [FIRInstallations installationsWithApp:firebaseApp]; + [installations deleteWithCompletion:^(NSError *_Nullable error) { + if (error != nil) { + // Handle any errors if the delete failed + DLog(@"Unable to delete Installations ID: %@", error); + [RNFBSharedUtils rejectPromiseWithUserInfo:reject + userInfo:(NSMutableDictionary *)@{ + @"code" : @"delete-error", + @"message" : [error localizedDescription], + }]; + return; + } + + resolve([NSNull null]); + }]; +} + +RCT_EXPORT_METHOD(getId + : (FIRApp *)firebaseApp + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) { + FIRInstallations *installations = [FIRInstallations installationsWithApp:firebaseApp]; + [installations installationIDWithCompletion:^(NSString *_Nullable id, NSError *_Nullable error) { + if (error != nil) { + // Handle any errors if the id was not retrieved. + DLog(@"Unable to retrieve Installations ID: %@", error); + [RNFBSharedUtils rejectPromiseWithUserInfo:reject + userInfo:(NSMutableDictionary *)@{ + @"code" : @"id-error", + @"message" : [error localizedDescription], + }]; + return; + } + if (id == nil) { + DLog(@"Unable to retrieve Installations ID."); + [RNFBSharedUtils rejectPromiseWithUserInfo:reject + userInfo:(NSMutableDictionary *)@{ + @"code" : @"id-null", + @"message" : @"no id fetched", + }]; + return; + } + + resolve(id); + }]; +} + +RCT_EXPORT_METHOD(getToken + : (FIRApp *)firebaseApp + : (BOOL)forceRefresh + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) { + FIRInstallations *installations = [FIRInstallations installationsWithApp:firebaseApp]; + [installations authTokenForcingRefresh:forceRefresh + completion:^(FIRInstallationsAuthTokenResult *_Nullable token, + NSError *_Nullable error) { + if (error != nil) { + // Handle any errors if the token was not retrieved. + DLog(@"Unable to retrieve Installations auth token: %@", error); + [RNFBSharedUtils + rejectPromiseWithUserInfo:reject + userInfo:(NSMutableDictionary *)@{ + @"code" : @"token-error", + @"message" : [error localizedDescription], + }]; + return; + } + if (token == nil) { + DLog(@"Unable to retrieve Installations auth token."); + [RNFBSharedUtils + rejectPromiseWithUserInfo:reject + userInfo:(NSMutableDictionary *)@{ + @"code" : @"token-null", + @"message" : @"no token fetched", + }]; + return; + } + + resolve(token.authToken); + }]; +} + +@end diff --git a/packages/installations/lib/index.d.ts b/packages/installations/lib/index.d.ts new file mode 100644 index 0000000000..834289ca2b --- /dev/null +++ b/packages/installations/lib/index.d.ts @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { ReactNativeFirebase } from '@react-native-firebase/app'; + +/** + * Firebase Installations package for React Native. + * + * #### Example 1 + * + * Access the firebase export from the `installations` package: + * + * ```js + * import { firebase } from '@react-native-firebase/installations'; + * + * // firebase.installations().X + * ``` + * + * #### Example 2 + * + * Using the default export from the `installations` package: + * + * ```js + * import installations from '@react-native-firebase/installations'; + * + * // installations().X + * ``` + * + * #### Example 3 + * + * Using the default export from the `app` package: + * + * ```js + * import firebase from '@react-native-firebase/app'; + * import '@react-native-firebase/installations'; + * + * // firebase.installations().X + * ``` + * + * @firebase installations + */ +export namespace FirebaseInstallationsTypes { + import FirebaseModule = ReactNativeFirebase.FirebaseModule; + + // eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface Statics { + // firebase.installations.* static props go here + } + + /** + * The Firebase Installations service is available for the default app or a given app. + * + * #### Example 1 + * + * Get the installations instance for the **default app**: + * + * ```js + * const installationsForDefaultApp = firebase.installations(); + * ``` + * + * #### Example 2 + * + * Get the installations instance for a **secondary app**: + *˚ + * ```js + * const otherApp = firebase.app('otherApp'); + * const installationsForOtherApp = firebase.installations(otherApp); + * ``` + * + */ + export class Module extends FirebaseModule { + /** + * Creates a Firebase Installation if there isn't one for the app and + * returns the Installation ID. The installation ID is a globally unique, + * stable, URL-safe base64 string identifier that uniquely identifies the app instance. + * NOTE: If the application already has an existing FirebaseInstanceID then the InstanceID identifier will be used. + * + * @return Firebase Installation ID, this is a url-safe base64 string of a 128-bit integer. + */ + getId(): Promise; + + /** + * Retrieves (locally or from the server depending on forceRefresh value) a valid installation auth token. + * An existing token may be invalidated or expire, so it is recommended to fetch the installation auth token + * before any request to external servers (it will be refreshed automatically for firebase API calls). + * This method should be used with forceRefresh == YES when e.g. a request with the previously fetched + * installation auth token failed with “Not Authorized” error. + * + * @param forceRefresh Options to get an auth token either by force refreshing or not. + * @return Firebase Installation Authentication Token + */ + getToken(forceRefresh?: boolean): Promise; + + /** + * Deletes the Firebase Installation and all associated data from the Firebase backend. + * This call may cause Firebase Cloud Messaging, Firebase Remote Config, Firebase Predictions, + * or Firebase In-App Messaging to not function properly. Fetching a new installations ID should + * reset all of the dependent services to a stable state again. A network connection is required + * for the method to succeed. If it fails, the existing installation data remains untouched. + */ + delete(): Promise; + + /** + * TODO implement id change listener for android. + * + * Sets a new callback that will get called when Installlation ID changes. + * Returns an unsubscribe function that will remove the callback when called. + * Only the Android SDK supports sending ID change events. + * + * @android + */ + // onIdChange(callback: (installationId: string) => void): () => void; + } +} + +declare const defaultExport: ReactNativeFirebase.FirebaseModuleWithStaticsAndApp< + Installations.Module, + Installations.Statics +>; + +export const firebase: ReactNativeFirebase.Module & { + installations: typeof defaultExport; + app( + name?: string, + ): ReactNativeFirebase.FirebaseApp & { installations(): FirebaseInstallationsTypes.Module }; +}; + +export default defaultExport; + +/** + * Attach namespace to `firebase.` and `FirebaseApp.`. + */ +declare module '@react-native-firebase/app' { + namespace ReactNativeFirebase { + import FirebaseModuleWithStaticsAndApp = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp; + interface Module { + installations: FirebaseModuleWithStaticsAndApp< + FirebaseInstallationsTypes.Module, + FirebaseInstallationsTypes.Statics + >; + } + interface FirebaseApp { + installations(): FirebaseInstallationsTypes.Module; + } + } +} diff --git a/packages/installations/lib/index.js b/packages/installations/lib/index.js new file mode 100644 index 0000000000..cc00baddca --- /dev/null +++ b/packages/installations/lib/index.js @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { isIOS } from '@react-native-firebase/app/lib/common'; +import { + createModuleNamespace, + FirebaseModule, + getFirebaseRoot, +} from '@react-native-firebase/app/lib/internal'; + +import version from './version'; + +const statics = {}; + +const namespace = 'installations'; + +const nativeModuleName = 'RNFBInstallationsModule'; + +class FirebaseInstallationsModule extends FirebaseModule { + getId() { + return this.native.getId(); + } + + getToken(forceRefresh) { + if (!forceRefresh) { + return this.native.getToken(false); + } else { + return this.native.getToken(true); + } + } + + delete() { + return this.native.delete(); + } + + onIdChange() { + if (isIOS) { + return () => {}; + } + + // TODO implement change listener on Android + return () => {}; + } +} + +// import { SDK_VERSION } from '@react-native-firebase/installations'; +export const SDK_VERSION = version; + +// import installations from '@react-native-firebase/installations'; +// installations().X(...); +export default createModuleNamespace({ + statics, + version, + namespace, + nativeModuleName, + nativeEvents: false, // TODO implement android id change listener: ['installations_id_changed'], + hasMultiAppSupport: true, + hasCustomUrlOrRegionSupport: false, + ModuleClass: FirebaseInstallationsModule, +}); + +// import installations, { firebase } from '@react-native-firebase/installations'; +// installations().X(...); +// firebase.installations().X(...); +export const firebase = getFirebaseRoot(); diff --git a/packages/installations/package.json b/packages/installations/package.json new file mode 100644 index 0000000000..eb1ebb5069 --- /dev/null +++ b/packages/installations/package.json @@ -0,0 +1,30 @@ +{ + "name": "@react-native-firebase/installations", + "version": "12.6.1", + "author": "Invertase (http://invertase.io)", + "description": "React Native Firebase - Installations", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "build": "genversion --semi lib/version.js", + "build:clean": "rimraf android/build && rimraf ios/build", + "prepare": "yarn run build" + }, + "repository": { + "type": "git", + "url": "https://github.com/invertase/react-native-firebase/tree/master/packages/installations" + }, + "license": "Apache-2.0", + "keywords": [ + "react", + "react-native", + "firebase", + "installations" + ], + "peerDependencies": { + "@react-native-firebase/app": "12.6.1" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/installations/type-test.ts b/packages/installations/type-test.ts new file mode 100644 index 0000000000..a0d0f17120 --- /dev/null +++ b/packages/installations/type-test.ts @@ -0,0 +1,26 @@ +import firebase from '@react-native-firebase/app'; +import defaultExport, { firebase as firebaseFromModule } from '@react-native-firebase/installations'; + +// checks module exists at root +console.log(firebase.installations().app.name); + +// checks module exists at app level +console.log(firebase.app().installations().app.name); + +// checks statics exist +console.log(firebase.installations.SDK_VERSION); + +// checks statics exist on defaultExport +console.log(defaultExport.SDK_VERSION); + +// checks root exists +console.log(firebase.SDK_VERSION); + +// checks firebase named export exists on module +console.log(firebaseFromModule.SDK_VERSION); + +// checks multi-app support exists +console.log(firebase.installations(firebase.app()).app.name); + +// checks default export supports app arg +console.log(defaultExport(firebase.app()).app.name); diff --git a/tests/app.js b/tests/app.js index 51fa792f13..03ff6abb04 100644 --- a/tests/app.js +++ b/tests/app.js @@ -27,6 +27,7 @@ import '@react-native-firebase/dynamic-links'; import '@react-native-firebase/firestore'; import '@react-native-firebase/functions'; import '@react-native-firebase/in-app-messaging'; +import '@react-native-firebase/installations'; import '@react-native-firebase/messaging'; import '@react-native-firebase/ml'; import '@react-native-firebase/perf'; diff --git a/tests/e2e/.mocharc.js b/tests/e2e/.mocharc.js index b3e23fe121..89631fb6ac 100644 --- a/tests/e2e/.mocharc.js +++ b/tests/e2e/.mocharc.js @@ -24,6 +24,7 @@ module.exports = { '../packages/messaging/e2e/**/*.e2e.js', '../packages/ml/e2e/**/*.e2e.js', '../packages/in-app-messaging/e2e/**/*.e2e.js', + '../packages/installations/e2e/**/*.e2e.js', '../packages/remote-config/e2e/**/*.e2e.js', '../packages/storage/e2e/**/*.e2e.js', ], diff --git a/tests/ios/Podfile.lock b/tests/ios/Podfile.lock index 7e21b867d7..3a33702120 100644 --- a/tests/ios/Podfile.lock +++ b/tests/ios/Podfile.lock @@ -385,6 +385,9 @@ PODS: - Firebase/InAppMessaging (8.5.0): - Firebase/CoreOnly - FirebaseInAppMessaging (~> 8.5.0-beta) + - Firebase/Installations (8.5.0): + - Firebase/CoreOnly + - FirebaseInstallations (~> 8.5.0) - Firebase/Messaging (8.5.0): - Firebase/CoreOnly - FirebaseMessaging (~> 8.5.0) @@ -397,7 +400,7 @@ PODS: - Firebase/Storage (8.5.0): - Firebase/CoreOnly - FirebaseStorage (~> 8.5.0) - - FirebaseABTesting (8.5.0): + - FirebaseABTesting (8.6.0): - FirebaseCore (~> 8.0) - FirebaseAnalytics (8.5.0): - FirebaseAnalytics/AdIdSupport (= 8.5.0) @@ -430,7 +433,7 @@ PODS: - FirebaseCoreDiagnostics (~> 8.0) - GoogleUtilities/Environment (~> 7.4) - GoogleUtilities/Logger (~> 7.4) - - FirebaseCoreDiagnostics (8.5.0): + - FirebaseCoreDiagnostics (8.6.0): - GoogleDataTransport (~> 9.0) - GoogleUtilities/Environment (~> 7.4) - GoogleUtilities/Logger (~> 7.4) @@ -517,25 +520,25 @@ PODS: - GoogleUtilities/Environment (~> 7.2) - nanopb (~> 2.30908.0) - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/AppDelegateSwizzler (7.5.0): + - GoogleUtilities/AppDelegateSwizzler (7.5.1): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - - GoogleUtilities/Environment (7.5.0): + - GoogleUtilities/Environment (7.5.1): - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/ISASwizzler (7.5.0) - - GoogleUtilities/Logger (7.5.0): + - GoogleUtilities/ISASwizzler (7.5.1) + - GoogleUtilities/Logger (7.5.1): - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (7.5.0): + - GoogleUtilities/MethodSwizzler (7.5.1): - GoogleUtilities/Logger - - GoogleUtilities/Network (7.5.0): + - GoogleUtilities/Network (7.5.1): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.5.0)" - - GoogleUtilities/Reachability (7.5.0): + - "GoogleUtilities/NSData+zlib (7.5.1)" + - GoogleUtilities/Reachability (7.5.1): - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (7.5.0): + - GoogleUtilities/UserDefaults (7.5.1): - GoogleUtilities/Logger - "gRPC-C++ (1.28.2)": - "gRPC-C++/Implementation (= 1.28.2)" @@ -829,62 +832,66 @@ PODS: - React-cxxreact (= 0.64.2) - React-jsi (= 0.64.2) - React-perflogger (= 0.64.2) - - RNFBAnalytics (12.6.0): + - RNFBAnalytics (12.6.1): - Firebase/Analytics (= 8.5.0) - React-Core - RNFBApp - - RNFBApp (12.6.0): + - RNFBApp (12.6.1): - Firebase/CoreOnly (= 8.5.0) - React-Core - - RNFBAppCheck (12.6.0): + - RNFBAppCheck (12.6.1): - Firebase/AppCheck (= 8.5.0) - React-Core - RNFBApp - - RNFBAuth (12.6.0): + - RNFBAuth (12.6.1): - Firebase/Auth (= 8.5.0) - React-Core - RNFBApp - - RNFBCrashlytics (12.6.0): + - RNFBCrashlytics (12.6.1): - Firebase/Crashlytics (= 8.5.0) - React-Core - RNFBApp - - RNFBDatabase (12.6.0): + - RNFBDatabase (12.6.1): - Firebase/Database (= 8.5.0) - React-Core - RNFBApp - - RNFBDynamicLinks (12.6.0): + - RNFBDynamicLinks (12.6.1): - Firebase/DynamicLinks (= 8.5.0) - GoogleUtilities/AppDelegateSwizzler - React-Core - RNFBApp - - RNFBFirestore (12.6.0): + - RNFBFirestore (12.6.1): - Firebase/Firestore (= 8.5.0) - React-Core - RNFBApp - - RNFBFunctions (12.6.0): + - RNFBFunctions (12.6.1): - Firebase/Functions (= 8.5.0) - React-Core - RNFBApp - - RNFBInAppMessaging (12.6.0): + - RNFBInAppMessaging (12.6.1): - Firebase/InAppMessaging (= 8.5.0) - React-Core - RNFBApp - - RNFBMessaging (12.6.0): + - RNFBInstallations (12.6.1): + - Firebase/Installations (= 8.5.0) + - React-Core + - RNFBApp + - RNFBMessaging (12.6.1): - Firebase/Messaging (= 8.5.0) - React-Core - RNFBApp - - RNFBML (12.6.0): + - RNFBML (12.6.1): - React-Core - RNFBApp - - RNFBPerf (12.6.0): + - RNFBPerf (12.6.1): - Firebase/Performance (= 8.5.0) - React-Core - RNFBApp - - RNFBRemoteConfig (12.6.0): + - RNFBRemoteConfig (12.6.1): - Firebase/RemoteConfig (= 8.5.0) - React-Core - RNFBApp - - RNFBStorage (12.6.0): + - RNFBStorage (12.6.1): - Firebase/Storage (= 8.5.0) - React-Core - RNFBApp @@ -931,6 +938,7 @@ DEPENDENCIES: - RNFBFirestore (from `../../packages/firestore`) - RNFBFunctions (from `../../packages/functions`) - RNFBInAppMessaging (from `../../packages/in-app-messaging`) + - RNFBInstallations (from `../../packages/installations`) - RNFBMessaging (from `../../packages/messaging`) - RNFBML (from `../../packages/ml`) - RNFBPerf (from `../../packages/perf`) @@ -1049,6 +1057,8 @@ EXTERNAL SOURCES: :path: "../../packages/functions" RNFBInAppMessaging: :path: "../../packages/in-app-messaging" + RNFBInstallations: + :path: "../../packages/installations" RNFBMessaging: :path: "../../packages/messaging" RNFBML: @@ -1070,12 +1080,12 @@ SPEC CHECKSUMS: FBLazyVector: e686045572151edef46010a6f819ade377dfeb4b FBReactNativeSpec: 25e094945df743fcfa1283399bf9715648bff333 Firebase: ff8c73105b90e33e1dc6c8e5445d7adc2ccdc7c1 - FirebaseABTesting: f7cb3fbed1c5bd3e733a79d9955447be3f3b06a5 + FirebaseABTesting: c3e48ebf5e7e5c674c5a131c68e941d7921d83dc FirebaseAnalytics: 96325c1e0acbd2bb805c6a613028b1fe599d6a37 FirebaseAppCheck: 0cced04f86b12f8b72d0a6437a7a4cf76e2ecc07 FirebaseAuth: b152ea261b60eeb9419ae7e5bf34761382b33277 FirebaseCore: 1c1ca72483b59b17050f5b4cec4fb748425a3901 - FirebaseCoreDiagnostics: 7bf55d386f9fc690d971b70a582142321a390eb8 + FirebaseCoreDiagnostics: 3721920bde3a9a6d5aa093c1d25e9d3e47f694af FirebaseCrashlytics: 8e7cf678cb149d421198388c6fc3d3acfd266539 FirebaseDatabase: 65c3742ed355f9b9db222036fd154e699ab7d672 FirebaseDynamicLinks: 6e406b3bb669f8c8a63e7254bb63251fa3f88a43 @@ -1090,7 +1100,7 @@ SPEC CHECKSUMS: glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62 GoogleAppMeasurement: 8d10c1c470fcb0e5143ed74fddd164f0a0384800 GoogleDataTransport: 85fd18ff3019bb85d3f2c551d04c481dedf71fc9 - GoogleUtilities: eea970f4a389963963bffe8d8fabe43540678b9c + GoogleUtilities: 3df19e3c24f7bbc291d8b5809aa6b0d41e642437 "gRPC-C++": 13d8ccef97d5c3c441b7e3c529ef28ebee86fad2 gRPC-Core: 4afa11bfbedf7cdecd04de535a9e046893404ed5 GTMSessionFetcher: 36689134877faeb055b27dfa4ccc9ceaa42e029e @@ -1122,21 +1132,22 @@ SPEC CHECKSUMS: React-RCTVibration: 24600e3b1aaa77126989bc58b6747509a1ba14f3 React-runtimeexecutor: a9904c6d0218fb9f8b19d6dd88607225927668f9 ReactCommon: 149906e01aa51142707a10665185db879898e966 - RNFBAnalytics: d176dc0b499a7d61a0a713d596742282c50a36d3 - RNFBApp: 6fbdb0d684c16507c4eb51689d4ff4cfef3bf11f - RNFBAppCheck: 591b7fc417c0df45c4096335b0bd298b30825c42 - RNFBAuth: 352fddc14c7de4fcac69b12c821e20212845d974 - RNFBCrashlytics: 629aeb5619dd7501a28a3be42d0728de8f3d7bf8 - RNFBDatabase: b5a92ea365161fef1c522b644ad2f723de6bf3fd - RNFBDynamicLinks: ef3c14bff6d716959999119161924005227e9059 - RNFBFirestore: b817db23e6cc021e60644efc04803be807fb07f1 - RNFBFunctions: 5cafd47980bca562d7c6175fde7aca154bb9ff77 - RNFBInAppMessaging: 7beecf33a06164b0de5a7f3744570c145d2b3e3b - RNFBMessaging: 18158b22e06e2297df9628486193455eb619b46d - RNFBML: 0742fa4815d7f9576c5d13b270fed7a51d1d030d - RNFBPerf: 5d5d4a6a8a5506703c119b8742e8a12a5af2caa9 - RNFBRemoteConfig: 60c686bd4e6227ac5a013378be2f2e34d76c7803 - RNFBStorage: 8084581b1133aa14267f6cc6272d9d22f4470b08 + RNFBAnalytics: c546bf14fbf0a19f0801890dc8569efd7e7892ba + RNFBApp: 169c26e7f857173bd17b3eb5aba4e80bab598b76 + RNFBAppCheck: 6c135d623d954f47e83f7b05654ab0deaabe3c1f + RNFBAuth: 018b6408d969c734455e72d508400be021ceafa3 + RNFBCrashlytics: e9026dec158d1d1bb303e6f01fc712aeee1b6fbb + RNFBDatabase: bcfffc8c1bcc595decb7567d2bce305d6e2ce5a5 + RNFBDynamicLinks: 92cd6c4ba5edef4d37a927d09122aeccda1def0e + RNFBFirestore: 2b5601224411db7f3ada77c286d299094f56caee + RNFBFunctions: 6376a08f448bc8f40ce6bf2459fb4282cc79dffa + RNFBInAppMessaging: 6f2b66ab43952da1fc91711774454cdefce2931d + RNFBInstallations: e6dd6113016a96518177a2e1eb170c4bf44e8c17 + RNFBMessaging: 5ceb208f9b65941db520be903cbd778f7ebd0065 + RNFBML: dd88f4f3ab120c48737ff3fbe07c2ba5ece1e5d9 + RNFBPerf: f2db4bed596bba3697a6bd8f801a592b21990fe2 + RNFBRemoteConfig: 2e2c2df520233083918647752a9b41a54aada45a + RNFBStorage: e4ddd8a58cf28a7f67876d6298d19273c1fd65e4 Yoga: 575c581c63e0d35c9a83f4b46d01d63abc1100ac PODFILE CHECKSUM: c61aa64b498060e6a9470f21629e95b1ece6f524 diff --git a/tests/package.json b/tests/package.json index ef95336f3c..7737446863 100644 --- a/tests/package.json +++ b/tests/package.json @@ -18,6 +18,7 @@ "@react-native-firebase/firestore": "12.6.1", "@react-native-firebase/functions": "12.6.1", "@react-native-firebase/in-app-messaging": "12.6.1", + "@react-native-firebase/installations": "12.6.1", "@react-native-firebase/messaging": "12.6.1", "@react-native-firebase/ml": "12.6.1", "@react-native-firebase/perf": "12.6.1", diff --git a/website/scripts/source-reference.js b/website/scripts/source-reference.js index e8df4fb7cd..82df859b22 100644 --- a/website/scripts/source-reference.js +++ b/website/scripts/source-reference.js @@ -165,6 +165,8 @@ function moduleNameToFullName(name) { return 'Instance ID'; case 'in-app-messaging': return 'In-App Messaging'; + case 'installations': + return 'Installations'; case 'messaging': return 'Cloud Messaging'; case 'ml': diff --git a/website/src/templates/utils.ts b/website/src/templates/utils.ts index 0bced9c3b1..91c7772052 100644 --- a/website/src/templates/utils.ts +++ b/website/src/templates/utils.ts @@ -47,6 +47,8 @@ function iconForModule(module: string): string { return '//static.invertase.io/assets/firebase/dynamic-links.svg'; case 'in-app-messaging': return '//static.invertase.io/assets/firebase/in-app-messaging.svg'; + case 'installations': + return '//static.invertase.io/assets/social/firebase-logo.png'; case 'ml': return '//static.invertase.io/assets/firebase/ml-kit.svg'; case 'remote-config': From 25962fcd43f6ccceac2e0ec49e5164959c05b103 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Tue, 17 Aug 2021 23:29:33 -0500 Subject: [PATCH 4/4] fix(app-check): getToken(false) fix, listener unsubscribe is a function - previously sending false through would crash android - forceRefresh currently ignored on iOS because of upstream issue causing native crash - fix docs --- packages/app-check/README.md | 14 +++++++++----- packages/app-check/e2e/appcheck.e2e.js | 15 ++++++++++++++- .../ios/RNFBAppcheck/RNFBAppCheckModule.m | 3 ++- packages/app-check/lib/index.js | 12 ++++++++---- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/packages/app-check/README.md b/packages/app-check/README.md index 3eceee080d..f5381f4910 100644 --- a/packages/app-check/README.md +++ b/packages/app-check/README.md @@ -21,9 +21,14 @@ --- -AppCheck description. +App Check works alongside other Firebase services to help protect your backend resources from abuse, such as billing fraud or phishing. With App Check, devices running your app will use an app or device attestation provider that attests to one or both of the following: -[> Learn More](https://firebase.google.com/products/app-check/) +- Requests originate from your authentic app +- Requests originate from an authentic, untampered device + +This attestation is attached to every request your app makes to your Firebase backend resources. + +[> Learn More](https://firebase.google.com/docs/app-check/) ## Installation @@ -35,9 +40,8 @@ yarn add @react-native-firebase/app-check ## Documentation -- [Guides](#TODO) -- [Installation](#TODO) -- [Reference](#TODO) +- [Guides](https://rnfirebase.io/app-check/usage/) +- [Reference](https://rnfirebase.io/reference/app-check) ## License diff --git a/packages/app-check/e2e/appcheck.e2e.js b/packages/app-check/e2e/appcheck.e2e.js index 6de89a42d1..eebbbafbd0 100644 --- a/packages/app-check/e2e/appcheck.e2e.js +++ b/packages/app-check/e2e/appcheck.e2e.js @@ -43,13 +43,26 @@ describe('appCheck()', function () { describe('getToken())', function () { it('token fetch attempt should work', async function () { // Our tests configure a debug provider with shared secret so we should get a valid token - const token = await firebase.appCheck().getToken(true); + const token = await firebase.appCheck().getToken(); token.should.not.equal(''); const decodedToken = jwt.decode(token); decodedToken.aud[1].should.equal('projects/react-native-firebase-testing'); if (decodedToken.exp < Date.now()) { Promise.reject('Token already expired'); } + + // Force refresh should get a different token? + // TODO iOS tokens are stale because of https://github.com/firebase/firebase-ios-sdk/issues/8544 + if (device.getPlatform() === 'android') { + const token2 = await firebase.appCheck().getToken(true); + token2.should.not.equal(''); + const decodedToken2 = jwt.decode(token2); + decodedToken2.aud[1].should.equal('projects/react-native-firebase-testing'); + if (decodedToken2.exp < Date.now()) { + Promise.reject('Token already expired'); + } + (token === token2).should.be.false(); + } }); }); describe('activate())', function () { diff --git a/packages/app-check/ios/RNFBAppcheck/RNFBAppCheckModule.m b/packages/app-check/ios/RNFBAppcheck/RNFBAppCheckModule.m index 5f77170e7a..a37e183d8f 100644 --- a/packages/app-check/ios/RNFBAppcheck/RNFBAppCheckModule.m +++ b/packages/app-check/ios/RNFBAppcheck/RNFBAppCheckModule.m @@ -75,7 +75,8 @@ - (dispatch_queue_t)methodQueue { : (RCTPromiseResolveBlock)resolve : (RCTPromiseRejectBlock)reject) { FIRAppCheck *appCheck = [FIRAppCheck appCheckWithApp:firebaseApp]; - [appCheck tokenForcingRefresh:NO + [appCheck tokenForcingRefresh:NO // TODO Cannot use forceRefresh argument, if we send 'YES' in + // https://github.com/firebase/firebase-ios-sdk/issues/8544 completion:^(FIRAppCheckToken *_Nullable token, NSError *_Nullable error) { if (error != nil) { // Handle any errors if the token was not retrieved. diff --git a/packages/app-check/lib/index.js b/packages/app-check/lib/index.js index 9342304d5a..126888d2e8 100644 --- a/packages/app-check/lib/index.js +++ b/packages/app-check/lib/index.js @@ -40,16 +40,20 @@ class FirebaseAppCheckModule extends FirebaseModule { } getToken(forceRefresh) { - return this.native.getToken(forceRefresh); + if (!forceRefresh) { + return this.native.getToken(false); + } else { + return this.native.getToken(true); + } } onTokenChanged() { // iOS does not provide any native listening feature if (isIOS) { - return; + return () => {}; } // TODO unimplemented on Android - return; + return () => {}; } } @@ -63,7 +67,7 @@ export default createModuleNamespace({ version, namespace, nativeModuleName, - nativeEvents: false, // TODO verify if this is interesting - token refresh listener perhaps? + nativeEvents: false, // TODO implement ['appcheck-token-changed'], hasMultiAppSupport: true, hasCustomUrlOrRegionSupport: false, ModuleClass: FirebaseAppCheckModule,