From 6dcd7754ef9b7ea48f4fe51a42a76f3d138529fe Mon Sep 17 00:00:00 2001 From: Mauricio Date: Wed, 3 Jun 2020 12:58:40 -0500 Subject: [PATCH 01/30] fixed typo --- packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m | 2 +- packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m index bfe29f981396..06fe74a613ae 100644 --- a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m +++ b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m @@ -187,7 +187,7 @@ - (void)addPayment:(FlutterMethodCall *)call result:(FlutterResult)result { result([FlutterError errorWithCode:@"storekit_duplicate_product_object" message:@"There is a pending transaction for the same product identifier. Please " - @"either wait for it to be finished or finish it manuelly using " + @"either wait for it to be finished or finish it manually using " @"`completePurchase` to avoid edge cases." details:call.arguments]); diff --git a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m index e6a18e0acf58..93f1c6ef803c 100644 --- a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m +++ b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m @@ -145,7 +145,7 @@ - (void)testAddPaymentWithSameProductIDWillFail { XCTAssertEqualObjects( error.message, @"There is a pending transaction for the same product identifier. Please " - @"either wait for it to be finished or finish it manuelly using " + @"either wait for it to be finished or finish it manually using " @"`completePurchase` to avoid edge cases."); [expectation fulfill]; }]; From e987d2542d896b68621ae4005496d369ec41c638 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Wed, 3 Jun 2020 16:41:28 -0700 Subject: [PATCH 02/30] [image_picker_for_web] Introduce image_picker_for_web package (#2802) --- .../image_picker_for_web/CHANGELOG.md | 3 + .../image_picker/image_picker_for_web/LICENSE | 27 +++ .../image_picker_for_web/README.md | 92 +++++++++ .../image_picker_for_web/android/.gitignore | 8 + .../image_picker_for_web/android/build.gradle | 33 ++++ .../android/gradle.properties | 2 + .../gradle/wrapper/gradle-wrapper.properties | 5 + .../android/settings.gradle | 1 + .../android/src/main/AndroidManifest.xml | 3 + .../ImagePickerWebPlugin.java | 28 +++ .../ios/image_picker_for_web.podspec | 20 ++ .../lib/image_picker_for_web.dart | 184 ++++++++++++++++++ .../image_picker_for_web/pubspec.yaml | 32 +++ .../test/image_picker_for_web_test.dart | 84 ++++++++ 14 files changed, 522 insertions(+) create mode 100644 packages/image_picker/image_picker_for_web/CHANGELOG.md create mode 100644 packages/image_picker/image_picker_for_web/LICENSE create mode 100644 packages/image_picker/image_picker_for_web/README.md create mode 100644 packages/image_picker/image_picker_for_web/android/.gitignore create mode 100644 packages/image_picker/image_picker_for_web/android/build.gradle create mode 100644 packages/image_picker/image_picker_for_web/android/gradle.properties create mode 100644 packages/image_picker/image_picker_for_web/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/image_picker/image_picker_for_web/android/settings.gradle create mode 100644 packages/image_picker/image_picker_for_web/android/src/main/AndroidManifest.xml create mode 100644 packages/image_picker/image_picker_for_web/android/src/main/java/io/flutter/image_picker_for_web/ImagePickerWebPlugin.java create mode 100644 packages/image_picker/image_picker_for_web/ios/image_picker_for_web.podspec create mode 100644 packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart create mode 100644 packages/image_picker/image_picker_for_web/pubspec.yaml create mode 100644 packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md new file mode 100644 index 000000000000..18ff7e526b11 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -0,0 +1,3 @@ +# 0.1.0 + +* Initial open-source release. diff --git a/packages/image_picker/image_picker_for_web/LICENSE b/packages/image_picker/image_picker_for_web/LICENSE new file mode 100644 index 000000000000..0c382ce171cc --- /dev/null +++ b/packages/image_picker/image_picker_for_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/image_picker/image_picker_for_web/README.md b/packages/image_picker/image_picker_for_web/README.md new file mode 100644 index 000000000000..81452e290984 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/README.md @@ -0,0 +1,92 @@ +# image_picker_for_web + +A web implementation of [`image_picker`][1]. + +## Browser Support + +Since Web Browsers don't offer direct access to their users' file system, +this plugin provides a `PickedFile` abstraction to make access access uniform +across platforms. + +The web version of the plugin puts network-accessible URIs as the `path` +in the returned `PickedFile`. + +### URL.createObjectURL() + +The `PickedFile` object in web is backed by [`URL.createObjectUrl` Web API](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL), +which is reasonably well supported across all browsers: + +![Data on support for the bloburls feature across the major browsers from caniuse.com](https://caniuse.bitsofco.de/image/bloburls.png) + +However, the returned `path` attribute of the `PickedFile` points to a `network` resource, and not a +local path in your users' drive. See **Use the plugin** below for some examples on how to use this +return value in a cross-platform way. + +### input file "accept" + +In order to filter only video/image content, some browsers offer an [`accept` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept) in their `input type="file"` form elements: + +![Data on support for the input-file-accept feature across the major browsers from caniuse.com](https://caniuse.bitsofco.de/image/input-file-accept.png) + +This feature is just a convenience for users, **not validation**. + +Users can override this setting on their browsers. You must validate in your app (or server) +that the user has picked the file type that you can handle. + +### input file "capture" + +In order to "take a photo", some mobile browsers offer a [`capture` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/capture): + +![Data on support for the html-media-capture feature across the major browsers from caniuse.com](https://caniuse.bitsofco.de/image/html-media-capture.png) + +Each browser may implement `capture` any way they please, so it may (or may not) make a +difference in your users' experience. + +## Usage + +### Import the package + +This package is an unendorsed web platform implementation of `image_picker`. + +In order to use this, you'll need to depend in `image_picker: ^0.6.7` (which was the first version of the plugin that allowed federation), and `image_picker_for_web: ^0.1.0`. + +```yaml +... +dependencies: + ... + image_picker: ^0.6.7 + image_picker_for_web: ^0.1.0 + ... +... +``` + +### Use the plugin + +You should be able to use `package:image_picker` _almost_ as normal. + +Once the user has picked a file, the returned `PickedFile` instance will contain a +`network`-accessible URL (pointing to a location within the browser). + +The instace will also let you retrieve the bytes of the selected file across all platforms. + +If you want to use the path directly, your code would need look like this: + +```dart +... +if (kIsWeb) { + Image.network(pickedFile.path); +} else { + Image.file(File(pickedFile.path)); +} +... +``` + +Or, using bytes: + +```dart +... +Image.memory(await pickedFile.readAsBytes()) +... +``` + +[1]: https://pub.dev/packages/image_picker diff --git a/packages/image_picker/image_picker_for_web/android/.gitignore b/packages/image_picker/image_picker_for_web/android/.gitignore new file mode 100644 index 000000000000..c6cbe562a427 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/android/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/packages/image_picker/image_picker_for_web/android/build.gradle b/packages/image_picker/image_picker_for_web/android/build.gradle new file mode 100644 index 000000000000..6d8d50eb7b6d --- /dev/null +++ b/packages/image_picker/image_picker_for_web/android/build.gradle @@ -0,0 +1,33 @@ +group 'io.flutter.image_picker_for_web' +version '1.0' + +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + } +} + +rootProject.allprojects { + repositories { + google() + jcenter() + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 16 + } + lintOptions { + disable 'InvalidPackage' + } +} diff --git a/packages/image_picker/image_picker_for_web/android/gradle.properties b/packages/image_picker/image_picker_for_web/android/gradle.properties new file mode 100644 index 000000000000..7be3d8b46841 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/android/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true diff --git a/packages/image_picker/image_picker_for_web/android/gradle/wrapper/gradle-wrapper.properties b/packages/image_picker/image_picker_for_web/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000000..019065d1d650 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip diff --git a/packages/image_picker/image_picker_for_web/android/settings.gradle b/packages/image_picker/image_picker_for_web/android/settings.gradle new file mode 100644 index 000000000000..07e3728d1fe7 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'image_picker_for_web' diff --git a/packages/image_picker/image_picker_for_web/android/src/main/AndroidManifest.xml b/packages/image_picker/image_picker_for_web/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000000..b6f6992b3fb9 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/packages/image_picker/image_picker_for_web/android/src/main/java/io/flutter/image_picker_for_web/ImagePickerWebPlugin.java b/packages/image_picker/image_picker_for_web/android/src/main/java/io/flutter/image_picker_for_web/ImagePickerWebPlugin.java new file mode 100644 index 000000000000..18b5bf21144b --- /dev/null +++ b/packages/image_picker/image_picker_for_web/android/src/main/java/io/flutter/image_picker_for_web/ImagePickerWebPlugin.java @@ -0,0 +1,28 @@ +// 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. + +package io.flutter.image_picker_for_web; + +import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.plugin.common.PluginRegistry.Registrar; + +/** ImagePickerWebPlugin */ +public class ImagePickerWebPlugin implements FlutterPlugin { + @Override + public void onAttachedToEngine(FlutterPluginBinding flutterPluginBinding) {} + + // This static function is optional and equivalent to onAttachedToEngine. It supports the old + // pre-Flutter-1.12 Android projects. You are encouraged to continue supporting + // plugin registration via this function while apps migrate to use the new Android APIs + // post-flutter-1.12 via https://flutter.dev/go/android-project-migration. + // + // It is encouraged to share logic between onAttachedToEngine and registerWith to keep + // them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called + // depending on the user's project. onAttachedToEngine or registerWith must both be defined + // in the same class. + public static void registerWith(Registrar registrar) {} + + @Override + public void onDetachedFromEngine(FlutterPluginBinding binding) {} +} diff --git a/packages/image_picker/image_picker_for_web/ios/image_picker_for_web.podspec b/packages/image_picker/image_picker_for_web/ios/image_picker_for_web.podspec new file mode 100644 index 000000000000..23fb795d1cc2 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/ios/image_picker_for_web.podspec @@ -0,0 +1,20 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'image_picker_for_web' + s.version = '0.0.1' + s.summary = 'No-op implementation of image_picker_for_web plugin to avoid build issues on iOS' + s.description = <<-DESC +temp fake image_picker_for_web plugin + DESC + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_for_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/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart new file mode 100644 index 000000000000..ce99dd6d5fc6 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -0,0 +1,184 @@ +import 'dart:async'; +import 'dart:html' as html; + +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; +import 'package:meta/meta.dart'; +import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; + +final String _kImagePickerInputsDomId = '__image_picker_web-file-input'; +final String _kAcceptImageMimeType = 'image/*'; +// TODO The value below seems to not be enough for Safari (https://github.com/flutter/flutter/issues/58532) +final String _kAcceptVideoMimeType = 'video/*'; + +/// The web implementation of [ImagePickerPlatform]. +/// +/// This class implements the `package:image_picker` functionality for the web. +class ImagePickerPlugin extends ImagePickerPlatform { + final ImagePickerPluginTestOverrides _overrides; + bool get _hasOverrides => _overrides != null; + + html.Element _target; + + /// A constructor that allows tests to override the function that creates file inputs. + ImagePickerPlugin({ + @visibleForTesting ImagePickerPluginTestOverrides overrides, + }) : _overrides = overrides { + _target = _ensureInitialized(_kImagePickerInputsDomId); + } + + /// Registers this class as the default instance of [ImagePickerPlatform]. + static void registerWith(Registrar registrar) { + ImagePickerPlatform.instance = ImagePickerPlugin(); + } + + @override + Future pickImage({ + @required ImageSource source, + double maxWidth, + double maxHeight, + int imageQuality, + CameraDevice preferredCameraDevice = CameraDevice.rear, + }) { + String capture = computeCaptureAttribute(source, preferredCameraDevice); + return pickFile(accept: _kAcceptImageMimeType, capture: capture); + } + + @override + Future pickVideo({ + @required ImageSource source, + CameraDevice preferredCameraDevice = CameraDevice.rear, + Duration maxDuration, + }) { + String capture = computeCaptureAttribute(source, preferredCameraDevice); + return pickFile(accept: _kAcceptVideoMimeType, capture: capture); + } + + /// Injects a file input with the specified accept+capture attributes, and + /// returns the PickedFile that the user selected locally. + /// + /// `capture` is only supported in mobile browsers. + /// See https://caniuse.com/#feat=html-media-capture + @visibleForTesting + Future pickFile({ + String accept, + String capture, + }) { + html.FileUploadInputElement input = createInputElement(accept, capture); + _injectAndActivate(input); + return _getSelectedFile(input); + } + + // DOM methods + + /// Converts plugin configuration into a proper value for the `capture` attribute. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#capture + @visibleForTesting + String computeCaptureAttribute(ImageSource source, CameraDevice device) { + if (source == ImageSource.camera) { + return (device == CameraDevice.front) ? 'user' : 'environment'; + } + return null; + } + + html.File _getFileFromInput(html.FileUploadInputElement input) { + if (_hasOverrides) { + return _overrides.getFileFromInput(input); + } + return input?.files?.first; + } + + /// Handles the OnChange event from a FileUploadInputElement object + /// Returns the objectURL of the selected file. + String _handleOnChangeEvent(html.Event event) { + final html.FileUploadInputElement input = event?.target; + final html.File file = _getFileFromInput(input); + + if (file != null) { + return html.Url.createObjectUrl(file); + } + return null; + } + + /// Monitors an and returns the selected file. + Future _getSelectedFile(html.FileUploadInputElement input) { + final Completer _completer = Completer(); + // Observe the input until we can return something + input.onChange.first.then((event) { + final objectUrl = _handleOnChangeEvent(event); + if (!_completer.isCompleted) { + _completer.complete(PickedFile(objectUrl)); + } + }); + input.onError.first.then((event) { + if (!_completer.isCompleted) { + _completer.completeError(event); + } + }); + // Note that we don't bother detaching from these streams, since the + // "input" gets re-created in the DOM every time the user needs to + // pick a file. + return _completer.future; + } + + /// Initializes a DOM container where we can host input elements. + html.Element _ensureInitialized(String id) { + var target = html.querySelector('#${id}'); + if (target == null) { + final html.Element targetElement = + html.Element.tag('flt-image-picker-inputs')..id = id; + + html.querySelector('body').children.add(targetElement); + target = targetElement; + } + return target; + } + + /// Creates an input element that accepts certain file types, and + /// allows to `capture` from the device's cameras (where supported) + @visibleForTesting + html.Element createInputElement(String accept, String capture) { + if (_hasOverrides) { + return _overrides.createInputElement(accept, capture); + } + + html.Element element = html.FileUploadInputElement()..accept = accept; + + if (capture != null) { + element.setAttribute('capture', capture); + } + + return element; + } + + /// Injects the file input element, and clicks on it + void _injectAndActivate(html.Element element) { + _target.children.clear(); + _target.children.add(element); + element.click(); + } +} + +// Some tools to override behavior for unit-testing +/// A function that creates a file input with the passed in `accept` and `capture` attributes. +@visibleForTesting +typedef OverrideCreateInputFunction = html.Element Function( + String accept, + String capture, +); + +/// A function that extracts a [html.File] from the file `input` passed in. +@visibleForTesting +typedef OverrideExtractFilesFromInputFunction = html.File Function( + html.Element input, +); + +/// Overrides for some of the functionality above. +@visibleForTesting +class ImagePickerPluginTestOverrides { + /// Override the creation of the input element. + OverrideCreateInputFunction createInputElement; + + /// Override the extraction of the selected file from an input element. + OverrideExtractFilesFromInputFunction getFileFromInput; +} diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml new file mode 100644 index 000000000000..d25da73847e8 --- /dev/null +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -0,0 +1,32 @@ +name: image_picker_for_web +description: Web platform implementation of image_picker +homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_for_web +# 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump +# the version to 2.0.0. +# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 +version: 0.1.0 + +flutter: + plugin: + platforms: + web: + pluginClass: ImagePickerPlugin + fileName: image_picker_for_web.dart + +dependencies: + image_picker_platform_interface: ^1.1.0 + flutter: + sdk: flutter + flutter_web_plugins: + sdk: flutter + meta: ^1.1.7 + js: ^0.6.0 + +dev_dependencies: + flutter_test: + sdk: flutter + pedantic: ^1.8.0 + +environment: + sdk: ">=2.5.0 <3.0.0" + flutter: ">=1.10.0 <2.0.0" diff --git a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart new file mode 100644 index 000000000000..96d048dd2a8e --- /dev/null +++ b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart @@ -0,0 +1,84 @@ +// 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('chrome') // Uses dart:html + +import 'dart:convert'; +import 'dart:html' as html; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:image_picker_for_web/image_picker_for_web.dart'; +import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; + +final String expectedStringContents = "Hello, world!"; +final Uint8List bytes = utf8.encode(expectedStringContents); +final html.File textFile = html.File([bytes], "hello.txt"); + +void main() { + // Under test... + ImagePickerPlugin plugin; + + setUp(() { + plugin = ImagePickerPlugin(); + }); + + test('Can select a file', () async { + final mockInput = html.FileUploadInputElement(); + + final overrides = ImagePickerPluginTestOverrides() + ..createInputElement = ((_, __) => mockInput) + ..getFileFromInput = ((_) => textFile); + + final plugin = ImagePickerPlugin(overrides: overrides); + + // Init the pick file dialog... + final file = plugin.pickFile(); + + // Mock the browser behavior of selecting a file... + mockInput.dispatchEvent(html.Event('change')); + + // Now the file should be available + expect(file, completes); + // And readable + expect((await file).readAsBytes(), completion(isNotEmpty)); + }); + + // There's no good way of detecting when the user has "aborted" the selection. + + test('computeCaptureAttribute', () { + expect( + plugin.computeCaptureAttribute(ImageSource.gallery, CameraDevice.front), + isNull, + ); + expect( + plugin.computeCaptureAttribute(ImageSource.gallery, CameraDevice.rear), + isNull, + ); + expect( + plugin.computeCaptureAttribute(ImageSource.camera, CameraDevice.front), + 'user', + ); + expect( + plugin.computeCaptureAttribute(ImageSource.camera, CameraDevice.rear), + 'environment', + ); + }); + + group('createInputElement', () { + test('accept: any, capture: null', () { + html.Element input = plugin.createInputElement('any', null); + + expect(input.attributes, containsPair('accept', 'any')); + expect(input.attributes, isNot(contains('capture'))); + }); + + test('accept: any, capture: something', () { + html.Element input = plugin.createInputElement('any', 'something'); + + expect(input.attributes, containsPair('accept', 'any')); + expect(input.attributes, containsPair('capture', 'something')); + }); + }); +} From 3e538e152bbae6b67ef21f97cf9a3154f73d8013 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Thu, 4 Jun 2020 17:35:36 -0700 Subject: [PATCH 03/30] [image_picker_for_web] Remove android directory. (#2817) --- .../image_picker_for_web/CHANGELOG.md | 4 +++ .../image_picker_for_web/android/.gitignore | 8 ----- .../image_picker_for_web/android/build.gradle | 33 ------------------- .../android/gradle.properties | 2 -- .../gradle/wrapper/gradle-wrapper.properties | 5 --- .../android/settings.gradle | 1 - .../android/src/main/AndroidManifest.xml | 3 -- .../ImagePickerWebPlugin.java | 28 ---------------- .../image_picker_for_web/pubspec.yaml | 2 +- 9 files changed, 5 insertions(+), 81 deletions(-) delete mode 100644 packages/image_picker/image_picker_for_web/android/.gitignore delete mode 100644 packages/image_picker/image_picker_for_web/android/build.gradle delete mode 100644 packages/image_picker/image_picker_for_web/android/gradle.properties delete mode 100644 packages/image_picker/image_picker_for_web/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 packages/image_picker/image_picker_for_web/android/settings.gradle delete mode 100644 packages/image_picker/image_picker_for_web/android/src/main/AndroidManifest.xml delete mode 100644 packages/image_picker/image_picker_for_web/android/src/main/java/io/flutter/image_picker_for_web/ImagePickerWebPlugin.java diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md index 18ff7e526b11..67320bcb3de2 100644 --- a/packages/image_picker/image_picker_for_web/CHANGELOG.md +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.1.0+1 + +* Remove `android` directory. + # 0.1.0 * Initial open-source release. diff --git a/packages/image_picker/image_picker_for_web/android/.gitignore b/packages/image_picker/image_picker_for_web/android/.gitignore deleted file mode 100644 index c6cbe562a427..000000000000 --- a/packages/image_picker/image_picker_for_web/android/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -*.iml -.gradle -/local.properties -/.idea/workspace.xml -/.idea/libraries -.DS_Store -/build -/captures diff --git a/packages/image_picker/image_picker_for_web/android/build.gradle b/packages/image_picker/image_picker_for_web/android/build.gradle deleted file mode 100644 index 6d8d50eb7b6d..000000000000 --- a/packages/image_picker/image_picker_for_web/android/build.gradle +++ /dev/null @@ -1,33 +0,0 @@ -group 'io.flutter.image_picker_for_web' -version '1.0' - -buildscript { - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - } -} - -rootProject.allprojects { - repositories { - google() - jcenter() - } -} - -apply plugin: 'com.android.library' - -android { - compileSdkVersion 28 - - defaultConfig { - minSdkVersion 16 - } - lintOptions { - disable 'InvalidPackage' - } -} diff --git a/packages/image_picker/image_picker_for_web/android/gradle.properties b/packages/image_picker/image_picker_for_web/android/gradle.properties deleted file mode 100644 index 7be3d8b46841..000000000000 --- a/packages/image_picker/image_picker_for_web/android/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true diff --git a/packages/image_picker/image_picker_for_web/android/gradle/wrapper/gradle-wrapper.properties b/packages/image_picker/image_picker_for_web/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 019065d1d650..000000000000 --- a/packages/image_picker/image_picker_for_web/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip diff --git a/packages/image_picker/image_picker_for_web/android/settings.gradle b/packages/image_picker/image_picker_for_web/android/settings.gradle deleted file mode 100644 index 07e3728d1fe7..000000000000 --- a/packages/image_picker/image_picker_for_web/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'image_picker_for_web' diff --git a/packages/image_picker/image_picker_for_web/android/src/main/AndroidManifest.xml b/packages/image_picker/image_picker_for_web/android/src/main/AndroidManifest.xml deleted file mode 100644 index b6f6992b3fb9..000000000000 --- a/packages/image_picker/image_picker_for_web/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/packages/image_picker/image_picker_for_web/android/src/main/java/io/flutter/image_picker_for_web/ImagePickerWebPlugin.java b/packages/image_picker/image_picker_for_web/android/src/main/java/io/flutter/image_picker_for_web/ImagePickerWebPlugin.java deleted file mode 100644 index 18b5bf21144b..000000000000 --- a/packages/image_picker/image_picker_for_web/android/src/main/java/io/flutter/image_picker_for_web/ImagePickerWebPlugin.java +++ /dev/null @@ -1,28 +0,0 @@ -// 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. - -package io.flutter.image_picker_for_web; - -import io.flutter.embedding.engine.plugins.FlutterPlugin; -import io.flutter.plugin.common.PluginRegistry.Registrar; - -/** ImagePickerWebPlugin */ -public class ImagePickerWebPlugin implements FlutterPlugin { - @Override - public void onAttachedToEngine(FlutterPluginBinding flutterPluginBinding) {} - - // This static function is optional and equivalent to onAttachedToEngine. It supports the old - // pre-Flutter-1.12 Android projects. You are encouraged to continue supporting - // plugin registration via this function while apps migrate to use the new Android APIs - // post-flutter-1.12 via https://flutter.dev/go/android-project-migration. - // - // It is encouraged to share logic between onAttachedToEngine and registerWith to keep - // them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called - // depending on the user's project. onAttachedToEngine or registerWith must both be defined - // in the same class. - public static void registerWith(Registrar registrar) {} - - @Override - public void onDetachedFromEngine(FlutterPluginBinding binding) {} -} diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index d25da73847e8..29b9b185cb90 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/i # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.0 +version: 0.1.0+1 flutter: plugin: From 20d8ad2673107d9845082e18381f5dd3a75428ff Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Thu, 4 Jun 2020 18:09:20 -0700 Subject: [PATCH 04/30] [image_picker] Add web support to the example app. (#2816) --- .../image_picker/image_picker/CHANGELOG.md | 4 +++ .../image_picker/example/lib/main.dart | 16 +++++++-- .../image_picker/example/pubspec.yaml | 1 + .../image_picker/example/web/favicon.png | Bin 0 -> 917 bytes .../example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../image_picker/example/web/index.html | 33 ++++++++++++++++++ .../image_picker/example/web/manifest.json | 23 ++++++++++++ .../image_picker/image_picker/pubspec.yaml | 2 +- 9 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 packages/image_picker/image_picker/example/web/favicon.png create mode 100644 packages/image_picker/image_picker/example/web/icons/Icon-192.png create mode 100644 packages/image_picker/image_picker/example/web/icons/Icon-512.png create mode 100644 packages/image_picker/image_picker/example/web/index.html create mode 100644 packages/image_picker/image_picker/example/web/manifest.json diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index a72e3bcbc221..e3856c266464 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+1 + +* Add web support to the example app. + ## 0.6.7 * Utilize the new platform_interface package. diff --git a/packages/image_picker/image_picker/example/lib/main.dart b/packages/image_picker/image_picker/example/lib/main.dart index 231dcb25931b..dff2906edf87 100755 --- a/packages/image_picker/image_picker/example/lib/main.dart +++ b/packages/image_picker/image_picker/example/lib/main.dart @@ -52,7 +52,11 @@ class _MyHomePageState extends State { Future _playVideo(PickedFile file) async { if (file != null && mounted) { await _disposeVideoController(); - _controller = VideoPlayerController.file(File(file.path)); + if (kIsWeb) { + _controller = VideoPlayerController.network(file.path); + } else { + _controller = VideoPlayerController.file(File(file.path)); + } await _controller.setVolume(1.0); await _controller.initialize(); await _controller.setLooping(true); @@ -139,7 +143,13 @@ class _MyHomePageState extends State { return retrieveError; } if (_imageFile != null) { - return Image.file(File(_imageFile.path)); + if (kIsWeb) { + // Why network? + // See https://pub.dev/packages/image_picker#getting-ready-for-the-web-platform + return Image.network(_imageFile.path); + } else { + return Image.file(File(_imageFile.path)); + } } else if (_pickImageError != null) { return Text( 'Pick image error: $_pickImageError', @@ -180,7 +190,7 @@ class _MyHomePageState extends State { title: Text(widget.title), ), body: Center( - child: defaultTargetPlatform == TargetPlatform.android + child: !kIsWeb && defaultTargetPlatform == TargetPlatform.android ? FutureBuilder( future: retrieveLostData(), builder: (BuildContext context, AsyncSnapshot snapshot) { diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml index f3171aa7ccf8..93df8dfdc010 100755 --- a/packages/image_picker/image_picker/example/pubspec.yaml +++ b/packages/image_picker/image_picker/example/pubspec.yaml @@ -9,6 +9,7 @@ dependencies: flutter_plugin_android_lifecycle: ^1.0.2 image_picker: path: ../ + image_picker_for_web: ^0.1.0 dev_dependencies: flutter_driver: diff --git a/packages/image_picker/image_picker/example/web/favicon.png b/packages/image_picker/image_picker/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/packages/image_picker/image_picker/example/web/icons/Icon-192.png b/packages/image_picker/image_picker/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/packages/image_picker/image_picker/example/web/icons/Icon-512.png b/packages/image_picker/image_picker/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/packages/image_picker/image_picker/example/web/index.html b/packages/image_picker/image_picker/example/web/index.html new file mode 100644 index 000000000000..787bbc72f6b1 --- /dev/null +++ b/packages/image_picker/image_picker/example/web/index.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + url_launcher web example + + + + + + + + diff --git a/packages/image_picker/image_picker/example/web/manifest.json b/packages/image_picker/image_picker/example/web/manifest.json new file mode 100644 index 000000000000..7d9c25627ebd --- /dev/null +++ b/packages/image_picker/image_picker/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "image_picker example", + "short_name": "image_picker", + "start_url": ".", + "display": "minimal-ui", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "An example of the image_picker on the web.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 51069b6e6690..9086028952ce 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7 +version: 0.6.7+1 flutter: plugin: From 2fb8bf023a43ef93b2f372f277fa16399d79b744 Mon Sep 17 00:00:00 2001 From: Panmari Date: Sun, 7 Jun 2020 01:17:49 +0200 Subject: [PATCH 05/30] Fix bug in example (#2801) By ensuring that flutter widget bindings are initialized. The current version fails on startup. --- packages/camera/CHANGELOG.md | 4 ++++ packages/camera/README.md | 1 + packages/camera/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/camera/CHANGELOG.md b/packages/camera/CHANGELOG.md index d59cb71758ca..43e5f463604c 100644 --- a/packages/camera/CHANGELOG.md +++ b/packages/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.8+3 + +* Fix bug in usage example in README.md + ## 0.5.8+2 * Post-v2 embedding cleanups. diff --git a/packages/camera/README.md b/packages/camera/README.md index 4c23236cd0aa..fbd73929e6de 100644 --- a/packages/camera/README.md +++ b/packages/camera/README.md @@ -53,6 +53,7 @@ import 'package:camera/camera.dart'; List cameras; Future main() async { + WidgetsFlutterBinding.ensureInitialized(); cameras = await availableCameras(); runApp(CameraApp()); } diff --git a/packages/camera/pubspec.yaml b/packages/camera/pubspec.yaml index 6cb514765e2d..a1ce42370191 100644 --- a/packages/camera/pubspec.yaml +++ b/packages/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.5.8+2 +version: 0.5.8+3 homepage: https://github.com/flutter/plugins/tree/master/packages/camera From 90462df1c11a47ffa3d31793d0a8c5f5179c92a6 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 12 Jun 2020 20:50:56 -0700 Subject: [PATCH 06/30] Update Linux desktop Dockerfile for GTK switch (#2826) Once the switch to GTK lands, libgtk-3-dev will be needed for building. --- .ci/Dockerfile-LinuxDesktop | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.ci/Dockerfile-LinuxDesktop b/.ci/Dockerfile-LinuxDesktop index 75308c4aa400..25924d4ea8d9 100644 --- a/.ci/Dockerfile-LinuxDesktop +++ b/.ci/Dockerfile-LinuxDesktop @@ -19,3 +19,5 @@ RUN sudo apt-get update && sudo apt-get install -y google-cloud-sdk && \ RUN sudo apt-get install -y xvfb libegl1-mesa # Install Linux desktop build tool requirements. RUN sudo apt-get install -y clang cmake ninja-build file pkg-config +# Install necessary libraries. +RUN sudo apt-get install -y libgtk-3-dev From ff53b70b53c79fa275bc78d9444f01b1918c0e89 Mon Sep 17 00:00:00 2001 From: chris-rutkowski <58718695+chris-rutkowski@users.noreply.github.com> Date: Mon, 15 Jun 2020 22:48:31 +0700 Subject: [PATCH 07/30] [image_picker] fixes for iOS which doesn't present camera/albums with more complex navigation (#2755) --- AUTHORS | 3 +- .../image_picker/image_picker/CHANGELOG.md | 4 ++ .../ios/Classes/FLTImagePickerPlugin.h | 2 +- .../ios/Classes/FLTImagePickerPlugin.m | 40 ++++++++++------ .../ios/Tests/ImagePickerPluginTests.m | 46 +++++++++++++------ .../image_picker/image_picker/pubspec.yaml | 2 +- 6 files changed, 65 insertions(+), 32 deletions(-) diff --git a/AUTHORS b/AUTHORS index b27c156188f8..17ede94e79ba 100644 --- a/AUTHORS +++ b/AUTHORS @@ -56,4 +56,5 @@ Giancarlo Rocha Ryo Miyake Théo Champion Kazuki Yamaguchi -Eitan Schwartz \ No newline at end of file +Eitan Schwartz +Chris Rutkowski diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index e3856c266464..6b85f26daf33 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+2 + +* iOS: Fixes unpresentable album/image picker if window's root view controller is already presenting other view controller. + ## 0.6.7+1 * Add web support to the example app. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h index 38e5b56600f3..b6d8687a32e3 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h @@ -7,7 +7,7 @@ @interface FLTImagePickerPlugin : NSObject // For testing only. -- (instancetype)initWithViewController:(UIViewController *)viewController; - (UIImagePickerController *)getImagePickerController; +- (UIViewController *)viewControllerWithWindow:(UIWindow *)window; @end diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 449157565e7f..00fdec245aaf 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -25,7 +25,6 @@ @interface FLTImagePickerPlugin () *)registrar { FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/image_picker" binaryMessenger:[registrar messenger]]; - UIViewController *viewController = - [UIApplication sharedApplication].delegate.window.rootViewController; - FLTImagePickerPlugin *instance = - [[FLTImagePickerPlugin alloc] initWithViewController:viewController]; + FLTImagePickerPlugin *instance = [FLTImagePickerPlugin new]; [registrar addMethodCallDelegate:instance channel:channel]; } -- (instancetype)initWithViewController:(UIViewController *)viewController { - self = [super init]; - if (self) { - _viewController = viewController; - } - return self; -} - - (UIImagePickerController *)getImagePickerController { return _imagePickerController; } +- (UIViewController *)viewControllerWithWindow:(UIWindow *)window { + UIWindow *windowToUse = window; + if (windowToUse == nil) { + for (UIWindow *window in [UIApplication sharedApplication].windows) { + if (window.isKeyWindow) { + windowToUse = window; + break; + } + } + } + + UIViewController *topController = windowToUse.rootViewController; + while (topController.presentedViewController) { + topController = topController.presentedViewController; + } + return topController; +} + - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { if (self.result) { self.result([FlutterError errorWithCode:@"multiple_request" @@ -136,7 +142,9 @@ - (void)showCamera { [UIImagePickerController isCameraDeviceAvailable:_device]) { _imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; _imagePickerController.cameraDevice = _device; - [_viewController presentViewController:_imagePickerController animated:YES completion:nil]; + [[self viewControllerWithWindow:nil] presentViewController:_imagePickerController + animated:YES + completion:nil]; } else { [[[UIAlertView alloc] initWithTitle:@"Error" message:@"Camera not available." @@ -241,7 +249,9 @@ - (void)errorNoPhotoAccess:(PHAuthorizationStatus)status { - (void)showPhotoLibrary { // No need to check if SourceType is available. It always is. _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; - [_viewController presentViewController:_imagePickerController animated:YES completion:nil]; + [[self viewControllerWithWindow:nil] presentViewController:_imagePickerController + animated:YES + completion:nil]; } - (void)imagePickerController:(UIImagePickerController *)picker diff --git a/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m b/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m index e5c681e7d956..c8d5a2bb5368 100644 --- a/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m +++ b/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m @@ -7,6 +7,19 @@ @import image_picker; @import XCTest; +@interface MockViewController : UIViewController +@property(nonatomic, retain) UIViewController *mockPresented; +@end + +@implementation MockViewController +@synthesize mockPresented; + +- (UIViewController *)presentedViewController { + return mockPresented; +} + +@end + @interface FLTImagePickerPlugin (Test) @property(copy, nonatomic) FlutterResult result; - (void)handleSavedPath:(NSString *)path; @@ -23,8 +36,7 @@ - (void)testPluginPickImageDeviceBack { if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; } - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}]; @@ -39,8 +51,7 @@ - (void)testPluginPickImageDeviceFront { if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; } - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}]; @@ -55,8 +66,7 @@ - (void)testPluginPickVideoDeviceBack { if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; } - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickVideo" arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}]; @@ -71,8 +81,7 @@ - (void)testPluginPickImageDeviceCancelClickMultipleTimes { if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; } - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}]; @@ -90,8 +99,7 @@ - (void)testPluginPickVideoDeviceFront { if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; } - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickVideo" arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}]; @@ -104,8 +112,7 @@ - (void)testPluginPickVideoDeviceFront { #pragma mark - Test video duration - (void)testPickingVideoWithDuration { - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickVideo" arguments:@{@"source" : @(0), @"cameraDevice" : @(0), @"maxDuration" : @95}]; @@ -116,8 +123,7 @@ - (void)testPickingVideoWithDuration { } - (void)testPluginPickImageSelectMultipleTimes { - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}]; @@ -131,4 +137,16 @@ - (void)testPluginPickImageSelectMultipleTimes { [plugin handleSavedPath:@"test"]; } +- (void)testViewController { + UIWindow *window = [UIWindow new]; + MockViewController *vc1 = [MockViewController new]; + window.rootViewController = vc1; + + UIViewController *vc2 = [UIViewController new]; + vc1.mockPresented = vc2; + + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; + XCTAssertEqual([plugin viewControllerWithWindow:window], vc2); +} + @end diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 9086028952ce..4f52b19c2659 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+1 +version: 0.6.7+2 flutter: plugin: From 0fab93dc91cc9085da0b9e5ff034c28b5541c9fb Mon Sep 17 00:00:00 2001 From: Tim Whiting Date: Tue, 16 Jun 2020 10:23:36 -0600 Subject: [PATCH 08/30] [path_provider] Updated documentation reflecting changes needed for testing (#2815) The recent federation of the Linux path provider might break tests, this updates the README.md to address those changes and direct the users how to mock the plugin in their tests. --- .../path_provider/path_provider/CHANGELOG.md | 3 +++ packages/path_provider/path_provider/README.md | 17 ++++++++++++++++- .../path_provider/path_provider/pubspec.yaml | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index a2df04613965..226d9ae01d0c 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,3 +1,6 @@ +## 1.6.11 +* Updated documentation to reflect the need for changes in testing for federated plugins + ## 1.6.10 * Linux implementation endorsement diff --git a/packages/path_provider/path_provider/README.md b/packages/path_provider/path_provider/README.md index 944137f4631c..982a9f49cae5 100644 --- a/packages/path_provider/path_provider/README.md +++ b/packages/path_provider/path_provider/README.md @@ -2,7 +2,8 @@ [![pub package](https://img.shields.io/pub/v/path_provider.svg)](https://pub.dartlang.org/packages/path_provider) -A Flutter plugin for finding commonly used locations on the filesystem. Supports iOS and Android. +A Flutter plugin for finding commonly used locations on the filesystem. Supports iOS, Android, Linux and MacOS. +Not all methods are supported on all platforms. ## Usage @@ -19,3 +20,17 @@ String appDocPath = appDocDir.path; ``` Please see the example app of this plugin for a full example. + +### Usage in tests + +`path_provider` now uses a `PlatformInterface`, meaning that not all platforms share the a single `PlatformChannel`-based implementation. +With that change, tests should be updated to mock `PathProviderPlatform` rather than `PlatformChannel`. + +See this `path_provider` [test](https://github.com/flutter/plugins/blob/master/packages/path_provider/path_provider/test/path_provider_test.dart) for an example. + +You will also have to temporarily add the following line to the setup of your test. +```dart +disablePathProviderPlatformOverride = true; +``` + +See this [issue](https://github.com/flutter/flutter/issues/52267), for more details on why this is needed. \ No newline at end of file diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index 98059e148140..d83911ddc2a8 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -2,7 +2,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on the Android & iOS file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 1.6.10 +version: 1.6.11 flutter: plugin: From 957fb75433c550382937299743f6f1025182c9c5 Mon Sep 17 00:00:00 2001 From: Corey Cole Date: Wed, 17 Jun 2020 13:25:56 -0700 Subject: [PATCH 09/30] [url_launcher] docs: note about encoding URIs (#2172) Add a note about encoding URLs passed to the url_launcher in the packages README. --- .../url_launcher/url_launcher/CHANGELOG.md | 6 +++++- packages/url_launcher/url_launcher/README.md | 21 +++++++++++++++++++ .../url_launcher/url_launcher/pubspec.yaml | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 2855eade4d21..6b1327a2da52 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.4.11 + +* Add documentation in README suggesting how to properly encode urls with special characters. + ## 5.4.10 * Post-v2 Android embedding cleanups. @@ -68,7 +72,7 @@ ## 5.2.3 -Android: Use android.arch.lifecycle instead of androidx.lifecycle:lifecycle in `build.gradle` to support apps that has not been migrated to AndroidX. +* Android: Use android.arch.lifecycle instead of androidx.lifecycle:lifecycle in `build.gradle` to support apps that has not been migrated to AndroidX. ## 5.2.2 diff --git a/packages/url_launcher/url_launcher/README.md b/packages/url_launcher/url_launcher/README.md index 2dcc6359c1af..53c7fe96cde7 100644 --- a/packages/url_launcher/url_launcher/README.md +++ b/packages/url_launcher/url_launcher/README.md @@ -53,6 +53,27 @@ Common schemes supported by both iOS and Android: More details can be found here for [iOS](https://developer.apple.com/library/content/featuredarticles/iPhoneURLScheme_Reference/Introduction/Introduction.html) and [Android](https://developer.android.com/guide/components/intents-common.html) +### Encoding URLs + +URLs must be properly encoded, especially when including spaces or other special characters. This can be done using the [`Uri` class](https://api.dart.dev/stable/2.7.1/dart-core/Uri-class.html): +```dart +import 'dart:core'; +import 'package:url_launcher/url_launcher.dart'; + +final Uri _emailLaunchUri = Uri( + scheme: 'mailto', + path: 'smith@example.com', + queryParameters: { + 'subject': 'Example Subject & Symbols are allowed!' + } +); + +// ... + +// mailto:smith@example.com?subject=Example+Subject+%26+Symbols+are+allowed%21 +launch(_emailLaunchUri.toString()); +``` + ## Handling missing URL receivers A particular mobile device may not be able to receive all supported URL schemes. diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 156d608583a5..08ac3f9f8b80 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 5.4.10 +version: 5.4.11 flutter: plugin: From 104e9bfb135e5a0e7bedbf11c611dcdc4494ea05 Mon Sep 17 00:00:00 2001 From: LHLL Date: Mon, 22 Jun 2020 10:50:51 -0700 Subject: [PATCH 10/30] [In_App_Purchase]queryPastPurchases() shouldn't block transaction updates. (#2834) * Allow all transactions except for purchasing ones to be passed back to the Flutter side. * Restore transactions shouldn't block transaction updates --- packages/in_app_purchase/CHANGELOG.md | 5 ++++ .../ios/Classes/FIAPaymentQueueHandler.m | 6 ++--- .../ios/Tests/InAppPurchasePluginTest.m | 1 + .../ios/Tests/PaymentQueueTest.m | 5 ++++ packages/in_app_purchase/ios/Tests/Stubs.m | 12 +++++++-- .../in_app_purchase/app_store_connection.dart | 6 +++-- .../in_app_purchase_connection.dart | 2 +- .../sk_payment_queue_wrapper.dart | 5 ++-- packages/in_app_purchase/pubspec.yaml | 2 +- .../app_store_connection_test.dart | 26 +++++++++++++++++-- .../sk_test_stub_objects.dart | 1 + 11 files changed, 56 insertions(+), 15 deletions(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index b7b025cbef6f..c159b094fb47 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.3.4+1 + +* iOS: Fix the bug that `SKPaymentQueueWrapper.transactions` doesn't return all transactions. +* iOS: Fix the app crashes if `InAppPurchaseConnection.instance` is called in the `main()`. + ## 0.3.4 * Expose SKError code to client apps. diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m index 8bdb7f25f111..57370e16fcbb 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m +++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m @@ -75,7 +75,7 @@ - (void)restoreTransactions:(nullable NSString *)applicationName { - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { - if (transaction.transactionIdentifier) { + if (transaction.transactionState != SKPaymentTransactionStatePurchasing) { // Use product identifier instead of transaction identifier for few reasons: // 1. Only transactions with purchased state and failed state will have a transaction id, it // will become impossible for clients to finish deferred transactions when needed. @@ -92,9 +92,7 @@ - (void)paymentQueue:(SKPaymentQueue *)queue - (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { - if (transaction.transactionIdentifier) { - [self.transactionsSetter removeObjectForKey:transaction.payment.productIdentifier]; - } + [self.transactionsSetter removeObjectForKey:transaction.payment.productIdentifier]; } self.transactionsRemoved(transactions); } diff --git a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m index e6a18e0acf58..20543a203a97 100644 --- a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m +++ b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m @@ -121,6 +121,7 @@ - (void)testAddPaymentWithSameProductIDWillFail { @"simulatesAskToBuyInSandBox" : @YES, }]; SKPaymentQueueStub* queue = [SKPaymentQueueStub new]; + queue.testState = SKPaymentTransactionStatePurchased; self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue transactionsUpdated:^(NSArray* _Nonnull transactions) { } diff --git a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m b/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m index 2085ba328140..8f5b66496f69 100644 --- a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m +++ b/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m @@ -66,6 +66,7 @@ - (void)testTransactionPurchased { [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; XCTAssertEqual(tran.transactionState, SKPaymentTransactionStatePurchased); + XCTAssertEqual(tran.transactionIdentifier, @"fakeID"); } - (void)testDuplicateTransactionsWillTriggerAnError { @@ -113,6 +114,7 @@ - (void)testTransactionFailed { [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; XCTAssertEqual(tran.transactionState, SKPaymentTransactionStateFailed); + XCTAssertEqual(tran.transactionIdentifier, nil); } - (void)testTransactionRestored { @@ -140,6 +142,7 @@ - (void)testTransactionRestored { [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; XCTAssertEqual(tran.transactionState, SKPaymentTransactionStateRestored); + XCTAssertEqual(tran.transactionIdentifier, @"fakeID"); } - (void)testTransactionPurchasing { @@ -167,6 +170,7 @@ - (void)testTransactionPurchasing { [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; XCTAssertEqual(tran.transactionState, SKPaymentTransactionStatePurchasing); + XCTAssertEqual(tran.transactionIdentifier, nil); } - (void)testTransactionDeferred { @@ -194,6 +198,7 @@ - (void)testTransactionDeferred { [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; XCTAssertEqual(tran.transactionState, SKPaymentTransactionStateDeferred); + XCTAssertEqual(tran.transactionIdentifier, nil); } - (void)testFinishTransaction { diff --git a/packages/in_app_purchase/ios/Tests/Stubs.m b/packages/in_app_purchase/ios/Tests/Stubs.m index 2c3460f17f4b..58b77c14127d 100644 --- a/packages/in_app_purchase/ios/Tests/Stubs.m +++ b/packages/in_app_purchase/ios/Tests/Stubs.m @@ -215,7 +215,11 @@ - (instancetype)initWithMap:(NSDictionary *)map { - (instancetype)initWithState:(SKPaymentTransactionState)state { self = [super init]; if (self) { - [self setValue:@"fakeID" forKey:@"transactionIdentifier"]; + // Only purchased and restored transactions have transactionIdentifier: + // https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc + if (state == SKPaymentTransactionStatePurchased || state == SKPaymentTransactionStateRestored) { + [self setValue:@"fakeID" forKey:@"transactionIdentifier"]; + } [self setValue:@(state) forKey:@"transactionState"]; } return self; @@ -224,7 +228,11 @@ - (instancetype)initWithState:(SKPaymentTransactionState)state { - (instancetype)initWithState:(SKPaymentTransactionState)state payment:(SKPayment *)payment { self = [super init]; if (self) { - [self setValue:@"fakeID" forKey:@"transactionIdentifier"]; + // Only purchased and restored transactions have transactionIdentifier: + // https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc + if (state == SKPaymentTransactionStatePurchased || state == SKPaymentTransactionStateRestored) { + [self setValue:@"fakeID" forKey:@"transactionIdentifier"]; + } [self setValue:@(state) forKey:@"transactionState"]; _payment = payment; } diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index 871879dca08e..da6fc7417585 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -208,12 +208,14 @@ class _TransactionObserver implements SKTransactionObserverWrapper { return wrapper.transactionState == SKPaymentTransactionStateWrapper.restored; }).map((SKPaymentTransactionWrapper wrapper) => wrapper)); - return; } String receiptData = await getReceiptData(); purchaseUpdatedController - .add(transactions.map((SKPaymentTransactionWrapper transaction) { + .add(transactions.where((SKPaymentTransactionWrapper wrapper) { + return wrapper.transactionState != + SKPaymentTransactionStateWrapper.restored; + }).map((SKPaymentTransactionWrapper transaction) { PurchaseDetails purchaseDetails = PurchaseDetails.fromSKTransaction(transaction, receiptData); return purchaseDetails; diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart index 2079f69dce6c..ba3932f73878 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart @@ -71,7 +71,7 @@ abstract class InAppPurchaseConnection { /// Enable the [InAppPurchaseConnection] to handle pending purchases. /// - /// Android Only: This method is required to be called when initialize the application. + /// This method is required to be called when initialize the application. /// It is to acknowledge your application has been updated to support pending purchases. /// See [Support pending transactions](https://developer.android.com/google/play/billing/billing_library_overview#pending) /// for more details. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart index 49c438e40231..33d9281d3ce0 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart @@ -37,9 +37,7 @@ class SKPaymentQueueWrapper { static final SKPaymentQueueWrapper _singleton = SKPaymentQueueWrapper._(); - SKPaymentQueueWrapper._() { - callbackChannel.setMethodCallHandler(_handleObserverCallbacks); - } + SKPaymentQueueWrapper._(); /// Calls [`-[SKPaymentQueue transactions]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506026-transactions?language=objc) Future> transactions() async { @@ -59,6 +57,7 @@ class SKPaymentQueueWrapper { /// addTransactionObserver:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506042-addtransactionobserver?language=objc). void setTransactionObserver(SKTransactionObserverWrapper observer) { _observer = observer; + callbackChannel.setMethodCallHandler(_handleObserverCallbacks); } /// Posts a payment to the queue. diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 12c7b45f7ddf..58f8e1174618 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.3.4 +version: 0.3.4+1 dependencies: async: ^2.0.8 diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index cb2e0e7cad56..881e1fcc75b7 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -90,6 +90,28 @@ void main() { expect(response.error, isNull); }); + test('queryPastPurchases should not block transaction updates', () async { + fakeIOSPlatform.transactions + .add(fakeIOSPlatform.createPurchasedTransactionWithProductID('foo')); + Completer completer = Completer(); + Stream> stream = + AppStoreConnection.instance.purchaseUpdatedStream; + + StreamSubscription subscription; + subscription = stream.listen((purchaseDetailsList) { + if (purchaseDetailsList.first.status == PurchaseStatus.purchased) { + completer.complete(purchaseDetailsList); + subscription.cancel(); + } + }); + QueryPurchaseDetailsResponse response = + await AppStoreConnection.instance.queryPastPurchases(); + List result = await completer.future; + expect(result.length, 1); + expect(result.first.productID, 'foo'); + expect(response.error, isNull); + }); + test('should get empty result if there is no restored transactions', () async { fakeIOSPlatform.testRestoredTransactionsNull = true; @@ -328,10 +350,10 @@ class FakeIOSPlatform { SKPaymentTransactionWrapper createPendingTransactionWithProductID(String id) { return SKPaymentTransactionWrapper( + transactionIdentifier: null, payment: SKPaymentWrapper(productIdentifier: id), transactionState: SKPaymentTransactionStateWrapper.purchasing, transactionTimeStamp: 123123.121, - transactionIdentifier: id, error: null, originalTransaction: null); } @@ -349,10 +371,10 @@ class FakeIOSPlatform { SKPaymentTransactionWrapper createFailedTransactionWithProductID(String id) { return SKPaymentTransactionWrapper( + transactionIdentifier: null, payment: SKPaymentWrapper(productIdentifier: id), transactionState: SKPaymentTransactionStateWrapper.failed, transactionTimeStamp: 123123.121, - transactionIdentifier: id, error: SKError( code: 0, domain: 'ios_domain', diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart index 1dc70748f1db..c976e80a90a5 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart @@ -22,6 +22,7 @@ final SKPaymentTransactionWrapper dummyOriginalTransaction = transactionIdentifier: '123123', error: dummyError, ); + final SKPaymentTransactionWrapper dummyTransaction = SKPaymentTransactionWrapper( transactionState: SKPaymentTransactionStateWrapper.purchased, From a0e880653458e27bb4afc988e18bf2e996491067 Mon Sep 17 00:00:00 2001 From: "Ming Lyu (CareF)" Date: Tue, 23 Jun 2020 14:03:15 -0400 Subject: [PATCH 11/30] [e2e] Fix e2e pixel ratio (#2842) * Fix e2e device pixel ratio * Update changelog and version * Formatting --- packages/e2e/CHANGELOG.md | 4 ++++ packages/e2e/lib/e2e.dart | 4 ++-- packages/e2e/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/e2e/CHANGELOG.md b/packages/e2e/CHANGELOG.md index 725b648dc5a5..0d349965371b 100644 --- a/packages/e2e/CHANGELOG.md +++ b/packages/e2e/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.0+1 + +* Fixed the device pixel ratio problem. + ## 0.5.0 * **Breaking change** by default, tests will use the device window size. diff --git a/packages/e2e/lib/e2e.dart b/packages/e2e/lib/e2e.dart index c2ddb2d6b801..ec1615e904b4 100644 --- a/packages/e2e/lib/e2e.dart +++ b/packages/e2e/lib/e2e.dart @@ -52,8 +52,8 @@ class E2EWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding { bool get registerTestTextInput => false; @override - ViewConfiguration createViewConfiguration() => - TestViewConfiguration(size: window.physicalSize); + ViewConfiguration createViewConfiguration() => TestViewConfiguration( + size: window.physicalSize / window.devicePixelRatio); final Completer _allTestsPassed = Completer(); diff --git a/packages/e2e/pubspec.yaml b/packages/e2e/pubspec.yaml index 82de42bd5c66..0d4bc99f64f3 100644 --- a/packages/e2e/pubspec.yaml +++ b/packages/e2e/pubspec.yaml @@ -1,6 +1,6 @@ name: e2e description: Runs tests that use the flutter_test API as integration tests. -version: 0.5.0 +version: 0.5.0+1 homepage: https://github.com/flutter/plugins/tree/master/packages/e2e environment: From 88319a90b5cc07070b68c794d9c09d776ee45fac Mon Sep 17 00:00:00 2001 From: "Ming Lyu (CareF)" Date: Wed, 24 Jun 2020 10:52:58 -0400 Subject: [PATCH 12/30] Update README for plugin list (#2843) --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index aeb03ffa23ac..026dd9d7739b 100644 --- a/README.md +++ b/README.md @@ -44,13 +44,18 @@ These are the available plugins in this repository. | [camera](./packages/camera/) | [![pub package](https://img.shields.io/pub/v/camera.svg)](https://pub.dev/packages/camera) | | [connectivity](./packages/connectivity/) | [![pub package](https://img.shields.io/pub/v/connectivity.svg)](https://pub.dev/packages/connectivity) | | [device_info](./packages/device_info/) | [![pub package](https://img.shields.io/pub/v/device_info.svg)](https://pub.dev/packages/device_info) | +| [e2e](./packages/e2e/) | [![pub package](https://img.shields.io/pub/v/e2e.svg)](https://pub.dev/packages/e2e) | +| [espresso](./packages/espresso/) | [![pub package](https://img.shields.io/pub/v/espresso.svg)](https://pub.dev/packages/espresso) | +| [flutter_plugin_android_lifecycle](./packages/flutter_plugin_android_lifecycle/) | [![pub package](https://img.shields.io/pub/v/flutter_plugin_android_lifecycle.svg)](https://pub.dev/packages/flutter_plugin_android_lifecycle) | | [google_maps_flutter](./packages/google_maps_flutter) | [![pub package](https://img.shields.io/pub/v/google_maps_flutter.svg)](https://pub.dev/packages/google_maps_flutter) | | [google_sign_in](./packages/google_sign_in/) | [![pub package](https://img.shields.io/pub/v/google_sign_in.svg)](https://pub.dev/packages/google_sign_in) | | [image_picker](./packages/image_picker/) | [![pub package](https://img.shields.io/pub/v/image_picker.svg)](https://pub.dev/packages/image_picker) | | [in_app_purchase](./packages/in_app_purchase/) | [![pub package](https://img.shields.io/pub/v/in_app_purchase.svg)](https://pub.dev/packages/in_app_purchase) | +| [ios_platform_images](./packages/ios_platform_images/) | [![pub package](https://img.shields.io/pub/v/ios_platform_images.svg)](https://pub.dev/packages/ios_platform_images) | | [local_auth](./packages/local_auth/) | [![pub package](https://img.shields.io/pub/v/local_auth.svg)](https://pub.dev/packages/local_auth) | | [package_info](./packages/package_info/) | [![pub package](https://img.shields.io/pub/v/package_info.svg)](https://pub.dev/packages/package_info) | | [path_provider](./packages/path_provider/) | [![pub package](https://img.shields.io/pub/v/path_provider.svg)](https://pub.dev/packages/path_provider) | +| [plugin_platform_interface](./packages/plugin_platform_interface/) | [![pub package](https://img.shields.io/pub/v/plugin_platform_interface.svg)](https://pub.dev/packages/plugin_platform_interface) | | [quick_actions](./packages/quick_actions/) | [![pub package](https://img.shields.io/pub/v/quick_actions.svg)](https://pub.dev/packages/quick_actions) | | [sensors](./packages/sensors/) | [![pub package](https://img.shields.io/pub/v/sensors.svg)](https://pub.dev/packages/sensors) | | [share](./packages/share/) | [![pub package](https://img.shields.io/pub/v/share.svg)](https://pub.dev/packages/share) | From 388c66e8e3da7914ba657bcfb9ee6aefc2cf38bd Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Mon, 29 Jun 2020 20:23:26 -0700 Subject: [PATCH 13/30] [connectivity_for_web] Introduce connectivity_for_web package. (#2820) Move the package formerly known as `experimental_connectivity_web` to flutter/plugins master, as `connectivity_for_web`. --- .../connectivity_for_web/.gitignore | 8 ++ .../connectivity_for_web/.metadata | 10 ++ .../connectivity_for_web/CHANGELOG.md | 11 ++ .../connectivity/connectivity_for_web/LICENSE | 26 ++++ .../connectivity_for_web/README.md | 62 ++++++++++ .../ios/connectivity_for_web.podspec | 23 ++++ .../lib/connectivity_for_web.dart | 63 ++++++++++ .../src/dart_html_connectivity_plugin.dart | 34 +++++ .../generated/network_information_types.dart | 78 ++++++++++++ ...k_information_api_connectivity_plugin.dart | 48 +++++++ .../lib/src/utils/connectivity_result.dart | 56 +++++++++ .../connectivity_for_web/pubspec.yaml | 31 +++++ .../connectivity_for_web/test/.gitignore | 8 ++ .../connectivity_for_web/test/lib/main.dart | 74 +++++++++++ .../test/lib/src/connectivity_mocks.dart | 60 +++++++++ .../connectivity_for_web/test/pubspec.yaml | 24 ++++ .../connectivity_for_web/test/web/index.html | 10 ++ .../connectivity_for_web/ts/.gitignore | 2 + .../connectivity_for_web/ts/README.md | 25 ++++ .../connectivity_for_web/ts/package-lock.json | 117 ++++++++++++++++++ .../connectivity_for_web/ts/package.json | 17 +++ .../ts/scripts/run_facade_gen.sh | 18 +++ 22 files changed, 805 insertions(+) create mode 100644 packages/connectivity/connectivity_for_web/.gitignore create mode 100644 packages/connectivity/connectivity_for_web/.metadata create mode 100644 packages/connectivity/connectivity_for_web/CHANGELOG.md create mode 100644 packages/connectivity/connectivity_for_web/LICENSE create mode 100644 packages/connectivity/connectivity_for_web/README.md create mode 100644 packages/connectivity/connectivity_for_web/ios/connectivity_for_web.podspec create mode 100644 packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart create mode 100644 packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart create mode 100644 packages/connectivity/connectivity_for_web/lib/src/generated/network_information_types.dart create mode 100644 packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart create mode 100644 packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart create mode 100644 packages/connectivity/connectivity_for_web/pubspec.yaml create mode 100644 packages/connectivity/connectivity_for_web/test/.gitignore create mode 100644 packages/connectivity/connectivity_for_web/test/lib/main.dart create mode 100644 packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart create mode 100644 packages/connectivity/connectivity_for_web/test/pubspec.yaml create mode 100644 packages/connectivity/connectivity_for_web/test/web/index.html create mode 100644 packages/connectivity/connectivity_for_web/ts/.gitignore create mode 100644 packages/connectivity/connectivity_for_web/ts/README.md create mode 100644 packages/connectivity/connectivity_for_web/ts/package-lock.json create mode 100644 packages/connectivity/connectivity_for_web/ts/package.json create mode 100755 packages/connectivity/connectivity_for_web/ts/scripts/run_facade_gen.sh diff --git a/packages/connectivity/connectivity_for_web/.gitignore b/packages/connectivity/connectivity_for_web/.gitignore new file mode 100644 index 000000000000..d7dee828a6b9 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +.dart_tool/ + +.packages +.pub/ + +build/ +lib/generated_plugin_registrant.dart diff --git a/packages/connectivity/connectivity_for_web/.metadata b/packages/connectivity/connectivity_for_web/.metadata new file mode 100644 index 000000000000..23eb55ba6da2 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 52ee8a6c6565cd421dfa32042941eb40691f4746 + channel: master + +project_type: plugin diff --git a/packages/connectivity/connectivity_for_web/CHANGELOG.md b/packages/connectivity/connectivity_for_web/CHANGELOG.md new file mode 100644 index 000000000000..89e186abe1cb --- /dev/null +++ b/packages/connectivity/connectivity_for_web/CHANGELOG.md @@ -0,0 +1,11 @@ +## 0.3.0 + +* Rename from "experimental_connectivity_web" to "connectivity_for_web", and move to flutter/plugins master. + +## 0.2.0 + +* Add fallback on dart:html for browsers where NetworkInformationAPI is not supported. + +## 0.1.0 + +* Initial release. diff --git a/packages/connectivity/connectivity_for_web/LICENSE b/packages/connectivity/connectivity_for_web/LICENSE new file mode 100644 index 000000000000..4da9688730d1 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/LICENSE @@ -0,0 +1,26 @@ +Copyright 2016, the Flutter project 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/connectivity/connectivity_for_web/README.md b/packages/connectivity/connectivity_for_web/README.md new file mode 100644 index 000000000000..66efc49fc840 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/README.md @@ -0,0 +1,62 @@ +# connectivity_for_web + +A web implementation of [connectivity](https://pub.dev/connectivity/connectivity). Currently this package uses an experimental API, with a fallback to dart:html, so not all features may be available to all browsers. + +## Usage + +### Import the package + +This package is a non-endorsed implementation of `connectivity` for the web platform, so you need to modify your `pubspec.yaml` to use it: + +```yaml +... +dependencies: + ... + connectivity: ^0.4.9 + connectivity_for_web: ^0.3.0 + ... +... +``` + +## Example + +Find the example wiring in the [Google sign-in example application](https://github.com/ditman/plugins/blob/connectivity-web/packages/connectivity/connectivity/example/lib/main.dart). + +## Limitations on the web platform + +In order to retrieve information about the quality/speed of a browser's connection, the web implementation of the `connectivity` plugin uses the browser's [**NetworkInformation** Web API](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation), which as of this writing (June 2020) is still "experimental", and not available in all browsers: + +![Data on support for the netinfo feature across the major browsers from caniuse.com](https://caniuse.bitsofco.de/image/netinfo.png) + +On desktop browsers, this API only returns a very broad set of connectivity statuses (One of `'slow-2g', '2g', '3g', or '4g'`), and may *not* provide a Stream of changes. Firefox still hasn't enabled this feature by default. + +**Fallback to `navigator.onLine`** + +For those browsers where the NetworkInformation Web API is not available, the plugin falls back to the [**NavigatorOnLine** Web API](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine), which is more broadly supported: + +![Data on support for the online-status feature across the major browsers from caniuse.com](https://caniuse.bitsofco.de/image/online-status.png) + + +The NavigatorOnLine API is [provided by `dart:html`](https://api.dart.dev/stable/2.7.2/dart-html/Navigator/onLine.html), and only supports a boolean connectivity status (either online or offline), with no network speed information. In those cases the plugin will return either `wifi` (when the browser is online) or `none` (when it's not). + +Other than the approximate "downlink" speed, where available, and due to security and privacy concerns, **no Web browser will provide** any specific information about the actual network your users' device is connected to, like **the SSID on a Wi-Fi, or the MAC address of their device.** + +## Contributions and Testing + +Tests are crucial to contributions to this package. All new contributions should be reasonably tested. + +In order to run tests in this package, do: + +``` +cd test +flutter run -d chrome +``` + +All contributions to this package are welcome. Read the [Contributing to Flutter Plugins](https://github.com/flutter/plugins/blob/master/CONTRIBUTING.md) guide to get started. + +## Issues and feedback + +Please file an [issue](https://github.com/ditman/plugins/issues/new) +to send feedback or report a bug. + +**Thank you!** diff --git a/packages/connectivity/connectivity_for_web/ios/connectivity_for_web.podspec b/packages/connectivity/connectivity_for_web/ios/connectivity_for_web.podspec new file mode 100644 index 000000000000..75b891c56533 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/ios/connectivity_for_web.podspec @@ -0,0 +1,23 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint connectivity_web.podspec' to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'connectivity_for_web' + s.version = '0.1.0' + s.summary = 'No-op implementation of connectivity web plugin to avoid build issues on iOS' + s.description = <<-DESC +temp fake connectivity_web plugin + DESC + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_for_web' + s.license = { :file => '../LICENSE' } + s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'Flutter' + s.platform = :ios, '8.0' + + # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } + s.swift_version = '5.0' +end diff --git a/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart b/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart new file mode 100644 index 000000000000..fd061a878867 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart @@ -0,0 +1,63 @@ +import 'dart:async'; + +import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + +import 'src/network_information_api_connectivity_plugin.dart'; +import 'src/dart_html_connectivity_plugin.dart'; + +/// The web implementation of the ConnectivityPlatform of the Connectivity plugin. +class ConnectivityPlugin extends ConnectivityPlatform { + /// Factory method that initializes the connectivity plugin platform with an instance + /// of the plugin for the web. + static void registerWith(Registrar registrar) { + if (NetworkInformationApiConnectivityPlugin.isSupported()) { + ConnectivityPlatform.instance = NetworkInformationApiConnectivityPlugin(); + } else { + ConnectivityPlatform.instance = DartHtmlConnectivityPlugin(); + } + } + + // The following are completely unsupported methods on the web platform. + + // Creates an "unsupported_operation" PlatformException for a given `method` name. + Object _unsupported(String method) { + return PlatformException( + code: 'UNSUPPORTED_OPERATION', + message: '$method() is not supported on the web platform.', + ); + } + + /// Obtains the wifi name (SSID) of the connected network + @override + Future getWifiName() { + throw _unsupported('getWifiName'); + } + + /// Obtains the wifi BSSID of the connected network. + @override + Future getWifiBSSID() { + throw _unsupported('getWifiBSSID'); + } + + /// Obtains the IP address of the connected wifi network + @override + Future getWifiIP() { + throw _unsupported('getWifiIP'); + } + + /// Request to authorize the location service (Only on iOS). + @override + Future requestLocationServiceAuthorization({ + bool requestAlwaysLocationUsage = false, + }) { + throw _unsupported('requestLocationServiceAuthorization'); + } + + /// Get the current location service authorization (Only on iOS). + @override + Future getLocationServiceAuthorization() { + throw _unsupported('getLocationServiceAuthorization'); + } +} diff --git a/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart new file mode 100644 index 000000000000..5caa5679d6ad --- /dev/null +++ b/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart @@ -0,0 +1,34 @@ +import 'dart:async'; +import 'dart:html' as html show window; + +import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; +import 'package:connectivity_for_web/connectivity_for_web.dart'; + +/// The web implementation of the ConnectivityPlatform of the Connectivity plugin. +class DartHtmlConnectivityPlugin extends ConnectivityPlugin { + /// Checks the connection status of the device. + @override + Future checkConnectivity() async { + return html.window.navigator.onLine + ? ConnectivityResult.wifi + : ConnectivityResult.none; + } + + StreamController _connectivityResult; + + /// Returns a Stream of ConnectivityResults changes. + @override + Stream get onConnectivityChanged { + if (_connectivityResult == null) { + _connectivityResult = StreamController(); + // Fallback to dart:html window.onOnline / window.onOffline + html.window.onOnline.listen((event) { + _connectivityResult.add(ConnectivityResult.wifi); + }); + html.window.onOffline.listen((event) { + _connectivityResult.add(ConnectivityResult.none); + }); + } + return _connectivityResult.stream; + } +} diff --git a/packages/connectivity/connectivity_for_web/lib/src/generated/network_information_types.dart b/packages/connectivity/connectivity_for_web/lib/src/generated/network_information_types.dart new file mode 100644 index 000000000000..c4045b3ec1fc --- /dev/null +++ b/packages/connectivity/connectivity_for_web/lib/src/generated/network_information_types.dart @@ -0,0 +1,78 @@ +@JS() +library network_information_types; + +import "package:js/js.dart"; +import "dart:html" show EventListener, EventTarget; + +/// W3C Spec Draft http://wicg.github.io/netinfo/ +/// Edition: Draft Community Group Report 20 February 2019 + +/// http://wicg.github.io/netinfo/#navigatornetworkinformation-interface +@anonymous +@JS() +abstract class Navigator implements NavigatorNetworkInformation {} + +@anonymous +@JS() +abstract class WorkerNavigator implements NavigatorNetworkInformation { + external factory WorkerNavigator({NetworkInformation connection}); +} + +/// http://wicg.github.io/netinfo/#navigatornetworkinformation-interface +@anonymous +@JS() +abstract class NavigatorNetworkInformation { + external NetworkInformation get connection; + external factory NavigatorNetworkInformation({NetworkInformation connection}); +} + +/// http://wicg.github.io/netinfo/#connection-types +/*type ConnectionType = + | 'bluetooth' + | 'cellular' + | 'ethernet' + | 'mixed' + | 'none' + | 'other' + | 'unknown' + | 'wifi' + | 'wimax'; +*/ + +/// http://wicg.github.io/netinfo/#effectiveconnectiontype-enum +/*type EffectiveConnectionType = '2g' | '3g' | '4g' | 'slow-2g';*/ + +/// http://wicg.github.io/netinfo/#dom-megabit +/*type Megabit = number;*/ +/// http://wicg.github.io/netinfo/#dom-millisecond +/*type Millisecond = number;*/ + +/// http://wicg.github.io/netinfo/#networkinformation-interface +@anonymous +@JS() +abstract class NetworkInformation implements EventTarget { + /// http://wicg.github.io/netinfo/#type-attribute + external String /*'bluetooth'|'cellular'|'ethernet'|'mixed'|'none'|'other'|'unknown'|'wifi'|'wimax'*/ get type; + + /// http://wicg.github.io/netinfo/#effectivetype-attribute + external String /*'2g'|'3g'|'4g'|'slow-2g'*/ get effectiveType; + + /// http://wicg.github.io/netinfo/#downlinkmax-attribute + external num get downlinkMax; + + /// http://wicg.github.io/netinfo/#downlink-attribute + external num get downlink; + + /// http://wicg.github.io/netinfo/#rtt-attribute + external num get rtt; + + /// http://wicg.github.io/netinfo/#savedata-attribute + external bool get saveData; + + /// http://wicg.github.io/netinfo/#handling-changes-to-the-underlying-connection + external EventListener get onchange; + external set onchange(EventListener v); +} + +@JS() +external Navigator get navigator; diff --git a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart new file mode 100644 index 000000000000..d88487b9c406 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart @@ -0,0 +1,48 @@ +import 'dart:async'; + +import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; +import 'package:connectivity_for_web/connectivity_for_web.dart'; +import 'package:flutter/foundation.dart'; +import 'package:js/js.dart'; + +import 'generated/network_information_types.dart' as dom; +import 'utils/connectivity_result.dart'; + +/// The web implementation of the ConnectivityPlatform of the Connectivity plugin. +class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { + final dom.NetworkInformation _networkInformation; + + /// A check to determine if this version of the plugin can be used. + static bool isSupported() => dom.navigator?.connection != null; + + /// The constructor of the plugin. + NetworkInformationApiConnectivityPlugin() + : this.withConnection(dom.navigator?.connection); + + /// Creates the plugin, with an override of the NetworkInformation object. + @visibleForTesting + NetworkInformationApiConnectivityPlugin.withConnection( + dom.NetworkInformation connection) + : _networkInformation = connection; + + /// Checks the connection status of the device. + @override + Future checkConnectivity() async { + return networkInformationToConnectivityResult(_networkInformation); + } + + StreamController _connectivityResult; + + /// Returns a Stream of ConnectivityResults changes. + @override + Stream get onConnectivityChanged { + if (_connectivityResult == null) { + _connectivityResult = StreamController(); + _networkInformation.onchange = allowInterop((_) { + _connectivityResult + .add(networkInformationToConnectivityResult(_networkInformation)); + }); + } + return _connectivityResult.stream; + } +} diff --git a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart new file mode 100644 index 000000000000..28943ef5c7e1 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart @@ -0,0 +1,56 @@ +import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; + +/// Converts an incoming NetworkInformation object into the correct ConnectivityResult. +// +// We can't be more specific on the signature of this method because the API is odd, +// data can come from a static value in the DOM, or as the 'target' of a DOM Event. +// +// If we type info as `NetworkInformation`, Dart will complain with: +// "Uncaught Error: Expected a value of type 'NetworkInformation', +// but got one of type 'NetworkInformation'" +ConnectivityResult networkInformationToConnectivityResult( + dynamic /* NetworkInformation */ info) { + if (info == null) { + return ConnectivityResult.none; + } + if (info.downlink == 0 && info.rtt == 0) { + return ConnectivityResult.none; + } + if (info.type != null) { + return _typeToConnectivityResult(info.type); + } + if (info.effectiveType != null) { + return _effectiveTypeToConnectivityResult(info.effectiveType); + } + return ConnectivityResult.none; +} + +ConnectivityResult _effectiveTypeToConnectivityResult(String effectiveType) { + // Possible values: + /*'2g'|'3g'|'4g'|'slow-2g'*/ + switch (effectiveType) { + case 'slow-2g': + case '2g': + case '3g': + return ConnectivityResult.mobile; + default: + return ConnectivityResult.wifi; + } +} + +ConnectivityResult _typeToConnectivityResult(String type) { + // Possible values: + /*'bluetooth'|'cellular'|'ethernet'|'mixed'|'none'|'other'|'unknown'|'wifi'|'wimax'*/ + switch (type) { + case 'none': + return ConnectivityResult.none; + case 'bluetooth': + case 'cellular': + case 'mixed': + case 'other': + case 'unknown': + return ConnectivityResult.mobile; + default: + return ConnectivityResult.wifi; + } +} diff --git a/packages/connectivity/connectivity_for_web/pubspec.yaml b/packages/connectivity/connectivity_for_web/pubspec.yaml new file mode 100644 index 000000000000..e4a1673e40c2 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/pubspec.yaml @@ -0,0 +1,31 @@ +name: connectivity_for_web +description: An implementation for the web platform of the Flutter `connectivity` plugin. This uses the NetworkInformation Web API, with a fallback to Navigator.onLine. +version: 0.3.0 +homepage: https://github.com/ditman/plugins/tree/connectivity-web/packages/connectivity/experimental_connectivity_web + +flutter: + plugin: + platforms: + web: + pluginClass: ConnectivityPlugin + fileName: connectivity_for_web.dart + +dependencies: + connectivity_platform_interface: ^1.0.3 + js: ^0.6.1+1 + flutter_web_plugins: + sdk: flutter + flutter: + sdk: flutter + +dev_dependencies: + test: any + flutter_driver: + sdk: flutter + flutter_test: + sdk: flutter + e2e: ^0.2.4+3 + +environment: + sdk: ">=2.6.0 <3.0.0" + flutter: ">=1.12.13+hotfix.4" diff --git a/packages/connectivity/connectivity_for_web/test/.gitignore b/packages/connectivity/connectivity_for_web/test/.gitignore new file mode 100644 index 000000000000..d7dee828a6b9 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/test/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +.dart_tool/ + +.packages +.pub/ + +build/ +lib/generated_plugin_registrant.dart diff --git a/packages/connectivity/connectivity_for_web/test/lib/main.dart b/packages/connectivity/connectivity_for_web/test/lib/main.dart new file mode 100644 index 000000000000..21621a947ee6 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/test/lib/main.dart @@ -0,0 +1,74 @@ +import 'package:e2e/e2e.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; +import 'package:connectivity_for_web/src/network_information_api_connectivity_plugin.dart'; + +import 'src/connectivity_mocks.dart'; + +void main() { + E2EWidgetsFlutterBinding.ensureInitialized(); + + group('checkConnectivity', () { + void testCheckConnectivity({ + String type, + String effectiveType, + num downlink = 10, + num rtt = 50, + ConnectivityResult expected, + }) { + MockNetworkInformation connection = MockNetworkInformation( + type: type, + effectiveType: effectiveType, + downlink: downlink, + rtt: rtt); + NetworkInformationApiConnectivityPlugin plugin = + NetworkInformationApiConnectivityPlugin.withConnection(connection); + expect(plugin.checkConnectivity(), completion(equals(expected))); + } + + test('0 downlink and rtt -> none', () { + testCheckConnectivity( + effectiveType: '4g', + downlink: 0, + rtt: 0, + expected: ConnectivityResult.none); + }); + test('slow-2g -> mobile', () { + testCheckConnectivity( + effectiveType: 'slow-2g', expected: ConnectivityResult.mobile); + }); + test('2g -> mobile', () { + testCheckConnectivity( + effectiveType: '2g', expected: ConnectivityResult.mobile); + }); + test('3g -> mobile', () { + testCheckConnectivity( + effectiveType: '3g', expected: ConnectivityResult.mobile); + }); + test('4g -> wifi', () { + testCheckConnectivity( + effectiveType: '4g', expected: ConnectivityResult.wifi); + }); + }); + + group('get onConnectivityChanged', () { + test('puts change events in a Stream', () async { + MockNetworkInformation connection = + MockNetworkInformation(effectiveType: '4g', downlink: 10, rtt: 50); + NetworkInformationApiConnectivityPlugin plugin = + NetworkInformationApiConnectivityPlugin.withConnection(connection); + + Stream results = plugin.onConnectivityChanged; + + // Fake a disconnect-reconnect + connection.mockChangeValue(downlink: 0, rtt: 0); + connection.mockChangeValue(downlink: 10, rtt: 50); + + // The stream of results is infinite, so we need to .take(2) for this test to complete. + expect( + results.take(2).toList(), + completion( + equals([ConnectivityResult.none, ConnectivityResult.wifi]))); + }); + }); +} diff --git a/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart b/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart new file mode 100644 index 000000000000..9ce2e811d461 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart @@ -0,0 +1,60 @@ +import 'dart:html'; + +import 'package:connectivity_for_web/src/generated/network_information_types.dart' + as dom; + +/// A Mock implementation of the NetworkInformation API that allows +/// for external modification of its values. +class MockNetworkInformation extends dom.NetworkInformation { + @override + String type; + + @override + String effectiveType; + + @override + num downlink; + + @override + num rtt; + + @override + EventListener onchange; + + /// Constructor of mocked instances... + MockNetworkInformation({ + this.type, + this.effectiveType, + this.downlink, + this.rtt, + }); + + /// Changes the desired values, and triggers the change event listener. + void mockChangeValue({ + String type, + String effectiveType, + num downlink, + num rtt, + }) { + this.type = type ?? this.type; + this.effectiveType = effectiveType ?? this.effectiveType; + this.downlink = downlink ?? this.downlink; + this.rtt = rtt ?? this.rtt; + + onchange(Event('change')); + } + + @override + void addEventListener(String type, listener, [bool useCapture]) {} + + @override + bool dispatchEvent(Event event) { + return true; + } + + @override + Events get on => null; + + @override + void removeEventListener(String type, listener, [bool useCapture]) {} +} diff --git a/packages/connectivity/connectivity_for_web/test/pubspec.yaml b/packages/connectivity/connectivity_for_web/test/pubspec.yaml new file mode 100644 index 000000000000..4d7d10a775e2 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/test/pubspec.yaml @@ -0,0 +1,24 @@ +name: connectivity_web_example +description: Example web app for the connectivity plugin +version: 0.1.0 +homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_web + +dependencies: + connectivity_for_web: + path: ../ + js: ^0.6.1+1 + flutter_web_plugins: + sdk: flutter + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_driver: + sdk: flutter + e2e: ^0.2.4+3 + +environment: + sdk: ">=2.6.0 <3.0.0" + flutter: ">=1.12.13+hotfix.4" diff --git a/packages/connectivity/connectivity_for_web/test/web/index.html b/packages/connectivity/connectivity_for_web/test/web/index.html new file mode 100644 index 000000000000..6eff9a740d43 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/test/web/index.html @@ -0,0 +1,10 @@ + + + + + example + + + + + diff --git a/packages/connectivity/connectivity_for_web/ts/.gitignore b/packages/connectivity/connectivity_for_web/ts/.gitignore new file mode 100644 index 000000000000..de4d1f007dd1 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/ts/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/packages/connectivity/connectivity_for_web/ts/README.md b/packages/connectivity/connectivity_for_web/ts/README.md new file mode 100644 index 000000000000..3372ad2f3790 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/ts/README.md @@ -0,0 +1,25 @@ +# JS Facade generator + +This npm script takes the `network-information-types` npm package, and runs it through Dart's `dart_js_facade_gen` to auto-generate (most) of the JS facades used by this plugin. + +The process is not completely automated yet, but it should be pretty close. + +To generate the facades, and after [installing `npm`](https://www.npmjs.com/get-npm), do: + +``` +npm install +npm run build +``` + +The above will fetch the required dependencies, and generate a `dist/network_information_types.dart` file that you can use with the plugin. + +``` +cp dist/*.dart ../lib/src/generated +``` + +This script should come handy once the Network Information Web API changes, or becomes stable, so the JS-interop part of this plugin can be regenerated more easily. + +Read more: + +* [Dart JS Interop](https://dart.dev/web/js-interop) +* [dart_js_facade_gen](https://www.npmjs.com/package/dart_js_facade_gen) \ No newline at end of file diff --git a/packages/connectivity/connectivity_for_web/ts/package-lock.json b/packages/connectivity/connectivity_for_web/ts/package-lock.json new file mode 100644 index 000000000000..45293a400492 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/ts/package-lock.json @@ -0,0 +1,117 @@ +{ + "name": "network-information-types-to-dart-generator", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/chai": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.9.tgz", + "integrity": "sha512-NeXgZj+MFL4izGqA4sapdYzkzQG+MtGra9vhQ58dnmDY++VgJaRUws+aLVV5zRJCYJl/8s9IjMmhiUw1WsKSmw==" + }, + "@types/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg==", + "requires": { + "@types/node": "*" + } + }, + "@types/minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=" + }, + "@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==" + }, + "@types/node": { + "version": "12.12.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.28.tgz", + "integrity": "sha512-g73GJYJDXgf0jqg+P9S8h2acWbDXNkoCX8DLtJVu7Fkn788pzQ/oJsrdJz/2JejRf/SjfZaAhsw+3nd1D5EWGg==" + }, + "@types/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@types/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LrnsgZIfJaysFkv9rRJp4/uAyqw87oVed3s1hhF83nwbo9c7MG9g5DqR0seHP+lkX4ldmMrVolPjQSe2ZfD0yA==", + "requires": { + "source-map": "*" + } + }, + "@types/source-map-support": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@types/source-map-support/-/source-map-support-0.5.1.tgz", + "integrity": "sha512-VDqnZe9D2zR19qbeRvwYyHSp7AtUtCkTaRVFQ8wzwH9TXw9kKKq/vBhfEnFEXVupO2M0lBMA9mr/XyQ6gEkUOA==", + "requires": { + "@types/node": "*" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "dart-style": { + "version": "1.3.2-dev", + "resolved": "https://registry.npmjs.org/dart-style/-/dart-style-1.3.2-dev.tgz", + "integrity": "sha512-NFI4UQYvG32t/cEkQAdkXT2ZT72tjF61tMWoALmnGwj03d2Co94zwGfbnFfdQUQvrhUNx8Wz2jKSVxGrmFaVJQ==" + }, + "dart_js_facade_gen": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/dart_js_facade_gen/-/dart_js_facade_gen-0.0.7.tgz", + "integrity": "sha512-AZiWsccbzhgJWmBjbFTPuvBhwGXk7AN8nOP91/I8PqUfSvVALiWshDc66TvywNkdNogAE5X8zlxjodw1C3iHpA==", + "requires": { + "@types/chai": "^4.2.3", + "@types/fs-extra": "^8.0.0", + "@types/minimist": "^1.2.0", + "@types/mocha": "^5.2.7", + "@types/node": "^12.7.8", + "@types/source-map": "^0.5.7", + "@types/source-map-support": "^0.5.0", + "dart-style": "^1.3.2-dev", + "minimist": "^1.2.0", + "source-map": "^0.7.3", + "source-map-support": "^0.5.13", + "typescript": "^3.6.3" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "network-information-types": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/network-information-types/-/network-information-types-0.1.0.tgz", + "integrity": "sha512-cRUCYZoRHTMjYcgk5MbwqM0h0Za34panRxAJKY8n+mQ+NLMuRIw7aKzmaZqkC/cte7bnRcdfTwFA27GgN62EtQ==" + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "typescript": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.2.tgz", + "integrity": "sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ==" + } + } +} diff --git a/packages/connectivity/connectivity_for_web/ts/package.json b/packages/connectivity/connectivity_for_web/ts/package.json new file mode 100644 index 000000000000..665c89d6afbb --- /dev/null +++ b/packages/connectivity/connectivity_for_web/ts/package.json @@ -0,0 +1,17 @@ +{ + "name": "network-information-types-to-dart-generator", + "version": "1.0.0", + "description": "Use dart_js_facade_gen to generate the facade for the network-information-types package.", + "main": "index.js", + "private": true, + "scripts": { + "build": "./scripts/run_facade_gen.sh", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "MIT", + "dependencies": { + "network-information-types": "0.1.0", + "dart_js_facade_gen": "^0.0.7" + } +} diff --git a/packages/connectivity/connectivity_for_web/ts/scripts/run_facade_gen.sh b/packages/connectivity/connectivity_for_web/ts/scripts/run_facade_gen.sh new file mode 100755 index 000000000000..c74b8ba171b2 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/ts/scripts/run_facade_gen.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +INDEX_PATH=node_modules/network-information-types/dist-types/index.d.ts +WORK_PATH=network_information_types.d.ts +DIST_PATH=dist + +# Create dist if it doesn't exist already +mkdir -p $DIST_PATH + +# Copy the input file(s) into our work path +cp $INDEX_PATH $WORK_PATH + +# Run dart_js_facade_gen +dart_js_facade_gen $WORK_PATH --trust-js-types --generate-html --destination . + +# Move output to the right place, and clean after yourself +mv *.dart $DIST_PATH +rm $WORK_PATH From 940c10ca28290a01a11f1d830972b88bdac672e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Palma?= Date: Tue, 30 Jun 2020 19:42:00 +0100 Subject: [PATCH 14/30] [url_launcher_web] Adds "tel" and "sms" URL support (#2847) --- .../url_launcher_web/CHANGELOG.md | 4 ++ .../lib/url_launcher_web.dart | 19 ++++-- .../url_launcher_web/pubspec.yaml | 2 +- .../test/url_launcher_web_test.dart | 65 ++++++++++++++++++- 4 files changed, 82 insertions(+), 8 deletions(-) diff --git a/packages/url_launcher/url_launcher_web/CHANGELOG.md b/packages/url_launcher/url_launcher_web/CHANGELOG.md index df1b2c97b744..e9f7bde63fda 100644 --- a/packages/url_launcher/url_launcher_web/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.1.2 + +- Adds "tel" and "sms" support + # 0.1.1+6 - Open "mailto" urls with target set as "\_top" on Safari browsers. diff --git a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart index e55ceb2269bc..1bac4d524122 100644 --- a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart +++ b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart @@ -7,7 +7,11 @@ import 'package:url_launcher_platform_interface/url_launcher_platform_interface. import 'package:platform_detect/platform_detect.dart' show browser; -const _mailtoScheme = 'mailto'; +const _safariTargetTopSchemes = { + 'mailto', + 'tel', + 'sms', +}; /// The web implementation of [UrlLauncherPlatform]. /// @@ -16,7 +20,10 @@ class UrlLauncherPlugin extends UrlLauncherPlatform { html.Window _window; // The set of schemes that can be handled by the plugin - static final _supportedSchemes = {'http', 'https', _mailtoScheme}; + static final _supportedSchemes = { + 'http', + 'https', + }.union(_safariTargetTopSchemes); /// A constructor that allows tests to override the window object used by the plugin. UrlLauncherPlugin({@visibleForTesting html.Window window}) @@ -29,16 +36,18 @@ class UrlLauncherPlugin extends UrlLauncherPlatform { String _getUrlScheme(String url) => Uri.tryParse(url)?.scheme; - bool _isMailtoScheme(String url) => _getUrlScheme(url) == _mailtoScheme; + bool _isSafariTargetTopScheme(String url) => + _safariTargetTopSchemes.contains(_getUrlScheme(url)); /// Opens the given [url] in a new window. /// /// Returns the newly created window. @visibleForTesting html.WindowBase openNewWindow(String url) { - // We need to open mailto urls on the _top window context on safari browsers. + // We need to open mailto, tel and sms urls on the _top window context on safari browsers. // See https://github.com/flutter/flutter/issues/51461 for reference. - final target = browser.isSafari && _isMailtoScheme(url) ? '_top' : ''; + final target = + browser.isSafari && _isSafariTargetTopScheme(url) ? '_top' : ''; return _window.open(url, target); } diff --git a/packages/url_launcher/url_launcher_web/pubspec.yaml b/packages/url_launcher/url_launcher_web/pubspec.yaml index 207f2dc15424..9a5beac00b94 100644 --- a/packages/url_launcher/url_launcher_web/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/u # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.1+6 +version: 0.1.2 flutter: plugin: diff --git a/packages/url_launcher/url_launcher_web/test/url_launcher_web_test.dart b/packages/url_launcher/url_launcher_web/test/url_launcher_web_test.dart index 4cf92062e10f..b7e107d892cf 100644 --- a/packages/url_launcher/url_launcher_web/test/url_launcher_web_test.dart +++ b/packages/url_launcher/url_launcher_web/test/url_launcher_web_test.dart @@ -36,8 +36,13 @@ void main() { plugin.canLaunch('mailto:name@mydomain.com'), completion(isTrue)); }); - test('"tel" URLs -> false', () { - expect(plugin.canLaunch('tel:5551234567'), completion(isFalse)); + test('"tel" URLs -> true', () { + expect(plugin.canLaunch('tel:5551234567'), completion(isTrue)); + }); + + test('"sms" URLs -> true', () { + expect(plugin.canLaunch('sms:+19725551212?body=hello%20there'), + completion(isTrue)); }); }); @@ -48,6 +53,9 @@ void main() { .thenReturn(MockWindow()); when(mockWindow.open('mailto:name@mydomain.com', '')) .thenReturn(MockWindow()); + when(mockWindow.open('tel:5551234567', '')).thenReturn(MockWindow()); + when(mockWindow.open('sms:+19725551212?body=hello%20there', '')) + .thenReturn(MockWindow()); }); test('launching a URL returns true', () { @@ -77,6 +85,34 @@ void main() { ), completion(isTrue)); }); + + test('launching a "tel" returns true', () { + expect( + plugin.launch( + 'tel:5551234567', + useSafariVC: null, + useWebView: null, + universalLinksOnly: null, + enableDomStorage: null, + enableJavaScript: null, + headers: null, + ), + completion(isTrue)); + }); + + test('launching a "sms" returns true', () { + expect( + plugin.launch( + 'sms:+19725551212?body=hello%20there', + useSafariVC: null, + useWebView: null, + universalLinksOnly: null, + enableDomStorage: null, + enableJavaScript: null, + headers: null, + ), + completion(isTrue)); + }); }); group('openNewWindow', () { @@ -98,6 +134,18 @@ void main() { verify(mockWindow.open('mailto:name@mydomain.com', '')); }); + test('tel urls should be launched on a new window', () { + plugin.openNewWindow('tel:5551234567'); + + verify(mockWindow.open('tel:5551234567', '')); + }); + + test('sms urls should be launched on a new window', () { + plugin.openNewWindow('sms:+19725551212?body=hello%20there'); + + verify(mockWindow.open('sms:+19725551212?body=hello%20there', '')); + }); + group('Safari', () { setUp(() { platform.configurePlatformForTesting(browser: platform.safari); @@ -120,6 +168,19 @@ void main() { verify(mockWindow.open('mailto:name@mydomain.com', '_top')); }); + + test('tel urls should be launched on the same window', () { + plugin.openNewWindow('tel:5551234567'); + + verify(mockWindow.open('tel:5551234567', '_top')); + }); + + test('sms urls should be launched on the same window', () { + plugin.openNewWindow('sms:+19725551212?body=hello%20there'); + + verify( + mockWindow.open('sms:+19725551212?body=hello%20there', '_top')); + }); }); }); }); From e08b09cb74a1a5f9fd4c1744de6cf0d69b688a07 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Wed, 1 Jul 2020 10:07:47 +1200 Subject: [PATCH 15/30] [shared_preferences_linux] Add support for Linux (#2836) Adds shared_preferences support for Linux. Part of flutter/flutter#41720 --- .../shared_preferences_linux/.gitignore | 7 ++ .../shared_preferences_linux/.metadata | 10 ++ .../shared_preferences_linux/CHANGELOG.md | 2 + .../shared_preferences_linux/LICENSE | 27 ++++++ .../shared_preferences_linux/README.md | 22 +++++ .../example/.gitignore | 43 +++++++++ .../example/.metadata | 10 ++ .../example/README.md | 8 ++ .../example/lib/main.dart | 87 +++++++++++++++++ .../example/pubspec.yaml | 15 +++ .../lib/shared_preferences_linux.dart | 96 +++++++++++++++++++ .../shared_preferences_linux/pubspec.yaml | 29 ++++++ .../test/shared_preferences_linux_test.dart | 74 ++++++++++++++ script/build_all_plugins_app.sh | 1 + 14 files changed, 431 insertions(+) create mode 100644 packages/shared_preferences/shared_preferences_linux/.gitignore create mode 100644 packages/shared_preferences/shared_preferences_linux/.metadata create mode 100644 packages/shared_preferences/shared_preferences_linux/CHANGELOG.md create mode 100644 packages/shared_preferences/shared_preferences_linux/LICENSE create mode 100644 packages/shared_preferences/shared_preferences_linux/README.md create mode 100644 packages/shared_preferences/shared_preferences_linux/example/.gitignore create mode 100644 packages/shared_preferences/shared_preferences_linux/example/.metadata create mode 100644 packages/shared_preferences/shared_preferences_linux/example/README.md create mode 100644 packages/shared_preferences/shared_preferences_linux/example/lib/main.dart create mode 100644 packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml create mode 100644 packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart create mode 100644 packages/shared_preferences/shared_preferences_linux/pubspec.yaml create mode 100644 packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart diff --git a/packages/shared_preferences/shared_preferences_linux/.gitignore b/packages/shared_preferences/shared_preferences_linux/.gitignore new file mode 100644 index 000000000000..e9dc58d3d6e2 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +.dart_tool/ + +.packages +.pub/ + +build/ diff --git a/packages/shared_preferences/shared_preferences_linux/.metadata b/packages/shared_preferences/shared_preferences_linux/.metadata new file mode 100644 index 000000000000..9615744e96d1 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: e491544588e8d34fdf31d5f840b4649850ef167a + channel: master + +project_type: plugin diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md new file mode 100644 index 000000000000..11694802aacf --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md @@ -0,0 +1,2 @@ +## 0.0.1 +* Initial release to support shared_preferences on Linux. diff --git a/packages/shared_preferences/shared_preferences_linux/LICENSE b/packages/shared_preferences/shared_preferences_linux/LICENSE new file mode 100644 index 000000000000..0c91662b3f2f --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/LICENSE @@ -0,0 +1,27 @@ +// Copyright 2020 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/shared_preferences/shared_preferences_linux/README.md b/packages/shared_preferences/shared_preferences_linux/README.md new file mode 100644 index 000000000000..1894f50ae99e --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/README.md @@ -0,0 +1,22 @@ +# shared_preferences_linux + +The Linux implementation of [`shared_preferences`][1]. + +## Usage + +### Import the package + +This package is an unendorsed Linux implementation of `shared_preferences`. + +In order to use this now, you'll need to depend on `shared_preferences_linux`. +When this package is endorsed it will be automatically used by the `shared_preferences` package and you can switch to that API. + +```yaml +... +dependencies: + ... + shared_preferences_linux: ^0.0.1 + ... +``` + +[1]: ../ diff --git a/packages/shared_preferences/shared_preferences_linux/example/.gitignore b/packages/shared_preferences/shared_preferences_linux/example/.gitignore new file mode 100644 index 000000000000..1ba9c339effb --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/packages/shared_preferences/shared_preferences_linux/example/.metadata b/packages/shared_preferences/shared_preferences_linux/example/.metadata new file mode 100644 index 000000000000..c0bc9a90268a --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: e491544588e8d34fdf31d5f840b4649850ef167a + channel: master + +project_type: app diff --git a/packages/shared_preferences/shared_preferences_linux/example/README.md b/packages/shared_preferences/shared_preferences_linux/example/README.md new file mode 100644 index 000000000000..9d3bf1faf406 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/README.md @@ -0,0 +1,8 @@ +# shared_preferences_example + +Demonstrates how to use the shared_preferences plugin. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart b/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart new file mode 100644 index 000000000000..ceacf2f95f28 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart @@ -0,0 +1,87 @@ +// Copyright 2017 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. + +// ignore_for_file: public_member_api_docs + +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:shared_preferences_linux/shared_preferences_linux.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'SharedPreferences Demo', + home: SharedPreferencesDemo(), + ); + } +} + +class SharedPreferencesDemo extends StatefulWidget { + SharedPreferencesDemo({Key key}) : super(key: key); + + @override + SharedPreferencesDemoState createState() => SharedPreferencesDemoState(); +} + +class SharedPreferencesDemoState extends State { + final prefs = SharedPreferencesLinux.instance; + Future _counter; + + Future _incrementCounter() async { + final values = await prefs.getAll(); + final int counter = (values['counter'] as int ?? 0) + 1; + + setState(() { + _counter = prefs.setValue(null, "counter", counter).then((bool success) { + return counter; + }); + }); + } + + @override + void initState() { + super.initState(); + _counter = prefs.getAll().then((Map values) { + return (values['counter'] ?? 0); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("SharedPreferences Demo"), + ), + body: Center( + child: FutureBuilder( + future: _counter, + builder: (BuildContext context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return const CircularProgressIndicator(); + default: + if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return Text( + 'Button tapped ${snapshot.data} time${snapshot.data == 1 ? '' : 's'}.\n\n' + 'This should persist across restarts.', + ); + } + } + })), + floatingActionButton: FloatingActionButton( + onPressed: _incrementCounter, + tooltip: 'Increment', + child: const Icon(Icons.add), + ), + ); + } +} diff --git a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml new file mode 100644 index 000000000000..1c0624035c54 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml @@ -0,0 +1,15 @@ +name: shared_preferences_linux_example +description: Demonstrates how to use the shared_preferences_linux plugin. + +dependencies: + flutter: + sdk: flutter + shared_preferences_linux: ^0.1.0 + +dependency_overrides: + shared_preferences_linux: + path: ../ + +flutter: + uses-material-design: true + diff --git a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart new file mode 100644 index 000000000000..dc93100c3277 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart @@ -0,0 +1,96 @@ +// Copyright 2020 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 'dart:convert' show json; +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; +import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; + +/// The Linux implementation of [SharedPreferencesStorePlatform]. +/// +/// This class implements the `package:shared_preferences` functionality for Linux. +class SharedPreferencesLinux extends SharedPreferencesStorePlatform { + /// The default instance of [SharedPreferencesLinux] to use. + static SharedPreferencesLinux instance = SharedPreferencesLinux(); + + /// Local copy of preferences + Map _cachedPreferences; + + /// File system used to store to disk. Exposed for testing only. + @visibleForTesting + FileSystem fs = LocalFileSystem(); + + /// Gets the file where the preferences are stored. + Future _getLocalDataFile() async { + var directory = await getApplicationSupportDirectory(); + var filePath = path.join(directory.path, 'shared_preferences.json'); + return fs.file(filePath); + } + + /// Gets the preferences from the stored file. Once read, the preferences are + /// maintained in memory. + Future> _readPreferences() async { + if (_cachedPreferences != null) { + return _cachedPreferences; + } + + _cachedPreferences = {}; + var localDataFile = await _getLocalDataFile(); + if (localDataFile.existsSync()) { + String stringMap = localDataFile.readAsStringSync(); + if (stringMap.isNotEmpty) { + _cachedPreferences = json.decode(stringMap) as Map; + } + } + + return _cachedPreferences; + } + + /// Writes the cached preferences to disk. Returns [true] if the operation + /// succeeded. + Future _writePreferences(Map preferences) async { + try { + var localDataFile = await _getLocalDataFile(); + if (!localDataFile.existsSync()) { + localDataFile.createSync(recursive: true); + } + var stringMap = json.encode(preferences); + localDataFile.writeAsStringSync(stringMap); + } catch (e) { + print("Error saving preferences to disk: $e"); + return false; + } + return true; + } + + @override + Future clear() async { + var preferences = await _readPreferences(); + preferences.clear(); + return _writePreferences(preferences); + } + + @override + Future> getAll() async { + return _readPreferences(); + } + + @override + Future remove(String key) async { + var preferences = await _readPreferences(); + preferences.remove(key); + return _writePreferences(preferences); + } + + @override + Future setValue(String valueType, String key, Object value) async { + var preferences = await _readPreferences(); + preferences[key] = value; + return _writePreferences(preferences); + } +} diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml new file mode 100644 index 000000000000..2539b937e006 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml @@ -0,0 +1,29 @@ +name: shared_preferences_linux +description: Linux implementation of the shared_preferences plugin +version: 0.0.1 +homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux + +flutter: + plugin: + platforms: + linux: + dartPluginClass: SharedPreferencesLinux + pluginClass: none + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.8 <2.0.0" + +dependencies: + file: ^5.1.0 + flutter: + sdk: flutter + meta: ^1.0.4 + path: ^1.6.4 + path_provider: ^1.6.11 + shared_preferences_platform_interface: ^1.0.0 + +dev_dependencies: + flutter_test: + sdk: flutter + pedantic: ^1.8.0 diff --git a/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart new file mode 100644 index 000000000000..8a794b1fa7c2 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart @@ -0,0 +1,74 @@ +// Copyright 2020 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 'package:file/memory.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; +import 'package:shared_preferences_linux/shared_preferences_linux.dart'; + +MemoryFileSystem fs = MemoryFileSystem.test(); + +void main() { + setUp(() {}); + + tearDown(() {}); + + Future _getFilePath() async { + var directory = await getApplicationSupportDirectory(); + return path.join(directory.path, 'shared_preferences.json'); + } + + _writeTestFile(String value) async { + fs.file(await _getFilePath()) + ..createSync(recursive: true) + ..writeAsStringSync(value); + } + + Future _readTestFile() async { + return fs.file(await _getFilePath()).readAsStringSync(); + } + + SharedPreferencesLinux _getPreferences() { + var prefs = SharedPreferencesLinux(); + prefs.fs = fs; + return prefs; + } + + test('getAll', () async { + await _writeTestFile('{"key1": "one", "key2": 2}'); + var prefs = _getPreferences(); + + var values = await prefs.getAll(); + expect(values, hasLength(2)); + expect(values['key1'], 'one'); + expect(values['key2'], 2); + }); + + test('remove', () async { + await _writeTestFile('{"key1":"one","key2":2}'); + var prefs = _getPreferences(); + + await prefs.remove('key2'); + + expect(await _readTestFile(), '{"key1":"one"}'); + }); + + test('setValue', () async { + await _writeTestFile('{}'); + var prefs = _getPreferences(); + + await prefs.setValue('', 'key1', 'one'); + await prefs.setValue('', 'key2', 2); + + expect(await _readTestFile(), '{"key1":"one","key2":2}'); + }); + + test('clear', () async { + await _writeTestFile('{"key1":"one","key2":2}'); + var prefs = _getPreferences(); + + await prefs.clear(); + expect(await _readTestFile(), '{}'); + }); +} diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 2c0a90693851..262c4ed7b1d3 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -26,6 +26,7 @@ readonly EXCLUDED_PLUGINS_LIST=( "path_provider_platform_interface" "path_provider_web" "plugin_platform_interface" + "shared_preferences_linux" "shared_preferences_macos" "shared_preferences_platform_interface" "shared_preferences_web" From 71cc865b2504a8f834588f79535f64a889632a93 Mon Sep 17 00:00:00 2001 From: Jia Hao Date: Wed, 1 Jul 2020 08:02:49 +0800 Subject: [PATCH 16/30] [e2e] Use SettableFuture instead of CompletableFuture (#2854) Expose a `Future` for `testResults` instead. This works better for internal use cases. --- packages/e2e/CHANGELOG.md | 4 ++++ packages/e2e/android/build.gradle | 3 ++- .../src/main/java/dev/flutter/plugins/e2e/E2EPlugin.java | 9 ++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/e2e/CHANGELOG.md b/packages/e2e/CHANGELOG.md index 0d349965371b..ad2f8d3e24f0 100644 --- a/packages/e2e/CHANGELOG.md +++ b/packages/e2e/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.0 + +* **Breaking change** `E2EPlugin` exports a `Future` for `testResults`. + ## 0.5.0+1 * Fixed the device pixel ratio problem. diff --git a/packages/e2e/android/build.gradle b/packages/e2e/android/build.gradle index ec686f4b4e3d..d0bb6c5a5967 100644 --- a/packages/e2e/android/build.gradle +++ b/packages/e2e/android/build.gradle @@ -33,11 +33,12 @@ android { } dependencies { api 'junit:junit:4.12' - implementation 'net.sourceforge.streamsupport:android-retrofuture:1.7.2' // https://developer.android.com/jetpack/androidx/releases/test/#1.2.0 api 'androidx.test:runner:1.2.0' api 'androidx.test:rules:1.2.0' api 'androidx.test.espresso:espresso-core:3.2.0' + + implementation 'com.google.guava:guava:28.1-android' } } diff --git a/packages/e2e/android/src/main/java/dev/flutter/plugins/e2e/E2EPlugin.java b/packages/e2e/android/src/main/java/dev/flutter/plugins/e2e/E2EPlugin.java index f6c5b306b5d9..31100d442731 100644 --- a/packages/e2e/android/src/main/java/dev/flutter/plugins/e2e/E2EPlugin.java +++ b/packages/e2e/android/src/main/java/dev/flutter/plugins/e2e/E2EPlugin.java @@ -5,6 +5,7 @@ package dev.flutter.plugins.e2e; import android.content.Context; +import com.google.common.util.concurrent.SettableFuture; import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; @@ -13,13 +14,15 @@ import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.PluginRegistry.Registrar; import java.util.Map; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; /** E2EPlugin */ public class E2EPlugin implements MethodCallHandler, FlutterPlugin { private MethodChannel methodChannel; - public static CompletableFuture> testResults = new CompletableFuture<>(); + private static final SettableFuture> testResultsSettable = + SettableFuture.create(); + public static final Future> testResults = testResultsSettable; private static final String CHANNEL = "plugins.flutter.io/e2e"; @@ -49,7 +52,7 @@ public void onDetachedFromEngine(FlutterPluginBinding binding) { public void onMethodCall(MethodCall call, Result result) { if (call.method.equals("allTestsFinished")) { Map results = call.argument("results"); - testResults.complete(results); + testResultsSettable.set(results); result.success(null); } else { result.notImplemented(); From a3dbe7357c593e3788b7a2cdfbb6aa1cb1722706 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 30 Jun 2020 17:32:17 -0700 Subject: [PATCH 17/30] [connectivity] Endorse connectivity_for_web. (#2853) --- .../connectivity/connectivity/CHANGELOG.md | 4 +++ .../connectivity/example/lib/main.dart | 6 ++-- .../connectivity/example/web/favicon.png | Bin 0 -> 917 bytes .../example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../connectivity/example/web/index.html | 33 ++++++++++++++++++ .../connectivity/example/web/manifest.json | 23 ++++++++++++ .../connectivity/connectivity/pubspec.yaml | 7 ++-- 8 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 packages/connectivity/connectivity/example/web/favicon.png create mode 100644 packages/connectivity/connectivity/example/web/icons/Icon-192.png create mode 100644 packages/connectivity/connectivity/example/web/icons/Icon-512.png create mode 100644 packages/connectivity/connectivity/example/web/index.html create mode 100644 packages/connectivity/connectivity/example/web/manifest.json diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index 9325f1a7868f..3bb777104c0e 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.9 + +* Add support for `web` (by endorsing `connectivity_for_web` 0.3.0) + ## 0.4.8+6 * Update lower bound of dart dependency to 2.1.0. diff --git a/packages/connectivity/connectivity/example/lib/main.dart b/packages/connectivity/connectivity/example/lib/main.dart index 4ad30972679a..f8486165fa70 100644 --- a/packages/connectivity/connectivity/example/lib/main.dart +++ b/packages/connectivity/connectivity/example/lib/main.dart @@ -91,7 +91,7 @@ class _MyHomePageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Plugin example app'), + title: const Text('Connectivity example app'), ), body: Center(child: Text('Connection Status: $_connectionStatus')), ); @@ -103,7 +103,7 @@ class _MyHomePageState extends State { String wifiName, wifiBSSID, wifiIP; try { - if (Platform.isIOS) { + if (!kIsWeb && Platform.isIOS) { LocationAuthorizationStatus status = await _connectivity.getLocationServiceAuthorization(); if (status == LocationAuthorizationStatus.notDetermined) { @@ -125,7 +125,7 @@ class _MyHomePageState extends State { } try { - if (Platform.isIOS) { + if (!kIsWeb && Platform.isIOS) { LocationAuthorizationStatus status = await _connectivity.getLocationServiceAuthorization(); if (status == LocationAuthorizationStatus.notDetermined) { diff --git a/packages/connectivity/connectivity/example/web/favicon.png b/packages/connectivity/connectivity/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/packages/connectivity/connectivity/example/web/icons/Icon-192.png b/packages/connectivity/connectivity/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/packages/connectivity/connectivity/example/web/icons/Icon-512.png b/packages/connectivity/connectivity/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/packages/connectivity/connectivity/example/web/index.html b/packages/connectivity/connectivity/example/web/index.html new file mode 100644 index 000000000000..9b7a438f823a --- /dev/null +++ b/packages/connectivity/connectivity/example/web/index.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + example + + + + + + + + diff --git a/packages/connectivity/connectivity/example/web/manifest.json b/packages/connectivity/connectivity/example/web/manifest.json new file mode 100644 index 000000000000..8c012917dab7 --- /dev/null +++ b/packages/connectivity/connectivity/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index 9aaa2620f82c..c7ef8fe6e723 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/c # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.8+6 +version: 0.4.9 flutter: plugin: @@ -17,13 +17,16 @@ flutter: pluginClass: FLTConnectivityPlugin macos: default_package: connectivity_macos + web: + default_package: connectivity_for_web dependencies: flutter: sdk: flutter - meta: "^1.0.5" + meta: ^1.0.5 connectivity_platform_interface: ^1.0.2 connectivity_macos: ^0.1.0 + connectivity_for_web: ^0.3.0 dev_dependencies: flutter_test: From 40db092fc71cd15f5b03e03a045cbb95e7a71424 Mon Sep 17 00:00:00 2001 From: Jia Hao Date: Wed, 1 Jul 2020 22:20:34 +0800 Subject: [PATCH 18/30] [e2e] Bump version to 0.6.0 (#2855) Missed this earlier in #2854 --- packages/e2e/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e/pubspec.yaml b/packages/e2e/pubspec.yaml index 0d4bc99f64f3..25eeb3ce1374 100644 --- a/packages/e2e/pubspec.yaml +++ b/packages/e2e/pubspec.yaml @@ -1,6 +1,6 @@ name: e2e description: Runs tests that use the flutter_test API as integration tests. -version: 0.5.0+1 +version: 0.6.0 homepage: https://github.com/flutter/plugins/tree/master/packages/e2e environment: From d3ccc34855b77afae39f4078cb4add8bec9e6b2b Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Wed, 1 Jul 2020 15:53:53 -0700 Subject: [PATCH 19/30] [multiple] Improve video playback in image_picker example (#2819) This change adds small bugfixes to the following packages: * video_player_web: * Prevent parsing Blob URLs so Safari can play from a PickedFile. * Allow users to 'mute' videos by setting their volume to 0.0 (this enables auto-play in most modern browsers) * video_player: * Fix an issue where aspect ratio calculations failed when some of the video sizes were zero (happened in web for incorrect videos) * image_picker (example app): * Start videos in web muted so they can auto-play * Dispose video controllers when they're really not needed. This fixes a fatal crash in Safari (not so fatal in other browsers). --- .../image_picker/image_picker/CHANGELOG.md | 6 +++ .../image_picker/example/lib/main.dart | 16 +++++-- .../image_picker/image_picker/pubspec.yaml | 2 +- .../video_player/video_player/CHANGELOG.md | 4 ++ .../video_player/lib/video_player.dart | 2 +- .../video_player/video_player/pubspec.yaml | 2 +- .../video_player/test/video_player_test.dart | 42 +++++++++++++++++++ .../video_player_web/CHANGELOG.md | 5 +++ .../lib/video_player_web.dart | 21 +++++++--- .../video_player_web/pubspec.yaml | 2 +- 10 files changed, 89 insertions(+), 13 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 6b85f26daf33..0cba0c8d92cb 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.6.7+3 + +* Fixes to the example app: + * Make videos in web start muted. This allows auto-play across browsers. + * Prevent the app from disposing of video controllers too early. + ## 0.6.7+2 * iOS: Fixes unpresentable album/image picker if window's root view controller is already presenting other view controller. diff --git a/packages/image_picker/image_picker/example/lib/main.dart b/packages/image_picker/image_picker/example/lib/main.dart index dff2906edf87..ece8c45d9c8e 100755 --- a/packages/image_picker/image_picker/example/lib/main.dart +++ b/packages/image_picker/image_picker/example/lib/main.dart @@ -42,6 +42,7 @@ class _MyHomePageState extends State { dynamic _pickImageError; bool isVideo = false; VideoPlayerController _controller; + VideoPlayerController _toBeDisposed; String _retrieveDataError; final ImagePicker _picker = ImagePicker(); @@ -54,10 +55,16 @@ class _MyHomePageState extends State { await _disposeVideoController(); if (kIsWeb) { _controller = VideoPlayerController.network(file.path); + // In web, most browsers won't honor a programmatic call to .play + // if the video has a sound track (and is not muted). + // Mute the video so it auto-plays in web! + // This is not needed if the call to .play is the result of user + // interaction (clicking on a "play" button, for example). + await _controller.setVolume(0.0); } else { _controller = VideoPlayerController.file(File(file.path)); + await _controller.setVolume(1.0); } - await _controller.setVolume(1.0); await _controller.initialize(); await _controller.setLooping(true); await _controller.play(); @@ -114,10 +121,11 @@ class _MyHomePageState extends State { } Future _disposeVideoController() async { - if (_controller != null) { - await _controller.dispose(); - _controller = null; + if (_toBeDisposed != null) { + await _toBeDisposed.dispose(); } + _toBeDisposed = _controller; + _controller = null; } Widget _previewVideo() { diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 4f52b19c2659..eedecd46e1ee 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+2 +version: 0.6.7+3 flutter: plugin: diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 9928fe31c5a3..e3f49e736411 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.11+2 + +* Fix aspectRatio calculation when size.width or size.height are zero. + ## 0.10.11+1 * Post-v2 Android embedding cleanups. diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index f2f9289c1fda..a2290b2e5916 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -97,7 +97,7 @@ class VideoPlayerValue { /// Returns [size.width] / [size.height] when size is non-null, or `1.0.` when /// size is null or the aspect ratio would be less than or equal to 0.0. double get aspectRatio { - if (size == null) { + if (size == null || size.width == 0 || size.height == 0) { return 1.0; } final double aspectRatio = size.width / size.height; diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index f967cd07ef7f..03f71bf4f412 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for displaying inline video with other Flutter # 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.10.11+1 +version: 0.10.11+2 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart index ac8459d0c9e9..ae236def4e57 100644 --- a/packages/video_player/video_player/test/video_player_test.dart +++ b/packages/video_player/video_player/test/video_player_test.dart @@ -517,6 +517,48 @@ void main() { expect(exactCopy.toString(), original.toString()); }); + + group('aspectRatio', () { + test('640x480 -> 4:3', () { + final value = VideoPlayerValue( + size: Size(640, 480), + duration: Duration(seconds: 1), + ); + expect(value.aspectRatio, 4 / 3); + }); + + test('null size -> 1.0', () { + final value = VideoPlayerValue( + size: null, + duration: Duration(seconds: 1), + ); + expect(value.aspectRatio, 1.0); + }); + + test('height = 0 -> 1.0', () { + final value = VideoPlayerValue( + size: Size(640, 0), + duration: Duration(seconds: 1), + ); + expect(value.aspectRatio, 1.0); + }); + + test('width = 0 -> 1.0', () { + final value = VideoPlayerValue( + size: Size(0, 480), + duration: Duration(seconds: 1), + ); + expect(value.aspectRatio, 1.0); + }); + + test('negative aspect ratio -> 1.0', () { + final value = VideoPlayerValue( + size: Size(640, -480), + duration: Duration(seconds: 1), + ); + expect(value.aspectRatio, 1.0); + }); + }); }); test('VideoProgressColors', () { diff --git a/packages/video_player/video_player_web/CHANGELOG.md b/packages/video_player/video_player_web/CHANGELOG.md index cd977c335d62..9c500e951122 100644 --- a/packages/video_player/video_player_web/CHANGELOG.md +++ b/packages/video_player/video_player_web/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.1.3+2 + +* Allow users to set the 'muted' attribute on video elements by setting their volume to 0. +* Do not parse URIs on 'network' videos to not break blobs (Safari). + ## 0.1.3+1 * Remove Android folder from `video_player_web`. diff --git a/packages/video_player/video_player_web/lib/video_player_web.dart b/packages/video_player/video_player_web/lib/video_player_web.dart index 039c3ce65a7e..3a849f45e0c1 100644 --- a/packages/video_player/video_player_web/lib/video_player_web.dart +++ b/packages/video_player/video_player_web/lib/video_player_web.dart @@ -66,10 +66,12 @@ class VideoPlayerPlugin extends VideoPlayerPlatform { final int textureId = _textureCounter; _textureCounter++; - Uri uri; + String uri; switch (dataSource.sourceType) { case DataSourceType.network: - uri = Uri.parse(dataSource.uri); + // Do NOT modify the incoming uri, it can be a Blob, and Safari doesn't + // like blobs that have changed. + uri = dataSource.uri; break; case DataSourceType.asset: String assetUrl = dataSource.asset; @@ -79,7 +81,7 @@ class VideoPlayerPlugin extends VideoPlayerPlatform { // 'webOnlyAssetManager' is only in the web version of dart:ui // ignore: undefined_prefixed_name assetUrl = ui.webOnlyAssetManager.getAssetUrl(assetUrl); - uri = Uri.parse(assetUrl); + uri = assetUrl; break; case DataSourceType.file: return Future.error(UnimplementedError( @@ -145,18 +147,21 @@ class _VideoPlayer { final StreamController eventController = StreamController(); - final Uri uri; + final String uri; final int textureId; VideoElement videoElement; bool isInitialized = false; void initialize() { videoElement = VideoElement() - ..src = uri.toString() + ..src = uri ..autoplay = false ..controls = false ..style.border = 'none'; + // Allows Safari iOS to play the video inline + videoElement.setAttribute('playsinline', 'true'); + // TODO(hterkelsen): Use initialization parameters once they are available // ignore: undefined_prefixed_name ui.platformViewRegistry.registerViewFactory( @@ -218,6 +223,12 @@ class _VideoPlayer { } void setVolume(double value) { + // TODO: Do we need to expose a "muted" API? https://github.com/flutter/flutter/issues/60721 + if (value > 0.0) { + videoElement.muted = false; + } else { + videoElement.muted = true; + } videoElement.volume = value; } diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml index 523d5a79a75b..891430d7483b 100644 --- a/packages/video_player/video_player_web/pubspec.yaml +++ b/packages/video_player/video_player_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/v # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.3+1 +version: 0.1.3+2 flutter: plugin: From a5db6e08042b3f6a44e554fc384c76b9e18c7c62 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Mon, 6 Jul 2020 14:42:10 -0500 Subject: [PATCH 20/30] [image_picker] updated VALID_ARCHS to support iPhone simulator (#2761) --- AUTHORS | 1 + packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ packages/image_picker/image_picker/ios/image_picker.podspec | 2 +- packages/image_picker/image_picker/pubspec.yaml | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 17ede94e79ba..51345c9a3481 100644 --- a/AUTHORS +++ b/AUTHORS @@ -58,3 +58,4 @@ Théo Champion Kazuki Yamaguchi Eitan Schwartz Chris Rutkowski +Juan Alvarez diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 0cba0c8d92cb..0cec3a32b5f1 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+4 + +* Support iOS simulator x86_64 architecture. + ## 0.6.7+3 * Fixes to the example app: diff --git a/packages/image_picker/image_picker/ios/image_picker.podspec b/packages/image_picker/image_picker/ios/image_picker.podspec index 47020f71711c..5c13cef272dd 100644 --- a/packages/image_picker/image_picker/ios/image_picker.podspec +++ b/packages/image_picker/image_picker/ios/image_picker.podspec @@ -18,7 +18,7 @@ Downloaded by pub (not CocoaPods). s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' s.platform = :ios, '8.0' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => 'armv7 arm64 x86_64' } + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } s.test_spec 'Tests' do |test_spec| test_spec.source_files = 'Tests/**/*' diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index eedecd46e1ee..06da5297d80c 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+3 +version: 0.6.7+4 flutter: plugin: From 65e7bdb699e3ae09091ac8a52d556e575fee2c3b Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Wed, 8 Jul 2020 02:36:39 +1200 Subject: [PATCH 21/30] [url_launcher_linux] Add Linux url_launcher plugin (#2857) Adds url_launcher_linux, the federated implementation of url_launcher. Not yet endorsed by url_launcher Part of https://github.com/flutter/flutter/issues/41721 --- .ci/Dockerfile-LinuxDesktop | 8 + .../url_launcher_linux/.gitignore | 3 + .../url_launcher/url_launcher_linux/.metadata | 10 + .../url_launcher_linux/CHANGELOG.md | 2 + .../url_launcher/url_launcher_linux/LICENSE | 27 +++ .../url_launcher/url_launcher_linux/README.md | 22 ++ .../url_launcher_linux/example/.gitignore | 44 ++++ .../url_launcher_linux/example/.metadata | 10 + .../url_launcher_linux/example/README.md | 8 + .../url_launcher_linux/example/lib/main.dart | 194 ++++++++++++++++++ .../example/linux/.gitignore | 1 + .../example/linux/CMakeLists.txt | 95 +++++++++ .../example/linux/flutter/CMakeLists.txt | 86 ++++++++ .../flutter/generated_plugin_registrant.cc | 13 ++ .../flutter/generated_plugin_registrant.h | 13 ++ .../linux/flutter/generated_plugins.cmake | 16 ++ .../url_launcher_linux/example/linux/main.cc | 6 + .../example/linux/my_application.cc | 44 ++++ .../example/linux/my_application.h | 18 ++ .../url_launcher_linux/example/pubspec.yaml | 18 ++ .../example/test_driver/url_launcher_e2e.dart | 23 +++ .../test_driver/url_launcher_e2e_test.dart | 15 ++ .../url_launcher_linux/ios/.gitignore | 37 ++++ .../ios/url_launcher_linux.podspec | 22 ++ .../lib/url_launcher_linux.dart | 3 + .../url_launcher_linux/linux/CMakeLists.txt | 17 ++ .../url_launcher_linux/url_launcher_plugin.h | 31 +++ .../linux/url_launcher_plugin.cc | 148 +++++++++++++ .../url_launcher_linux/pubspec.yaml | 19 ++ 29 files changed, 953 insertions(+) create mode 100644 packages/url_launcher/url_launcher_linux/.gitignore create mode 100644 packages/url_launcher/url_launcher_linux/.metadata create mode 100644 packages/url_launcher/url_launcher_linux/CHANGELOG.md create mode 100644 packages/url_launcher/url_launcher_linux/LICENSE create mode 100644 packages/url_launcher/url_launcher_linux/README.md create mode 100644 packages/url_launcher/url_launcher_linux/example/.gitignore create mode 100644 packages/url_launcher/url_launcher_linux/example/.metadata create mode 100644 packages/url_launcher/url_launcher_linux/example/README.md create mode 100644 packages/url_launcher/url_launcher_linux/example/lib/main.dart create mode 100644 packages/url_launcher/url_launcher_linux/example/linux/.gitignore create mode 100644 packages/url_launcher/url_launcher_linux/example/linux/CMakeLists.txt create mode 100644 packages/url_launcher/url_launcher_linux/example/linux/flutter/CMakeLists.txt create mode 100644 packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugin_registrant.cc create mode 100644 packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugin_registrant.h create mode 100644 packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugins.cmake create mode 100644 packages/url_launcher/url_launcher_linux/example/linux/main.cc create mode 100644 packages/url_launcher/url_launcher_linux/example/linux/my_application.cc create mode 100644 packages/url_launcher/url_launcher_linux/example/linux/my_application.h create mode 100644 packages/url_launcher/url_launcher_linux/example/pubspec.yaml create mode 100644 packages/url_launcher/url_launcher_linux/example/test_driver/url_launcher_e2e.dart create mode 100644 packages/url_launcher/url_launcher_linux/example/test_driver/url_launcher_e2e_test.dart create mode 100644 packages/url_launcher/url_launcher_linux/ios/.gitignore create mode 100644 packages/url_launcher/url_launcher_linux/ios/url_launcher_linux.podspec create mode 100644 packages/url_launcher/url_launcher_linux/lib/url_launcher_linux.dart create mode 100644 packages/url_launcher/url_launcher_linux/linux/CMakeLists.txt create mode 100644 packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h create mode 100644 packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc create mode 100644 packages/url_launcher/url_launcher_linux/pubspec.yaml diff --git a/.ci/Dockerfile-LinuxDesktop b/.ci/Dockerfile-LinuxDesktop index 25924d4ea8d9..63e4516e26fc 100644 --- a/.ci/Dockerfile-LinuxDesktop +++ b/.ci/Dockerfile-LinuxDesktop @@ -21,3 +21,11 @@ RUN sudo apt-get install -y xvfb libegl1-mesa RUN sudo apt-get install -y clang cmake ninja-build file pkg-config # Install necessary libraries. RUN sudo apt-get install -y libgtk-3-dev + +# Add repo for Google Chrome and install it, for url_launcher tests. +RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - +RUN echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee /etc/apt/sources.list.d/google-chrome.list +RUN sudo apt-get update && sudo apt-get install -y --no-install-recommends google-chrome-stable +# Make it the default so http: has a handler. +RUN sudo apt-get install -y xdg-utils +RUN xdg-settings set default-web-browser google-chrome.desktop diff --git a/packages/url_launcher/url_launcher_linux/.gitignore b/packages/url_launcher/url_launcher_linux/.gitignore new file mode 100644 index 000000000000..53e92cc4181f --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/.gitignore @@ -0,0 +1,3 @@ +.packages +.flutter-plugins +pubspec.lock diff --git a/packages/url_launcher/url_launcher_linux/.metadata b/packages/url_launcher/url_launcher_linux/.metadata new file mode 100644 index 000000000000..457a92ae1645 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 4b12050112afd581ddf53df848275fa681f908f3 + channel: master + +project_type: plugin diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md new file mode 100644 index 000000000000..18ba82adbe4d --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md @@ -0,0 +1,2 @@ +# 0.0.1 +* The initial implementation of url_launcher for Linux diff --git a/packages/url_launcher/url_launcher_linux/LICENSE b/packages/url_launcher/url_launcher_linux/LICENSE new file mode 100644 index 000000000000..0c91662b3f2f --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/LICENSE @@ -0,0 +1,27 @@ +// Copyright 2020 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/url_launcher/url_launcher_linux/README.md b/packages/url_launcher/url_launcher_linux/README.md new file mode 100644 index 000000000000..9b16bdfad813 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/README.md @@ -0,0 +1,22 @@ +# url_launcher_linux + +The Linux implementation of [`url_launcher`][1]. + +## Usage + +### Import the package + +This package is an unendorsed Linux implementation of `url_launcher`. + +In order to use this now, you'll need to depend on `url_launcher_linux`. +When this package is endorsed it will be automatically used by the `url_launcher` package and you can switch to that API. + +```yaml +... +dependencies: + ... + url_launcher_linux: ^0.0.1 + ... +``` + +[1]: ../ diff --git a/packages/url_launcher/url_launcher_linux/example/.gitignore b/packages/url_launcher/url_launcher_linux/example/.gitignore new file mode 100644 index 000000000000..f3c205341e7d --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/packages/url_launcher/url_launcher_linux/example/.metadata b/packages/url_launcher/url_launcher_linux/example/.metadata new file mode 100644 index 000000000000..99b1a7456d66 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 4b12050112afd581ddf53df848275fa681f908f3 + channel: master + +project_type: app diff --git a/packages/url_launcher/url_launcher_linux/example/README.md b/packages/url_launcher/url_launcher_linux/example/README.md new file mode 100644 index 000000000000..28dd90d71700 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/README.md @@ -0,0 +1,8 @@ +# url_launcher_example + +Demonstrates how to use the url_launcher plugin. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/url_launcher/url_launcher_linux/example/lib/main.dart b/packages/url_launcher/url_launcher_linux/example/lib/main.dart new file mode 100644 index 000000000000..b5cce7482d07 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/lib/main.dart @@ -0,0 +1,194 @@ +// Copyright 2017 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. + +// ignore_for_file: public_member_api_docs + +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'URL Launcher', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: MyHomePage(title: 'URL Launcher'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + Future _launched; + String _phone = ''; + + Future _launchInBrowser(String url) async { + if (await canLaunch(url)) { + await launch( + url, + forceSafariVC: false, + forceWebView: false, + headers: {'my_header_key': 'my_header_value'}, + ); + } else { + throw 'Could not launch $url'; + } + } + + Future _launchInWebViewOrVC(String url) async { + if (await canLaunch(url)) { + await launch( + url, + forceSafariVC: true, + forceWebView: true, + headers: {'my_header_key': 'my_header_value'}, + ); + } else { + throw 'Could not launch $url'; + } + } + + Future _launchInWebViewWithJavaScript(String url) async { + if (await canLaunch(url)) { + await launch( + url, + forceSafariVC: true, + forceWebView: true, + enableJavaScript: true, + ); + } else { + throw 'Could not launch $url'; + } + } + + Future _launchInWebViewWithDomStorage(String url) async { + if (await canLaunch(url)) { + await launch( + url, + forceSafariVC: true, + forceWebView: true, + enableDomStorage: true, + ); + } else { + throw 'Could not launch $url'; + } + } + + Future _launchUniversalLinkIos(String url) async { + if (await canLaunch(url)) { + final bool nativeAppLaunchSucceeded = await launch( + url, + forceSafariVC: false, + universalLinksOnly: true, + ); + if (!nativeAppLaunchSucceeded) { + await launch( + url, + forceSafariVC: true, + ); + } + } + } + + Widget _launchStatus(BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return const Text(''); + } + } + + Future _makePhoneCall(String url) async { + if (await canLaunch(url)) { + await launch(url); + } else { + throw 'Could not launch $url'; + } + } + + @override + Widget build(BuildContext context) { + const String toLaunch = 'https://www.cylog.org/headers/'; + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: ListView( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: TextField( + onChanged: (String text) => _phone = text, + decoration: const InputDecoration( + hintText: 'Input the phone number to launch')), + ), + RaisedButton( + onPressed: () => setState(() { + _launched = _makePhoneCall('tel:$_phone'); + }), + child: const Text('Make phone call'), + ), + const Padding( + padding: EdgeInsets.all(16.0), + child: Text(toLaunch), + ), + RaisedButton( + onPressed: () => setState(() { + _launched = _launchInBrowser(toLaunch); + }), + child: const Text('Launch in browser'), + ), + const Padding(padding: EdgeInsets.all(16.0)), + RaisedButton( + onPressed: () => setState(() { + _launched = _launchInWebViewOrVC(toLaunch); + }), + child: const Text('Launch in app'), + ), + RaisedButton( + onPressed: () => setState(() { + _launched = _launchInWebViewWithJavaScript(toLaunch); + }), + child: const Text('Launch in app(JavaScript ON)'), + ), + RaisedButton( + onPressed: () => setState(() { + _launched = _launchInWebViewWithDomStorage(toLaunch); + }), + child: const Text('Launch in app(DOM storage ON)'), + ), + const Padding(padding: EdgeInsets.all(16.0)), + RaisedButton( + onPressed: () => setState(() { + _launched = _launchUniversalLinkIos(toLaunch); + }), + child: const Text( + 'Launch a universal link in a native app, fallback to Safari.(Youtube)'), + ), + const Padding(padding: EdgeInsets.all(16.0)), + FutureBuilder(future: _launched, builder: _launchStatus), + ], + ), + ], + ), + ); + } +} diff --git a/packages/url_launcher/url_launcher_linux/example/linux/.gitignore b/packages/url_launcher/url_launcher_linux/example/linux/.gitignore new file mode 100644 index 000000000000..d3896c98444f --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/packages/url_launcher/url_launcher_linux/example/linux/CMakeLists.txt b/packages/url_launcher/url_launcher_linux/example/linux/CMakeLists.txt new file mode 100644 index 000000000000..0236a8806654 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/linux/CMakeLists.txt @@ -0,0 +1,95 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/packages/url_launcher/url_launcher_linux/example/linux/flutter/CMakeLists.txt b/packages/url_launcher/url_launcher_linux/example/linux/flutter/CMakeLists.txt new file mode 100644 index 000000000000..94f43ff7fa6a --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + linux-x64 ${CMAKE_BUILD_TYPE} +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugin_registrant.cc b/packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000000..026851fa2f96 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#include "generated_plugin_registrant.h" + +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); +} diff --git a/packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugin_registrant.h b/packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000000..9bf7478940c1 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugins.cmake b/packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000000..1fc8ed344297 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,16 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + url_launcher_linux +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/packages/url_launcher/url_launcher_linux/example/linux/main.cc b/packages/url_launcher/url_launcher_linux/example/linux/main.cc new file mode 100644 index 000000000000..e7c5c5437037 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc b/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc new file mode 100644 index 000000000000..c2357f17ea9c --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc @@ -0,0 +1,44 @@ +#include "my_application.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), nullptr)); +} diff --git a/packages/url_launcher/url_launcher_linux/example/linux/my_application.h b/packages/url_launcher/url_launcher_linux/example/linux/my_application.h new file mode 100644 index 000000000000..72271d5e4170 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml new file mode 100644 index 000000000000..a4d08f30d6b4 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml @@ -0,0 +1,18 @@ +name: url_launcher_example +description: Demonstrates how to use the url_launcher plugin. + +dependencies: + flutter: + sdk: flutter + url_launcher: any + url_launcher_linux: + path: ../ + +dev_dependencies: + e2e: "^0.2.0" + flutter_driver: + sdk: flutter + pedantic: ^1.8.0 + +flutter: + uses-material-design: true diff --git a/packages/url_launcher/url_launcher_linux/example/test_driver/url_launcher_e2e.dart b/packages/url_launcher/url_launcher_linux/example/test_driver/url_launcher_e2e.dart new file mode 100644 index 000000000000..516835cec33b --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/test_driver/url_launcher_e2e.dart @@ -0,0 +1,23 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:e2e/e2e.dart'; +import 'package:url_launcher/url_launcher.dart'; + +void main() { + E2EWidgetsFlutterBinding.ensureInitialized(); + + test('canLaunch', () async { + expect(await canLaunch('randomstring'), false); + + // Generally all devices should have some default browser. + expect(await canLaunch('http://flutter.dev'), true); + + // Desktop will not necessarily support sms:. + + // tel: and mailto: links may not be openable on every device. iOS + // simulators notably can't open these link types. + }); +} diff --git a/packages/url_launcher/url_launcher_linux/example/test_driver/url_launcher_e2e_test.dart b/packages/url_launcher/url_launcher_linux/example/test_driver/url_launcher_e2e_test.dart new file mode 100644 index 000000000000..1bcd0d37f450 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/example/test_driver/url_launcher_e2e_test.dart @@ -0,0 +1,15 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. 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:io'; + +import 'package:flutter_driver/flutter_driver.dart'; + +Future main() async { + final FlutterDriver driver = await FlutterDriver.connect(); + final String result = + await driver.requestData(null, timeout: const Duration(minutes: 1)); + await driver.close(); + exit(result == 'pass' ? 0 : 1); +} diff --git a/packages/url_launcher/url_launcher_linux/ios/.gitignore b/packages/url_launcher/url_launcher_linux/ios/.gitignore new file mode 100644 index 000000000000..aa479fd3ce8a --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/ios/.gitignore @@ -0,0 +1,37 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m + +.generated/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/Generated.xcconfig +/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/packages/url_launcher/url_launcher_linux/ios/url_launcher_linux.podspec b/packages/url_launcher/url_launcher_linux/ios/url_launcher_linux.podspec new file mode 100644 index 000000000000..1359fd403d8d --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/ios/url_launcher_linux.podspec @@ -0,0 +1,22 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint url_launcher_linux.podspec' to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'url_launcher_linux' + s.version = '0.0.1' + s.summary = 'url_launcher_linux iOS stub' + s.description = <<-DESC + No-op implementation of the Linux url_launcher plugin to avoid build issues on iOS + DESC + s.homepage = 'https://github.com/flutter/plugins' + s.license = { :type => 'BSD', :file => '../LICENSE' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux' } + s.dependency 'Flutter' + s.platform = :ios, '8.0' + + # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } + s.swift_version = '5.0' +end diff --git a/packages/url_launcher/url_launcher_linux/lib/url_launcher_linux.dart b/packages/url_launcher/url_launcher_linux/lib/url_launcher_linux.dart new file mode 100644 index 000000000000..18f7af1836ce --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/lib/url_launcher_linux.dart @@ -0,0 +1,3 @@ +// The url_launcher_platform_interface defaults to MethodChannelUrlLauncher +// as its instance, which is all the Linux implementation needs. This file +// is here to silence warnings when publishing to pub. diff --git a/packages/url_launcher/url_launcher_linux/linux/CMakeLists.txt b/packages/url_launcher/url_launcher_linux/linux/CMakeLists.txt new file mode 100644 index 000000000000..1403d0cbc9e4 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/linux/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.10) +set(PROJECT_NAME "url_launcher_linux") +project(${PROJECT_NAME} LANGUAGES CXX) + +set(PLUGIN_NAME "${PROJECT_NAME}_plugin") + +add_library(${PLUGIN_NAME} SHARED + "url_launcher_plugin.cc" +) +apply_standard_settings(${PLUGIN_NAME}) +set_target_properties(${PLUGIN_NAME} PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) +target_include_directories(${PLUGIN_NAME} INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) +target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) diff --git a/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h b/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h new file mode 100644 index 000000000000..efcfe62e706a --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h @@ -0,0 +1,31 @@ +// Copyright 2020 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. + +#ifndef PACKAGES_URL_LAUNCHER_URL_LAUNCHER_LINUX_LINUX_INCLUDE_URL_LAUNCHER_URL_LAUNCHER_PLUGIN_H_ +#define PACKAGES_URL_LAUNCHER_URL_LAUNCHER_LINUX_LINUX_INCLUDE_URL_LAUNCHER_URL_LAUNCHER_PLUGIN_H_ + +// A plugin to launch URLs. + +#include + +G_BEGIN_DECLS + +#ifdef FLUTTER_PLUGIN_IMPL +#define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) +#else +#define FLUTTER_PLUGIN_EXPORT +#endif + +G_DECLARE_FINAL_TYPE(FlUrlLauncherPlugin, fl_url_launcher_plugin, FL, + URL_LAUNCHER_PLUGIN, GObject) + +FLUTTER_PLUGIN_EXPORT FlUrlLauncherPlugin* fl_url_launcher_plugin_new( + FlPluginRegistrar* registrar); + +FLUTTER_PLUGIN_EXPORT void url_launcher_plugin_register_with_registrar( + FlPluginRegistrar* registrar); + +G_END_DECLS + +#endif // PACKAGES_URL_LAUNCHER_URL_LAUNCHER_LINUX_LINUX_INCLUDE_URL_LAUNCHER_URL_LAUNCHER_PLUGIN_H_ diff --git a/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc b/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc new file mode 100644 index 000000000000..592bb965e83f --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc @@ -0,0 +1,148 @@ +// Copyright 2020 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. + +#include "include/url_launcher_linux/url_launcher_plugin.h" + +#include +#include + +// See url_launcher_channel.dart for documentation. +const char kChannelName[] = "plugins.flutter.io/url_launcher"; +const char kBadArgumentsError[] = "Bad Arguments"; +const char kLaunchError[] = "Launch Error"; +const char kCanLaunchMethod[] = "canLaunch"; +const char kLaunchMethod[] = "launch"; +const char kUrlKey[] = "url"; + +struct _FlUrlLauncherPlugin { + GObject parent_instance; + + FlPluginRegistrar* registrar; + + // Connection to Flutter engine. + FlMethodChannel* channel; +}; + +G_DEFINE_TYPE(FlUrlLauncherPlugin, fl_url_launcher_plugin, g_object_get_type()) + +// Gets the URL from the arguments or generates an error. +static gchar* get_url(FlValue* args, GError** error) { + if (fl_value_get_type(args) != FL_VALUE_TYPE_MAP) { + g_set_error(error, 0, 0, "Argument map missing or malformed"); + return nullptr; + } + FlValue* url_value = fl_value_lookup_string(args, kUrlKey); + if (url_value == nullptr) { + g_set_error(error, 0, 0, "Missing URL"); + return nullptr; + } + + return g_strdup(fl_value_get_string(url_value)); +} + +// Called to check if a URL can be launched. +static FlMethodResponse* can_launch(FlUrlLauncherPlugin* self, FlValue* args) { + g_autoptr(GError) error = nullptr; + g_autofree gchar* url = get_url(args, &error); + if (url == nullptr) { + return FL_METHOD_RESPONSE(fl_method_error_response_new( + kBadArgumentsError, error->message, nullptr)); + } + + gboolean is_launchable = FALSE; + g_autofree gchar* scheme = g_uri_parse_scheme(url); + if (scheme != nullptr) { + g_autoptr(GAppInfo) app_info = + g_app_info_get_default_for_uri_scheme(scheme); + is_launchable = app_info != nullptr; + } + + g_autoptr(FlValue) result = fl_value_new_bool(is_launchable); + return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); +} + +// Called when a URL should launch. +static FlMethodResponse* launch(FlUrlLauncherPlugin* self, FlValue* args) { + g_autoptr(GError) error = nullptr; + g_autofree gchar* url = get_url(args, &error); + if (url == nullptr) { + return FL_METHOD_RESPONSE(fl_method_error_response_new( + kBadArgumentsError, error->message, nullptr)); + } + + FlView* view = fl_plugin_registrar_get_view(self->registrar); + gboolean launched; + if (view != nullptr) { + GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); + launched = gtk_show_uri_on_window(window, url, GDK_CURRENT_TIME, &error); + } else { + launched = g_app_info_launch_default_for_uri(url, nullptr, &error); + } + if (!launched) { + g_autofree gchar* message = + g_strdup_printf("Failed to launch URL: %s", error->message); + return FL_METHOD_RESPONSE( + fl_method_error_response_new(kLaunchError, message, nullptr)); + } + + g_autoptr(FlValue) result = fl_value_new_bool(TRUE); + return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); +} + +// Called when a method call is received from Flutter. +static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, + gpointer user_data) { + FlUrlLauncherPlugin* self = FL_URL_LAUNCHER_PLUGIN(user_data); + + const gchar* method = fl_method_call_get_name(method_call); + FlValue* args = fl_method_call_get_args(method_call); + + g_autoptr(FlMethodResponse) response = nullptr; + if (strcmp(method, kCanLaunchMethod) == 0) + response = can_launch(self, args); + else if (strcmp(method, kLaunchMethod) == 0) + response = launch(self, args); + else + response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); + + g_autoptr(GError) error = nullptr; + if (!fl_method_call_respond(method_call, response, &error)) + g_warning("Failed to send method call response: %s", error->message); +} + +static void fl_url_launcher_plugin_dispose(GObject* object) { + FlUrlLauncherPlugin* self = FL_URL_LAUNCHER_PLUGIN(object); + + g_clear_object(&self->registrar); + g_clear_object(&self->channel); + + G_OBJECT_CLASS(fl_url_launcher_plugin_parent_class)->dispose(object); +} + +static void fl_url_launcher_plugin_class_init(FlUrlLauncherPluginClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_url_launcher_plugin_dispose; +} + +FlUrlLauncherPlugin* fl_url_launcher_plugin_new(FlPluginRegistrar* registrar) { + FlUrlLauncherPlugin* self = FL_URL_LAUNCHER_PLUGIN( + g_object_new(fl_url_launcher_plugin_get_type(), nullptr)); + + self->registrar = FL_PLUGIN_REGISTRAR(g_object_ref(registrar)); + + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + self->channel = + fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), + kChannelName, FL_METHOD_CODEC(codec)); + fl_method_channel_set_method_call_handler(self->channel, method_call_cb, + g_object_ref(self), g_object_unref); + + return self; +} + +static void fl_url_launcher_plugin_init(FlUrlLauncherPlugin* self) {} + +void url_launcher_plugin_register_with_registrar(FlPluginRegistrar* registrar) { + FlUrlLauncherPlugin* plugin = fl_url_launcher_plugin_new(registrar); + g_object_unref(plugin); +} diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml new file mode 100644 index 000000000000..2662176ca9e6 --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml @@ -0,0 +1,19 @@ +name: url_launcher_linux +description: Linux implementation of the url_launcher plugin. +version: 0.0.1 +homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux + +flutter: + plugin: + platforms: + linux: + pluginClass: UrlLauncherPlugin + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.8 <2.0.0" + +dependencies: + flutter: + sdk: flutter + From 8db69f34b6e17c4256c48934bbbf03821f478f68 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 7 Jul 2020 11:32:38 -0700 Subject: [PATCH 22/30] [url_launcher] Endorse url_launcher_linux (#2863) Adds an endorsement for url_launcher_linux, so that Linux is supported automatically. Part of https://github.com/flutter/flutter/issues/41721 --- .../url_launcher/url_launcher/CHANGELOG.md | 6 +- .../url_launcher/example/linux/CMakeLists.txt | 95 +++++++++++++++++++ .../example/linux/flutter/CMakeLists.txt | 86 +++++++++++++++++ .../flutter/generated_plugin_registrant.cc | 13 +++ .../flutter/generated_plugin_registrant.h | 13 +++ .../linux/flutter/generated_plugins.cmake | 16 ++++ .../url_launcher/example/linux/main.cc | 6 ++ .../example/linux/my_application.cc | 44 +++++++++ .../example/linux/my_application.h | 18 ++++ .../example/test_driver/url_launcher_e2e.dart | 9 +- .../url_launcher/url_launcher/pubspec.yaml | 5 +- .../url_launcher_linux/CHANGELOG.md | 3 + .../url_launcher/url_launcher_linux/README.md | 18 +++- .../url_launcher_linux/pubspec.yaml | 2 +- script/build_all_plugins_app.sh | 1 + 15 files changed, 327 insertions(+), 8 deletions(-) create mode 100644 packages/url_launcher/url_launcher/example/linux/CMakeLists.txt create mode 100644 packages/url_launcher/url_launcher/example/linux/flutter/CMakeLists.txt create mode 100644 packages/url_launcher/url_launcher/example/linux/flutter/generated_plugin_registrant.cc create mode 100644 packages/url_launcher/url_launcher/example/linux/flutter/generated_plugin_registrant.h create mode 100644 packages/url_launcher/url_launcher/example/linux/flutter/generated_plugins.cmake create mode 100644 packages/url_launcher/url_launcher/example/linux/main.cc create mode 100644 packages/url_launcher/url_launcher/example/linux/my_application.cc create mode 100644 packages/url_launcher/url_launcher/example/linux/my_application.h diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 6b1327a2da52..a5364726bee3 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.5.0 + +* Support Linux by default. + ## 5.4.11 * Add documentation in README suggesting how to properly encode urls with special characters. @@ -46,7 +50,7 @@ ## 5.4.0 -* Support macos by default. +* Support macOS by default. ## 5.3.0 diff --git a/packages/url_launcher/url_launcher/example/linux/CMakeLists.txt b/packages/url_launcher/url_launcher/example/linux/CMakeLists.txt new file mode 100644 index 000000000000..0236a8806654 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/linux/CMakeLists.txt @@ -0,0 +1,95 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/packages/url_launcher/url_launcher/example/linux/flutter/CMakeLists.txt b/packages/url_launcher/url_launcher/example/linux/flutter/CMakeLists.txt new file mode 100644 index 000000000000..94f43ff7fa6a --- /dev/null +++ b/packages/url_launcher/url_launcher/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + linux-x64 ${CMAKE_BUILD_TYPE} +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/packages/url_launcher/url_launcher/example/linux/flutter/generated_plugin_registrant.cc b/packages/url_launcher/url_launcher/example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000000..026851fa2f96 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#include "generated_plugin_registrant.h" + +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); +} diff --git a/packages/url_launcher/url_launcher/example/linux/flutter/generated_plugin_registrant.h b/packages/url_launcher/url_launcher/example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000000..9bf7478940c1 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/packages/url_launcher/url_launcher/example/linux/flutter/generated_plugins.cmake b/packages/url_launcher/url_launcher/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000000..1fc8ed344297 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,16 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + url_launcher_linux +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/packages/url_launcher/url_launcher/example/linux/main.cc b/packages/url_launcher/url_launcher/example/linux/main.cc new file mode 100644 index 000000000000..e7c5c5437037 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/packages/url_launcher/url_launcher/example/linux/my_application.cc b/packages/url_launcher/url_launcher/example/linux/my_application.cc new file mode 100644 index 000000000000..c2357f17ea9c --- /dev/null +++ b/packages/url_launcher/url_launcher/example/linux/my_application.cc @@ -0,0 +1,44 @@ +#include "my_application.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), nullptr)); +} diff --git a/packages/url_launcher/url_launcher/example/linux/my_application.h b/packages/url_launcher/url_launcher/example/linux/my_application.h new file mode 100644 index 000000000000..72271d5e4170 --- /dev/null +++ b/packages/url_launcher/url_launcher/example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e.dart b/packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e.dart index e1d75f93b326..6cf1168c81bd 100644 --- a/packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e.dart +++ b/packages/url_launcher/url_launcher/example/test_driver/url_launcher_e2e.dart @@ -2,6 +2,9 @@ // for details. 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:io' show Platform; + +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter_test/flutter_test.dart'; import 'package:e2e/e2e.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -15,8 +18,10 @@ void main() { // Generally all devices should have some default browser. expect(await canLaunch('http://flutter.dev'), true); - // Generally all devices should have some default SMS app. - expect(await canLaunch('sms:5555555555'), true); + // SMS handling is available by default on most platforms. + if (kIsWeb || !Platform.isLinux) { + expect(await canLaunch('sms:5555555555'), true); + } // tel: and mailto: links may not be openable on every device. iOS // simulators notably can't open these link types. diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 08ac3f9f8b80..299de938165f 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 5.4.11 +version: 5.5.0 flutter: plugin: @@ -14,6 +14,8 @@ flutter: pluginClass: FLTURLLauncherPlugin web: default_package: url_launcher_web + linux: + default_package: url_laucher_linux macos: default_package: url_laucher_macos @@ -27,6 +29,7 @@ dependencies: # TODO(amirh): Revisit this (either update this part in the design or the pub tool). # https://github.com/flutter/flutter/issues/46264 url_launcher_web: ^0.1.0+1 + url_launcher_linux: ^0.0.1 url_launcher_macos: ^0.0.1 dev_dependencies: diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md index 18ba82adbe4d..e03b1d387c55 100644 --- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md @@ -1,2 +1,5 @@ +# 0.0.1+1 +* README update for endorsement by url_launcher. + # 0.0.1 * The initial implementation of url_launcher for Linux diff --git a/packages/url_launcher/url_launcher_linux/README.md b/packages/url_launcher/url_launcher_linux/README.md index 9b16bdfad813..0474c58da40e 100644 --- a/packages/url_launcher/url_launcher_linux/README.md +++ b/packages/url_launcher/url_launcher_linux/README.md @@ -6,10 +6,22 @@ The Linux implementation of [`url_launcher`][1]. ### Import the package -This package is an unendorsed Linux implementation of `url_launcher`. +This package has been endorsed, meaning that you only need to add `url_launcher` +as a dependency in your `pubspec.yaml`. It will be automatically included in your app +when you depend on `package:url_launcher`. -In order to use this now, you'll need to depend on `url_launcher_linux`. -When this package is endorsed it will be automatically used by the `url_launcher` package and you can switch to that API. +This is what the above means to your `pubspec.yaml`: + +```yaml +... +dependencies: + ... + url_launcher: ^5.5.0 + ... +``` + +If you wish to use the Linux package only, you can add `url_launcher_linux` as a +dependency: ```yaml ... diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml index 2662176ca9e6..74c2968aba69 100644 --- a/packages/url_launcher/url_launcher_linux/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: url_launcher_linux description: Linux implementation of the url_launcher plugin. -version: 0.0.1 +version: 0.0.1+1 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux flutter: diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 262c4ed7b1d3..961cecce7903 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -31,6 +31,7 @@ readonly EXCLUDED_PLUGINS_LIST=( "shared_preferences_platform_interface" "shared_preferences_web" "shared_preferences_windows" + "url_launcher_linux" "url_launcher_macos" "url_launcher_platform_interface" "url_launcher_web" From f3f7e8c02ab6979a6582fcfcac12eaa002d577da Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 7 Jul 2020 18:33:49 -0700 Subject: [PATCH 23/30] [shared_preferences_linux] Add iOS stub (#2865) Add missing iOS stub to shared_preferences_linux --- .../shared_preferences_linux/CHANGELOG.md | 3 +++ .../ios/shared_preferences_linux.podspec | 22 +++++++++++++++++++ .../shared_preferences_linux/pubspec.yaml | 2 +- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 packages/shared_preferences/shared_preferences_linux/ios/shared_preferences_linux.podspec diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md index 11694802aacf..de171a9fcf80 100644 --- a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md @@ -1,2 +1,5 @@ +## 0.0.2 +* Add iOS stub. + ## 0.0.1 * Initial release to support shared_preferences on Linux. diff --git a/packages/shared_preferences/shared_preferences_linux/ios/shared_preferences_linux.podspec b/packages/shared_preferences/shared_preferences_linux/ios/shared_preferences_linux.podspec new file mode 100644 index 000000000000..8f4d3cdddcd5 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/ios/shared_preferences_linux.podspec @@ -0,0 +1,22 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint shared_preferences_launcher_linux.podspec' to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'shared_preferences_linux' + s.version = '0.0.1' + s.summary = 'shared_preferences_linux iOS stub' + s.description = <<-DESC + No-op implementation of the Linux shared_preferences plugin to avoid build issues on iOS + DESC + s.homepage = 'https://github.com/flutter/plugins' + s.license = { :type => 'BSD', :file => '../LICENSE' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux' } + s.dependency 'Flutter' + s.platform = :ios, '8.0' + + # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } + s.swift_version = '5.0' +end diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml index 2539b937e006..95c3aca71237 100644 --- a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: shared_preferences_linux description: Linux implementation of the shared_preferences plugin -version: 0.0.1 +version: 0.0.2 homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux flutter: From 3b931d0a9c10e6a833cff1dffcd8e6a947a43936 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 7 Jul 2020 21:00:58 -0700 Subject: [PATCH 24/30] [shared_preferences] Shared preferences linux endorsement (#2864) Endorses shared_preferences_linux. Since shared_preferences_linux is pure Dart, this uses manual registration of the Linux implementation. It is similar to the solution used for path_provider, but improves on it by more narrowly tailoring the registration to cases where another registration hasn't already been done, and only checking the first time, thus avoiding the need for a variable to override it. Updates shared_preferences_linux to depend on path_provider_linux rather than path_provider, to avoid adding unnecessary native plugin dependencies to other platforms. Also adds a driver test for shared_preference_linux, which I missed in reviewing the initial shared_preferences_linux landing. --- .../shared_preferences/CHANGELOG.md | 4 + .../shared_preferences/README.md | 8 +- .../lib/shared_preferences.dart | 25 ++++- .../shared_preferences/pubspec.yaml | 5 +- .../shared_preferences_linux/CHANGELOG.md | 3 + .../example/linux/CMakeLists.txt | 95 +++++++++++++++++++ .../example/linux/flutter/CMakeLists.txt | 86 +++++++++++++++++ .../flutter/generated_plugin_registrant.cc | 9 ++ .../flutter/generated_plugin_registrant.h | 13 +++ .../linux/flutter/generated_plugins.cmake | 15 +++ .../example/linux/main.cc | 6 ++ .../example/linux/my_application.cc | 44 +++++++++ .../example/linux/my_application.h | 18 ++++ .../example/pubspec.yaml | 11 +++ .../test_driver/shared_preferences_e2e.dart | 89 +++++++++++++++++ .../shared_preferences_e2e_test.dart | 15 +++ .../lib/shared_preferences_linux.dart | 9 +- .../shared_preferences_linux/pubspec.yaml | 4 +- .../test/shared_preferences_linux_test.dart | 13 ++- 19 files changed, 454 insertions(+), 18 deletions(-) create mode 100644 packages/shared_preferences/shared_preferences_linux/example/linux/CMakeLists.txt create mode 100644 packages/shared_preferences/shared_preferences_linux/example/linux/flutter/CMakeLists.txt create mode 100644 packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugin_registrant.cc create mode 100644 packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugin_registrant.h create mode 100644 packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugins.cmake create mode 100644 packages/shared_preferences/shared_preferences_linux/example/linux/main.cc create mode 100644 packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc create mode 100644 packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h create mode 100644 packages/shared_preferences/shared_preferences_linux/example/test_driver/shared_preferences_e2e.dart create mode 100644 packages/shared_preferences/shared_preferences_linux/example/test_driver/shared_preferences_e2e_test.dart diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 8c7ee24dfa6b..d17bbb96289b 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.8 + +* Support Linux by default. + ## 0.5.7+3 * Post-v2 Android embedding cleanup. diff --git a/packages/shared_preferences/shared_preferences/README.md b/packages/shared_preferences/shared_preferences/README.md index b5bf4050a8fd..9ccac0ac49ae 100644 --- a/packages/shared_preferences/shared_preferences/README.md +++ b/packages/shared_preferences/shared_preferences/README.md @@ -2,10 +2,10 @@ [![pub package](https://img.shields.io/pub/v/shared_preferences.svg)](https://pub.dartlang.org/packages/shared_preferences) -Wraps NSUserDefaults (on iOS) and SharedPreferences (on Android), providing -a persistent store for simple data. Data is persisted to disk asynchronously. -Neither platform can guarantee that writes will be persisted to disk after -returning and this plugin must not be used for storing critical data. +Wraps platform-specific persistent storage for simple data +(NSUserDefaults on iOS and macOS, SharedPreferences on Android, etc.). Data may be persisted to disk asynchronously, +and there is no guarantee that writes will be persisted to disk after +returning, so this plugin must not be used for storing critical data. **Please set your constraint to `shared_preferences: '>=0.5.y+x <2.0.0'`** diff --git a/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart b/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart index 62160dee20fd..b8d3452a0a0e 100644 --- a/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart +++ b/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart @@ -3,10 +3,14 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:io' show Platform; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:meta/meta.dart'; +import 'package:shared_preferences_linux/shared_preferences_linux.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; +import 'package:shared_preferences_platform_interface/method_channel_shared_preferences.dart'; /// Wraps NSUserDefaults (on iOS) and SharedPreferences (on Android), providing /// a persistent store for simple data. @@ -17,9 +21,26 @@ class SharedPreferences { static const String _prefix = 'flutter.'; static Completer _completer; + static bool _manualDartRegistrationNeeded = true; + + static SharedPreferencesStorePlatform get _store { + // This is to manually endorse the Linux implementation until automatic + // registration of dart plugins is implemented. For details see + // https://github.com/flutter/flutter/issues/52267. + if (_manualDartRegistrationNeeded) { + // Only do the initial registration if it hasn't already been overridden + // with a non-default instance. + if (!kIsWeb && + Platform.isLinux && + SharedPreferencesStorePlatform.instance + is MethodChannelSharedPreferencesStore) { + SharedPreferencesStorePlatform.instance = SharedPreferencesLinux(); + } + _manualDartRegistrationNeeded = false; + } - static SharedPreferencesStorePlatform get _store => - SharedPreferencesStorePlatform.instance; + return SharedPreferencesStorePlatform.instance; + } /// Loads and parses the [SharedPreferences] for this app from disk. /// diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 2b278248745a..ca8c443cd753 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/shared_prefere # 0.5.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.5.7+3 +version: 0.5.8 flutter: plugin: @@ -15,6 +15,8 @@ flutter: pluginClass: SharedPreferencesPlugin ios: pluginClass: FLTSharedPreferencesPlugin + linux: + default_package: shared_preferences_linux macos: default_package: shared_preferences_macos web: @@ -30,6 +32,7 @@ dependencies: # validation, so we set a ^ constraint. # TODO(franciscojma): Revisit this (either update this part in the design or the pub tool). # https://github.com/flutter/flutter/issues/46264 + shared_preferences_linux: ^0.0.2 shared_preferences_macos: ^0.0.1 shared_preferences_web: ^0.1.2 diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md index de171a9fcf80..353a921ff281 100644 --- a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.2+1 +* Replace path_provider dependency with path_provider_linux. + ## 0.0.2 * Add iOS stub. diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/CMakeLists.txt b/packages/shared_preferences/shared_preferences_linux/example/linux/CMakeLists.txt new file mode 100644 index 000000000000..0236a8806654 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/CMakeLists.txt @@ -0,0 +1,95 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/CMakeLists.txt b/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/CMakeLists.txt new file mode 100644 index 000000000000..94f43ff7fa6a --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + linux-x64 ${CMAKE_BUILD_TYPE} +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugin_registrant.cc b/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000000..d38195aa0412 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,9 @@ +// +// Generated file. Do not edit. +// + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugin_registrant.h b/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000000..9bf7478940c1 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugins.cmake b/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000000..51436ae8c982 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,15 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc b/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc new file mode 100644 index 000000000000..e7c5c5437037 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc new file mode 100644 index 000000000000..c2357f17ea9c --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc @@ -0,0 +1,44 @@ +#include "my_application.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), nullptr)); +} diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h new file mode 100644 index 000000000000..72271d5e4170 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml index 1c0624035c54..8e726d642274 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml @@ -4,11 +4,22 @@ description: Demonstrates how to use the shared_preferences_linux plugin. dependencies: flutter: sdk: flutter + shared_preferences: any shared_preferences_linux: ^0.1.0 dependency_overrides: shared_preferences_linux: path: ../ + # Remove this override once the endorsement is published. + shared_preferences: + path: ../../shared_preferences/ + +dev_dependencies: + flutter_driver: + sdk: flutter + test: any + e2e: ^0.2.0 + pedantic: ^1.8.0 flutter: uses-material-design: true diff --git a/packages/shared_preferences/shared_preferences_linux/example/test_driver/shared_preferences_e2e.dart b/packages/shared_preferences/shared_preferences_linux/example/test_driver/shared_preferences_e2e.dart new file mode 100644 index 000000000000..b693df2131ed --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/test_driver/shared_preferences_e2e.dart @@ -0,0 +1,89 @@ +import 'dart:async'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:e2e/e2e.dart'; + +void main() { + E2EWidgetsFlutterBinding.ensureInitialized(); + + group('$SharedPreferences', () { + const Map kTestValues = { + 'flutter.String': 'hello world', + 'flutter.bool': true, + 'flutter.int': 42, + 'flutter.double': 3.14159, + 'flutter.List': ['foo', 'bar'], + }; + + const Map kTestValues2 = { + 'flutter.String': 'goodbye world', + 'flutter.bool': false, + 'flutter.int': 1337, + 'flutter.double': 2.71828, + 'flutter.List': ['baz', 'quox'], + }; + + SharedPreferences preferences; + + setUp(() async { + preferences = await SharedPreferences.getInstance(); + }); + + tearDown(() { + preferences.clear(); + }); + + test('reading', () async { + expect(preferences.get('String'), isNull); + expect(preferences.get('bool'), isNull); + expect(preferences.get('int'), isNull); + expect(preferences.get('double'), isNull); + expect(preferences.get('List'), isNull); + expect(preferences.getString('String'), isNull); + expect(preferences.getBool('bool'), isNull); + expect(preferences.getInt('int'), isNull); + expect(preferences.getDouble('double'), isNull); + expect(preferences.getStringList('List'), isNull); + }); + + test('writing', () async { + await Future.wait(>[ + preferences.setString('String', kTestValues2['flutter.String']), + preferences.setBool('bool', kTestValues2['flutter.bool']), + preferences.setInt('int', kTestValues2['flutter.int']), + preferences.setDouble('double', kTestValues2['flutter.double']), + preferences.setStringList('List', kTestValues2['flutter.List']) + ]); + expect(preferences.getString('String'), kTestValues2['flutter.String']); + expect(preferences.getBool('bool'), kTestValues2['flutter.bool']); + expect(preferences.getInt('int'), kTestValues2['flutter.int']); + expect(preferences.getDouble('double'), kTestValues2['flutter.double']); + expect(preferences.getStringList('List'), kTestValues2['flutter.List']); + }); + + test('removing', () async { + const String key = 'testKey'; + await preferences.setString(key, kTestValues['flutter.String']); + await preferences.setBool(key, kTestValues['flutter.bool']); + await preferences.setInt(key, kTestValues['flutter.int']); + await preferences.setDouble(key, kTestValues['flutter.double']); + await preferences.setStringList(key, kTestValues['flutter.List']); + await preferences.remove(key); + expect(preferences.get('testKey'), isNull); + }); + + test('clearing', () async { + await preferences.setString('String', kTestValues['flutter.String']); + await preferences.setBool('bool', kTestValues['flutter.bool']); + await preferences.setInt('int', kTestValues['flutter.int']); + await preferences.setDouble('double', kTestValues['flutter.double']); + await preferences.setStringList('List', kTestValues['flutter.List']); + await preferences.clear(); + expect(preferences.getString('String'), null); + expect(preferences.getBool('bool'), null); + expect(preferences.getInt('int'), null); + expect(preferences.getDouble('double'), null); + expect(preferences.getStringList('List'), null); + }); + }); +} diff --git a/packages/shared_preferences/shared_preferences_linux/example/test_driver/shared_preferences_e2e_test.dart b/packages/shared_preferences/shared_preferences_linux/example/test_driver/shared_preferences_e2e_test.dart new file mode 100644 index 000000000000..f3aa9e218d82 --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/example/test_driver/shared_preferences_e2e_test.dart @@ -0,0 +1,15 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. 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 'dart:io'; +import 'package:flutter_driver/flutter_driver.dart'; + +Future main() async { + final FlutterDriver driver = await FlutterDriver.connect(); + final String result = + await driver.requestData(null, timeout: const Duration(minutes: 1)); + await driver.close(); + exit(result == 'pass' ? 0 : 1); +} diff --git a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart index dc93100c3277..c975ad1a7544 100644 --- a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart +++ b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart @@ -4,11 +4,12 @@ import 'dart:async'; import 'dart:convert' show json; + import 'package:file/file.dart'; import 'package:file/local.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; -import 'package:path_provider/path_provider.dart'; +import 'package:path_provider_linux/path_provider_linux.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; /// The Linux implementation of [SharedPreferencesStorePlatform]. @@ -27,9 +28,9 @@ class SharedPreferencesLinux extends SharedPreferencesStorePlatform { /// Gets the file where the preferences are stored. Future _getLocalDataFile() async { - var directory = await getApplicationSupportDirectory(); - var filePath = path.join(directory.path, 'shared_preferences.json'); - return fs.file(filePath); + final pathProvider = PathProviderLinux(); + final directory = await pathProvider.getApplicationSupportPath(); + return fs.file(path.join(directory, 'shared_preferences.json')); } /// Gets the preferences from the stored file. Once read, the preferences are diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml index 95c3aca71237..3d40d39241ac 100644 --- a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: shared_preferences_linux description: Linux implementation of the shared_preferences plugin -version: 0.0.2 +version: 0.0.2+1 homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux flutter: @@ -20,7 +20,7 @@ dependencies: sdk: flutter meta: ^1.0.4 path: ^1.6.4 - path_provider: ^1.6.11 + path_provider_linux: ^0.0.1 shared_preferences_platform_interface: ^1.0.0 dev_dependencies: diff --git a/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart index 8a794b1fa7c2..8c659f212aa5 100644 --- a/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart @@ -4,19 +4,22 @@ import 'package:file/memory.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:path/path.dart' as path; -import 'package:path_provider/path_provider.dart'; +import 'package:path_provider_linux/path_provider_linux.dart'; import 'package:shared_preferences_linux/shared_preferences_linux.dart'; -MemoryFileSystem fs = MemoryFileSystem.test(); +MemoryFileSystem fs; void main() { - setUp(() {}); + setUp(() { + fs = MemoryFileSystem.test(); + }); tearDown(() {}); Future _getFilePath() async { - var directory = await getApplicationSupportDirectory(); - return path.join(directory.path, 'shared_preferences.json'); + final pathProvider = PathProviderLinux(); + final directory = await pathProvider.getApplicationSupportPath(); + return path.join(directory, 'shared_preferences.json'); } _writeTestFile(String value) async { From d6435f03595bc65bcf826f52f87ffad248179af8 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Mon, 13 Jul 2020 15:45:57 -0700 Subject: [PATCH 25/30] [connectivity_for_web] Fix JS Interop in release mode. (#2869) * Switch to dart:html window.navigator.connection instead of package:js JS-interop. * Overwrite connection.onchange instead of listening to connection.onChange Stream (prevents multiple subscriptions after hot-reload). * Cleaned up old code related to generating the JS facade. --- .../connectivity_for_web/CHANGELOG.md | 4 + .../generated/network_information_types.dart | 78 ------------ ...k_information_api_connectivity_plugin.dart | 39 ++++-- .../lib/src/utils/connectivity_result.dart | 17 +-- .../connectivity_for_web/pubspec.yaml | 4 +- .../connectivity_for_web/test/lib/main.dart | 21 ++-- .../test/lib/src/connectivity_mocks.dart | 53 ++------ .../connectivity_for_web/test/pubspec.yaml | 3 +- .../connectivity_for_web/ts/.gitignore | 2 - .../connectivity_for_web/ts/README.md | 25 ---- .../connectivity_for_web/ts/package-lock.json | 117 ------------------ .../connectivity_for_web/ts/package.json | 17 --- .../ts/scripts/run_facade_gen.sh | 18 --- 13 files changed, 61 insertions(+), 337 deletions(-) delete mode 100644 packages/connectivity/connectivity_for_web/lib/src/generated/network_information_types.dart delete mode 100644 packages/connectivity/connectivity_for_web/ts/.gitignore delete mode 100644 packages/connectivity/connectivity_for_web/ts/README.md delete mode 100644 packages/connectivity/connectivity_for_web/ts/package-lock.json delete mode 100644 packages/connectivity/connectivity_for_web/ts/package.json delete mode 100755 packages/connectivity/connectivity_for_web/ts/scripts/run_facade_gen.sh diff --git a/packages/connectivity/connectivity_for_web/CHANGELOG.md b/packages/connectivity/connectivity_for_web/CHANGELOG.md index 89e186abe1cb..83dc386a0314 100644 --- a/packages/connectivity/connectivity_for_web/CHANGELOG.md +++ b/packages/connectivity/connectivity_for_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.1 + +* Use NetworkInformation API from dart:html, instead of the JS-interop version. + ## 0.3.0 * Rename from "experimental_connectivity_web" to "connectivity_for_web", and move to flutter/plugins master. diff --git a/packages/connectivity/connectivity_for_web/lib/src/generated/network_information_types.dart b/packages/connectivity/connectivity_for_web/lib/src/generated/network_information_types.dart deleted file mode 100644 index c4045b3ec1fc..000000000000 --- a/packages/connectivity/connectivity_for_web/lib/src/generated/network_information_types.dart +++ /dev/null @@ -1,78 +0,0 @@ -@JS() -library network_information_types; - -import "package:js/js.dart"; -import "dart:html" show EventListener, EventTarget; - -/// W3C Spec Draft http://wicg.github.io/netinfo/ -/// Edition: Draft Community Group Report 20 February 2019 - -/// http://wicg.github.io/netinfo/#navigatornetworkinformation-interface -@anonymous -@JS() -abstract class Navigator implements NavigatorNetworkInformation {} - -@anonymous -@JS() -abstract class WorkerNavigator implements NavigatorNetworkInformation { - external factory WorkerNavigator({NetworkInformation connection}); -} - -/// http://wicg.github.io/netinfo/#navigatornetworkinformation-interface -@anonymous -@JS() -abstract class NavigatorNetworkInformation { - external NetworkInformation get connection; - external factory NavigatorNetworkInformation({NetworkInformation connection}); -} - -/// http://wicg.github.io/netinfo/#connection-types -/*type ConnectionType = - | 'bluetooth' - | 'cellular' - | 'ethernet' - | 'mixed' - | 'none' - | 'other' - | 'unknown' - | 'wifi' - | 'wimax'; -*/ - -/// http://wicg.github.io/netinfo/#effectiveconnectiontype-enum -/*type EffectiveConnectionType = '2g' | '3g' | '4g' | 'slow-2g';*/ - -/// http://wicg.github.io/netinfo/#dom-megabit -/*type Megabit = number;*/ -/// http://wicg.github.io/netinfo/#dom-millisecond -/*type Millisecond = number;*/ - -/// http://wicg.github.io/netinfo/#networkinformation-interface -@anonymous -@JS() -abstract class NetworkInformation implements EventTarget { - /// http://wicg.github.io/netinfo/#type-attribute - external String /*'bluetooth'|'cellular'|'ethernet'|'mixed'|'none'|'other'|'unknown'|'wifi'|'wimax'*/ get type; - - /// http://wicg.github.io/netinfo/#effectivetype-attribute - external String /*'2g'|'3g'|'4g'|'slow-2g'*/ get effectiveType; - - /// http://wicg.github.io/netinfo/#downlinkmax-attribute - external num get downlinkMax; - - /// http://wicg.github.io/netinfo/#downlink-attribute - external num get downlink; - - /// http://wicg.github.io/netinfo/#rtt-attribute - external num get rtt; - - /// http://wicg.github.io/netinfo/#savedata-attribute - external bool get saveData; - - /// http://wicg.github.io/netinfo/#handling-changes-to-the-underlying-connection - external EventListener get onchange; - external set onchange(EventListener v); -} - -@JS() -external Navigator get navigator; diff --git a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart index d88487b9c406..99bac2ab8d30 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart @@ -1,28 +1,29 @@ import 'dart:async'; +import 'dart:html' as html show window, NetworkInformation; +import 'dart:js'; +import 'dart:js_util'; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:connectivity_for_web/connectivity_for_web.dart'; import 'package:flutter/foundation.dart'; -import 'package:js/js.dart'; -import 'generated/network_information_types.dart' as dom; import 'utils/connectivity_result.dart'; /// The web implementation of the ConnectivityPlatform of the Connectivity plugin. class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { - final dom.NetworkInformation _networkInformation; + final html.NetworkInformation _networkInformation; /// A check to determine if this version of the plugin can be used. - static bool isSupported() => dom.navigator?.connection != null; + static bool isSupported() => html.window.navigator.connection != null; /// The constructor of the plugin. NetworkInformationApiConnectivityPlugin() - : this.withConnection(dom.navigator?.connection); + : this.withConnection(html.window.navigator.connection); /// Creates the plugin, with an override of the NetworkInformation object. @visibleForTesting NetworkInformationApiConnectivityPlugin.withConnection( - dom.NetworkInformation connection) + html.NetworkInformation connection) : _networkInformation = connection; /// Checks the connection status of the device. @@ -31,18 +32,30 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { return networkInformationToConnectivityResult(_networkInformation); } - StreamController _connectivityResult; + StreamController _connectivityResultStreamController; + Stream _connectivityResultStream; /// Returns a Stream of ConnectivityResults changes. @override Stream get onConnectivityChanged { - if (_connectivityResult == null) { - _connectivityResult = StreamController(); - _networkInformation.onchange = allowInterop((_) { - _connectivityResult + if (_connectivityResultStreamController == null) { + _connectivityResultStreamController = + StreamController(); + setProperty(_networkInformation, 'onchange', allowInterop((_) { + _connectivityResultStreamController .add(networkInformationToConnectivityResult(_networkInformation)); - }); + })); + // TODO: Implement the above with _networkInformation.onChange: + // _networkInformation.onChange.listen((_) { + // _connectivityResult + // .add(networkInformationToConnectivityResult(_networkInformation)); + // }); + // Once we can detect when to *cancel* a subscription to the _networkInformation + // onChange Stream upon hot restart. + // https://github.com/dart-lang/sdk/issues/42679 + _connectivityResultStream = + _connectivityResultStreamController.stream.asBroadcastStream(); } - return _connectivityResult.stream; + return _connectivityResultStream; } } diff --git a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart index 28943ef5c7e1..efefd8d52440 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart @@ -1,27 +1,22 @@ +import 'dart:html' as html show NetworkInformation; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; /// Converts an incoming NetworkInformation object into the correct ConnectivityResult. -// -// We can't be more specific on the signature of this method because the API is odd, -// data can come from a static value in the DOM, or as the 'target' of a DOM Event. -// -// If we type info as `NetworkInformation`, Dart will complain with: -// "Uncaught Error: Expected a value of type 'NetworkInformation', -// but got one of type 'NetworkInformation'" ConnectivityResult networkInformationToConnectivityResult( - dynamic /* NetworkInformation */ info) { + html.NetworkInformation info, +) { if (info == null) { return ConnectivityResult.none; } if (info.downlink == 0 && info.rtt == 0) { return ConnectivityResult.none; } - if (info.type != null) { - return _typeToConnectivityResult(info.type); - } if (info.effectiveType != null) { return _effectiveTypeToConnectivityResult(info.effectiveType); } + if (info.type != null) { + return _typeToConnectivityResult(info.type); + } return ConnectivityResult.none; } diff --git a/packages/connectivity/connectivity_for_web/pubspec.yaml b/packages/connectivity/connectivity_for_web/pubspec.yaml index e4a1673e40c2..e1142a75c91f 100644 --- a/packages/connectivity/connectivity_for_web/pubspec.yaml +++ b/packages/connectivity/connectivity_for_web/pubspec.yaml @@ -1,6 +1,6 @@ name: connectivity_for_web description: An implementation for the web platform of the Flutter `connectivity` plugin. This uses the NetworkInformation Web API, with a fallback to Navigator.onLine. -version: 0.3.0 +version: 0.3.1 homepage: https://github.com/ditman/plugins/tree/connectivity-web/packages/connectivity/experimental_connectivity_web flutter: @@ -12,7 +12,6 @@ flutter: dependencies: connectivity_platform_interface: ^1.0.3 - js: ^0.6.1+1 flutter_web_plugins: sdk: flutter flutter: @@ -25,6 +24,7 @@ dev_dependencies: flutter_test: sdk: flutter e2e: ^0.2.4+3 + mockito: ^4.1.1 environment: sdk: ">=2.6.0 <3.0.0" diff --git a/packages/connectivity/connectivity_for_web/test/lib/main.dart b/packages/connectivity/connectivity_for_web/test/lib/main.dart index 21621a947ee6..93b9a73cf31b 100644 --- a/packages/connectivity/connectivity_for_web/test/lib/main.dart +++ b/packages/connectivity/connectivity_for_web/test/lib/main.dart @@ -3,6 +3,8 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:connectivity_for_web/src/network_information_api_connectivity_plugin.dart'; +import 'package:mockito/mockito.dart'; + import 'src/connectivity_mocks.dart'; void main() { @@ -16,11 +18,12 @@ void main() { num rtt = 50, ConnectivityResult expected, }) { - MockNetworkInformation connection = MockNetworkInformation( - type: type, - effectiveType: effectiveType, - downlink: downlink, - rtt: rtt); + final connection = MockNetworkInformation(); + when(connection.type).thenReturn(type); + when(connection.effectiveType).thenReturn(effectiveType); + when(connection.downlink).thenReturn(downlink); + when(connection.rtt).thenReturn(downlink); + NetworkInformationApiConnectivityPlugin plugin = NetworkInformationApiConnectivityPlugin.withConnection(connection); expect(plugin.checkConnectivity(), completion(equals(expected))); @@ -53,16 +56,16 @@ void main() { group('get onConnectivityChanged', () { test('puts change events in a Stream', () async { - MockNetworkInformation connection = - MockNetworkInformation(effectiveType: '4g', downlink: 10, rtt: 50); + final connection = MockNetworkInformation(); NetworkInformationApiConnectivityPlugin plugin = NetworkInformationApiConnectivityPlugin.withConnection(connection); Stream results = plugin.onConnectivityChanged; // Fake a disconnect-reconnect - connection.mockChangeValue(downlink: 0, rtt: 0); - connection.mockChangeValue(downlink: 10, rtt: 50); + await connection.mockChangeValue(downlink: 0, rtt: 0); + await connection.mockChangeValue( + downlink: 10, rtt: 50, effectiveType: '4g'); // The stream of results is infinite, so we need to .take(2) for this test to complete. expect( diff --git a/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart b/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart index 9ce2e811d461..7b82b512065b 100644 --- a/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart +++ b/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart @@ -1,33 +1,12 @@ import 'dart:html'; -import 'package:connectivity_for_web/src/generated/network_information_types.dart' - as dom; +import 'package:mockito/mockito.dart'; /// A Mock implementation of the NetworkInformation API that allows /// for external modification of its values. -class MockNetworkInformation extends dom.NetworkInformation { - @override - String type; - - @override - String effectiveType; - - @override - num downlink; - - @override - num rtt; - - @override - EventListener onchange; - - /// Constructor of mocked instances... - MockNetworkInformation({ - this.type, - this.effectiveType, - this.downlink, - this.rtt, - }); +class MockNetworkInformation extends Mock implements NetworkInformation { + /// The callback that will fire after the network information values change. + Function onchange; /// Changes the desired values, and triggers the change event listener. void mockChangeValue({ @@ -35,26 +14,12 @@ class MockNetworkInformation extends dom.NetworkInformation { String effectiveType, num downlink, num rtt, - }) { - this.type = type ?? this.type; - this.effectiveType = effectiveType ?? this.effectiveType; - this.downlink = downlink ?? this.downlink; - this.rtt = rtt ?? this.rtt; + }) async { + when(this.type).thenAnswer((_) => type); + when(this.effectiveType).thenAnswer((_) => effectiveType); + when(this.downlink).thenAnswer((_) => downlink); + when(this.rtt).thenAnswer((_) => rtt); onchange(Event('change')); } - - @override - void addEventListener(String type, listener, [bool useCapture]) {} - - @override - bool dispatchEvent(Event event) { - return true; - } - - @override - Events get on => null; - - @override - void removeEventListener(String type, listener, [bool useCapture]) {} } diff --git a/packages/connectivity/connectivity_for_web/test/pubspec.yaml b/packages/connectivity/connectivity_for_web/test/pubspec.yaml index 4d7d10a775e2..44f4b552b443 100644 --- a/packages/connectivity/connectivity_for_web/test/pubspec.yaml +++ b/packages/connectivity/connectivity_for_web/test/pubspec.yaml @@ -1,6 +1,6 @@ name: connectivity_web_example description: Example web app for the connectivity plugin -version: 0.1.0 +version: 0.1.1 homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_web dependencies: @@ -18,6 +18,7 @@ dev_dependencies: flutter_driver: sdk: flutter e2e: ^0.2.4+3 + mockito: ^4.1.1 environment: sdk: ">=2.6.0 <3.0.0" diff --git a/packages/connectivity/connectivity_for_web/ts/.gitignore b/packages/connectivity/connectivity_for_web/ts/.gitignore deleted file mode 100644 index de4d1f007dd1..000000000000 --- a/packages/connectivity/connectivity_for_web/ts/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules diff --git a/packages/connectivity/connectivity_for_web/ts/README.md b/packages/connectivity/connectivity_for_web/ts/README.md deleted file mode 100644 index 3372ad2f3790..000000000000 --- a/packages/connectivity/connectivity_for_web/ts/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# JS Facade generator - -This npm script takes the `network-information-types` npm package, and runs it through Dart's `dart_js_facade_gen` to auto-generate (most) of the JS facades used by this plugin. - -The process is not completely automated yet, but it should be pretty close. - -To generate the facades, and after [installing `npm`](https://www.npmjs.com/get-npm), do: - -``` -npm install -npm run build -``` - -The above will fetch the required dependencies, and generate a `dist/network_information_types.dart` file that you can use with the plugin. - -``` -cp dist/*.dart ../lib/src/generated -``` - -This script should come handy once the Network Information Web API changes, or becomes stable, so the JS-interop part of this plugin can be regenerated more easily. - -Read more: - -* [Dart JS Interop](https://dart.dev/web/js-interop) -* [dart_js_facade_gen](https://www.npmjs.com/package/dart_js_facade_gen) \ No newline at end of file diff --git a/packages/connectivity/connectivity_for_web/ts/package-lock.json b/packages/connectivity/connectivity_for_web/ts/package-lock.json deleted file mode 100644 index 45293a400492..000000000000 --- a/packages/connectivity/connectivity_for_web/ts/package-lock.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "name": "network-information-types-to-dart-generator", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/chai": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.9.tgz", - "integrity": "sha512-NeXgZj+MFL4izGqA4sapdYzkzQG+MtGra9vhQ58dnmDY++VgJaRUws+aLVV5zRJCYJl/8s9IjMmhiUw1WsKSmw==" - }, - "@types/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg==", - "requires": { - "@types/node": "*" - } - }, - "@types/minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=" - }, - "@types/mocha": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", - "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==" - }, - "@types/node": { - "version": "12.12.28", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.28.tgz", - "integrity": "sha512-g73GJYJDXgf0jqg+P9S8h2acWbDXNkoCX8DLtJVu7Fkn788pzQ/oJsrdJz/2JejRf/SjfZaAhsw+3nd1D5EWGg==" - }, - "@types/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@types/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LrnsgZIfJaysFkv9rRJp4/uAyqw87oVed3s1hhF83nwbo9c7MG9g5DqR0seHP+lkX4ldmMrVolPjQSe2ZfD0yA==", - "requires": { - "source-map": "*" - } - }, - "@types/source-map-support": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@types/source-map-support/-/source-map-support-0.5.1.tgz", - "integrity": "sha512-VDqnZe9D2zR19qbeRvwYyHSp7AtUtCkTaRVFQ8wzwH9TXw9kKKq/vBhfEnFEXVupO2M0lBMA9mr/XyQ6gEkUOA==", - "requires": { - "@types/node": "*" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "dart-style": { - "version": "1.3.2-dev", - "resolved": "https://registry.npmjs.org/dart-style/-/dart-style-1.3.2-dev.tgz", - "integrity": "sha512-NFI4UQYvG32t/cEkQAdkXT2ZT72tjF61tMWoALmnGwj03d2Co94zwGfbnFfdQUQvrhUNx8Wz2jKSVxGrmFaVJQ==" - }, - "dart_js_facade_gen": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/dart_js_facade_gen/-/dart_js_facade_gen-0.0.7.tgz", - "integrity": "sha512-AZiWsccbzhgJWmBjbFTPuvBhwGXk7AN8nOP91/I8PqUfSvVALiWshDc66TvywNkdNogAE5X8zlxjodw1C3iHpA==", - "requires": { - "@types/chai": "^4.2.3", - "@types/fs-extra": "^8.0.0", - "@types/minimist": "^1.2.0", - "@types/mocha": "^5.2.7", - "@types/node": "^12.7.8", - "@types/source-map": "^0.5.7", - "@types/source-map-support": "^0.5.0", - "dart-style": "^1.3.2-dev", - "minimist": "^1.2.0", - "source-map": "^0.7.3", - "source-map-support": "^0.5.13", - "typescript": "^3.6.3" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "network-information-types": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/network-information-types/-/network-information-types-0.1.0.tgz", - "integrity": "sha512-cRUCYZoRHTMjYcgk5MbwqM0h0Za34panRxAJKY8n+mQ+NLMuRIw7aKzmaZqkC/cte7bnRcdfTwFA27GgN62EtQ==" - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - }, - "source-map-support": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", - "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "typescript": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.2.tgz", - "integrity": "sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ==" - } - } -} diff --git a/packages/connectivity/connectivity_for_web/ts/package.json b/packages/connectivity/connectivity_for_web/ts/package.json deleted file mode 100644 index 665c89d6afbb..000000000000 --- a/packages/connectivity/connectivity_for_web/ts/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "network-information-types-to-dart-generator", - "version": "1.0.0", - "description": "Use dart_js_facade_gen to generate the facade for the network-information-types package.", - "main": "index.js", - "private": true, - "scripts": { - "build": "./scripts/run_facade_gen.sh", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "MIT", - "dependencies": { - "network-information-types": "0.1.0", - "dart_js_facade_gen": "^0.0.7" - } -} diff --git a/packages/connectivity/connectivity_for_web/ts/scripts/run_facade_gen.sh b/packages/connectivity/connectivity_for_web/ts/scripts/run_facade_gen.sh deleted file mode 100755 index c74b8ba171b2..000000000000 --- a/packages/connectivity/connectivity_for_web/ts/scripts/run_facade_gen.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -INDEX_PATH=node_modules/network-information-types/dist-types/index.d.ts -WORK_PATH=network_information_types.d.ts -DIST_PATH=dist - -# Create dist if it doesn't exist already -mkdir -p $DIST_PATH - -# Copy the input file(s) into our work path -cp $INDEX_PATH $WORK_PATH - -# Run dart_js_facade_gen -dart_js_facade_gen $WORK_PATH --trust-js-types --generate-html --destination . - -# Move output to the right place, and clean after yourself -mv *.dart $DIST_PATH -rm $WORK_PATH From 5971e2f5bca9c07fc037effeabbf4410ce48e644 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Mon, 13 Jul 2020 17:32:57 -0700 Subject: [PATCH 26/30] [google_sign_in] Bridge google_sign_in and googleapis. (#2824) Introduce the first version of the `extension_google_sign_in_as_googleapis_auth` package. This package lets users of the `google_sign_in` plugin to create an authenticated HTTP clients (from `googleapis_auth`) that can access any APIs from the `googleapis` package. --- .../.gitignore | 75 +++ .../.metadata | 10 + .../CHANGELOG.md | 3 + .../LICENSE | 27 + .../README.md | 46 ++ .../example/README.md | 8 + .../example/android/app/build.gradle | 64 +++ .../example/android/app/google-services.json | 246 +++++++++ .../gradle/wrapper/gradle-wrapper.properties | 5 + .../android/app/src/main/AndroidManifest.xml | 25 + .../main/java/io/flutter/plugins/.gitignore | 1 + .../EmbeddingV1Activity.java | 19 + .../EmbeddingV1ActivityTest.java | 17 + .../FlutterActivityTest.java | 17 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values/strings.xml | 4 + .../example/android/build.gradle | 29 + .../example/android/gradle.properties | 4 + .../gradle/wrapper/gradle-wrapper.properties | 5 + .../example/android/settings.gradle | 15 + .../ios/Flutter/AppFrameworkInfo.plist | 30 ++ .../example/ios/Flutter/Debug.xcconfig | 2 + .../example/ios/Flutter/Release.xcconfig | 2 + .../ios/GoogleSignInPluginTest/Info.plist | 22 + .../ios/Runner.xcodeproj/project.pbxproj | 502 ++++++++++++++++++ .../contents.xcworkspacedata | 10 + .../xcshareddata/xcschemes/Runner.xcscheme | 87 +++ .../contents.xcworkspacedata | 10 + .../example/ios/Runner/AppDelegate.h | 10 + .../example/ios/Runner/AppDelegate.m | 17 + .../AppIcon.appiconset/Contents.json | 116 ++++ .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../Runner/Base.lproj/LaunchScreen.storyboard | 27 + .../ios/Runner/Base.lproj/Main.storyboard | 26 + .../ios/Runner/GoogleService-Info.plist | 44 ++ .../example/ios/Runner/Info.plist | 62 +++ .../example/ios/Runner/main.m | 13 + .../example/lib/main.dart | 149 ++++++ .../example/pubspec.yaml | 23 + .../example/web/index.html | 11 + ...ion_google_sign_in_as_googleapis_auth.dart | 36 ++ .../pubspec.yaml | 28 + ...oogle_sign_in_as_googleapis_auth_test.dart | 46 ++ script/build_all_plugins_app.sh | 1 + 61 files changed, 1894 insertions(+) create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.gitignore create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.metadata create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/LICENSE create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/README.md create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/build.gradle create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/google-services.json create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/AndroidManifest.xml create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/values/strings.xml create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/build.gradle create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle.properties create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/settings.gradle create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/AppFrameworkInfo.plist create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Debug.xcconfig create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Release.xcconfig create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/GoogleSignInPluginTest/Info.plist create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.pbxproj create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.h create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.m create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/GoogleService-Info.plist create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Info.plist create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/main.m create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart create mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/web/index.html create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml create mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.gitignore b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.gitignore new file mode 100644 index 000000000000..bb431f0d5b47 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.gitignore @@ -0,0 +1,75 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.metadata b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.metadata new file mode 100644 index 000000000000..2c91cc0fc35a --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 5e3e5a2a1a977c34b22f3709109fd237b5cab9c6 + channel: master + +project_type: package diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md new file mode 100644 index 000000000000..7f35c8490e1f --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +* First published version. diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/LICENSE b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/LICENSE new file mode 100644 index 000000000000..14fbc7c48e1c --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/LICENSE @@ -0,0 +1,27 @@ +Copyright 2020 The Flutter 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 LLC 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/google_sign_in/extension_google_sign_in_as_googleapis_auth/README.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/README.md new file mode 100644 index 000000000000..78ddb4bdc91b --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/README.md @@ -0,0 +1,46 @@ +# extension_google_sign_in_as_googleapis_auth + +A bridge package between Flutter's [`google_sign_in` plugin](https://pub.dev/packages/google_sign_in) and Dart's [`googleapis` package](https://pub.dev/packages/googleapis), that is able to create [`googleapis_auth`-like `AuthClient` instances](https://pub.dev/documentation/googleapis_auth/latest/googleapis_auth.auth/AuthClient-class.html) directly from the `GoogleSignIn` plugin. + +## Usage + +This package is implemented as an [extension method](https://dart.dev/guides/language/extension-methods) on top of the `GoogleSignIn` plugin. + +In order to use it, you need to add a `dependency` to your `pubspec.yaml`. Then, wherever you're importing `package:google_sign_in/google_sign_in.dart`, add the following: + +```dart +... +import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; +... +``` + +From that moment on, your `GoogleSignIn` instance will have an additional `Future authenticatedClient()` method that you can call once your sign in is successful to retrieve an `AuthClient`. + +That object can then be used to create instances of `googleapis` API clients: + +```dart +... +final peopleApi = PeopleApi(await _googleSignIn.authenticatedClient()); +final response = await peopleApi.people.connections.list( + 'people/me', + personFields: 'names', +); +... +``` + +## Example + +This package contains a modified version of Flutter's Google Sign In example app that uses `package:googleapis`' API clients, instead of raw http requests. + +See it [here](https://github.com/flutter/plugins/blob/master/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart). + +The original code (and its license) can be seen [here](https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in/example/lib/main.dart). + +## Testing + +Run tests with `flutter test`. + +## Issues and feedback + +Please file [issues](https://github.com/flutter/flutter/issues/new) +to send feedback or report a bug. Thank you! diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md new file mode 100755 index 000000000000..689071dcfe8d --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md @@ -0,0 +1,8 @@ +# extension_google_sign_in_example + +Demonstrates how to use the google_sign_in plugin with the `googleapis` package. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/build.gradle b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/build.gradle new file mode 100755 index 000000000000..e6da1a0aebf5 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/build.gradle @@ -0,0 +1,64 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + applicationId "io.flutter.plugins.googlesigninexample" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } + + testOptions { + unitTests.returnDefaultValues = true + } +} + +flutter { + source '../..' +} + +dependencies { + implementation 'com.google.android.gms:play-services-auth:16.0.1' + testImplementation'junit:junit:4.12' + testImplementation 'org.mockito:mockito-core:2.17.0' +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/google-services.json b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/google-services.json new file mode 100644 index 000000000000..efa524535553 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/google-services.json @@ -0,0 +1,246 @@ +{ + "project_info": { + "project_number": "479882132969", + "firebase_url": "https://my-flutter-proj.firebaseio.com", + "project_id": "my-flutter-proj", + "storage_bucket": "my-flutter-proj.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:479882132969:android:c73fd19ff7e2c0be", + "android_client_info": { + "package_name": "io.flutter.plugins.cameraexample" + } + }, + "oauth_client": [ + { + "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCrZz9T0Pg0rDnpxfNuPBrOxGhXskfebXs" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 2 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:479882132969:android:632cdf3fc0a17139", + "android_client_info": { + "package_name": "io.flutter.plugins.firebasedynamiclinksexample" + } + }, + "oauth_client": [ + { + "client_id": "479882132969-32qusitiag53931ck80h121ajhlc5a7e.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "io.flutter.plugins.firebasedynamiclinksexample", + "certificate_hash": "e733b7a303250b63e06de6f7c9767c517d69cfa0" + } + }, + { + "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCrZz9T0Pg0rDnpxfNuPBrOxGhXskfebXs" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 2, + "other_platform_oauth_client": [ + { + "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "479882132969-gjp4e63ogu2h6guttj2ie6t3f10ic7i8.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.flutter.plugins.firebaseMlVisionExample" + } + } + ] + }, + "ads_service": { + "status": 2 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:479882132969:android:ae50362b4bc06086", + "android_client_info": { + "package_name": "io.flutter.plugins.firebasemlvisionexample" + } + }, + "oauth_client": [ + { + "client_id": "479882132969-9pp74fkgmtvt47t9rikc1p861v7n85tn.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "io.flutter.plugins.firebasemlvisionexample", + "certificate_hash": "e733b7a303250b63e06de6f7c9767c517d69cfa0" + } + }, + { + "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCrZz9T0Pg0rDnpxfNuPBrOxGhXskfebXs" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 2, + "other_platform_oauth_client": [ + { + "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "479882132969-gjp4e63ogu2h6guttj2ie6t3f10ic7i8.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.flutter.plugins.firebaseMlVisionExample" + } + } + ] + }, + "ads_service": { + "status": 2 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:479882132969:android:215a22700e1b466b", + "android_client_info": { + "package_name": "io.flutter.plugins.firebaseperformanceexample" + } + }, + "oauth_client": [ + { + "client_id": "479882132969-8h4kiv8m7ho4tvn6uuujsfcrf69unuf7.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "io.flutter.plugins.firebaseperformanceexample", + "certificate_hash": "e733b7a303250b63e06de6f7c9767c517d69cfa0" + } + }, + { + "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCrZz9T0Pg0rDnpxfNuPBrOxGhXskfebXs" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 2, + "other_platform_oauth_client": [ + { + "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "479882132969-gjp4e63ogu2h6guttj2ie6t3f10ic7i8.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.flutter.plugins.firebaseMlVisionExample" + } + } + ] + }, + "ads_service": { + "status": 2 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:479882132969:android:5e9f1f89e134dc86", + "android_client_info": { + "package_name": "io.flutter.plugins.googlesigninexample" + } + }, + "oauth_client": [ + { + "client_id": "479882132969-90ml692hkonp587sl0v0rurmnvkekgrg.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "io.flutter.plugins.googlesigninexample", + "certificate_hash": "e733b7a303250b63e06de6f7c9767c517d69cfa0" + } + }, + { + "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCrZz9T0Pg0rDnpxfNuPBrOxGhXskfebXs" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 2, + "other_platform_oauth_client": [ + { + "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "479882132969-gjp4e63ogu2h6guttj2ie6t3f10ic7i8.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.flutter.plugins.firebaseMlVisionExample" + } + } + ] + }, + "ads_service": { + "status": 2 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000000..9a4163a4f5ee --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/AndroidManifest.xml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..df80f829c1e7 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore new file mode 100755 index 000000000000..9eb4563d2ae1 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore @@ -0,0 +1 @@ +GeneratedPluginRegistrant.java diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java new file mode 100644 index 000000000000..f7ea0c4043a6 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +package io.flutter.plugins.googlesigninexample; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.googlesignin.GoogleSignInPlugin; +import io.flutter.view.FlutterMain; + +public class EmbeddingV1Activity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + FlutterMain.startInitialization(this); + super.onCreate(savedInstanceState); + GoogleSignInPlugin.registerWith(registrarFor("io.flutter.plugins.googlesignin")); + } +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java new file mode 100644 index 000000000000..8bddbff7ce27 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java @@ -0,0 +1,17 @@ +// Copyright 2020 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. + +package io.flutter.plugins.googlesigninexample; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.e2e.FlutterRunner; +import org.junit.Rule; +import org.junit.runner.RunWith; + +@RunWith(FlutterRunner.class) +public class EmbeddingV1ActivityTest { + @Rule + public ActivityTestRule rule = + new ActivityTestRule<>(EmbeddingV1Activity.class); +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java new file mode 100644 index 000000000000..77cdcee9bcdb --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java @@ -0,0 +1,17 @@ +// Copyright 2020 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. + +package io.flutter.plugins.googlesigninexample; + +import androidx.test.rule.ActivityTestRule; +import dev.flutter.plugins.e2e.FlutterRunner; +import io.flutter.embedding.android.FlutterActivity; +import org.junit.Rule; +import org.junit.runner.RunWith; + +@RunWith(FlutterRunner.class) +public class FlutterActivityTest { + @Rule + public ActivityTestRule rule = new ActivityTestRule<>(FlutterActivity.class); +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100755 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100755 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100755 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100755 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/values/strings.xml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000000..c7e28ffcedd1 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + YOUR_WEB_CLIENT_ID + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/build.gradle b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/build.gradle new file mode 100755 index 000000000000..541636cc492a --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.3.0' + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle.properties b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle.properties new file mode 100755 index 000000000000..38c8d4544ff1 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000000..019065d1d650 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/settings.gradle b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/settings.gradle new file mode 100755 index 000000000000..115da6cb4f4d --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withInputStream { stream -> plugins.load(stream) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/AppFrameworkInfo.plist b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100755 index 000000000000..6c2de8086bcd --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + UIRequiredDeviceCapabilities + + arm64 + + MinimumOSVersion + 8.0 + + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Debug.xcconfig b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Debug.xcconfig new file mode 100755 index 000000000000..9803018ca79d --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Generated.xcconfig" +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Release.xcconfig b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Release.xcconfig new file mode 100755 index 000000000000..a4a8c604e13d --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Generated.xcconfig" +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/GoogleSignInPluginTest/Info.plist b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/GoogleSignInPluginTest/Info.plist new file mode 100644 index 000000000000..64d65ca49577 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/GoogleSignInPluginTest/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000000..faaaa58070bd --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,502 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5C6F5A6E1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C6F5A6D1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m */; }; + 7A303C2E1E89D76400B1F19E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7A303C2D1E89D76400B1F19E /* GoogleService-Info.plist */; }; + 7ACDFB0E1E8944C400BE2D00 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7ACDFB0D1E8944C400BE2D00 /* AppFrameworkInfo.plist */; }; + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; + 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + C2FB9CBA01DB0A2DE5F31E12 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0263E28FA425D1CE928BDE15 /* libPods-Runner.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0263E28FA425D1CE928BDE15 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5A76713E622F06379AEDEBFA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 5C6F5A6C1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 5C6F5A6D1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 7A303C2D1E89D76400B1F19E /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 7ACDFB0D1E8944C400BE2D00 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F582639B44581540871D9BB0 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C2FB9CBA01DB0A2DE5F31E12 /* libPods-Runner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { + isa = PBXGroup; + children = ( + 5A76713E622F06379AEDEBFA /* Pods-Runner.debug.xcconfig */, + F582639B44581540871D9BB0 /* Pods-Runner.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 7ACDFB0D1E8944C400BE2D00 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 840012C8B5EDBCF56B0E4AC1 /* Pods */, + CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 5C6F5A6C1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.h */, + 5C6F5A6D1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m */, + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 7A303C2D1E89D76400B1F19E /* GoogleService-Info.plist */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 97C146F21CF9000F007C117D /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 0263E28FA425D1CE928BDE15 /* libPods-Runner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */, + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1100; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7A303C2E1E89D76400B1F19E /* GoogleService-Info.plist in Resources */, + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 7ACDFB0E1E8944C400BE2D00 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin\n"; + }; + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", + "${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../Flutter/Flutter.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, + 97C146F31CF9000F007C117D /* main.m in Sources */, + 5C6F5A6E1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + 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_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + 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_OBJC_ROOT_CLASS = YES_ERROR; + 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; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + 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_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + 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_OBJC_ROOT_CLASS = YES_ERROR; + 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; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.googleSignInExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.googleSignInExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100755 index 000000000000..3bb3697ef41c --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.h b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.h new file mode 100644 index 000000000000..d9e18e990f2e --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.h @@ -0,0 +1,10 @@ +// Copyright 2017 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 +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.m b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.m new file mode 100644 index 000000000000..f08675707182 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.m @@ -0,0 +1,17 @@ +// Copyright 2017 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. + +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + // Override point for customization after application launch. + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 000000000000..d22f10b2ab63 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100755 index 0000000000000000000000000000000000000000..28c6bf03016f6c994b70f38d1b7346e5831b531f GIT binary patch literal 564 zcmV-40?Yl0P)Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100755 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 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 literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100755 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100755 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 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 literal 0 HcmV?d00001 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100755 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 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 iW8 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Base.lproj/Main.storyboard b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100755 index 000000000000..f3c28516fb38 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/GoogleService-Info.plist b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/GoogleService-Info.plist new file mode 100644 index 000000000000..6042aab908af --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,44 @@ + + + + + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 + CLIENT_ID + 479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u + ANDROID_CLIENT_ID + 479882132969-jie8r1me6dsra60pal6ejaj8dgme3tg0.apps.googleusercontent.com + API_KEY + AIzaSyBECOwLTAN6PU4Aet1b2QLGIb3kRK8Xjew + GCM_SENDER_ID + 479882132969 + PLIST_VERSION + 1 + BUNDLE_ID + io.flutter.plugins.googleSignInExample + PROJECT_ID + my-flutter-proj + STORAGE_BUCKET + my-flutter-proj.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:479882132969:ios:2643f950e0a0da08 + DATABASE_URL + https://my-flutter-proj.firebaseio.com + SERVER_CLIENT_ID + YOUR_SERVER_CLIENT_ID + + \ No newline at end of file diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Info.plist b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Info.plist new file mode 100755 index 000000000000..e03ccfe55e37 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Info.plist @@ -0,0 +1,62 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Google Sign-In Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleSignInExample + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + com.googleusercontent.apps.479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u + + + + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/main.m b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/main.m new file mode 100644 index 000000000000..bec320c0bee0 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/main.m @@ -0,0 +1,13 @@ +// Copyright 2017 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 +#import +#import "AppDelegate.h" + +int main(int argc, char* argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart new file mode 100755 index 000000000000..a238ca3bf8b5 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart @@ -0,0 +1,149 @@ +// Copyright 2019 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:google_sign_in/google_sign_in.dart'; + +import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; +import 'package:googleapis/people/v1.dart'; + +GoogleSignIn _googleSignIn = GoogleSignIn( + scopes: [ + 'email', + 'https://www.googleapis.com/auth/contacts.readonly', + ], +); + +void main() { + runApp( + MaterialApp( + title: 'Google Sign In', + home: SignInDemo(), + ), + ); +} + +class SignInDemo extends StatefulWidget { + @override + State createState() => SignInDemoState(); +} + +class SignInDemoState extends State { + GoogleSignInAccount _currentUser; + String _contactText; + + @override + void initState() { + super.initState(); + _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account) { + setState(() { + _currentUser = account; + }); + if (_currentUser != null) { + _handleGetContact(); + } + }); + _googleSignIn.signInSilently(); + } + + Future _handleGetContact() async { + setState(() { + _contactText = 'Loading contact info...'; + }); + + final peopleApi = PeopleApi(await _googleSignIn.authenticatedClient()); + final response = await peopleApi.people.connections.list( + 'people/me', + personFields: 'names', + ); + + final firstNamedContactName = _pickFirstNamedContact(response.connections); + + setState(() { + if (firstNamedContactName != null) { + _contactText = 'I see you know $firstNamedContactName!'; + } else { + _contactText = 'No contacts to display.'; + } + }); + } + + String _pickFirstNamedContact(List connections) { + return connections + ?.firstWhere( + (person) => person.names != null, + orElse: () => null, + ) + ?.names + ?.firstWhere( + (name) => name.displayName != null, + orElse: () => null, + ) + ?.displayName; + } + + Future _handleSignIn() async { + try { + await _googleSignIn.signIn(); + } catch (error) { + print(error); + } + } + + Future _handleSignOut() => _googleSignIn.disconnect(); + + Widget _buildBody() { + if (_currentUser != null) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ListTile( + leading: GoogleUserCircleAvatar( + identity: _currentUser, + ), + title: Text(_currentUser.displayName ?? ''), + subtitle: Text(_currentUser.email ?? ''), + ), + const Text('Signed in successfully.'), + Text(_contactText ?? ''), + RaisedButton( + child: const Text('SIGN OUT'), + onPressed: _handleSignOut, + ), + RaisedButton( + child: const Text('REFRESH'), + onPressed: _handleGetContact, + ), + ], + ); + } else { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + const Text('You are not currently signed in.'), + RaisedButton( + child: const Text('SIGN IN'), + onPressed: _handleSignIn, + ), + ], + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Google Sign In'), + ), + body: ConstrainedBox( + constraints: const BoxConstraints.expand(), + child: _buildBody(), + )); + } +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml new file mode 100755 index 000000000000..aee073971d2c --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml @@ -0,0 +1,23 @@ +name: extension_google_sign_in_example +description: Example of Google Sign-In plugin and googleapis. + +dependencies: + flutter: + sdk: flutter + google_sign_in: ^4.4.1 + extension_google_sign_in_as_googleapis_auth: + path: ../ + googleapis: ^0.55.0 + +dev_dependencies: + pedantic: ^1.8.0 + e2e: ^0.2.1 + flutter_driver: + sdk: flutter + +flutter: + uses-material-design: true + +environment: + sdk: ">=2.0.0-dev.28.0 <3.0.0" + flutter: ">=1.12.13+hotfix.4 <2.0.0" diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/web/index.html b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/web/index.html new file mode 100644 index 000000000000..42a7d93582ba --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/web/index.html @@ -0,0 +1,11 @@ + + + + + + Google Sign-in Example + + + + + diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart new file mode 100644 index 000000000000..eec45cc0e89a --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart @@ -0,0 +1,36 @@ +// Copyright 2020 The Flutter Authors +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +import 'package:meta/meta.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:googleapis_auth/auth.dart' as googleapis_auth; +import 'package:http/http.dart' as http; + +/// Extension on [GoogleSignIn] that adds an `authenticatedClient` method. +/// +/// This method can be used to retrieve an authenticated [googleapis_auth.AuthClient] +/// client that can be used with the rest of the `googleapis` libraries. +extension GoogleApisGoogleSignInAuth on GoogleSignIn { + /// Retrieve a `googleapis` authenticated client. + Future authenticatedClient({ + @visibleForTesting GoogleSignInAuthentication debugAuthentication, + @visibleForTesting List debugScopes = const [], + }) async { + final auth = debugAuthentication ?? await currentUser.authentication; + final credentials = googleapis_auth.AccessCredentials( + googleapis_auth.AccessToken( + 'Bearer', + auth.accessToken, + // We don't know when the token expires, so we assume "never" + DateTime.now().toUtc().add(Duration(days: 365)), + ), + null, // We don't have a refreshToken + debugScopes ?? this.scopes, + ); + + return googleapis_auth.authenticatedClient(http.Client(), credentials); + } +} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml new file mode 100644 index 000000000000..f94b5e505946 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml @@ -0,0 +1,28 @@ +# Copyright 2020 The Flutter Authors +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +name: extension_google_sign_in_as_googleapis_auth +description: A bridge package between google_sign_in and googleapis_auth, to create Authenticated Clients from google_sign_in user credentials. +version: 1.0.0 +homepage: https://github.com/flutter/plugins/google_sign_in/extension_google_sign_in_as_googleapis_auth + +dependencies: + flutter: + sdk: flutter + google_sign_in: ^4.4.1 + googleapis_auth: ^0.2.11+1 + meta: ^1.1.8 + http: ^0.12.1 + +dev_dependencies: + mockito: ^4.1.1 + pedantic: ^1.9.0 + flutter_test: + sdk: flutter + +environment: + sdk: ">=2.7.0 <3.0.0" + flutter: ">=1.12.13+hotfix.4 <2.0.0" diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart new file mode 100644 index 000000000000..9f86703d4bb8 --- /dev/null +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart @@ -0,0 +1,46 @@ +// Copyright 2020 The Flutter Authors +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:googleapis_auth/auth.dart' as auth; +import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; +import 'package:mockito/mockito.dart'; +import 'package:flutter_test/flutter_test.dart'; + +// Mocks so I don't have to prepare all the GoogleSignIn environment. +class MockGoogleSignIn extends Mock implements GoogleSignIn {} + +class MockGoogleSignInAuthentication extends Mock + implements GoogleSignInAuthentication {} + +const SOME_FAKE_ACCESS_TOKEN = 'this-is-something-not-null'; +const SOME_FAKE_SCOPES = ['some-scope', 'another-scope']; + +void main() { + GoogleSignIn signIn = MockGoogleSignIn(); + final authMock = MockGoogleSignInAuthentication(); + + setUp(() { + when(authMock.accessToken).thenReturn(SOME_FAKE_ACCESS_TOKEN); + }); + + test('authenticatedClient returns an authenticated client', () async { + final client = await signIn.authenticatedClient( + debugAuthentication: authMock, + ); + expect(client, isA()); + }); + + test('authenticatedClient returned client contains the passed-in credentials', + () async { + final client = await signIn.authenticatedClient( + debugAuthentication: authMock, + debugScopes: SOME_FAKE_SCOPES, + ); + expect(client.credentials.accessToken.data, equals(SOME_FAKE_ACCESS_TOKEN)); + expect(client.credentials.scopes, equals(SOME_FAKE_SCOPES)); + }); +} diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 961cecce7903..f1f68ddbe985 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -14,6 +14,7 @@ readonly EXCLUDED_PLUGINS_LIST=( "connectivity_macos" "connectivity_platform_interface" "connectivity_web" + "extension_google_sign_in_as_googleapis_auth" "flutter_plugin_android_lifecycle" "google_maps_flutter_platform_interface" "google_maps_flutter_web" From fbd65101596d31e30b6b521d4e79861e7ccc6a93 Mon Sep 17 00:00:00 2001 From: "Ming Lyu (CareF)" Date: Wed, 15 Jul 2020 22:21:34 -0400 Subject: [PATCH 27/30] [e2e] add support to report extra information (#2873) * add extra info report --- packages/e2e/CHANGELOG.md | 4 ++ packages/e2e/lib/common.dart | 19 ++++-- packages/e2e/lib/e2e.dart | 60 ++++++++++++------- packages/e2e/pubspec.yaml | 4 +- packages/e2e/test/binding_test.dart | 41 +++++++++++++ .../e2e/test/response_serialization_test.dart | 47 +++++++++++++++ 6 files changed, 144 insertions(+), 31 deletions(-) create mode 100644 packages/e2e/test/binding_test.dart create mode 100644 packages/e2e/test/response_serialization_test.dart diff --git a/packages/e2e/CHANGELOG.md b/packages/e2e/CHANGELOG.md index ad2f8d3e24f0..255d7ce08c2d 100644 --- a/packages/e2e/CHANGELOG.md +++ b/packages/e2e/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.1 + +* Added `data` in the reported json. + ## 0.6.0 * **Breaking change** `E2EPlugin` exports a `Future` for `testResults`. diff --git a/packages/e2e/lib/common.dart b/packages/e2e/lib/common.dart index 39efcc867704..4325b6555ba8 100644 --- a/packages/e2e/lib/common.dart +++ b/packages/e2e/lib/common.dart @@ -11,13 +11,17 @@ class Response { final bool _allTestsPassed; + /// The extra information to be added along side the test result. + Map data; + /// Constructor to use for positive response. - Response.allTestsPassed() + Response.allTestsPassed({this.data}) : this._allTestsPassed = true, this._failureDetails = null; /// Constructor for failure response. - Response.someTestsFailed(this._failureDetails) : this._allTestsPassed = false; + Response.someTestsFailed(this._failureDetails, {this.data}) + : this._allTestsPassed = false; /// Whether the test ran successfully or not. bool get allTestsPassed => _allTestsPassed; @@ -33,16 +37,19 @@ class Response { String toJson() => json.encode({ 'result': allTestsPassed.toString(), 'failureDetails': _failureDetailsAsString(), + if (data != null) 'data': data }); /// Deserializes the result from JSON. static Response fromJson(String source) { - Map responseJson = json.decode(source); - if (responseJson['result'] == 'true') { - return Response.allTestsPassed(); + final Map responseJson = json.decode(source); + if (responseJson['result'] as String == 'true') { + return Response.allTestsPassed(data: responseJson['data']); } else { return Response.someTestsFailed( - _failureDetailsFromJson(responseJson['failureDetails'])); + _failureDetailsFromJson(responseJson['failureDetails']), + data: responseJson['data'], + ); } } diff --git a/packages/e2e/lib/e2e.dart b/packages/e2e/lib/e2e.dart index ec1615e904b4..a9bf83041e40 100644 --- a/packages/e2e/lib/e2e.dart +++ b/packages/e2e/lib/e2e.dart @@ -78,33 +78,47 @@ class E2EWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding { static Map _results = {}; + /// The extra data for the reported result. + /// + /// The values in `reportData` must be json-serializable objects or `null`. + /// If it's `null`, no extra data is attached to the result. + /// + /// The default value is `null`. + Map reportData; + + /// the callback function to response the driver side input. + @visibleForTesting + Future> callback(Map params) async { + final String command = params['command']; + Map response; + switch (command) { + case 'request_data': + final bool allTestsPassed = await _allTestsPassed.future; + response = { + 'message': allTestsPassed + ? Response.allTestsPassed(data: reportData).toJson() + : Response.someTestsFailed( + _failureMethodsDetails, + data: reportData, + ).toJson(), + }; + break; + case 'get_health': + response = {'status': 'ok'}; + break; + default: + throw UnimplementedError('$command is not implemented'); + } + return { + 'isError': false, + 'response': response, + }; + } + // Emulates the Flutter driver extension, returning 'pass' or 'fail'. @override void initServiceExtensions() { super.initServiceExtensions(); - Future> callback(Map params) async { - final String command = params['command']; - Map response; - switch (command) { - case 'request_data': - final bool allTestsPassed = await _allTestsPassed.future; - response = { - 'message': allTestsPassed - ? Response.allTestsPassed().toJson() - : Response.someTestsFailed(_failureMethodsDetails).toJson(), - }; - break; - case 'get_health': - response = {'status': 'ok'}; - break; - default: - throw UnimplementedError('$command is not implemented'); - } - return { - 'isError': false, - 'response': response, - }; - } if (kIsWeb) { registerWebServiceExtension(callback); diff --git a/packages/e2e/pubspec.yaml b/packages/e2e/pubspec.yaml index 25eeb3ce1374..70e57d0cb4f7 100644 --- a/packages/e2e/pubspec.yaml +++ b/packages/e2e/pubspec.yaml @@ -1,10 +1,10 @@ name: e2e description: Runs tests that use the flutter_test API as integration tests. -version: 0.6.0 +version: 0.6.1 homepage: https://github.com/flutter/plugins/tree/master/packages/e2e environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.2.2 <3.0.0" flutter: ">=1.12.13+hotfix.5 <2.0.0" dependencies: diff --git a/packages/e2e/test/binding_test.dart b/packages/e2e/test/binding_test.dart new file mode 100644 index 000000000000..8c97e161b0fe --- /dev/null +++ b/packages/e2e/test/binding_test.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; + +import 'package:e2e/e2e.dart'; +import 'package:e2e/common.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() async { + Future> request; + + group('Test E2E binding', () { + final WidgetsBinding binding = E2EWidgetsFlutterBinding.ensureInitialized(); + assert(binding is E2EWidgetsFlutterBinding); + final E2EWidgetsFlutterBinding e2ebinding = + binding as E2EWidgetsFlutterBinding; + + setUp(() { + request = e2ebinding.callback({ + 'command': 'request_data', + }); + }); + + testWidgets('Run E2E app', (WidgetTester tester) async { + runApp(MaterialApp( + home: Text('Test'), + )); + expect(tester.binding, e2ebinding); + e2ebinding.reportData = {'answer': 42}; + }); + }); + + tearDownAll(() async { + // This part is outside the group so that `request` has been compeleted as + // part of the `tearDownAll` registerred in the group during + // `E2EWidgetsFlutterBinding` initialization. + final Map response = + (await request)['response'] as Map; + final String message = response['message'] as String; + Response result = Response.fromJson(message); + assert(result.data['answer'] == 42); + }); +} diff --git a/packages/e2e/test/response_serialization_test.dart b/packages/e2e/test/response_serialization_test.dart new file mode 100644 index 000000000000..4d823e2ebf10 --- /dev/null +++ b/packages/e2e/test/response_serialization_test.dart @@ -0,0 +1,47 @@ +import 'package:flutter_test/flutter_test.dart'; + +import 'package:e2e/common.dart'; + +void main() { + test('Serialize and deserialize Failure', () { + Failure fail = Failure('what a name', 'no detail'); + Failure restored = Failure.fromJsonString(fail.toString()); + expect(restored.methodName, fail.methodName); + expect(restored.details, fail.details); + }); + + test('Serialize and deserialize Response', () { + Response response, restored; + String jsonString; + + response = Response.allTestsPassed(); + jsonString = response.toJson(); + expect(jsonString, '{"result":"true","failureDetails":[]}'); + restored = Response.fromJson(jsonString); + expect(restored.allTestsPassed, response.allTestsPassed); + expect(restored.data, null); + expect(restored.formattedFailureDetails, ''); + + final Failure fail = Failure('what a name', 'no detail'); + final Failure fail2 = Failure('what a name2', 'no detail2'); + response = Response.someTestsFailed([fail, fail2]); + jsonString = response.toJson(); + restored = Response.fromJson(jsonString); + expect(restored.allTestsPassed, response.allTestsPassed); + expect(restored.data, null); + expect(restored.formattedFailureDetails, response.formattedFailureDetails); + + Map data = {'aaa': 'bbb'}; + response = Response.allTestsPassed(data: data); + jsonString = response.toJson(); + restored = Response.fromJson(jsonString); + expect(restored.data.keys, ['aaa']); + expect(restored.data.values, ['bbb']); + + response = Response.someTestsFailed([fail, fail2], data: data); + jsonString = response.toJson(); + restored = Response.fromJson(jsonString); + expect(restored.data.keys, ['aaa']); + expect(restored.data.values, ['bbb']); + }); +} From e8882675ecc525f73a33ea2b52e2094c1cf8e161 Mon Sep 17 00:00:00 2001 From: Mauricio Date: Wed, 3 Jun 2020 12:58:40 -0500 Subject: [PATCH 28/30] fixed typo --- packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m | 2 +- packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m index bfe29f981396..06fe74a613ae 100644 --- a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m +++ b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m @@ -187,7 +187,7 @@ - (void)addPayment:(FlutterMethodCall *)call result:(FlutterResult)result { result([FlutterError errorWithCode:@"storekit_duplicate_product_object" message:@"There is a pending transaction for the same product identifier. Please " - @"either wait for it to be finished or finish it manuelly using " + @"either wait for it to be finished or finish it manually using " @"`completePurchase` to avoid edge cases." details:call.arguments]); diff --git a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m index 20543a203a97..f1290b074ad9 100644 --- a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m +++ b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m @@ -146,7 +146,7 @@ - (void)testAddPaymentWithSameProductIDWillFail { XCTAssertEqualObjects( error.message, @"There is a pending transaction for the same product identifier. Please " - @"either wait for it to be finished or finish it manuelly using " + @"either wait for it to be finished or finish it manually using " @"`completePurchase` to avoid edge cases."); [expectation fulfill]; }]; From 7b5d55291affb71d0ac5b969df9d77163a41ca05 Mon Sep 17 00:00:00 2001 From: Mauricio Date: Mon, 20 Jul 2020 12:40:34 -0500 Subject: [PATCH 29/30] Updated CHANGELOG and pubspec.yaml to reflect changes in commit 6dcd7754ef9b7ea48f4fe51a42a76f3d138529fe --- packages/in_app_purchase/CHANGELOG.md | 5 +++++ packages/in_app_purchase/pubspec.yaml | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index c159b094fb47..ca935a3e12f4 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.3.4+2 + +* Fixed typo 'manuelly' for 'manually' in documentation. +* Updated CHANGELOG and pubspec.yaml to reflect the above. + ## 0.3.4+1 * iOS: Fix the bug that `SKPaymentQueueWrapper.transactions` doesn't return all transactions. diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 58f8e1174618..f049ccf1991e 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,14 +1,15 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.3.4+1 +version: 0.3.4+2 dependencies: async: ^2.0.8 collection: ^1.14.11 flutter: sdk: flutter - json_annotation: ^3.0.0 + json_annotation + : ^3.0.0 meta: ^1.1.6 dev_dependencies: From ab7595d8e88dd90dbf176d97253d7566013d62c2 Mon Sep 17 00:00:00 2001 From: Mauricio Date: Mon, 20 Jul 2020 13:22:36 -0500 Subject: [PATCH 30/30] fixed typo --- packages/in_app_purchase/pubspec.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index f049ccf1991e..96432507a7af 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -8,8 +8,7 @@ dependencies: collection: ^1.14.11 flutter: sdk: flutter - json_annotation - : ^3.0.0 + json_annotation: ^3.0.0 meta: ^1.1.6 dev_dependencies: