Skip to content

Commit b498372

Browse files
author
Harry Terkelsen
authored
[firebase_core_web] Add initial implementation (#1488)
* WIP on firebase_core_web * Implement firebase_core * Touch up tests in firebase_core_web * Update README.md to include instructions to add js script * Fix analyzer errors * Update tests * Add documentation * Add more docs. Dartfmt * Add dummy podspec so ios doesn't break
1 parent 19caad7 commit b498372

File tree

8 files changed

+366
-0
lines changed

8 files changed

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

0 commit comments

Comments
 (0)