diff --git a/packages/firebase_core/firebase_core_web/CHANGELOG.md b/packages/firebase_core/firebase_core_web/CHANGELOG.md new file mode 100644 index 000000000000..7be26166a1f2 --- /dev/null +++ b/packages/firebase_core/firebase_core_web/CHANGELOG.md @@ -0,0 +1,3 @@ +# 0.1.0 + +- Initial open-source release. diff --git a/packages/firebase_core/firebase_core_web/LICENSE b/packages/firebase_core/firebase_core_web/LICENSE new file mode 100644 index 000000000000..0c382ce171cc --- /dev/null +++ b/packages/firebase_core/firebase_core_web/LICENSE @@ -0,0 +1,27 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/firebase_core/firebase_core_web/README.md b/packages/firebase_core/firebase_core_web/README.md new file mode 100644 index 000000000000..87303f0375f6 --- /dev/null +++ b/packages/firebase_core/firebase_core_web/README.md @@ -0,0 +1,51 @@ +# firebase_core_web + +The web implementation of [`firebase_core`][1]. + +## Usage + +### Import the package + +To use this plugin in your Flutter app on the web, simply add it as a +dependency in your `pubspec.yaml` alongside the base `firebase_core` +plugin. + +_(This is only temporary: in the future we hope to make this package +an "endorsed" implementation of `firebase_core`, so it will automatically +be included in your app when you run your Flutter app on the web.)_ + +Add this to your `pubspec.yaml`: + +```yaml +... +dependencies: + ... + firebase_core: ^0.4.1 + firebase_core_web: ^0.1.0 + ... +``` + +### Updating `index.html` + +Due to [this bug in dartdevc][2], you will need to manually add the Firebase +JavaScript file to you `index.html` file. + +In your app directory, edit `web/index.html` to add the line: + +```html + + ... + + + + + +``` + +### Using the plugin + +Once you have added the `firebase_core_web` dependency to your pubspec, +you can use `package:firebase_core` as normal. + +[1]: ../firebase_core/firebase_core +[2]: https://github.com/dart-lang/sdk/issues/33979 diff --git a/packages/firebase_core/firebase_core_web/ios/firebase_core_web.podspec b/packages/firebase_core/firebase_core_web/ios/firebase_core_web.podspec new file mode 100644 index 000000000000..c6e11ef16e16 --- /dev/null +++ b/packages/firebase_core/firebase_core_web/ios/firebase_core_web.podspec @@ -0,0 +1,21 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'firebase_core_web' + s.version = '0.1.0' + s.summary = 'No-op implementation of firebase_core_web web plugin to avoid build issues on iOS' + s.description = <<-DESC + temp fake google_sign_in_web plugin + DESC + s.homepage = 'https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_core/firebase_core_web' + s.license = { :file => '../LICENSE' } + s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.public_header_files = 'Classes/**/*.h' + s.dependency 'Flutter' + + s.ios.deployment_target = '8.0' + end + diff --git a/packages/firebase_core/firebase_core_web/lib/firebase_core_web.dart b/packages/firebase_core/firebase_core_web/lib/firebase_core_web.dart new file mode 100644 index 000000000000..75ae87075aa6 --- /dev/null +++ b/packages/firebase_core/firebase_core_web/lib/firebase_core_web.dart @@ -0,0 +1,86 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'; +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; +import 'package:js/js_util.dart' as js_util; + +import 'src/firebase_js.dart'; + +/// The implementation of `firebase_core` for web. +class FirebaseCoreWeb extends FirebaseCorePlatform { + /// Creates a new instance of [FirebaseCoreWeb]. + FirebaseCoreWeb() { + if (firebase == null) { + throw StateError('firebase.js has not been loaded'); + } + } + + /// Registers that [FirebaseCoreWeb] is the platform implementation. + static void registerWith(Registrar registrar) { + FirebaseCorePlatform.instance = FirebaseCoreWeb(); + } + + @override + Future appNamed(String name) async { + try { + final App jsApp = firebase.app(name); + if (jsApp == null) { + return null; + } + return _createFromJsApp(jsApp); + } catch (e) { + if (_isFirebaseError(e)) { + return null; + } + rethrow; + } + } + + @override + Future configure(String name, FirebaseOptions options) async { + firebase.initializeApp(_createFromFirebaseOptions(options), name); + } + + @override + Future> allApps() async { + final List jsApps = firebase.apps; + return jsApps.map(_createFromJsApp).toList(); + } +} + +/// Returns `true` if [e] is a `FirebaseError`. +bool _isFirebaseError(dynamic e) { + return js_util.getProperty(e, 'name') == 'FirebaseError'; +} + +PlatformFirebaseApp _createFromJsApp(App jsApp) { + return PlatformFirebaseApp(jsApp.name, _createFromJsOptions(jsApp.options)); +} + +FirebaseOptions _createFromJsOptions(Options options) { + return FirebaseOptions( + apiKey: options.apiKey, + trackingID: options.measurementId, + gcmSenderID: options.messagingSenderId, + projectID: options.projectId, + googleAppID: options.appId, + databaseURL: options.databaseURL, + storageBucket: options.storageBucket, + ); +} + +Options _createFromFirebaseOptions(FirebaseOptions options) { + return Options( + apiKey: options.apiKey, + measurementId: options.trackingID, + messagingSenderId: options.gcmSenderID, + projectId: options.projectID, + appId: options.googleAppID, + databaseURL: options.databaseURL, + storageBucket: options.storageBucket, + ); +} diff --git a/packages/firebase_core/firebase_core_web/lib/src/firebase_js.dart b/packages/firebase_core/firebase_core_web/lib/src/firebase_js.dart new file mode 100644 index 000000000000..d7323c874b27 --- /dev/null +++ b/packages/firebase_core/firebase_core_web/lib/src/firebase_js.dart @@ -0,0 +1,76 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@JS() +library firebase_js; + +import 'package:js/js.dart'; + +/// A Firebase app. +@JS() +class App { + /// The name of the app. + external String get name; + + /// The options that the app was configured with. + external Options get options; +} + +/// Options for configuring an app. +@JS() +@anonymous +class Options { + /// Creates an options JavaScript object. + external factory Options({ + String apiKey, + String authDomain, + String databaseURL, + String projectId, + String storageBucket, + String messagingSenderId, + String appId, + String measurementId, + }); + + /// The API key used to authenticate requests. + external String get apiKey; + + /// Domain for authentication. + external String get authDomain; + + /// Realtime Database URL. + external String get databaseURL; + + /// The Google Cloud project ID. + external String get projectId; + + /// The Google Cloud Storage bucket name. + external String get storageBucket; + + /// The project number used to configure Messaging. + external String get messagingSenderId; + + /// The Google App ID that uniquely identifies an app instance. + external String get appId; + + /// An ID used for analytics. + external String get measurementId; +} + +/// The `firebase` namespace. +@JS() +class FirebaseCore { + /// Returns a list of initialized apps. + external List get apps; + + /// Initializes the app named [name] with the given [options]. + external App initializeApp(Options options, String name); + + /// Returns the already-initialized app with the given [name]. + external App app(String name); +} + +/// Return the `firebase` object. +@JS() +external FirebaseCore get firebase; diff --git a/packages/firebase_core/firebase_core_web/pubspec.yaml b/packages/firebase_core/firebase_core_web/pubspec.yaml new file mode 100644 index 000000000000..ca39fd5d1b8f --- /dev/null +++ b/packages/firebase_core/firebase_core_web/pubspec.yaml @@ -0,0 +1,30 @@ +name: firebase_core_web +description: The web implementation of firebase_core +author: Flutter Team +homepage: https://github.com/FirebaseExtended/flutterfire/packages/firebase_core/firebase_core_web +version: 0.1.0 + +flutter: + plugin: + platforms: + web: + pluginClass: FirebaseCoreWeb + fileName: firebase_core_web.dart + +dependencies: + firebase_core_platform_interface: ^1.0.0 + flutter: + sdk: flutter + flutter_web_plugins: + sdk: flutter + meta: ^1.1.7 + js: ^0.6.1 + +dev_dependencies: + flutter_test: + sdk: flutter + firebase_core: ^0.4.2+1 + +environment: + sdk: ">=2.0.0-dev.28.0 <3.0.0" + flutter: ">=1.9.1+hotfix.2 <2.0.0" diff --git a/packages/firebase_core/firebase_core_web/test/firebase_core_web_test.dart b/packages/firebase_core/firebase_core_web/test/firebase_core_web_test.dart new file mode 100644 index 000000000000..f2bd164a07b4 --- /dev/null +++ b/packages/firebase_core/firebase_core_web/test/firebase_core_web_test.dart @@ -0,0 +1,72 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +@TestOn('browser') + +import 'dart:js' as js; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_core_web/firebase_core_web.dart'; +import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'; + +void main() { + group('$FirebaseCoreWeb', () { + setUp(() async { + final js.JsObject firebaseMock = js.JsObject.jsify({}); + js.context['firebase'] = firebaseMock; + FirebaseCorePlatform.instance = FirebaseCoreWeb(); + }); + + test('FirebaseApp.allApps() calls firebase.apps', () async { + js.context['firebase']['apps'] = js.JsArray(); + final List apps = await FirebaseApp.allApps(); + expect(apps, hasLength(0)); + }); + + test('FirebaseApp.appNamed() calls firebase.app', () async { + js.context['firebase']['app'] = js.allowInterop((String name) { + return js.JsObject.jsify({ + 'name': name, + 'options': {'appId': '123'}, + }); + }); + final FirebaseApp app = await FirebaseApp.appNamed('foo'); + expect(app.name, equals('foo')); + + final FirebaseOptions options = await app.options; + expect(options.googleAppID, equals('123')); + }); + + test('FirebaseApp.configure() calls firebase.initializeApp', () async { + bool appConfigured = false; + + js.context['firebase']['app'] = js.allowInterop((String name) { + if (appConfigured) { + return js.JsObject.jsify({ + 'name': name, + 'options': {'appId': '123'}, + }); + } else { + return null; + } + }); + js.context['firebase']['initializeApp'] = + js.allowInterop((js.JsObject options, String name) { + appConfigured = true; + return js.JsObject.jsify({ + 'name': name, + 'options': options, + }); + }); + final FirebaseApp app = await FirebaseApp.configure( + name: 'foo', + options: const FirebaseOptions(googleAppID: '123'), + ); + expect(app.name, equals('foo')); + + final FirebaseOptions options = await app.options; + expect(options.googleAppID, equals('123')); + }); + }); +}