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':