diff --git a/packages/firebase_analytics/.gitignore b/packages/firebase_analytics/.gitignore new file mode 100755 index 000000000000..14c7d4c3f73e --- /dev/null +++ b/packages/firebase_analytics/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock diff --git a/packages/firebase_analytics/LICENSE b/packages/firebase_analytics/LICENSE new file mode 100755 index 000000000000..282a0f51aa4a --- /dev/null +++ b/packages/firebase_analytics/LICENSE @@ -0,0 +1,26 @@ +Copyright 2017, 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/firebase_analytics/README.md b/packages/firebase_analytics/README.md new file mode 100755 index 000000000000..5e757d5e8c2e --- /dev/null +++ b/packages/firebase_analytics/README.md @@ -0,0 +1,13 @@ +# Firebase Analytics for Flutter + +**WARNING: this is incomplete and highly experimental** + +This plugin allows Flutter apps use the Firebase Analytics API from their Dart +code. + +## Getting Started + +The the `example` directory for a sample app using Firebase Analytics. + +To learn more about Flutter plugins, view our online +[documentation](https://flutter.io/platform-plugins). diff --git a/packages/firebase_analytics/android/.gitignore b/packages/firebase_analytics/android/.gitignore new file mode 100755 index 000000000000..5c4ef82869b5 --- /dev/null +++ b/packages/firebase_analytics/android/.gitignore @@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/firebase_analytics/android/build.gradle b/packages/firebase_analytics/android/build.gradle new file mode 100755 index 000000000000..cf7ace763e2e --- /dev/null +++ b/packages/firebase_analytics/android/build.gradle @@ -0,0 +1,36 @@ +group 'io.flutter.firebase_analytics' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.0' + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.2' + + defaultConfig { + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + lintOptions { + disable 'InvalidPackage' + } + dependencies { + compile 'com.google.firebase:firebase-auth:10.2.1' + compile 'com.google.firebase:firebase-analytics:10.2.1' + } +} diff --git a/packages/firebase_analytics/android/gradle.properties b/packages/firebase_analytics/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/firebase_analytics/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/firebase_analytics/android/settings.gradle b/packages/firebase_analytics/android/settings.gradle new file mode 100755 index 000000000000..4b80dda8afc7 --- /dev/null +++ b/packages/firebase_analytics/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'firebase_analytics' diff --git a/packages/firebase_analytics/android/src/main/AndroidManifest.xml b/packages/firebase_analytics/android/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..fe60fa496e73 --- /dev/null +++ b/packages/firebase_analytics/android/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/packages/firebase_analytics/android/src/main/java/io/flutter/firebase_analytics/FirebaseAnalyticsPlugin.java b/packages/firebase_analytics/android/src/main/java/io/flutter/firebase_analytics/FirebaseAnalyticsPlugin.java new file mode 100755 index 000000000000..c4fe7b7cff52 --- /dev/null +++ b/packages/firebase_analytics/android/src/main/java/io/flutter/firebase_analytics/FirebaseAnalyticsPlugin.java @@ -0,0 +1,147 @@ +// 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.firebase_analytics; + +import java.util.Map; + +import com.google.firebase.FirebaseApp; +import com.google.firebase.analytics.FirebaseAnalytics; + +import android.app.Activity; +import android.os.Bundle; + +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.PluginRegistry; + +/** + * Flutter plugin for Firebase Analytics. + */ +public class FirebaseAnalyticsPlugin implements MethodCallHandler { + private final Activity activity; + private final FirebaseAnalytics firebaseAnalytics; + + public static void registerWith(PluginRegistry.Registrar registrar) { + final MethodChannel channel = new MethodChannel(registrar.messenger(), "firebase_analytics"); + channel.setMethodCallHandler(new FirebaseAnalyticsPlugin(registrar.activity())); + } + + private FirebaseAnalyticsPlugin(Activity activity) { + this.activity = activity; + FirebaseApp.initializeApp(activity); + this.firebaseAnalytics = FirebaseAnalytics.getInstance(activity); + } + + @Override + public void onMethodCall(MethodCall call, Result result) { + switch (call.method) { + case "logEvent": + handleLogEvent(call, result); + break; + case "setUserId": + handleSetUserId(call, result); + break; + case "setCurrentScreen": + handleSetCurrentScreen(call, result); + break; + case "setAnalyticsCollectionEnabled": + handleSetAnalyticsCollectionEnabled(call, result); + break; + case "setMinimumSessionDuration": + handleSetMinimumSessionDuration(call, result); + break; + case "setSessionTimeoutDuration": + handleSetSessionTimeoutDuration(call, result); + break; + case "setUserProperty": + handleSetUserProperty(call, result); + break; + default: + result.notImplemented(); + break; + } + } + + private void handleLogEvent(MethodCall call, Result result) { + @SuppressWarnings("unchecked") + Map arguments = (Map) call.arguments; + final String eventName = (String) arguments.get("name"); + + @SuppressWarnings("unchecked") + final Bundle parameterBundle = createBundleFromMap((Map) arguments.get("parameters")); + firebaseAnalytics.logEvent(eventName, parameterBundle); + result.success(null); + } + + private void handleSetUserId(MethodCall call, Result result) { + final String id = (String) call.arguments; + firebaseAnalytics.setUserId(id); + result.success(null); + } + + private void handleSetCurrentScreen(MethodCall call, Result result) { + @SuppressWarnings("unchecked") + Map arguments = (Map) call.arguments; + final String screenName = (String) arguments.get("screenName"); + final String screenClassOverride = (String) arguments.get("screenClassOverride"); + + firebaseAnalytics.setCurrentScreen(activity, screenName, screenClassOverride); + result.success(null); + } + + private void handleSetAnalyticsCollectionEnabled(MethodCall call, Result result) { + final Boolean enabled = (Boolean) call.arguments; + firebaseAnalytics.setAnalyticsCollectionEnabled(enabled); + result.success(null); + } + + private void handleSetMinimumSessionDuration(MethodCall call, Result result) { + final Integer milliseconds = (Integer) call.arguments; + firebaseAnalytics.setMinimumSessionDuration(milliseconds); + result.success(null); + } + + private void handleSetSessionTimeoutDuration(MethodCall call, Result result) { + final Integer milliseconds = (Integer) call.arguments; + firebaseAnalytics.setSessionTimeoutDuration(milliseconds); + result.success(null); + } + + private void handleSetUserProperty(MethodCall call, Result result) { + @SuppressWarnings("unchecked") + Map arguments = (Map) call.arguments; + final String name = (String) arguments.get("name"); + final String value = (String) arguments.get("value"); + + firebaseAnalytics.setUserProperty(name, value); + result.success(null); + } + + private static Bundle createBundleFromMap(Map map) { + if (map == null) { + return null; + } + + Bundle bundle = new Bundle(); + for (Map.Entry jsonParam : map.entrySet()) { + final Object value = jsonParam.getValue(); + final String key = jsonParam.getKey(); + if (value instanceof String) { + bundle.putString(key, (String) value); + } else if (value instanceof Integer) { + bundle.putInt(key, (Integer) value); + } else if (value instanceof Double) { + bundle.putDouble(key, (Double) value); + } else if (value instanceof Boolean) { + bundle.putBoolean(key, (Boolean) value); + } else { + throw new IllegalArgumentException("Unsupported value type: " + value.getClass().getCanonicalName()); + } + } + return bundle; + } +} diff --git a/packages/firebase_analytics/example/.gitignore b/packages/firebase_analytics/example/.gitignore new file mode 100755 index 000000000000..eb15c3d27cab --- /dev/null +++ b/packages/firebase_analytics/example/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock +.flutter-plugins diff --git a/packages/firebase_analytics/example/README.md b/packages/firebase_analytics/example/README.md new file mode 100755 index 000000000000..101d033eea86 --- /dev/null +++ b/packages/firebase_analytics/example/README.md @@ -0,0 +1,8 @@ +# firebase_analytics_example + +Demonstrates how to use the firebase_analytics plugin. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/firebase_analytics/example/android.iml b/packages/firebase_analytics/example/android.iml new file mode 100755 index 000000000000..462b903e05b6 --- /dev/null +++ b/packages/firebase_analytics/example/android.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/firebase_analytics/example/android/.gitignore b/packages/firebase_analytics/example/android/.gitignore new file mode 100755 index 000000000000..5c4ef82869b5 --- /dev/null +++ b/packages/firebase_analytics/example/android/.gitignore @@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/firebase_analytics/example/android/app/build.gradle b/packages/firebase_analytics/example/android/app/build.gradle new file mode 100755 index 000000000000..c4d9481743ec --- /dev/null +++ b/packages/firebase_analytics/example/android/app/build.gradle @@ -0,0 +1,46 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withInputStream { stream -> + localProperties.load(stream) + } +} + +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.") +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.2' + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + testInstrumentationRunner "android.support.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 + } + } +} + +flutter { + source '../..' +} + +dependencies { + compile 'com.google.firebase:firebase-core:10.0.1' +} + +apply plugin: 'com.google.gms.google-services' diff --git a/packages/firebase_analytics/example/android/app/google-services.json b/packages/firebase_analytics/example/android/app/google-services.json new file mode 100755 index 000000000000..20259483c372 --- /dev/null +++ b/packages/firebase_analytics/example/android/app/google-services.json @@ -0,0 +1,62 @@ +{ + "project_info": { + "project_number": "389050544128", + "firebase_url": "https://flutterfire-analytics-test.firebaseio.com", + "project_id": "flutterfire-analytics-test", + "storage_bucket": "flutterfire-analytics-test.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:389050544128:android:2a61bf3bd685ab07", + "android_client_info": { + "package_name": "io.flutter.firebase_analytics_example" + } + }, + "oauth_client": [ + { + "client_id": "389050544128-7uac6td8i05t4bph5tndb87fn3tsj270.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "io.flutter.firebase_analytics_example", + "certificate_hash": "329274e93660a35697463bd44f4e7deaf54f6cd4" + } + }, + { + "client_id": "389050544128-ia9mchg12k1nla2je9untm2tv0fv6cv2.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBDV1YB19hn6lyF_Ie9AcChrlgA9k8W0WI" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 2, + "other_platform_oauth_client": [ + { + "client_id": "389050544128-ia9mchg12k1nla2je9untm2tv0fv6cv2.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "389050544128-8b1peb2i3ai7o7gpdoemu044m61db209.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "io.flutter.firebaseanalytics" + } + } + ] + }, + "ads_service": { + "status": 2 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/packages/firebase_analytics/example/android/app/src/main/AndroidManifest.xml b/packages/firebase_analytics/example/android/app/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..4fd8e239c262 --- /dev/null +++ b/packages/firebase_analytics/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_analytics/example/android/app/src/main/java/io/flutter/firebase_analytics_example/MainActivity.java b/packages/firebase_analytics/example/android/app/src/main/java/io/flutter/firebase_analytics_example/MainActivity.java new file mode 100755 index 000000000000..472f6a42850f --- /dev/null +++ b/packages/firebase_analytics/example/android/app/src/main/java/io/flutter/firebase_analytics_example/MainActivity.java @@ -0,0 +1,13 @@ +package io.flutter.firebase_analytics_example; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class MainActivity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/packages/firebase_analytics/example/android/app/src/main/java/io/flutter/plugins/.gitignore b/packages/firebase_analytics/example/android/app/src/main/java/io/flutter/plugins/.gitignore new file mode 100755 index 000000000000..0f2aeaa1dc2c --- /dev/null +++ b/packages/firebase_analytics/example/android/app/src/main/java/io/flutter/plugins/.gitignore @@ -0,0 +1,3 @@ +GeneratedPluginRegistrant.java + + diff --git a/packages/firebase_analytics/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/firebase_analytics/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100755 index 000000000000..db77bb4b7b09 Binary files /dev/null and b/packages/firebase_analytics/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/firebase_analytics/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/firebase_analytics/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100755 index 000000000000..17987b79bb8a Binary files /dev/null and b/packages/firebase_analytics/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/firebase_analytics/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/firebase_analytics/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100755 index 000000000000..09d4391482be Binary files /dev/null and b/packages/firebase_analytics/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/firebase_analytics/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/firebase_analytics/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100755 index 000000000000..d5f1c8d34e7a Binary files /dev/null and b/packages/firebase_analytics/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/firebase_analytics/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/firebase_analytics/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100755 index 000000000000..4d6372eebdb2 Binary files /dev/null and b/packages/firebase_analytics/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/firebase_analytics/example/android/build.gradle b/packages/firebase_analytics/example/android/build.gradle new file mode 100755 index 000000000000..eabb32cea02a --- /dev/null +++ b/packages/firebase_analytics/example/android/build.gradle @@ -0,0 +1,30 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.1' + classpath 'com.google.gms:google-services:3.0.0' + } +} + +allprojects { + repositories { + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.14.1' +} diff --git a/packages/firebase_analytics/example/android/gradle.properties b/packages/firebase_analytics/example/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/firebase_analytics/example/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/firebase_analytics/example/android/settings.gradle b/packages/firebase_analytics/example/android/settings.gradle new file mode 100755 index 000000000000..115da6cb4f4d --- /dev/null +++ b/packages/firebase_analytics/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/firebase_analytics/example/firebase_analytics_example.iml b/packages/firebase_analytics/example/firebase_analytics_example.iml new file mode 100755 index 000000000000..1ae40a0f7f54 --- /dev/null +++ b/packages/firebase_analytics/example/firebase_analytics_example.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/firebase_analytics/example/ios/.gitignore b/packages/firebase_analytics/example/ios/.gitignore new file mode 100755 index 000000000000..664e66b11f16 --- /dev/null +++ b/packages/firebase_analytics/example/ios/.gitignore @@ -0,0 +1,42 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/app.flx +/Flutter/app.zip +/Flutter/App.framework +/Flutter/Flutter.framework +/Flutter/Generated.xcconfig +/ServiceDefinitions.json + +Podfile.lock +Pods +/Runner/GeneratedPluginRegistrant.h +/Runner/GeneratedPluginRegistrant.m diff --git a/packages/firebase_analytics/example/ios/Flutter/AppFrameworkInfo.plist b/packages/firebase_analytics/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100755 index 000000000000..6c2de8086bcd --- /dev/null +++ b/packages/firebase_analytics/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/firebase_analytics/example/ios/Flutter/Debug.xcconfig b/packages/firebase_analytics/example/ios/Flutter/Debug.xcconfig new file mode 100755 index 000000000000..9803018ca79d --- /dev/null +++ b/packages/firebase_analytics/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/firebase_analytics/example/ios/Flutter/Release.xcconfig b/packages/firebase_analytics/example/ios/Flutter/Release.xcconfig new file mode 100755 index 000000000000..a4a8c604e13d --- /dev/null +++ b/packages/firebase_analytics/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/firebase_analytics/example/ios/Podfile b/packages/firebase_analytics/example/ios/Podfile new file mode 100755 index 000000000000..90b5f651fb63 --- /dev/null +++ b/packages/firebase_analytics/example/ios/Podfile @@ -0,0 +1,36 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +if ENV['FLUTTER_FRAMEWORK_DIR'] == nil + abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework') +end + +target 'Runner' do + # Pods for Runner + + # Flutter Pods + pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR'] + + if File.exists? '../.flutter-plugins' + flutter_root = File.expand_path('..') + File.foreach('../.flutter-plugins') { |line| + plugin = line.split(pattern='=') + if plugin.length == 2 + name = plugin[0].strip() + path = plugin[1].strip() + resolved_path = File.expand_path("#{path}/ios", flutter_root) + pod name, :path => resolved_path + else + puts "Invalid plugin specification: #{line}" + end + } + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/packages/firebase_analytics/example/ios/Runner.xcodeproj/project.pbxproj b/packages/firebase_analytics/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100755 index 000000000000..cef65a5b036c --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,499 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 5C6F5A6B1EC3AF0E008D64B5 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C6F5A6A1EC3AF0E008D64B5 /* GeneratedPluginRegistrant.m */; }; + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; }; + 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 */; }; + B1F3D14E8117A6C9F65810E0 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D558BB7489B1C82B42A9097 /* libPods-Runner.a */; }; + B43DDBB51EA0304000A48ABE /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B43DDBB41EA0304000A48ABE /* GoogleService-Info.plist */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 4D558BB7489B1C82B42A9097 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5C6F5A691EC3AF0E008D64B5 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 5C6F5A6A1EC3AF0E008D64B5 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; 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 = ""; }; + 9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = ""; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; 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 = ""; }; + B43DDBB41EA0304000A48ABE /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + B1F3D14E8117A6C9F65810E0 /* libPods-Runner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 9740EEB71CF902C7004384FC /* app.flx */, + 3B80C3931E831B6300D905FE /* App.framework */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 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 = ( + 5C6F5A691EC3AF0E008D64B5 /* GeneratedPluginRegistrant.h */, + 5C6F5A6A1EC3AF0E008D64B5 /* GeneratedPluginRegistrant.m */, + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + B43DDBB41EA0304000A48ABE /* GoogleService-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 = ( + 4D558BB7489B1C82B42A9097 /* 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 = 0830; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = 3GRKCVVJ22; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + 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 = ( + 9740EEBB1CF902C7004384FC /* app.flx in Resources */, + B43DDBB51EA0304000A48ABE /* GoogleService-Info.plist in Resources */, + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* 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\" thin"; + }; + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/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 = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../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"; + 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 */, + 5C6F5A6B1EC3AF0E008D64B5 /* 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; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + 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_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + 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_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = 3GRKCVVJ22; + 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.firebaseAnalyticsExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = 3GRKCVVJ22; + 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.firebaseAnalyticsExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + }; + 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/firebase_analytics/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/firebase_analytics/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/firebase_analytics/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/firebase_analytics/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100755 index 000000000000..1c9580788197 --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_analytics/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/firebase_analytics/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/firebase_analytics/example/ios/Runner/AppDelegate.h b/packages/firebase_analytics/example/ios/Runner/AppDelegate.h new file mode 100755 index 000000000000..cf210d213f27 --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/packages/firebase_analytics/example/ios/Runner/AppDelegate.m b/packages/firebase_analytics/example/ios/Runner/AppDelegate.m new file mode 100755 index 000000000000..0e94ecd7e4e8 --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner/AppDelegate.m @@ -0,0 +1,12 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 000000000000..d22f10b2ab63 --- /dev/null +++ b/packages/firebase_analytics/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/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100755 index 000000000000..28c6bf03016f Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100755 index 000000000000..2ccbfd967d96 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100755 index 000000000000..f091b6b0bca8 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100755 index 000000000000..4cde12118dda Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100755 index 000000000000..d0ef06e7edb8 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100755 index 000000000000..dcdc2306c285 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100755 index 000000000000..2ccbfd967d96 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100755 index 000000000000..c8f9ed8f5cee Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100755 index 000000000000..a6d6b8609df0 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100755 index 000000000000..a6d6b8609df0 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100755 index 000000000000..75b2d164a5a9 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100755 index 000000000000..c4df70d39da7 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100755 index 000000000000..6a84f41e14e2 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100755 index 000000000000..d0e1f5853602 Binary files /dev/null and b/packages/firebase_analytics/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/firebase_analytics/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/firebase_analytics/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100755 index 000000000000..ebf48f603974 --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_analytics/example/ios/Runner/Base.lproj/Main.storyboard b/packages/firebase_analytics/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100755 index 000000000000..f3c28516fb38 --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_analytics/example/ios/Runner/GoogleService-Info.plist b/packages/firebase_analytics/example/ios/Runner/GoogleService-Info.plist new file mode 100755 index 000000000000..515c84c63cdf --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,40 @@ + + + + + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 + CLIENT_ID + 389050544128-8b1peb2i3ai7o7gpdoemu044m61db209.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.389050544128-8b1peb2i3ai7o7gpdoemu044m61db209 + API_KEY + AIzaSyCKms_Et6CUgO9xu2RxwM6z5qFWXMdbMNc + GCM_SENDER_ID + 389050544128 + PLIST_VERSION + 1 + BUNDLE_ID + io.flutter.firebaseanalytics + PROJECT_ID + flutterfire-analytics-test + STORAGE_BUCKET + flutterfire-analytics-test.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:389050544128:ios:d6252587c74a8055 + DATABASE_URL + https://flutterfire-analytics-test.firebaseio.com + + \ No newline at end of file diff --git a/packages/firebase_analytics/example/ios/Runner/Info.plist b/packages/firebase_analytics/example/ios/Runner/Info.plist new file mode 100755 index 000000000000..50d501fd1f7f --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + firebase_analytics_example + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/firebase_analytics/example/ios/Runner/main.m b/packages/firebase_analytics/example/ios/Runner/main.m new file mode 100755 index 000000000000..1bdb8e28d1db --- /dev/null +++ b/packages/firebase_analytics/example/ios/Runner/main.m @@ -0,0 +1,10 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, + NSStringFromClass([AppDelegate class])); + } +} diff --git a/packages/firebase_analytics/example/lib/main.dart b/packages/firebase_analytics/example/lib/main.dart new file mode 100755 index 000000000000..ec15812ced98 --- /dev/null +++ b/packages/firebase_analytics/example/lib/main.dart @@ -0,0 +1,291 @@ +// 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 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:firebase_analytics/firebase_analytics.dart'; + +void main() { + runApp(new MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'Firebase Analytics Demo', + theme: new ThemeData( + primarySwatch: Colors.blue, + ), + home: new MyHomePage(title: 'Firebase Analytics Demo'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => new _MyHomePageState(); +} + +class _MyHomePageState extends State { + String _message = ''; + final FirebaseAnalytics analytics = new FirebaseAnalytics(); + + void setMessage(String message) { + setState(() { + _message = message; + }); + } + + Future _sendAnalyticsEvent() async { + await analytics.logEvent(name: 'test_event'); + setMessage('logEvent succeeded'); + } + + Future _testSetUserId() async { + await analytics.setUserId('some-user'); + setMessage('setUserId succeeded'); + } + + Future _testSetCurrentScreen() async { + await analytics.setCurrentScreen( + screenName: 'Analytics Demo', + screenClassOverride: 'AnalyticsDemo', + ); + setMessage('setCurrentScreen succeeded'); + } + + Future _testSetAnalyticsCollectionEnabled() async { + await analytics.android?.setAnalyticsCollectionEnabled(false); + await analytics.android?.setAnalyticsCollectionEnabled(true); + setMessage('setAnalyticsCollectionEnabled succeeded'); + } + + Future _testSetMinimumSessionDuration() async { + await analytics.android?.setMinimumSessionDuration(20000); + setMessage('setMinimumSessionDuration succeeded'); + } + + Future _testSetSessionTimeoutDuration() async { + await analytics.android?.setSessionTimeoutDuration(2000000); + setMessage('setSessionTimeoutDuration succeeded'); + } + + Future _testSetUserProperty() async { + await analytics.setUserProperty(name: 'regular', value: 'indeed'); + setMessage('setUserProperty succeeded'); + } + + Future _testAllEventTypes() async { + await analytics.logAddPaymentInfo(); + await analytics.logAddToCart( + currency: 'USD', + value: 123.0, + itemId: 'test item id', + itemName: 'test item name', + itemCategory: 'test item category', + quantity: 5, + price: 24.0, + origin: 'test origin', + itemLocationId: 'test location id', + destination: 'test destination', + startDate: '2015-09-14', + endDate: '2015-09-17', + ); + await analytics.logAddToWishlist( + itemId: 'test item id', + itemName: 'test item name', + itemCategory: 'test item category', + quantity: 5, + price: 24.0, + value: 123.0, + currency: 'USD', + itemLocationId: 'test location id', + ); + await analytics.logAppOpen(); + await analytics.logBeginCheckout( + value: 123.0, + currency: 'USD', + transactionId: 'test tx id', + numberOfNights: 2, + numberOfRooms: 3, + numberOfPassengers: 4, + origin: 'test origin', + destination: 'test destination', + startDate: '2015-09-14', + endDate: '2015-09-17', + travelClass: 'test travel class', + ); + await analytics.logCampaignDetails( + source: 'test source', + medium: 'test medium', + campaign: 'test campaign', + term: 'test term', + content: 'test content', + aclid: 'test aclid', + cp1: 'test cp1', + ); + await analytics.logEarnVirtualCurrency( + virtualCurrencyName: 'bitcoin', + value: 345.66, + ); + await analytics.logEcommercePurchase( + currency: 'USD', + value: 432.45, + transactionId: 'test tx id', + tax: 3.45, + shipping: 5.67, + coupon: 'test coupon', + location: 'test location', + numberOfNights: 3, + numberOfRooms: 4, + numberOfPassengers: 5, + origin: 'test origin', + destination: 'test destination', + startDate: '2015-09-13', + endDate: '2015-09-14', + travelClass: 'test travel class', + ); + await analytics.logGenerateLead( + currency: 'USD', + value: 123.45, + ); + await analytics.logJoinGroup( + groupId: 'test group id', + ); + await analytics.logLevelUp( + level: 5, + character: 'witch doctor', + ); + await analytics.logLogin(); + await analytics.logPostScore( + score: 1000000, + level: 70, + character: 'tiefling cleric', + ); + await analytics.logPresentOffer( + itemId: 'test item id', + itemName: 'test item name', + itemCategory: 'test item category', + quantity: 6, + price: 3.45, + value: 67.8, + currency: 'USD', + itemLocationId: 'test item location id', + ); + await analytics.logPurchaseRefund( + currency: 'USD', + value: 45.67, + transactionId: 'test tx id', + ); + await analytics.logSearch( + searchTerm: 'hotel', + numberOfNights: 2, + numberOfRooms: 1, + numberOfPassengers: 3, + origin: 'test origin', + destination: 'test destination', + startDate: '2015-09-14', + endDate: '2015-09-16', + travelClass: 'test travel class', + ); + await analytics.logSelectContent( + contentType: 'test content type', + itemId: 'test item id', + ); + await analytics.logShare( + contentType: 'test content type', + itemId: 'test item id', + ); + await analytics.logSignUp( + signUpMethod: 'test sign up method', + ); + await analytics.logSpendVirtualCurrency( + itemName: 'test item name', + virtualCurrencyName: 'bitcoin', + value: 34, + ); + await analytics.logTutorialBegin(); + await analytics.logTutorialComplete(); + await analytics.logUnlockAchievement(id: 'all Firebase API covered'); + await analytics.logViewItem( + itemId: 'test item id', + itemName: 'test item name', + itemCategory: 'test item category', + itemLocationId: 'test item location id', + price: 3.45, + quantity: 6, + currency: 'USD', + value: 67.8, + flightNumber: 'test flight number', + numberOfPassengers: 3, + numberOfRooms: 1, + numberOfNights: 2, + origin: 'test origin', + destination: 'test destination', + startDate: '2015-09-14', + endDate: '2015-09-15', + searchTerm: 'test search term', + travelClass: 'test travel class', + ); + await analytics.logViewItemList( + itemCategory: 'test item category', + ); + await analytics.logViewSearchResults( + searchTerm: 'test search term', + ); + setMessage('All standard events logged successfully'); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + ), + body: new Column( + children: [ + new MaterialButton( + child: const Text('Test logEvent'), + onPressed: _sendAnalyticsEvent, + ), + new MaterialButton( + child: const Text('Test standard event types'), + onPressed: _testAllEventTypes, + ), + new MaterialButton( + child: const Text('Test setUserId'), + onPressed: _testSetUserId, + ), + new MaterialButton( + child: const Text('Test setCurrentScreen'), + onPressed: _testSetCurrentScreen, + ), + new MaterialButton( + child: const Text('Test setAnalyticsCollectionEnabled'), + onPressed: _testSetAnalyticsCollectionEnabled, + ), + new MaterialButton( + child: const Text('Test setMinimumSessionDuration'), + onPressed: _testSetMinimumSessionDuration, + ), + new MaterialButton( + child: const Text('Test setSessionTimeoutDuration'), + onPressed: _testSetSessionTimeoutDuration, + ), + new MaterialButton( + child: const Text('Test setUserProperty'), + onPressed: _testSetUserProperty, + ), + new Text(_message, style: const TextStyle(color: const Color.fromARGB(255, 0, 155, 0))), + ], + ), + ); + } +} diff --git a/packages/firebase_analytics/example/pubspec.yaml b/packages/firebase_analytics/example/pubspec.yaml new file mode 100755 index 000000000000..c4cb03a3242f --- /dev/null +++ b/packages/firebase_analytics/example/pubspec.yaml @@ -0,0 +1,53 @@ +name: firebase_analytics_example +description: Demonstrates how to use the firebase_analytics plugin. + +dependencies: + flutter: + sdk: flutter + firebase_analytics: + path: ../ + +# For information on the generic Dart part of this file, see the +# following page: https://www.dartlang.org/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section here, in + # this "flutter" section, as in: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # To add assets from package dependencies, first ensure the asset + # is in the lib/ directory of the dependency. Then, + # refer to the asset with a path prefixed with + # `packages/PACKAGE_NAME/`. Note: the `lib/` is implied, do not + # include `lib/` in the asset path. + # + # Here is an example: + # + # assets: + # - packages/PACKAGE_NAME/path/to/asset + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 diff --git a/packages/firebase_analytics/ios/.gitignore b/packages/firebase_analytics/ios/.gitignore new file mode 100755 index 000000000000..956c87f3aa28 --- /dev/null +++ b/packages/firebase_analytics/ios/.gitignore @@ -0,0 +1,31 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + diff --git a/packages/firebase_analytics/ios/Assets/.gitkeep b/packages/firebase_analytics/ios/Assets/.gitkeep new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/packages/firebase_analytics/ios/Classes/FirebaseAnalyticsPlugin.h b/packages/firebase_analytics/ios/Classes/FirebaseAnalyticsPlugin.h new file mode 100755 index 000000000000..93f8d43c3cf7 --- /dev/null +++ b/packages/firebase_analytics/ios/Classes/FirebaseAnalyticsPlugin.h @@ -0,0 +1,8 @@ +// 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 + +@interface FirebaseAnalyticsPlugin : NSObject +@end diff --git a/packages/firebase_analytics/ios/Classes/FirebaseAnalyticsPlugin.m b/packages/firebase_analytics/ios/Classes/FirebaseAnalyticsPlugin.m new file mode 100755 index 000000000000..60d44966c174 --- /dev/null +++ b/packages/firebase_analytics/ios/Classes/FirebaseAnalyticsPlugin.m @@ -0,0 +1,63 @@ +// 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 "FirebaseAnalyticsPlugin.h" + +#import "Firebase/Firebase.h" + +@implementation FirebaseAnalyticsPlugin { +} + ++ (void)registerWithRegistrar:(NSObject *)registrar { + FlutterMethodChannel *channel = + [FlutterMethodChannel methodChannelWithName:@"firebase_analytics" + binaryMessenger:[registrar messenger]]; + FirebaseAnalyticsPlugin *instance = [[FirebaseAnalyticsPlugin alloc] init]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (instancetype)init { + self = [super init]; + if (self) { + if (![FIRApp defaultApp]) { + [FIRApp configure]; + } + } + return self; +} + +- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { + if ([@"logEvent" isEqualToString:call.method]) { + NSString *eventName = call.arguments[@"name"]; + id parameterMap = call.arguments[@"parameters"]; + + if (parameterMap != [NSNull null]) { + [FIRAnalytics logEventWithName:eventName + parameters:parameterMap]; + } else { + [FIRAnalytics logEventWithName:eventName + parameters:nil]; + } + + result(nil); + } else if ([@"setUserId" isEqualToString:call.method]) { + NSString *userId = call.arguments; + [FIRAnalytics setUserID:userId]; + result(nil); + } else if ([@"setCurrentScreen" isEqualToString:call.method]) { + NSString *screenName = call.arguments[@"screenName"]; + NSString *screenClassOverride = call.arguments[@"screenClassOverride"]; + [FIRAnalytics setScreenName:screenName screenClass:screenClassOverride]; + result(nil); + } else if ([@"setUserProperty" isEqualToString:call.method]) { + NSString *name = call.arguments[@"name"]; + NSString *value = call.arguments[@"value"]; + [FIRAnalytics setUserPropertyString:value forName:name]; + result(nil); + } else { + result(FlutterMethodNotImplemented); + } +} + +@end diff --git a/packages/firebase_analytics/ios/firebase_analytics.podspec b/packages/firebase_analytics/ios/firebase_analytics.podspec new file mode 100755 index 000000000000..5ab1bbb86f46 --- /dev/null +++ b/packages/firebase_analytics/ios/firebase_analytics.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 = 'firebase_analytics' + s.version = '0.0.1' + s.summary = 'Firebase Analytics plugin for Flutter.' + s.description = <<-DESC +Firebase Analytics plugin for Flutter. + DESC + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/firebase_analytics' + 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.ios.deployment_target = '6.0' + s.dependency 'Flutter' + s.dependency 'Firebase/Core' +end diff --git a/packages/firebase_analytics/lib/firebase_analytics.dart b/packages/firebase_analytics/lib/firebase_analytics.dart new file mode 100755 index 000000000000..62b2a0800abd --- /dev/null +++ b/packages/firebase_analytics/lib/firebase_analytics.dart @@ -0,0 +1,968 @@ +// 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 'dart:async'; + +import 'package:meta/meta.dart'; + +import 'package:flutter/services.dart'; +import 'package:flutter/foundation.dart'; + +/// Firebase Analytics API. +class FirebaseAnalytics { + static final FirebaseAnalytics _instance = new FirebaseAnalytics.private(const MethodChannel('firebase_analytics')); + + /// Provides an instance of this class. + factory FirebaseAnalytics() => _instance; + + /// We don't want people to extend this class, but implementing its interface, + /// e.g. in tests, is OK. + @visibleForTesting + FirebaseAnalytics.private(MethodChannel platformChannel) + : _channel = platformChannel, + android = defaultTargetPlatform == TargetPlatform.android + ? new FirebaseAnalyticsAndroid.private(platformChannel) + : null; + + final MethodChannel _channel; + + /// Namespace for analytics API available on Android only. + /// + /// The value of this field is `null` on non-Android platforms. If you are + /// writing cross-platform code, consider using null-aware operator when + /// accessing it. + /// + /// Example: + /// + /// FirebaseAnalytics analytics = new FirebaseAnalytics(); + /// analytics.android?.setMinimumSessionDuration(200000); + final FirebaseAnalyticsAndroid android; + + /// Logs a custom Flutter Analytics event with the given [name] and event [parameters]. + Future logEvent({@required String name, Map parameters}) async { + if (_reservedEventNames.contains(name)) { + throw new ArgumentError.value(name, 'name', + 'Event name is reserved and cannot be used'); + } + + const String kReservedPrefix = 'firebase_'; + + if (name.startsWith(kReservedPrefix)) { + throw new ArgumentError.value(name, 'name', + 'Prefix "$kReservedPrefix" is reserved and cannot be used.'); + } + + await _channel.invokeMethod('logEvent', { + 'name': name, + 'parameters': parameters, + }); + } + + /// Sets the user ID property. + /// + /// This feature must be used in accordance with [Google's Privacy Policy][1]. + /// + /// [1]: https://www.google.com/policies/privacy/ + Future setUserId(String id) async { + if (id == null) + throw new ArgumentError.notNull('id'); + + await _channel.invokeMethod('setUserId', id); + } + + /// Sets the current [screenName], which specifies the current visual context + /// in your app. + /// + /// This helps identify the areas in your app where users spend their time + /// and how they interact with your app. + /// + /// The class name can optionally be overridden by the [screenClassOverride] + /// parameter. + /// + /// The [screenName] and [screenClassOverride] remain in effect until the + /// current `Activity` (in Android) or `UIViewController` (in iOS) changes or + /// a new call to [setCurrentScreen] is made. + /// + /// See also: + /// + /// https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.html#setCurrentScreen(android.app.Activity, java.lang.String, java.lang.String) + /// https://firebase.google.com/docs/reference/ios/firebaseanalytics/api/reference/Classes/FIRAnalytics#setscreennamescreenclass + Future setCurrentScreen({@required String screenName, String screenClassOverride}) async { + if (screenName == null) + throw new ArgumentError.notNull('screenName'); + + await _channel.invokeMethod('setCurrentScreen', { + 'screenName': screenName, + 'screenClassOverride': screenClassOverride, + }); + } + + static final RegExp _nonAlphaNumeric = new RegExp(r'[^a-zA-Z0-9_]'); + static final RegExp _alpha = new RegExp(r'[a-zA-Z]'); + + /// Sets a user property to a given value. + /// + /// Up to 25 user property names are supported. Once set, user property + /// values persist throughout the app lifecycle and across sessions. + /// + /// [name] is the name of the user property to set. Should contain 1 to 24 + /// alphanumeric characters or underscores and must start with an alphabetic + /// character. The "firebase_" prefix is reserved and should not be used for + /// user property names. + Future setUserProperty({@required String name, @required String value}) async { + if (name == null) + throw new ArgumentError.notNull('name'); + + if (name.isEmpty || name.length > 24 || name.indexOf(_alpha) != 0 || name.contains(_nonAlphaNumeric)) + throw new ArgumentError.value(name, 'name', 'must contain 1 to 24 alphanumeric characters.'); + + if (name.startsWith('firebase_')) + throw new ArgumentError.value(name, 'name', '"firebase_" prefix is reserved'); + + await _channel.invokeMethod('setUserProperty', { + 'name': name, + 'value': value, + }); + } + + /// Logs the standard `add_payment_info` event. + /// + /// This event signifies that a user has submitted their payment information + /// to your app. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#ADD_PAYMENT_INFO + Future logAddPaymentInfo() { + return logEvent(name: 'add_payment_info'); + } + + /// Logs the standard `add_to_cart` event. + /// + /// This event signifies that an item was added to a cart for purchase. Add + /// this event to a funnel with [logEcommercePurchase] to gauge the + /// effectiveness of your checkout process. Note: If you supply the + /// [value] parameter, you must also supply the [currency] parameter so that + /// revenue metrics can be computed accurately. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#ADD_TO_CART + Future logAddToCart({ + @required String itemId, + @required String itemName, + @required String itemCategory, + @required int quantity, + double price, + double value, + String currency, + String origin, + String itemLocationId, + String destination, + String startDate, + String endDate, + }) { + _requireValueAndCurrencyTogether(value, currency); + + return logEvent( + name: 'add_to_cart', + parameters: filterOutNulls({ + _ITEM_ID: itemId, + _ITEM_NAME: itemName, + _ITEM_CATEGORY: itemCategory, + _QUANTITY: quantity, + _PRICE: price, + _VALUE: value, + _CURRENCY: currency, + _ORIGIN: origin, + _ITEM_LOCATION_ID: itemLocationId, + _DESTINATION: destination, + _START_DATE: startDate, + _END_DATE: endDate, + }), + ); + } + + /// Logs the standard `add_to_wishlist` event. + /// + /// This event signifies that an item was added to a wishlist. Use this event + /// to identify popular gift items in your app. Note: If you supply the + /// [value] parameter, you must also supply the [currency] parameter so that + /// revenue metrics can be computed accurately. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#ADD_TO_WISHLIST + Future logAddToWishlist({ + @required String itemId, + @required String itemName, + @required String itemCategory, + @required int quantity, + double price, + double value, + String currency, + String itemLocationId, + }) { + _requireValueAndCurrencyTogether(value, currency); + + return logEvent( + name: 'add_to_wishlist', + parameters: filterOutNulls({ + _ITEM_ID: itemId, + _ITEM_NAME: itemName, + _ITEM_CATEGORY: itemCategory, + _QUANTITY: quantity, + _PRICE: price, + _VALUE: value, + _CURRENCY: currency, + _ITEM_LOCATION_ID: itemLocationId, + }), + ); + } + + /// Logs the standard `app_open` event. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#APP_OPEN + Future logAppOpen() { + return logEvent(name: 'app_open'); + } + + /// Logs the standard `begin_checkout` event. + /// + /// This event signifies that a user has begun the process of checking out. + /// Add this event to a funnel with your [logEcommercePurchase] event to + /// gauge the effectiveness of your checkout process. Note: If you supply the + /// [value] parameter, you must also supply the [currency] parameter so that + /// revenue metrics can be computed accurately. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#BEGIN_CHECKOUT + Future logBeginCheckout({ + double value, + String currency, + String transactionId, + int numberOfNights, + int numberOfRooms, + int numberOfPassengers, + String origin, + String destination, + String startDate, + String endDate, + String travelClass, + }) { + _requireValueAndCurrencyTogether(value, currency); + + return logEvent( + name: 'begin_checkout', + parameters: filterOutNulls({ + _VALUE: value, + _CURRENCY: currency, + _TRANSACTION_ID: transactionId, + _NUMBER_OF_NIGHTS: numberOfNights, + _NUMBER_OF_ROOMS: numberOfRooms, + _NUMBER_OF_PASSENGERS: numberOfPassengers, + _ORIGIN: origin, + _DESTINATION: destination, + _START_DATE: startDate, + _END_DATE: endDate, + _TRAVEL_CLASS: travelClass, + }), + ); + } + + /// Logs the standard `campaign_details` event. + /// + /// Log this event to supply the referral details of a re-engagement campaign. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#CAMPAIGN_DETAILS + Future logCampaignDetails({ + @required String source, + @required String medium, + @required String campaign, + String term, + String content, + String aclid, + String cp1, + }) { + return logEvent( + name: 'campaign_details', + parameters: filterOutNulls({ + _SOURCE: source, + _MEDIUM: medium, + _CAMPAIGN: campaign, + _TERM: term, + _CONTENT: content, + _ACLID: aclid, + _CP1: cp1, + }), + ); + } + + /// Logs the standard `earn_virtual_currency` event. + /// + /// This event tracks the awarding of virtual currency in your app. Log this + /// along with [logSpendVirtualCurrency] to better understand your virtual + /// economy. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#EARN_VIRTUAL_CURRENCY + Future logEarnVirtualCurrency({ + @required String virtualCurrencyName, + @required num value, + }) { + return logEvent( + name: 'earn_virtual_currency', + parameters: filterOutNulls({ + _VIRTUAL_CURRENCY_NAME: virtualCurrencyName, + _VALUE: value, + }), + ); + } + + /// Logs the standard `ecommerce_purchase` event. + /// + /// This event signifies that an item was purchased by a user. Note: This is + /// different from the in-app purchase event, which is reported automatically + /// for Google Play-based apps. Note: If you supply the [value] parameter, + /// you must also supply the [currency] parameter so that revenue metrics can + /// be computed accurately. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#ECOMMERCE_PURCHASE + Future logEcommercePurchase({ + String currency, + double value, + String transactionId, + double tax, + double shipping, + String coupon, + String location, + int numberOfNights, + int numberOfRooms, + int numberOfPassengers, + String origin, + String destination, + String startDate, + String endDate, + String travelClass, + }) { + _requireValueAndCurrencyTogether(value, currency); + + return logEvent( + name: 'ecommerce_purchase', + parameters: filterOutNulls({ + _CURRENCY: currency, + _VALUE: value, + _TRANSACTION_ID: transactionId, + _TAX: tax, + _SHIPPING: shipping, + _COUPON: coupon, + _LOCATION: location, + _NUMBER_OF_NIGHTS: numberOfNights, + _NUMBER_OF_ROOMS: numberOfRooms, + _NUMBER_OF_PASSENGERS: numberOfPassengers, + _ORIGIN: origin, + _DESTINATION: destination, + _START_DATE: startDate, + _END_DATE: endDate, + _TRAVEL_CLASS: travelClass, + }), + ); + } + + /// Logs the standard `generate_lead` event. + /// + /// Log this event when a lead has been generated in the app to understand + /// the efficacy of your install and re-engagement campaigns. Note: If you + /// supply the [value] parameter, you must also supply the [currency] + /// parameter so that revenue metrics can be computed accurately. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#GENERATE_LEAD + Future logGenerateLead({ + String currency, + double value, + }) { + _requireValueAndCurrencyTogether(value, currency); + + return logEvent( + name: 'generate_lead', + parameters: filterOutNulls({ + _CURRENCY: currency, + _VALUE: value, + }), + ); + } + + /// Logs the standard `join_group` event. + /// + /// Log this event when a user joins a group such as a guild, team or family. + /// Use this event to analyze how popular certain groups or social features + /// are in your app. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#JOIN_GROUP + Future logJoinGroup({ + @required String groupId, + }) { + return logEvent( + name: 'join_group', + parameters: filterOutNulls({ + _GROUP_ID: groupId, + }), + ); + } + + /// Logs the standard `level_up` event. + /// + /// This event signifies that a player has leveled up in your gaming app. It + /// can help you gauge the level distribution of your userbase and help you + /// identify certain levels that are difficult to pass. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#LEVEL_UP + Future logLevelUp({ + @required int level, + String character, + }) { + return logEvent( + name: 'level_up', + parameters: filterOutNulls({ + _LEVEL: level, + _CHARACTER: character, + }), + ); + } + + /// Logs the standard `login` event. + /// + /// Apps with a login feature can report this event to signify that a user + /// has logged in. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#LOGIN + Future logLogin() { + return logEvent(name: 'login'); + } + + /// Logs the standard `post_score` event. + /// + /// Log this event when the user posts a score in your gaming app. This event + /// can help you understand how users are actually performing in your game + /// and it can help you correlate high scores with certain audiences or + /// behaviors. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#POST_SCORE + Future logPostScore({ + @required int score, + int level, + String character, + }) { + return logEvent( + name: 'post_score', + parameters: filterOutNulls({ + _SCORE: score, + _LEVEL: level, + _CHARACTER: character, + }), + ); + } + + /// Logs the standard `present_offer` event. + /// + /// This event signifies that the app has presented a purchase offer to a + /// user. Add this event to a funnel with the [logAddToCart] and + /// [logEcommercePurchase] to gauge your conversion process. Note: If you + /// supply the [value] parameter, you must also supply the [currency] + /// parameter so that revenue metrics can be computed accurately. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#PRESENT_OFFER + Future logPresentOffer({ + @required String itemId, + @required String itemName, + @required String itemCategory, + @required int quantity, + double price, + double value, + String currency, + String itemLocationId, + }) { + _requireValueAndCurrencyTogether(value, currency); + + return logEvent( + name: 'present_offer', + parameters: filterOutNulls({ + _ITEM_ID: itemId, + _ITEM_NAME: itemName, + _ITEM_CATEGORY: itemCategory, + _QUANTITY: quantity, + _PRICE: price, + _VALUE: value, + _CURRENCY: currency, + _ITEM_LOCATION_ID: itemLocationId, + }), + ); + } + + /// Logs the standard `purchase_refund` event. + /// + /// This event signifies that an item purchase was refunded. Note: If you + /// supply the [value] parameter, you must also supply the [currency] + /// parameter so that revenue metrics can be computed accurately. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#PURCHASE_REFUND + Future logPurchaseRefund({ + String currency, + double value, + String transactionId, + }) { + _requireValueAndCurrencyTogether(value, currency); + + return logEvent( + name: 'purchase_refund', + parameters: filterOutNulls({ + _CURRENCY: currency, + _VALUE: value, + _TRANSACTION_ID: transactionId, + }), + ); + } + + /// Logs the standard `search` event. + /// + /// Apps that support search features can use this event to contextualize + /// search operations by supplying the appropriate, corresponding parameters. + /// This event can help you identify the most popular content in your app. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#SEARCH + Future logSearch({ + @required String searchTerm, + int numberOfNights, + int numberOfRooms, + int numberOfPassengers, + String origin, + String destination, + String startDate, + String endDate, + String travelClass, + }) { + return logEvent( + name: 'search', + parameters: filterOutNulls({ + _SEARCH_TERM: searchTerm, + _NUMBER_OF_NIGHTS: numberOfNights, + _NUMBER_OF_ROOMS: numberOfRooms, + _NUMBER_OF_PASSENGERS: numberOfPassengers, + _ORIGIN: origin, + _DESTINATION: destination, + _START_DATE: startDate, + _END_DATE: endDate, + _TRAVEL_CLASS: travelClass, + }), + ); + } + + /// Logs the standard `select_content` event. + /// + /// This general purpose event signifies that a user has selected some + /// content of a certain type in an app. The content can be any object in + /// your app. This event can help you identify popular content and categories + /// of content in your app. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#SELECT_CONTENT + Future logSelectContent({ + @required String contentType, + @required String itemId, + }) { + return logEvent( + name: 'select_content', + parameters: filterOutNulls({ + _CONTENT_TYPE: contentType, + _ITEM_ID: itemId, + }), + ); + } + + /// Logs the standard `share` event. + /// + /// Apps with social features can log the Share event to identify the most + /// viral content. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#SHARE + Future logShare({ + @required String contentType, + @required String itemId, + }) { + return logEvent( + name: 'share', + parameters: filterOutNulls({ + _CONTENT_TYPE: contentType, + _ITEM_ID: itemId, + }), + ); + } + + /// Logs the standard `sign_up` event. + /// + /// This event indicates that a user has signed up for an account in your + /// app. The parameter signifies the method by which the user signed up. Use + /// this event to understand the different behaviors between logged in and + /// logged out users. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#SIGN_UP + Future logSignUp({ + @required String signUpMethod, + }) { + return logEvent( + name: 'sign_up', + parameters: filterOutNulls({ + _SIGN_UP_METHOD: signUpMethod, + }), + ); + } + + /// Logs the standard `spend_virtual_currency` event. + /// + /// This event tracks the sale of virtual goods in your app and can help you + /// identify which virtual goods are the most popular objects of purchase. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#SPEND_VIRTUAL_CURRENCY + Future logSpendVirtualCurrency({ + @required String itemName, + @required String virtualCurrencyName, + @required num value, + }) { + return logEvent( + name: 'spend_virtual_currency', + parameters: filterOutNulls({ + _ITEM_NAME: itemName, + _VIRTUAL_CURRENCY_NAME: virtualCurrencyName, + _VALUE: value, + }), + ); + } + + /// Logs the standard `tutorial_begin` event. + /// + /// This event signifies the start of the on-boarding process in your app. + /// Use this in a funnel with [logTutorialComplete] to understand how many + /// users complete this process and move on to the full app experience. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#TUTORIAL_BEGIN + Future logTutorialBegin() { + return logEvent(name: 'tutorial_begin'); + } + + /// Logs the standard `tutorial_complete` event. + /// + /// Use this event to signify the user's completion of your app's on-boarding + /// process. Add this to a funnel with [logTutorialBegin] to gauge the + /// completion rate of your on-boarding process. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#TUTORIAL_COMPLETE + Future logTutorialComplete() { + return logEvent(name: 'tutorial_complete'); + } + + /// Logs the standard `unlock_achievement` event with a given achievement + /// [id]. + /// + /// Log this event when the user has unlocked an achievement in your game. + /// Since achievements generally represent the breadth of a gaming + /// experience, this event can help you understand how many users are + /// experiencing all that your game has to offer. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#UNLOCK_ACHIEVEMENT + Future logUnlockAchievement({ + @required String id, + }) { + return logEvent( + name: 'unlock_achievement', + parameters: filterOutNulls({ + _ACHIEVEMENT_ID: id, + }), + ); + } + + /// Logs the standard `view_item` event. + /// + /// This event signifies that some content was shown to the user. This + /// content may be a product, a webpage or just a simple image or text. Use + /// the appropriate parameters to contextualize the event. Use this event to + /// discover the most popular items viewed in your app. Note: If you supply + /// the [value] parameter, you must also supply the [currency] parameter so + /// that revenue metrics can be computed accurately. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#VIEW_ITEM + Future logViewItem({ + @required String itemId, + @required String itemName, + @required String itemCategory, + String itemLocationId, + double price, + int quantity, + String currency, + double value, + String flightNumber, + int numberOfPassengers, + int numberOfNights, + int numberOfRooms, + String origin, + String destination, + String startDate, + String endDate, + String searchTerm, + String travelClass, + }) { + _requireValueAndCurrencyTogether(value, currency); + + return logEvent( + name: 'view_item', + parameters: filterOutNulls({ + _ITEM_ID: itemId, + _ITEM_NAME: itemName, + _ITEM_CATEGORY: itemCategory, + _ITEM_LOCATION_ID: itemLocationId, + _PRICE: price, + _QUANTITY: quantity, + _CURRENCY: currency, + _VALUE: value, + _FLIGHT_NUMBER: flightNumber, + _NUMBER_OF_PASSENGERS: numberOfPassengers, + _NUMBER_OF_NIGHTS: numberOfNights, + _NUMBER_OF_ROOMS: numberOfRooms, + _ORIGIN: origin, + _DESTINATION: destination, + _START_DATE: startDate, + _END_DATE: endDate, + _SEARCH_TERM: searchTerm, + _TRAVEL_CLASS: travelClass, + }), + ); + } + + /// Logs the standard `view_item_list` event. + /// + /// Log this event when the user has been presented with a list of items of a + /// certain category. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#VIEW_ITEM_LIST + Future logViewItemList({ + @required String itemCategory, + }) { + return logEvent( + name: 'view_item_list', + parameters: filterOutNulls({ + _ITEM_CATEGORY: itemCategory, + }), + ); + } + + /// Logs the standard `view_search_results` event. + /// + /// Log this event when the user has been presented with the results of a + /// search. + /// + /// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html#VIEW_SEARCH_RESULTS + Future logViewSearchResults({ + @required String searchTerm, + }) { + return logEvent( + name: 'view_search_results', + parameters: filterOutNulls({ + _SEARCH_TERM: searchTerm, + }), + ); + } +} + +/// Android-specific analytics API. +class FirebaseAnalyticsAndroid { + final MethodChannel _channel; + + @visibleForTesting + const FirebaseAnalyticsAndroid.private(this._channel); + + /// Sets whether analytics collection is enabled for this app on this device. + /// + /// This setting is persisted across app sessions. By default it is enabled. + Future setAnalyticsCollectionEnabled(bool enabled) async { + if (enabled == null) + throw new ArgumentError.notNull('enabled'); + + await _channel.invokeMethod('setAnalyticsCollectionEnabled', enabled); + } + + /// Sets the minimum engagement time required before starting a session. + /// + /// The default value is 10000 (10 seconds). + Future setMinimumSessionDuration(int milliseconds) async { + if (milliseconds == null) + throw new ArgumentError.notNull('milliseconds'); + + await _channel.invokeMethod('setMinimumSessionDuration', milliseconds); + } + + /// Sets the duration of inactivity that terminates the current session. + /// + /// The default value is 1800000 (30 minutes). + Future setSessionTimeoutDuration(int milliseconds) async { + if (milliseconds == null) + throw new ArgumentError.notNull('milliseconds'); + + await _channel.invokeMethod('setSessionTimeoutDuration', milliseconds); + } +} + +/// Creates a new map containing all of the key/value pairs from [parameters] +/// except those whose value is `null`. +@visibleForTesting +Map filterOutNulls(Map parameters) { + final Map filtered = {}; + parameters.forEach((String key, dynamic value) { + if (value != null) + filtered[key] = value; + }); + return filtered; +} + +@visibleForTesting +const String valueAndCurrencyMustBeTogetherError = 'If you supply the "value" ' + 'parameter, you must also supply the "currency" parameter.'; + +void _requireValueAndCurrencyTogether(double value, String currency) { + if (value != null && currency == null) { + throw new ArgumentError(valueAndCurrencyMustBeTogetherError); + } +} + +/// Reserved event names that cannot be used. +/// +/// See: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html +const List _reservedEventNames = const [ + 'app_clear_data', + 'app_uninstall', + 'app_update', + 'error', + 'first_open', + 'in_app_purchase', + 'notification_dismiss', + 'notification_foreground', + 'notification_open', + 'notification_receive', + 'os_update', + 'session_start', + 'user_engagement', +]; + +// The following constants are defined in: +// +// https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Param.html + +/// Game achievement ID. +const String _ACHIEVEMENT_ID = 'achievement_id'; + +/// `CAMPAIGN_DETAILS` click ID. +const String _ACLID = 'aclid'; + +/// `CAMPAIGN_DETAILS` name; used for keyword analysis to identify a specific +/// product promotion or strategic campaign. +const String _CAMPAIGN = 'campaign'; + +/// Character used in game. +const String _CHARACTER = 'character'; + +/// `CAMPAIGN_DETAILS` content; used for A/B testing and content-targeted ads to +/// differentiate ads or links that point to the same URL. +const String _CONTENT = 'content'; + +/// Type of content selected. +const String _CONTENT_TYPE = 'content_type'; + +/// Coupon code for a purchasable item. +const String _COUPON = 'coupon'; + +/// `CAMPAIGN_DETAILS` custom parameter. +const String _CP1 = 'cp1'; + +/// Purchase currency in 3 letter ISO_4217 format. +const String _CURRENCY = 'currency'; + +/// Flight or Travel destination. +const String _DESTINATION = 'destination'; + +/// The arrival date, check-out date, or rental end date for the item. +const String _END_DATE = 'end_date'; + +/// Flight number for travel events. +const String _FLIGHT_NUMBER = 'flight_number'; + +/// Group/clan/guild id. +const String _GROUP_ID = 'group_id'; + +/// Item category. +const String _ITEM_CATEGORY = 'item_category'; + +/// Item ID. +const String _ITEM_ID = 'item_id'; + +/// The Google Place ID that corresponds to the associated item. +const String _ITEM_LOCATION_ID = 'item_location_id'; + +/// Item name. +const String _ITEM_NAME = 'item_name'; + +/// Level in game (long). +const String _LEVEL = 'level'; + +/// Location. +const String _LOCATION = 'location'; + +/// `CAMPAIGN_DETAILS` medium; used to identify a medium such as email or +/// cost-per-click (cpc). +const String _MEDIUM = 'medium'; + +/// Number of nights staying at hotel (long). +const String _NUMBER_OF_NIGHTS = 'number_of_nights'; + +/// Number of passengers traveling (long). +const String _NUMBER_OF_PASSENGERS = 'number_of_passengers'; + +/// Number of rooms for travel events (long). +const String _NUMBER_OF_ROOMS = 'number_of_rooms'; + +/// Flight or Travel origin. +const String _ORIGIN = 'origin'; + +/// Purchase price (double). +const String _PRICE = 'price'; + +/// Purchase quantity (long). +const String _QUANTITY = 'quantity'; + +/// Score in game (long). +const String _SCORE = 'score'; + +/// The search string/keywords used. +const String _SEARCH_TERM = 'search_term'; + +/// Shipping cost (double). +const String _SHIPPING = 'shipping'; + +/// Signup method. +const String _SIGN_UP_METHOD = 'sign_up_method'; + +/// `CAMPAIGN_DETAILS` source; used to identify a search engine, newsletter, or +/// other source. +const String _SOURCE = 'source'; + +/// The departure date, check-in date, or rental start date for the item. +const String _START_DATE = 'start_date'; + +/// Tax amount (double). +const String _TAX = 'tax'; + +/// `CAMPAIGN_DETAILS` term; used with paid search to supply the keywords for +/// ads. +const String _TERM = 'term'; + +/// A single ID for a ecommerce group transaction. +const String _TRANSACTION_ID = 'transaction_id'; + +/// Travel class. +const String _TRAVEL_CLASS = 'travel_class'; + +/// A context-specific numeric value which is accumulated automatically for +/// each event type. +const String _VALUE = 'value'; + +/// Name of virtual currency type. +const String _VIRTUAL_CURRENCY_NAME = 'virtual_currency_name'; diff --git a/packages/firebase_analytics/pubspec.yaml b/packages/firebase_analytics/pubspec.yaml new file mode 100755 index 000000000000..d91b8efd361d --- /dev/null +++ b/packages/firebase_analytics/pubspec.yaml @@ -0,0 +1,16 @@ +name: firebase_analytics +description: Firebase Analytics plugin for Flutter. + +flutter: + plugin: + androidPackage: io.flutter.firebase_analytics + pluginClass: FirebaseAnalyticsPlugin + +dependencies: + meta: ^1.0.4 + flutter: + sdk: flutter + +dev_dependencies: + mockito: ^2.0.2 + test: ^0.12.20 diff --git a/packages/firebase_analytics/test/firebase_analytics_test.dart b/packages/firebase_analytics/test/firebase_analytics_test.dart new file mode 100755 index 000000000000..afadcbe8dd4b --- /dev/null +++ b/packages/firebase_analytics/test/firebase_analytics_test.dart @@ -0,0 +1,328 @@ +// 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 'dart:async'; + +import 'package:mockito/mockito.dart'; +import 'package:test/test.dart'; + +import 'package:flutter/services.dart'; + +import 'package:firebase_analytics/firebase_analytics.dart'; + +void main() { + group('filterOutNulls', () { + test('filters out null values', () { + final Map original = {'a': 1, 'b': null, 'c': 'd'}; + final Map filtered = filterOutNulls(original); + + expect(filtered, isNot(same(original))); + expect(original, {'a': 1, 'b': null, 'c': 'd'}); + expect(filtered, {'a': 1, 'c': 'd'}); + }); + }); + + group('$FirebaseAnalytics', () { + FirebaseAnalytics analytics; + + String invokedMethod; + dynamic arguments; + + setUp(() { + MockPlatformChannel mockChannel = new MockPlatformChannel(); + + invokedMethod = null; + arguments = null; + + when(mockChannel.invokeMethod(any, any)).thenAnswer((Invocation invocation) { + invokedMethod = invocation.positionalArguments[0]; + arguments = invocation.positionalArguments[1]; + }); + + analytics = new FirebaseAnalytics.private(mockChannel); + }); + + test('setUserId', () async { + await analytics.setUserId('test-user-id'); + expect(invokedMethod, 'setUserId'); + expect(arguments, 'test-user-id'); + }); + + test('setCurrentScreen', () async { + await analytics.setCurrentScreen(screenName: 'test-screen-name', screenClassOverride: 'test-class-override'); + expect(invokedMethod, 'setCurrentScreen'); + expect(arguments, { + 'screenName': 'test-screen-name', + 'screenClassOverride': 'test-class-override', + }); + }); + + test('setUserProperty', () async { + await analytics.setUserProperty(name: 'test_name', value: 'test-value'); + expect(invokedMethod, 'setUserProperty'); + expect(arguments, { + 'name': 'test_name', + 'value': 'test-value', + }); + }); + + test('setUserProperty rejects invalid names', () async { + // invalid character + expect(analytics.setUserProperty(name: 'test-name', value: 'test-value'), throwsArgumentError); + // non-alpha first character + expect(analytics.setUserProperty(name: '0test', value: 'test-value'), throwsArgumentError); + // null + expect(analytics.setUserProperty(name: null, value: 'test-value'), throwsArgumentError); + // blank + expect(analytics.setUserProperty(name: '', value: 'test-value'), throwsArgumentError); + // reserved prefix + expect(analytics.setUserProperty(name: 'firebase_test', value: 'test-value'), throwsArgumentError); + }); + + test('setAnalyticsCollectionEnabled', () async { + await analytics.android.setAnalyticsCollectionEnabled(false); + expect(invokedMethod, 'setAnalyticsCollectionEnabled'); + expect(arguments, false); + }); + + test('setMinimumSessionDuration', () async { + await analytics.android.setMinimumSessionDuration(123); + expect(invokedMethod, 'setMinimumSessionDuration'); + expect(arguments, 123); + }); + + test('setSessionTimeoutDuration', () async { + await analytics.android.setSessionTimeoutDuration(234); + expect(invokedMethod, 'setSessionTimeoutDuration'); + expect(arguments, 234); + }); + }); + + group('$FirebaseAnalytics analytics events', () { + FirebaseAnalytics analytics; + + String name; + Map parameters; + + setUp(() { + MockPlatformChannel mockChannel = new MockPlatformChannel(); + + name = null; + parameters = null; + + when(mockChannel.invokeMethod('logEvent', any)).thenAnswer((Invocation invocation) { + Map args = invocation.positionalArguments[1]; + name = args['name']; + parameters = args['parameters']; + expect(args.keys, unorderedEquals(['name', 'parameters'])); + }); + + when(mockChannel.invokeMethod(isNot('logEvent') as dynamic, any)) + .thenThrow(new ArgumentError('Only logEvent invocations expected')); + + analytics = new FirebaseAnalytics.private(mockChannel); + }); + + test('logEvent log events', () async { + await analytics.logEvent(name: 'test-event', parameters: {'a': 'b'}); + expect(name, 'test-event'); + expect(parameters, {'a': 'b'}); + }); + + test('logEvent rejects events with reserved names', () async { + expect(analytics.logEvent(name: 'app_clear_data'), throwsArgumentError); + }); + + test('logEvent rejects events with reserved prefix', () async { + expect(analytics.logEvent(name: 'firebase_foo'), throwsArgumentError); + }); + + void smokeTest(String testFunctionName, Future testFunction()) { + test('$testFunctionName works', () async { + await testFunction(); + expect(name, testFunctionName); + }); + } + + smokeTest('add_payment_info', () => analytics.logAddPaymentInfo()); + + smokeTest('add_to_cart', () => analytics.logAddToCart( + itemId: 'test-id', + itemName: 'test-name', + itemCategory: 'test-category', + quantity: 5, + )); + + smokeTest('add_to_wishlist', () => analytics.logAddToWishlist( + itemId: 'test-id', + itemName: 'test-name', + itemCategory: 'test-category', + quantity: 5, + )); + + smokeTest('app_open', () => analytics.logAppOpen()); + + smokeTest('begin_checkout', () => analytics.logBeginCheckout()); + + smokeTest('campaign_details', () => analytics.logCampaignDetails( + source: 'test-source', + medium: 'test-medium', + campaign: 'test-campaign', + )); + + smokeTest('earn_virtual_currency', () => analytics.logEarnVirtualCurrency( + virtualCurrencyName: 'bitcoin', + value: 34, + )); + + smokeTest('ecommerce_purchase', () => analytics.logEcommercePurchase()); + + smokeTest('generate_lead', () => analytics.logGenerateLead()); + + smokeTest('join_group', () => analytics.logJoinGroup( + groupId: 'test-group-id', + )); + + smokeTest('level_up', () => analytics.logLevelUp( + level: 56, + )); + + smokeTest('login', () => analytics.logLogin()); + + smokeTest('post_score', () => analytics.logPostScore( + score: 34, + )); + + smokeTest('present_offer', () => analytics.logPresentOffer( + itemId: 'test-id', + itemName: 'test-name', + itemCategory: 'test-category', + quantity: 5, + )); + + smokeTest('purchase_refund', () => analytics.logPurchaseRefund()); + + smokeTest('search', () => analytics.logSearch( + searchTerm: 'test search term', + )); + + smokeTest('select_content', () => analytics.logSelectContent( + contentType: 'test content type', + itemId: 'test item id', + )); + + smokeTest('share', () => analytics.logShare( + contentType: 'test content type', + itemId: 'test item id', + )); + + smokeTest('sign_up', () => analytics.logSignUp( + signUpMethod: 'test sign-up method', + )); + + smokeTest('spend_virtual_currency', () => analytics.logSpendVirtualCurrency( + itemName: 'test-item-name', + virtualCurrencyName: 'bitcoin', + value: 345, + )); + + smokeTest('tutorial_begin', () => analytics.logTutorialBegin()); + + smokeTest('tutorial_complete', () => analytics.logTutorialComplete()); + + smokeTest('unlock_achievement', () => analytics.logUnlockAchievement( + id: 'firebase analytics api coverage', + )); + + smokeTest('view_item', () => analytics.logViewItem( + itemId: 'test-id', + itemName: 'test-name', + itemCategory: 'test-category', + )); + + smokeTest('view_item_list', () => analytics.logViewItemList( + itemCategory: 'test-category', + )); + + smokeTest('view_search_results', () => analytics.logViewSearchResults( + searchTerm: 'test search term', + )); + + void testRequiresValueAndCurrencyTogether(String methodName, Future testFn()) { + test('$methodName requires value and currency together', () async { + try { + testFn(); + fail('Expected ArgumentError'); + } on ArgumentError catch(error) { + expect(error.message, valueAndCurrencyMustBeTogetherError); + } + }); + } + + testRequiresValueAndCurrencyTogether('logAddToCart', () { + return analytics.logAddToCart( + itemId: 'test-id', + itemName: 'test-name', + itemCategory: 'test-category', + quantity: 5, + value: 123.90, + ); + }); + + testRequiresValueAndCurrencyTogether('logAddToWishlist', () { + return analytics.logAddToWishlist( + itemId: 'test-id', + itemName: 'test-name', + itemCategory: 'test-category', + quantity: 5, + value: 123.90, + ); + }); + + testRequiresValueAndCurrencyTogether('logBeginCheckout', () { + return analytics.logBeginCheckout( + value: 123.90, + ); + }); + + testRequiresValueAndCurrencyTogether('logEcommercePurchase', () { + return analytics.logEcommercePurchase( + value: 123.90, + ); + }); + + testRequiresValueAndCurrencyTogether('logGenerateLead', () { + return analytics.logGenerateLead( + value: 123.90, + ); + }); + + testRequiresValueAndCurrencyTogether('logPresentOffer', () { + return analytics.logPresentOffer( + itemId: 'test-id', + itemName: 'test-name', + itemCategory: 'test-category', + quantity: 5, + value: 123.90, + ); + }); + + testRequiresValueAndCurrencyTogether('logPurchaseRefund', () { + return analytics.logPurchaseRefund( + value: 123.90, + ); + }); + + testRequiresValueAndCurrencyTogether('logViewItem', () { + return analytics.logViewItem( + itemId: 'test-id', + itemName: 'test-name', + itemCategory: 'test-category', + value: 123.90, + ); + }); + }); +} + +class MockPlatformChannel extends Mock implements MethodChannel { } diff --git a/packages/firebase_auth/.gitignore b/packages/firebase_auth/.gitignore new file mode 100755 index 000000000000..14c7d4c3f73e --- /dev/null +++ b/packages/firebase_auth/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock diff --git a/packages/firebase_auth/LICENSE b/packages/firebase_auth/LICENSE new file mode 100755 index 000000000000..86928f657555 --- /dev/null +++ b/packages/firebase_auth/LICENSE @@ -0,0 +1,27 @@ +// Copyright 2017 Your Company. 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 Your Company nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/firebase_auth/README.md b/packages/firebase_auth/README.md new file mode 100755 index 000000000000..aac93dbcaf71 --- /dev/null +++ b/packages/firebase_auth/README.md @@ -0,0 +1,8 @@ +# firebase_auth + +A new flutter plugin project. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/firebase_auth/android/.gitignore b/packages/firebase_auth/android/.gitignore new file mode 100755 index 000000000000..5c4ef82869b5 --- /dev/null +++ b/packages/firebase_auth/android/.gitignore @@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/firebase_auth/android/build.gradle b/packages/firebase_auth/android/build.gradle new file mode 100755 index 000000000000..aa9bc67f3667 --- /dev/null +++ b/packages/firebase_auth/android/build.gradle @@ -0,0 +1,37 @@ +group 'com.yourcompany.firebase_auth' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.0' + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.0' + + defaultConfig { + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + lintOptions { + disable 'InvalidPackage' + } + dependencies { + compile 'com.google.guava:guava:20.0' + compile 'com.google.firebase:firebase-core:10.2.1' + compile 'com.google.firebase:firebase-auth:10.2.1' + } +} diff --git a/packages/firebase_auth/android/gradle.properties b/packages/firebase_auth/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/firebase_auth/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/firebase_auth/android/settings.gradle b/packages/firebase_auth/android/settings.gradle new file mode 100755 index 000000000000..acfe1855910f --- /dev/null +++ b/packages/firebase_auth/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'firebase_auth' diff --git a/packages/firebase_auth/android/src/main/AndroidManifest.xml b/packages/firebase_auth/android/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..13d1ce1b00e9 --- /dev/null +++ b/packages/firebase_auth/android/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/firebase_auth/android/src/main/java/io/flutter/firebase_auth/FirebaseAuthPlugin.java b/packages/firebase_auth/android/src/main/java/io/flutter/firebase_auth/FirebaseAuthPlugin.java new file mode 100755 index 000000000000..cb460b2ed229 --- /dev/null +++ b/packages/firebase_auth/android/src/main/java/io/flutter/firebase_auth/FirebaseAuthPlugin.java @@ -0,0 +1,132 @@ +// 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.firebase_auth; + +import android.app.Activity; +import android.support.annotation.NonNull; + +import com.google.android.gms.tasks.Task; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.firebase.FirebaseApp; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.AuthCredential; +import com.google.firebase.auth.GoogleAuthProvider; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.auth.UserInfo; + +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.PluginRegistry; + +import java.util.Map; + +/** + * Flutter plugin for Firebase Auth. + */ +public class FirebaseAuthPlugin implements MethodCallHandler { + private final Activity activity; + private final FirebaseAuth firebaseAuth; + + private static final String ERROR_REASON_EXCEPTION = "exception"; + + + public static void registerWith(PluginRegistry.Registrar registrar) { + final MethodChannel channel = + new MethodChannel(registrar.messenger(), "plugins.flutter.io/firebase_auth"); + channel.setMethodCallHandler(new FirebaseAuthPlugin(registrar.activity())); + } + + private FirebaseAuthPlugin(Activity activity) { + this.activity = activity; + FirebaseApp.initializeApp(activity); + this.firebaseAuth = FirebaseAuth.getInstance(); + } + + @Override + public void onMethodCall(MethodCall call, Result result) { + switch (call.method) { + case "signInAnonymously": + handleSignInAnonymously(call, result); + break; + case "signInWithGoogle": + handleSignInWithGoogle(call, result); + break; + default: + result.notImplemented(); + break; + } + } + + private void handleSignInAnonymously(MethodCall call, final Result result) { + firebaseAuth + .signInAnonymously() + .addOnCompleteListener(activity, new SignInCompleteListener(result)); + } + + private void handleSignInWithGoogle(MethodCall call, final Result result) { + @SuppressWarnings("unchecked") + Map arguments = (Map) call.arguments; + String idToken = arguments.get("idToken"); + String accessToken = arguments.get("accessToken"); + AuthCredential credential = GoogleAuthProvider.getCredential(idToken, accessToken); + firebaseAuth.signInWithCredential(credential) + .addOnCompleteListener(activity, new SignInCompleteListener(result)); + } + + private class SignInCompleteListener implements OnCompleteListener { + private final Result result; + + SignInCompleteListener(Result result) { + this.result = result; + } + + private ImmutableMap.Builder userInfoToMap(UserInfo userInfo) { + ImmutableMap.Builder builder = + ImmutableMap.builder() + .put("providerId", userInfo.getProviderId()) + .put("uid", userInfo.getUid()); + if (userInfo.getDisplayName() != null) { + builder.put("displayName", userInfo.getDisplayName()); + } + if (userInfo.getPhotoUrl() != null) { + builder.put("photoUrl", userInfo.getPhotoUrl().toString()); + } + if (userInfo.getEmail() != null) { + builder.put("email", userInfo.getEmail()); + } + return builder; + } + + @Override + public void onComplete(@NonNull Task task) { + if (!task.isSuccessful()) { + Exception e = task.getException(); + result.error(ERROR_REASON_EXCEPTION, e.getMessage(), null); + } else { + FirebaseUser user = task.getResult().getUser(); + if (user != null) { + ImmutableList.Builder> providerDataBuilder = + ImmutableList.>builder(); + for (UserInfo userInfo : user.getProviderData()) { + providerDataBuilder.add(userInfoToMap(userInfo).build()); + } + ImmutableMap userMap = userInfoToMap(user) + .put("isAnonymous", user.isAnonymous()) + .put("isEmailVerified", user.isEmailVerified()) + .put("providerData", providerDataBuilder.build()) + .build(); + result.success(userMap); + } else { + result.success(null); + } + } + } + } +} diff --git a/packages/firebase_auth/example/.gitignore b/packages/firebase_auth/example/.gitignore new file mode 100755 index 000000000000..eb15c3d27cab --- /dev/null +++ b/packages/firebase_auth/example/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock +.flutter-plugins diff --git a/packages/firebase_auth/example/README.md b/packages/firebase_auth/example/README.md new file mode 100755 index 000000000000..228dede4b027 --- /dev/null +++ b/packages/firebase_auth/example/README.md @@ -0,0 +1,8 @@ +# firebase_auth_example + +Demonstrates how to use the firebase_auth plugin. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/firebase_auth/example/android.iml b/packages/firebase_auth/example/android.iml new file mode 100755 index 000000000000..462b903e05b6 --- /dev/null +++ b/packages/firebase_auth/example/android.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/firebase_auth/example/android/.gitignore b/packages/firebase_auth/example/android/.gitignore new file mode 100755 index 000000000000..5c4ef82869b5 --- /dev/null +++ b/packages/firebase_auth/example/android/.gitignore @@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/firebase_auth/example/android/app/build.gradle b/packages/firebase_auth/example/android/app/build.gradle new file mode 100755 index 000000000000..50474b6ac11d --- /dev/null +++ b/packages/firebase_auth/example/android/app/build.gradle @@ -0,0 +1,49 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withInputStream { stream -> + localProperties.load(stream) + } +} + +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.") +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.2' + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + applicationId 'com.yourcompany.firebaseauth.example' + testInstrumentationRunner "android.support.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 + } + } +} + +flutter { + source '../..' +} + +dependencies { + androidTestCompile 'com.android.support:support-annotations:24.0.0' + androidTestCompile 'com.android.support.test:runner:0.5' + androidTestCompile 'com.android.support.test:rules:0.5' +} + +apply plugin: 'com.google.gms.google-services' diff --git a/packages/firebase_auth/example/android/app/google-services.json b/packages/firebase_auth/example/android/app/google-services.json new file mode 100755 index 000000000000..11dc3ae0bf4d --- /dev/null +++ b/packages/firebase_auth/example/android/app/google-services.json @@ -0,0 +1,42 @@ +{ + "project_info": { + "project_number": "297855924061", + "firebase_url": "https://flutterfire-cd2f7.firebaseio.com", + "project_id": "flutterfire-cd2f7", + "storage_bucket": "flutterfire-cd2f7.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:297855924061:android:669871c998cc21bd", + "android_client_info": { + "package_name": "com.yourcompany.firebaseauth.example" + } + }, + "oauth_client": [ + { + "client_id": "297855924061-f68m5v860ms5faiotn5mv9f50cmpacdq.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyD_shO5mfO9lhy2TVWhfo1VUmARKlG4suk" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 2 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/packages/firebase_auth/example/android/app/src/main/AndroidManifest.xml b/packages/firebase_auth/example/android/app/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..b9cf7689b923 --- /dev/null +++ b/packages/firebase_auth/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore b/packages/firebase_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore new file mode 100755 index 000000000000..9eb4563d2ae1 --- /dev/null +++ b/packages/firebase_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore @@ -0,0 +1 @@ +GeneratedPluginRegistrant.java diff --git a/packages/firebase_auth/example/android/app/src/main/java/io/flutter/plugins/firebase_auth_example/MainActivity.java b/packages/firebase_auth/example/android/app/src/main/java/io/flutter/plugins/firebase_auth_example/MainActivity.java new file mode 100755 index 000000000000..fe418a9d1d1a --- /dev/null +++ b/packages/firebase_auth/example/android/app/src/main/java/io/flutter/plugins/firebase_auth_example/MainActivity.java @@ -0,0 +1,13 @@ +package io.flutter.plugins.firebase_auth_example; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class MainActivity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/packages/firebase_auth/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/firebase_auth/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100755 index 000000000000..db77bb4b7b09 Binary files /dev/null and b/packages/firebase_auth/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/firebase_auth/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/firebase_auth/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100755 index 000000000000..17987b79bb8a Binary files /dev/null and b/packages/firebase_auth/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/firebase_auth/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/firebase_auth/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100755 index 000000000000..09d4391482be Binary files /dev/null and b/packages/firebase_auth/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/firebase_auth/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/firebase_auth/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100755 index 000000000000..d5f1c8d34e7a Binary files /dev/null and b/packages/firebase_auth/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/firebase_auth/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/firebase_auth/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100755 index 000000000000..4d6372eebdb2 Binary files /dev/null and b/packages/firebase_auth/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/firebase_auth/example/android/build.gradle b/packages/firebase_auth/example/android/build.gradle new file mode 100755 index 000000000000..2023b0f5725e --- /dev/null +++ b/packages/firebase_auth/example/android/build.gradle @@ -0,0 +1,30 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.google.gms:google-services:3.0.0' + } +} + +allprojects { + repositories { + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.14.1' +} diff --git a/packages/firebase_auth/example/android/gradle.properties b/packages/firebase_auth/example/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/firebase_auth/example/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/firebase_auth/example/android/settings.gradle b/packages/firebase_auth/example/android/settings.gradle new file mode 100755 index 000000000000..115da6cb4f4d --- /dev/null +++ b/packages/firebase_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/firebase_auth/example/firebase_auth_example.iml b/packages/firebase_auth/example/firebase_auth_example.iml new file mode 100755 index 000000000000..1ae40a0f7f54 --- /dev/null +++ b/packages/firebase_auth/example/firebase_auth_example.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/firebase_auth/example/ios/.gitignore b/packages/firebase_auth/example/ios/.gitignore new file mode 100755 index 000000000000..0c4c14679cff --- /dev/null +++ b/packages/firebase_auth/example/ios/.gitignore @@ -0,0 +1,41 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/app.flx +/Flutter/app.zip +/Flutter/App.framework +/Flutter/Flutter.framework +/Flutter/Generated.xcconfig +/ServiceDefinitions.json +/Runner/GeneratedPluginRegistrant.h +/Runner/GeneratedPluginRegistrant.m +Podfile.lock +Pods/ diff --git a/packages/firebase_auth/example/ios/Flutter/AppFrameworkInfo.plist b/packages/firebase_auth/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100755 index 000000000000..6c2de8086bcd --- /dev/null +++ b/packages/firebase_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/firebase_auth/example/ios/Flutter/Debug.xcconfig b/packages/firebase_auth/example/ios/Flutter/Debug.xcconfig new file mode 100755 index 000000000000..9803018ca79d --- /dev/null +++ b/packages/firebase_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/firebase_auth/example/ios/Flutter/Release.xcconfig b/packages/firebase_auth/example/ios/Flutter/Release.xcconfig new file mode 100755 index 000000000000..a4a8c604e13d --- /dev/null +++ b/packages/firebase_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/firebase_auth/example/ios/Podfile b/packages/firebase_auth/example/ios/Podfile new file mode 100755 index 000000000000..90b5f651fb63 --- /dev/null +++ b/packages/firebase_auth/example/ios/Podfile @@ -0,0 +1,36 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +if ENV['FLUTTER_FRAMEWORK_DIR'] == nil + abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework') +end + +target 'Runner' do + # Pods for Runner + + # Flutter Pods + pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR'] + + if File.exists? '../.flutter-plugins' + flutter_root = File.expand_path('..') + File.foreach('../.flutter-plugins') { |line| + plugin = line.split(pattern='=') + if plugin.length == 2 + name = plugin[0].strip() + path = plugin[1].strip() + resolved_path = File.expand_path("#{path}/ios", flutter_root) + pod name, :path => resolved_path + else + puts "Invalid plugin specification: #{line}" + end + } + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/packages/firebase_auth/example/ios/Runner.xcodeproj/project.pbxproj b/packages/firebase_auth/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100755 index 000000000000..0bee7281e1ac --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,498 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0690AA46E879ED4CF7B7AEB4 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A6A0D603F1BEC33B95572EC3 /* libPods-Runner.a */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 5C97AA501EC3F2C300D441D1 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C97AA4F1EC3F2C300D441D1 /* GeneratedPluginRegistrant.m */; }; + 7ABDE8F71EA727FA0074FEFB /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7ABDE8F61EA727FA0074FEFB /* GoogleService-Info.plist */; }; + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; }; + 9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; }; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 5C97AA4E1EC3F2C300D441D1 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 5C97AA4F1EC3F2C300D441D1 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 7ABDE8F61EA727FA0074FEFB /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.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 = ""; }; + 9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = ""; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; 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 = ""; }; + A6A0D603F1BEC33B95572EC3 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + 0690AA46E879ED4CF7B7AEB4 /* libPods-Runner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 9740EEB71CF902C7004384FC /* app.flx */, + 3B80C3931E831B6300D905FE /* App.framework */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 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 = ( + 5C97AA4E1EC3F2C300D441D1 /* GeneratedPluginRegistrant.h */, + 5C97AA4F1EC3F2C300D441D1 /* GeneratedPluginRegistrant.m */, + 7ABDE8F61EA727FA0074FEFB /* GoogleService-Info.plist */, + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 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 = ( + A6A0D603F1BEC33B95572EC3 /* 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 = 0830; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = 3GRKCVVJ22; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + 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 = ( + 9740EEBB1CF902C7004384FC /* app.flx in Resources */, + 7ABDE8F71EA727FA0074FEFB /* GoogleService-Info.plist in Resources */, + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 9740EEB41CF90195004384FC /* Debug.xcconfig 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\" thin"; + }; + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/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 = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../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"; + 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 */, + 5C97AA501EC3F2C300D441D1 /* 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; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + 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_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + 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_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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 = { + ARCHS = arm64; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 3GRKCVVJ22; + 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 = com.yourcompany.firebaseAuthExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ARCHS = arm64; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 3GRKCVVJ22; + 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 = com.yourcompany.firebaseAuthExample; + 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/firebase_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/firebase_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/firebase_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/firebase_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100755 index 000000000000..1c9580788197 --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/firebase_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/firebase_auth/example/ios/Runner/AppDelegate.h b/packages/firebase_auth/example/ios/Runner/AppDelegate.h new file mode 100755 index 000000000000..cf210d213f27 --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/packages/firebase_auth/example/ios/Runner/AppDelegate.m b/packages/firebase_auth/example/ios/Runner/AppDelegate.m new file mode 100755 index 000000000000..ce9c30f9f812 --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner/AppDelegate.m @@ -0,0 +1,12 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application +didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 000000000000..d22f10b2ab63 --- /dev/null +++ b/packages/firebase_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/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100755 index 000000000000..28c6bf03016f Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100755 index 000000000000..2ccbfd967d96 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100755 index 000000000000..f091b6b0bca8 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100755 index 000000000000..4cde12118dda Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100755 index 000000000000..d0ef06e7edb8 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100755 index 000000000000..dcdc2306c285 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100755 index 000000000000..2ccbfd967d96 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100755 index 000000000000..c8f9ed8f5cee Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100755 index 000000000000..a6d6b8609df0 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100755 index 000000000000..a6d6b8609df0 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100755 index 000000000000..75b2d164a5a9 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100755 index 000000000000..c4df70d39da7 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100755 index 000000000000..6a84f41e14e2 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100755 index 000000000000..d0e1f5853602 Binary files /dev/null and b/packages/firebase_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/firebase_auth/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/firebase_auth/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100755 index 000000000000..ebf48f603974 --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_auth/example/ios/Runner/Base.lproj/Main.storyboard b/packages/firebase_auth/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100755 index 000000000000..f3c28516fb38 --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_auth/example/ios/Runner/GoogleService-Info.plist b/packages/firebase_auth/example/ios/Runner/GoogleService-Info.plist new file mode 100755 index 000000000000..dd1067c0166c --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,40 @@ + + + + + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 + CLIENT_ID + 297855924061-48k2m6hl6pa4q9hukijjd0c20ev4qans.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.297855924061-48k2m6hl6pa4q9hukijjd0c20ev4qans + API_KEY + AIzaSyBq6mcufFXfyqr79uELCiqM_O_1-G72PVU + GCM_SENDER_ID + 297855924061 + PLIST_VERSION + 1 + BUNDLE_ID + com.yourcompany.firebaseAuthExample + PROJECT_ID + flutterfire-cd2f7 + STORAGE_BUCKET + flutterfire-cd2f7.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:297855924061:ios:9441bad932d26629 + DATABASE_URL + https://flutterfire-cd2f7.firebaseio.com + + \ No newline at end of file diff --git a/packages/firebase_auth/example/ios/Runner/Info.plist b/packages/firebase_auth/example/ios/Runner/Info.plist new file mode 100755 index 000000000000..0d20e1c5f477 --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner/Info.plist @@ -0,0 +1,60 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + firebase_auth_example + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + com.googleusercontent.apps.297855924061-48k2m6hl6pa4q9hukijjd0c20ev4qans + + + + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/firebase_auth/example/ios/Runner/main.m b/packages/firebase_auth/example/ios/Runner/main.m new file mode 100755 index 000000000000..1bdb8e28d1db --- /dev/null +++ b/packages/firebase_auth/example/ios/Runner/main.m @@ -0,0 +1,10 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, + NSStringFromClass([AppDelegate class])); + } +} diff --git a/packages/firebase_auth/example/lib/main.dart b/packages/firebase_auth/example/lib/main.dart new file mode 100755 index 000000000000..b84f45c7151b --- /dev/null +++ b/packages/firebase_auth/example/lib/main.dart @@ -0,0 +1,112 @@ +// 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 'dart:async'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:google_sign_in/google_sign_in.dart'; + +final FirebaseAuth auth = FirebaseAuth.instance; +final GoogleSignIn googleSignIn = new GoogleSignIn(); + +void main() { + runApp(new MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'Firebase Auth Demo', + home: new MyHomePage(title: 'Firebase Auth Demo'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => new _MyHomePageState(); +} + +class _MyHomePageState extends State { + Future _message = new Future.value(''); + + Future _testSignInAnonymously() async { + FirebaseUser user = await auth.signInAnonymously(); + assert(user != null); + assert(user == auth.currentUser); + assert(user.isAnonymous); + assert(!user.isEmailVerified); + if (Platform.isIOS) { + // Anonymous auth doesn't show up as a provider on iOS + assert(user.providerData.length == 0); + } else if (Platform.isAndroid) { + // Anonymous auth does show up as a provider on Android + assert(user.providerData.length == 1); + assert(user.providerData[0].providerId == 'firebase'); + assert(user.providerData[0].uid != null); + assert(user.providerData[0].displayName == null); + assert(user.providerData[0].photoUrl == null); + assert(user.providerData[0].email == null); + } + return 'signInAnonymously succeeded: $user'; + } + + Future _testSignInWithGoogle() async { + GoogleSignInAccount googleUser = await googleSignIn.signIn(); + GoogleSignInAuthentication googleAuth = await googleUser.authentication; + FirebaseUser user = await auth.signInWithGoogle( + accessToken: googleAuth.accessToken, + idToken: googleAuth.idToken, + ); + assert(user.email != null); + assert(user.displayName != null); + return 'signInWithGoogle succeeded: $user'; + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + ), + body: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new MaterialButton( + child: const Text('Test signInAnonymously'), + onPressed: () { + setState(() { + _message = _testSignInAnonymously(); + }); + } + ), + new MaterialButton( + child: const Text('Test signInWithGoogle'), + onPressed: () { + setState(() { + _message = _testSignInWithGoogle(); + }); + } + ), + new FutureBuilder( + future: _message, + builder: (_, AsyncSnapshot snapshot) { + return new Text( + snapshot.data ?? '', + style: const TextStyle(color: const Color.fromARGB(255, 0, 155, 0)) + ); + } + ), + ], + ), + ); + } +} diff --git a/packages/firebase_auth/example/pubspec.yaml b/packages/firebase_auth/example/pubspec.yaml new file mode 100755 index 000000000000..db9fc539f8f3 --- /dev/null +++ b/packages/firebase_auth/example/pubspec.yaml @@ -0,0 +1,14 @@ +name: firebase_auth_example +description: Demonstrates how to use the firebase_auth plugin. + +dependencies: + flutter: + sdk: flutter + firebase_auth: + path: ../ + # TODO(jackson): Point this at pub once a stable version is published + google_sign_in: + git: git://github.com/flutter/google_sign_in + +flutter: + uses-material-design: true diff --git a/packages/firebase_auth/ios/.gitignore b/packages/firebase_auth/ios/.gitignore new file mode 100755 index 000000000000..fc95c100cffd --- /dev/null +++ b/packages/firebase_auth/ios/.gitignore @@ -0,0 +1,32 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +Pods/ diff --git a/packages/firebase_auth/ios/Assets/.gitkeep b/packages/firebase_auth/ios/Assets/.gitkeep new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.h b/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.h new file mode 100755 index 000000000000..429a2015f6ac --- /dev/null +++ b/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface FirebaseAuthPlugin : NSObject +@end diff --git a/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m b/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m new file mode 100755 index 000000000000..019520a999cf --- /dev/null +++ b/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m @@ -0,0 +1,96 @@ +#import "FirebaseAuthPlugin.h" + +#import "Firebase/Firebase.h" + +@interface NSError (FlutterError) +@property(readonly, nonatomic) FlutterError *flutterError; +@end + +@implementation NSError (FlutterError) +- (FlutterError *)flutterError { + return [FlutterError + errorWithCode:[NSString stringWithFormat:@"Error %d", (int)self.code] + message:self.domain + details:self.localizedDescription]; +} +@end + +NSDictionary *toDictionary(id userInfo) { + return @{ + @"providerId" : userInfo.providerID, + @"displayName" : userInfo.displayName ?: [NSNull null], + @"uid" : userInfo.uid, + @"photoUrl" : userInfo.photoURL.absoluteString ?: [NSNull null], + @"email" : userInfo.email ?: [NSNull null], + }; +} + +@implementation FirebaseAuthPlugin { +} + ++ (void)registerWithRegistrar:(NSObject *)registrar { + FlutterMethodChannel *channel = + [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/firebase_auth" + binaryMessenger:[registrar messenger]]; + FirebaseAuthPlugin *instance = [[FirebaseAuthPlugin alloc] init]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + + + +- (instancetype)init { + self = [super init]; + if (self) { + if (![FIRApp defaultApp]) { + [FIRApp configure]; + } + } + return self; +} + + +- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { + if ([@"signInAnonymously" isEqualToString:call.method]) { + [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRUser *user, + NSError *error) { + [self sendResult:result forUser:user error:error]; + }]; + } else if ([@"signInWithGoogle" isEqualToString:call.method]) { + NSString *idToken = call.arguments[@"idToken"]; + NSString *accessToken = call.arguments[@"accessToken"]; + FIRAuthCredential *credential = + [FIRGoogleAuthProvider credentialWithIDToken:idToken + accessToken:accessToken]; + [[FIRAuth auth] + signInWithCredential:credential + completion:^(FIRUser *user, NSError *error) { + [self sendResult:result forUser:user error:error]; + }]; + } else { + result(FlutterMethodNotImplemented); + } +} + +- (void)sendResult:(FlutterResult)result + forUser:(FIRUser *)user + error:(NSError *)error { + if (error != nil) { + result(error.flutterError); + } else if (user == nil) { + result(nil); + } else { + NSMutableArray *> *providerData = + [NSMutableArray arrayWithCapacity:user.providerData.count]; + for (id userInfo in user.providerData) { + [providerData addObject:toDictionary(userInfo)]; + } + NSMutableDictionary *userData = [toDictionary(user) mutableCopy]; + userData[@"isAnonymous"] = [NSNumber numberWithBool:user.isAnonymous]; + userData[@"isEmailVerified"] = + [NSNumber numberWithBool:user.isEmailVerified]; + userData[@"providerData"] = providerData; + result(userData); + } +} + +@end diff --git a/packages/firebase_auth/ios/firebase_auth.podspec b/packages/firebase_auth/ios/firebase_auth.podspec new file mode 100755 index 000000000000..5d9041f106c8 --- /dev/null +++ b/packages/firebase_auth/ios/firebase_auth.podspec @@ -0,0 +1,24 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'firebase_auth' + s.version = '0.0.1' + s.summary = 'Firebase Auth plugin for Flutter.' + s.description = <<-DESC +Firebase Auth plugin for Flutter. + DESC + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/firebase_auth' + 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.ios.deployment_target = '6.0' + s.dependency 'Flutter' + s.dependency 'Firebase/Auth' + s.dependency 'Firebase/Core' + s.dependency 'FirebaseUI/Auth', '~> 3.0' + s.dependency 'FirebaseUI/Google' + s.dependency 'Google/SignIn' +end diff --git a/packages/firebase_auth/lib/firebase_auth.dart b/packages/firebase_auth/lib/firebase_auth.dart new file mode 100755 index 000000000000..20ce2d19690a --- /dev/null +++ b/packages/firebase_auth/lib/firebase_auth.dart @@ -0,0 +1,110 @@ +// 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 'dart:async'; + +import 'package:meta/meta.dart'; +import 'package:flutter/services.dart'; + +/// Represents user data returned from an identity provider. +class UserInfo { + final Map _data; + UserInfo._(this._data); + + /// The provider identifier. + String get providerId => _data['providerId']; + + /// The provider’s user ID for the user. + String get uid => _data['uid']; + + /// The name of the user. + String get displayName => _data['displayName']; + + /// The URL of the user’s profile photo. + String get photoUrl => _data['photoUrl']; + + /// The user’s email address. + String get email => _data['email']; + + @override + String toString() { + return '$runtimeType($_data)'; + } +} + +/// Represents a user. +class FirebaseUser extends UserInfo { + final Map _data; + final List providerData; + FirebaseUser._(this._data) + : providerData = (_data['providerData'] as List>) + .map((Map info) => new UserInfo._(info)).toList(), + super._(_data); + + // Returns true if the user is anonymous; that is, the user account was + // created with signInAnonymously() and has not been linked to another + // account. + bool get isAnonymous => _data['isAnonymous']; + + /// Returns true if the user's email is verified. + bool get isEmailVerified => _data['isEmailVerified']; + + @override + String toString() { + return '$runtimeType($_data)'; + } +} + +class FirebaseAuth { + final MethodChannel _channel; + + /// Provides an instance of this class corresponding to the default app. + /// + /// TODO(jackson): Support for non-default apps. + static FirebaseAuth instance = new FirebaseAuth.private( + const MethodChannel('plugins.flutter.io/firebase_auth'), + ); + + /// We don't want people to extend this class, but implementing its interface, + /// e.g. in tests, is OK. + @visibleForTesting + FirebaseAuth.private(this._channel); + + /// Asynchronously creates and becomes an anonymous user. + /// + /// If there is already an anonymous user signed in, that user will be + /// returned instead. If there is any other existing user signed in, that + /// user will be signed out. + /// + /// Will throw a PlatformException if + /// FIRAuthErrorCodeOperationNotAllowed - Indicates that anonymous accounts are not enabled. Enable them in the Auth section of the Firebase console. + /// See FIRAuthErrors for a list of error codes that are common to all API methods. + Future signInAnonymously() async { + Map data = await _channel.invokeMethod('signInAnonymously'); + _currentUser = new FirebaseUser._(data); + return _currentUser; + } + + Future signInWithGoogle({ + @required String idToken, + @required String accessToken, + }) async { + assert(idToken != null); + assert(accessToken != null); + Map data = await _channel.invokeMethod( + 'signInWithGoogle', + { + 'idToken': idToken, + 'accessToken': accessToken, + }, + ); + _currentUser = new FirebaseUser._(data); + return _currentUser; + } + + FirebaseUser _currentUser; + + /// Synchronously gets the cached current user, or `null` if there is none. + FirebaseUser get currentUser => _currentUser; +} diff --git a/packages/firebase_auth/pubspec.yaml b/packages/firebase_auth/pubspec.yaml new file mode 100755 index 000000000000..e4eee2ef1ac9 --- /dev/null +++ b/packages/firebase_auth/pubspec.yaml @@ -0,0 +1,16 @@ +name: firebase_auth +description: Firebase Auth plugin for Flutter. + +flutter: + plugin: + androidPackage: io.flutter.firebase_auth + pluginClass: FirebaseAuthPlugin + +dependencies: + meta: ^1.0.4 + flutter: + sdk: flutter + +dev_dependencies: + mockito: ^2.0.2 + test: ^0.12.20 diff --git a/packages/firebase_auth/test/firebase_auth_test.dart b/packages/firebase_auth/test/firebase_auth_test.dart new file mode 100755 index 000000000000..93144ec0f665 --- /dev/null +++ b/packages/firebase_auth/test/firebase_auth_test.dart @@ -0,0 +1,61 @@ +// 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 'package:mockito/mockito.dart'; +import 'package:test/test.dart'; + +import 'package:flutter/services.dart'; + +import 'package:firebase_auth/firebase_auth.dart'; + +void main() { + group('$FirebaseAuth', () { + FirebaseAuth auth; + + const String kMockProviderId = 'firebase'; + const String kMockUid = '12345'; + const String kMockDisplayName = 'Flutter Test User'; + const String kMockPhotoUrl = 'http://www.example.com/'; + const String kMockEmail = 'test@example.com'; + + setUp(() { + MockPlatformChannel mockChannel = new MockPlatformChannel(); + + when(mockChannel.invokeMethod('signInAnonymously')).thenAnswer((Invocation invocation) { + return { + 'isAnonymous': true, + 'isEmailVerified': false, + 'providerData': >[ + { + 'providerId': kMockProviderId, + 'uid': kMockUid, + 'displayName': kMockDisplayName, + 'photoUrl': kMockPhotoUrl, + 'email': kMockEmail, + }, + ], + }; + }); + + auth = new FirebaseAuth.private(mockChannel); + }); + + test('signInAnonymously', () async { + FirebaseUser user = await auth.signInAnonymously(); + expect(user, isNotNull); + expect(user, auth.currentUser); + expect(user.isAnonymous, isTrue); + expect(user.isEmailVerified, isFalse); + expect(user.providerData.length, 1); + UserInfo userInfo = user.providerData[0]; + expect(userInfo.providerId, kMockProviderId); + expect(userInfo.uid, kMockUid); + expect(userInfo.displayName, kMockDisplayName); + expect(userInfo.photoUrl, kMockPhotoUrl); + expect(userInfo.email, kMockEmail); + }); + }); +} + +class MockPlatformChannel extends Mock implements MethodChannel { } diff --git a/packages/firebase_database/.gitignore b/packages/firebase_database/.gitignore new file mode 100755 index 000000000000..14c7d4c3f73e --- /dev/null +++ b/packages/firebase_database/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock diff --git a/packages/firebase_database/LICENSE b/packages/firebase_database/LICENSE new file mode 100755 index 000000000000..282a0f51aa4a --- /dev/null +++ b/packages/firebase_database/LICENSE @@ -0,0 +1,26 @@ +Copyright 2017, 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/firebase_database/README.md b/packages/firebase_database/README.md new file mode 100755 index 000000000000..a6d3c58e6408 --- /dev/null +++ b/packages/firebase_database/README.md @@ -0,0 +1,8 @@ +# firebase_database + +A new flutter plugin project. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/firebase_database/android/.gitignore b/packages/firebase_database/android/.gitignore new file mode 100755 index 000000000000..5c4ef82869b5 --- /dev/null +++ b/packages/firebase_database/android/.gitignore @@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/firebase_database/android/build.gradle b/packages/firebase_database/android/build.gradle new file mode 100755 index 000000000000..e115f5a9d50c --- /dev/null +++ b/packages/firebase_database/android/build.gradle @@ -0,0 +1,37 @@ +group 'io.flutter.plugins.firebase.database' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.0' + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.0' + + defaultConfig { + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + lintOptions { + disable 'InvalidPackage' + } + dependencies { + compile 'com.google.firebase:firebase-core:10.2.1' + compile 'com.google.firebase:firebase-auth:10.2.1' + compile 'com.google.firebase:firebase-database:10.2.1' + } +} diff --git a/packages/firebase_database/android/gradle.properties b/packages/firebase_database/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/firebase_database/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/firebase_database/android/settings.gradle b/packages/firebase_database/android/settings.gradle new file mode 100755 index 000000000000..853b33390159 --- /dev/null +++ b/packages/firebase_database/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'firebase_database' diff --git a/packages/firebase_database/android/src/main/AndroidManifest.xml b/packages/firebase_database/android/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..1bf01412d974 --- /dev/null +++ b/packages/firebase_database/android/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/firebase_database/android/src/main/java/io/flutter/plugins/firebase/database/FirebaseDatabasePlugin.java b/packages/firebase_database/android/src/main/java/io/flutter/plugins/firebase/database/FirebaseDatabasePlugin.java new file mode 100755 index 000000000000..170e555bdec3 --- /dev/null +++ b/packages/firebase_database/android/src/main/java/io/flutter/plugins/firebase/database/FirebaseDatabasePlugin.java @@ -0,0 +1,71 @@ +package io.flutter.plugins.firebase.database; + +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.ChildEventListener; + +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.PluginRegistry; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * FirebaseDatabasePlugin + */ +public class FirebaseDatabasePlugin implements MethodCallHandler { + + public static void registerWith(PluginRegistry.Registrar registrar) { + final MethodChannel channel = new MethodChannel(registrar.messenger(), "plugins.flutter.io/firebase_database"); + channel.setMethodCallHandler(new FirebaseDatabasePlugin(channel)); + } + + private FirebaseDatabasePlugin(final MethodChannel channel) { + FirebaseDatabase.getInstance().getReference().limitToLast(10).addChildEventListener(new ChildEventListener() { + @Override + public void onCancelled(DatabaseError error) { + } + @Override + public void onChildAdded(DataSnapshot snapshot, String previousChildName) { + List arguments = Arrays.asList(snapshot.getKey(), snapshot.getValue()); + channel.invokeMethod("DatabaseReference#childAdded", arguments); + } + @Override + public void onChildChanged(DataSnapshot snapshot, String previousChildName) { + } + @Override + public void onChildMoved(DataSnapshot snapshot, String previousChildName) { + } + @Override + public void onChildRemoved(DataSnapshot snapshot) { + } + }); + } + + @Override + public void onMethodCall(MethodCall call, final Result result) { + if (call.method.equals("DatabaseReference#set")) { + List arguments = (List) call.arguments; + Map data = (Map) arguments.get(0); + DatabaseReference ref = FirebaseDatabase.getInstance().getReference().push(); + ref.updateChildren(data, new DatabaseReference.CompletionListener() { + @Override + public void onComplete(DatabaseError error, DatabaseReference ref) { + if (error != null) { + result.error(String.valueOf(error.getCode()), error.getMessage(), error.getDetails()); + } else { + result.success(null); + } + } + }); + } else { + result.notImplemented(); + } + } +} diff --git a/packages/firebase_database/ios/.gitignore b/packages/firebase_database/ios/.gitignore new file mode 100755 index 000000000000..956c87f3aa28 --- /dev/null +++ b/packages/firebase_database/ios/.gitignore @@ -0,0 +1,31 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + diff --git a/packages/firebase_database/ios/Assets/.gitkeep b/packages/firebase_database/ios/Assets/.gitkeep new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/packages/firebase_database/ios/Classes/FirebaseDatabasePlugin.h b/packages/firebase_database/ios/Classes/FirebaseDatabasePlugin.h new file mode 100755 index 000000000000..10c5c5cb2039 --- /dev/null +++ b/packages/firebase_database/ios/Classes/FirebaseDatabasePlugin.h @@ -0,0 +1,4 @@ +#import + +@interface FirebaseDatabasePlugin : NSObject +@end diff --git a/packages/firebase_database/ios/Classes/FirebaseDatabasePlugin.m b/packages/firebase_database/ios/Classes/FirebaseDatabasePlugin.m new file mode 100755 index 000000000000..b8d5b797629c --- /dev/null +++ b/packages/firebase_database/ios/Classes/FirebaseDatabasePlugin.m @@ -0,0 +1,64 @@ +#import "FirebaseDatabasePlugin.h" + +#import + +@interface NSError (FlutterError) +@property(readonly, nonatomic) FlutterError *flutterError; +@end + +@implementation NSError (FlutterError) +- (FlutterError *)flutterError { + return [FlutterError + errorWithCode:[NSString stringWithFormat:@"Error %d", self.code] + message:self.domain + details:self.localizedDescription]; +} +@end + +@implementation FirebaseDatabasePlugin { +} + ++ (void)registerWithRegistrar:(NSObject *)registrar { + FlutterMethodChannel *channel = + [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/firebase_database" + binaryMessenger:[registrar messenger]]; + FirebaseDatabasePlugin *instance = [[FirebaseDatabasePlugin alloc] init]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (instancetype)init { + self = [super init]; + if (self) { + if (![FIRApp defaultApp]) { + [FIRApp configure]; + } + [[[FIRDatabase database].reference queryLimitedToLast:10] + observeEventType:FIRDataEventTypeChildAdded + withBlock:^(FIRDataSnapshot *_Nonnull snapshot) { + [channel invokeMethod:@"DatabaseReference#childAdded" + arguments:@[ snapshot.key, snapshot.value ]]; + }]; + } + return self; +} + +- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { + if ([@"DatabaseReference#set" isEqualToString:call.method]) { + NSDictionary *data = call.arguments[0]; + FIRDatabaseReference *ref = + [[FIRDatabase database].reference childByAutoId]; + [ref updateChildValues:data + withCompletionBlock:^(NSError *_Nullable error, + FIRDatabaseReference *_Nonnull ref) { + if (error != nil) { + result(error.flutterError); + } else { + result(nil); + } + }]; + } else { + result(FlutterMethodNotImplemented); + } +} + +@end diff --git a/packages/firebase_database/ios/firebase_database.podspec b/packages/firebase_database/ios/firebase_database.podspec new file mode 100755 index 000000000000..2a1038d0aa2a --- /dev/null +++ b/packages/firebase_database/ios/firebase_database.podspec @@ -0,0 +1,21 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'firebase_database' + s.version = '0.0.1' + s.summary = 'Firebase Database plugin for Flutter.' + s.description = <<-DESC +Firebase Database plugin for Flutter. + DESC + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/firebase_database' + 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.ios.deployment_target = '6.0' + s.dependency 'Flutter' + s.dependency 'Firebase/Database' +end + diff --git a/packages/firebase_database/lib/firebase_database.dart b/packages/firebase_database/lib/firebase_database.dart new file mode 100755 index 000000000000..dc86d6d4d6db --- /dev/null +++ b/packages/firebase_database/lib/firebase_database.dart @@ -0,0 +1,56 @@ +// Copyright 2017, the Flutter 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 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class FirebaseDatabase { + static const MethodChannel _channel = + const MethodChannel('plugins.flutter.io/firebase_database'); + + FirebaseDatabase() { + // stub implementation + _channel.setMethodCallHandler((MethodCall call) { + if (call.method == "DatabaseReference#childAdded") { + Event event = new Event._(call.arguments[0], call.arguments[1]); + Query._childAdded.add(event); + } + }); + } + + static FirebaseDatabase _instance = new FirebaseDatabase(); + static FirebaseDatabase get instance => _instance; + DatabaseReference reference() => new DatabaseReference(); +} + +class Query { + // stub implementation + static StreamController _childAdded = new StreamController.broadcast(); + Stream get onChildAdded => _childAdded.stream; +} + +class DatabaseReference extends Query { + DatabaseReference push() => new DatabaseReference(); // stub implementation + DatabaseReference child(String name) => new DatabaseReference(); // stub implementation + + Future set(Map value) async { + await FirebaseDatabase._channel.invokeMethod( + "DatabaseReference#set", + [value] + ); + return value; + } +} + +class Event { + Event._(String key, dynamic value) : snapshot = new DataSnapshot(key, value); + final DataSnapshot snapshot; +} + +class DataSnapshot { + final String key; + final dynamic value; + DataSnapshot(this.key, this.value); +} diff --git a/packages/firebase_database/lib/ui/firebase_animated_list.dart b/packages/firebase_database/lib/ui/firebase_animated_list.dart new file mode 100755 index 000000000000..3be382c20516 --- /dev/null +++ b/packages/firebase_database/lib/ui/firebase_animated_list.dart @@ -0,0 +1,236 @@ +// Copyright 2017, the Flutter 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 '../firebase_database.dart'; +import 'package:flutter/material.dart'; + +typedef Widget FirebaseAnimatedListItemBuilder( + BuildContext context, + DataSnapshot snapshot, + Animation animation, +); + +/// An AnimatedList widget that is bound to a query +class FirebaseAnimatedList extends StatefulWidget { + /// Creates a scrolling container that animates items when they are inserted or removed. + FirebaseAnimatedList({ + Key key, + @required this.query, + @required this.itemBuilder, + this.defaultChild, + this.scrollDirection: Axis.vertical, + this.reverse: false, + this.controller, + this.primary, + this.physics, + this.shrinkWrap: false, + this.padding, + this.duration: const Duration(milliseconds: 300), + }) : super(key: key) { + assert(itemBuilder != null); + } + + /// A Firebase query to use to populate the animated list + final Query query; + + /// A widget to display while the query is loading. Defaults to an empty + /// Container(). + final Widget defaultChild; + + /// Called, as needed, to build list item widgets. + /// + /// List items are only built when they're scrolled into view. + /// + /// The [AnimatedListItemBuilder] index parameter indicates the item's + /// posiition in the list. The value of the index parameter will be between 0 and + /// [initialItemCount] plus the total number of items that have been inserted + /// with [AnimatedListState.insertItem] and less the total number of items + /// that have been removed with [AnimatedList.removeItem]. + /// + /// Implementations of this callback should assume that [AnimatedList.removeItem] + /// removes an item immediately. + final FirebaseAnimatedListItemBuilder itemBuilder; + + /// The axis along which the scroll view scrolls. + /// + /// Defaults to [Axis.vertical]. + final Axis scrollDirection; + + /// Whether the scroll view scrolls in the reading direction. + /// + /// For example, if the reading direction is left-to-right and + /// [scrollDirection] is [Axis.horizontal], then the scroll view scrolls from + /// left to right when [reverse] is false and from right to left when + /// [reverse] is true. + /// + /// Similarly, if [scrollDirection] is [Axis.vertical], then the scroll view + /// scrolls from top to bottom when [reverse] is false and from bottom to top + /// when [reverse] is true. + /// + /// Defaults to false. + final bool reverse; + + /// An object that can be used to control the position to which this scroll + /// view is scrolled. + /// + /// Must be null if [primary] is true. + final ScrollController controller; + + /// Whether this is the primary scroll view associated with the parent + /// [PrimaryScrollController]. + /// + /// On iOS, this identifies the scroll view that will scroll to top in + /// response to a tap in the status bar. + /// + /// Defaults to true when [scrollDirection] is [Axis.vertical] and + /// [controller] is null. + final bool primary; + + /// How the scroll view should respond to user input. + /// + /// For example, determines how the scroll view continues to animate after the + /// user stops dragging the scroll view. + /// + /// Defaults to matching platform conventions. + final ScrollPhysics physics; + + /// Whether the extent of the scroll view in the [scrollDirection] should be + /// determined by the contents being viewed. + /// + /// If the scroll view does not shrink wrap, then the scroll view will expand + /// to the maximum allowed size in the [scrollDirection]. If the scroll view + /// has unbounded constraints in the [scrollDirection], then [shrinkWrap] must + /// be true. + /// + /// Shrink wrapping the content of the scroll view is significantly more + /// expensive than expanding to the maximum allowed size because the content + /// can expand and contract during scrolling, which means the size of the + /// scroll view needs to be recomputed whenever the scroll position changes. + /// + /// Defaults to false. + final bool shrinkWrap; + + /// The amount of space by which to inset the children. + final EdgeInsets padding; + + /// The duration of the insert and remove animation. + /// + /// Defaults to const Duration(milliseconds: 300). + final Duration duration; + + @override + FirebaseAnimatedListState createState() => new FirebaseAnimatedListState(); +} + +class FirebaseAnimatedListState extends State { + GlobalKey _animatedListKey = new GlobalKey(); + _ListModel _model; + bool _dataAvailable = false; + + @override initState() { + super.initState(); + _model = new _ListModel( + query: widget.query, + onValue: _onValue, + onChildAdded: _onChildAdded, + onChildRemoved: _onChildRemoved, + ); + } + + void _onValue() { + setState(() { + _dataAvailable = true; + }); + } + + void _onChildAdded(int index, DataSnapshot snapshot) { + _animatedListKey.currentState.insertItem(index, duration: widget.duration); + } + + void _onChildRemoved(int index, DataSnapshot snapshot) { + _animatedListKey.currentState.removeItem( + index, + (BuildContext context, int index, Animation animation) { + return new widget.itemBuilder(context, snapshot, animation); + }, + duration: widget.duration, + ); + } + + Widget _buildItem(BuildContext context, int index, Animation animation) { + return widget.itemBuilder(context, _model[index], animation); + } + + @override + Widget build(BuildContext context) { + if (!_dataAvailable) + return defaultChild ?? new Container(); + return new AnimatedList( + key: _animatedListKey, + itemBuilder: _buildItem, + initialItemCount: _model.length, + scrollDirection: widget.scrollDirection, + reverse: widget.reverse, + controller: widget.controller, + primary: widget.primary, + physics: widget.physics, + shrinkWrap: widget.shrinkWrap, + padding: widget.padding, + ); + } + + @override void dispose() { + _model.dispose(); + super.dispose(); + } +} + +typedef void _ChildCallback(int index, DataSnapshot snapshot); + +// Wrapper around an array that is bound to a query that notifies on changes. +// TODO(jackson): Refactor this into a public class supporting more use cases. +class _ListModel { + _ListModel({ + @required this.query, + @required VoidCallback this.onValue, + @required _ChildCallback this.onChildAdded, + @required _ChildCallback this.onChildRemoved, + }) { + _subscriptions = [ + query.onChildAdded.listen(_onChildAdded), + // TODO(jackson): Add support for more types of data events + // query.onChildRemoved.listen(_onChildRemoved), + // query.onValue.listen(_onValue), + ]; + // For now, pretend all the data is loaded immediately. + onValue(); + } + + final Query query; + final VoidCallback onValue; + final _ChildCallback onChildAdded; + final _ChildCallback onChildRemoved; + + final List _items = []; + List> _subscriptions; + + // TODO(jackson): Find the correct position in the array to insert into + void _onChildAdded(Event event) + { + _items.insert(0, event.snapshot); + onChildAdded(0, event.snapshot); + } + + int get length => _items.length; + DataSnapshot operator [](int index) => _items[index]; + int indexOf(DataSnapshot item) => _items.indexOf(item); + + void dispose() { + assert(_subscriptions != null); + for (StreamSubscription subscription in _subscriptions) + subscription.cancel(); + _subscriptions = null; + } +} diff --git a/packages/firebase_database/pubspec.yaml b/packages/firebase_database/pubspec.yaml new file mode 100755 index 000000000000..ce7b4fe124b9 --- /dev/null +++ b/packages/firebase_database/pubspec.yaml @@ -0,0 +1,11 @@ +name: firebase_database +description: Firebase Database plugin for Flutter. + +flutter: + plugin: + androidPackage: io.flutter.plugins.firebase.database + pluginClass: FirebaseDatabasePlugin + +dependencies: + flutter: + sdk: flutter diff --git a/packages/firebase_storage/.gitignore b/packages/firebase_storage/.gitignore new file mode 100755 index 000000000000..14c7d4c3f73e --- /dev/null +++ b/packages/firebase_storage/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock diff --git a/packages/firebase_storage/LICENSE b/packages/firebase_storage/LICENSE new file mode 100755 index 000000000000..282a0f51aa4a --- /dev/null +++ b/packages/firebase_storage/LICENSE @@ -0,0 +1,26 @@ +Copyright 2017, 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/firebase_storage/README.md b/packages/firebase_storage/README.md new file mode 100755 index 000000000000..0f30bb96bd50 --- /dev/null +++ b/packages/firebase_storage/README.md @@ -0,0 +1,8 @@ +# firebase_storage + +A new flutter plugin project. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/firebase_storage/android/.gitignore b/packages/firebase_storage/android/.gitignore new file mode 100755 index 000000000000..5c4ef82869b5 --- /dev/null +++ b/packages/firebase_storage/android/.gitignore @@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/firebase_storage/android/build.gradle b/packages/firebase_storage/android/build.gradle new file mode 100755 index 000000000000..293a2ce56975 --- /dev/null +++ b/packages/firebase_storage/android/build.gradle @@ -0,0 +1,36 @@ +group 'io.flutter.plugins.firebase.storage' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.0' + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.0' + + defaultConfig { + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + lintOptions { + disable 'InvalidPackage' + } + dependencies { + compile 'com.google.firebase:firebase-core:10.2.1' + compile 'com.google.firebase:firebase-storage:10.2.1' + } +} diff --git a/packages/firebase_storage/android/gradle.properties b/packages/firebase_storage/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/firebase_storage/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/firebase_storage/android/settings.gradle b/packages/firebase_storage/android/settings.gradle new file mode 100755 index 000000000000..f0aec4453e6d --- /dev/null +++ b/packages/firebase_storage/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'firebase_storage' diff --git a/packages/firebase_storage/android/src/main/AndroidManifest.xml b/packages/firebase_storage/android/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..aa09b8304e51 --- /dev/null +++ b/packages/firebase_storage/android/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java b/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java new file mode 100755 index 000000000000..ddee7a790e8a --- /dev/null +++ b/packages/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FirebaseStoragePlugin.java @@ -0,0 +1,69 @@ +// 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.firebase.storage; + +import android.app.Activity; +import android.net.Uri; + +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.OnFailureListener; + +import com.google.firebase.FirebaseApp; +import com.google.firebase.storage.FirebaseStorage; +import com.google.firebase.storage.StorageReference; +import com.google.firebase.storage.UploadTask; + +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.PluginRegistry.Registrar; + +import java.util.Map; +import java.io.File; + +/** + * FirebaseStoragePlugin + */ +public class FirebaseStoragePlugin implements MethodCallHandler { + private FirebaseStorage firebaseStorage; + + public static void registerWith(Registrar registrar) { + final MethodChannel channel = new MethodChannel(registrar.messenger(), "firebase_storage"); + channel.setMethodCallHandler(new FirebaseStoragePlugin(registrar.activity())); + } + + + private FirebaseStoragePlugin(Activity activity) { + FirebaseApp.initializeApp(activity); + this.firebaseStorage = FirebaseStorage.getInstance(); + } + + @Override + public void onMethodCall(MethodCall call, final Result result) { + if (call.method.equals("StorageReference#putFile")) { + Map arguments = (Map) call.arguments; + String filename = arguments.get("filename"); + String path = arguments.get("path"); + File file = new File(filename); + StorageReference ref = firebaseStorage.getReference().child(path); + UploadTask uploadTask = ref.putFile(Uri.fromFile(file)); + uploadTask.addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(UploadTask.TaskSnapshot snapshot) { + result.success(snapshot.getDownloadUrl().toString()); + } + }); + uploadTask.addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(Exception e) { + result.error("upload_error", e.getMessage(), e.getStackTrace()); + } + }); + } else { + result.notImplemented(); + } + } +} diff --git a/packages/firebase_storage/example/.gitignore b/packages/firebase_storage/example/.gitignore new file mode 100755 index 000000000000..eb15c3d27cab --- /dev/null +++ b/packages/firebase_storage/example/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock +.flutter-plugins diff --git a/packages/firebase_storage/example/README.md b/packages/firebase_storage/example/README.md new file mode 100755 index 000000000000..8ed83b61da22 --- /dev/null +++ b/packages/firebase_storage/example/README.md @@ -0,0 +1,8 @@ +# firebase_storage_example + +Demonstrates how to use the firebase_storage plugin. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/firebase_storage/example/android.iml b/packages/firebase_storage/example/android.iml new file mode 100755 index 000000000000..462b903e05b6 --- /dev/null +++ b/packages/firebase_storage/example/android.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/firebase_storage/example/android/.gitignore b/packages/firebase_storage/example/android/.gitignore new file mode 100755 index 000000000000..1fd9325cac44 --- /dev/null +++ b/packages/firebase_storage/example/android/.gitignore @@ -0,0 +1,13 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +GeneratedPluginRegistrant.java + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/firebase_storage/example/android/app/build.gradle b/packages/firebase_storage/example/android/app/build.gradle new file mode 100755 index 000000000000..3ceeab740252 --- /dev/null +++ b/packages/firebase_storage/example/android/app/build.gradle @@ -0,0 +1,49 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withInputStream { stream -> + localProperties.load(stream) + } +} + +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.") +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.2' + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + applicationId 'io.flutter.plugins.firebase_storage_example' + testInstrumentationRunner "android.support.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 + } + } +} + +flutter { + source '../..' +} + +dependencies { + androidTestCompile 'com.android.support:support-annotations:25.0.0' + androidTestCompile 'com.android.support.test:runner:0.5' + androidTestCompile 'com.android.support.test:rules:0.5' +} + +apply plugin: 'com.google.gms.google-services' diff --git a/packages/firebase_storage/example/android/app/google-services.json b/packages/firebase_storage/example/android/app/google-services.json new file mode 100755 index 000000000000..2359882f146e --- /dev/null +++ b/packages/firebase_storage/example/android/app/google-services.json @@ -0,0 +1,93 @@ +{ + "project_info": { + "project_number": "297855924061", + "firebase_url": "https://flutterfire-cd2f7.firebaseio.com", + "project_id": "flutterfire-cd2f7", + "storage_bucket": "flutterfire-cd2f7.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:297855924061:android:669871c998cc21bd", + "android_client_info": { + "package_name": "com.yourcompany.firebaseauth.example" + } + }, + "oauth_client": [ + { + "client_id": "297855924061-col4in4uubarifm60nbq8id01ec3ss4c.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.yourcompany.firebaseauth.example", + "certificate_hash": "8a4e194f5bfc3fb1075e7daae8dcddd526fde207" + } + }, + { + "client_id": "297855924061-f68m5v860ms5faiotn5mv9f50cmpacdq.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyD_shO5mfO9lhy2TVWhfo1VUmARKlG4suk" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 2, + "other_platform_oauth_client": [ + { + "client_id": "297855924061-48k2m6hl6pa4q9hukijjd0c20ev4qans.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.yourcompany.firebaseAuthExample" + } + }, + { + "client_id": "297855924061-f68m5v860ms5faiotn5mv9f50cmpacdq.apps.googleusercontent.com", + "client_type": 3 + } + ] + }, + "ads_service": { + "status": 2 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:297855924061:android:92efa9a0df6f077f", + "android_client_info": { + "package_name": "io.flutter.plugins.firebase_storage_example" + } + }, + "oauth_client": [ + { + "client_id": "297855924061-f68m5v860ms5faiotn5mv9f50cmpacdq.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyD_shO5mfO9lhy2TVWhfo1VUmARKlG4suk" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 2 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/packages/firebase_storage/example/android/app/src/main/AndroidManifest.xml b/packages/firebase_storage/example/android/app/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..cc545c10e829 --- /dev/null +++ b/packages/firebase_storage/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_storage/example/android/app/src/main/java/io/flutter/plugins/firebase_storage_example/MainActivity.java b/packages/firebase_storage/example/android/app/src/main/java/io/flutter/plugins/firebase_storage_example/MainActivity.java new file mode 100755 index 000000000000..4b3a3c2ada6c --- /dev/null +++ b/packages/firebase_storage/example/android/app/src/main/java/io/flutter/plugins/firebase_storage_example/MainActivity.java @@ -0,0 +1,13 @@ +package io.flutter.plugins.firebase_storage_example; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class MainActivity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/packages/firebase_storage/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/firebase_storage/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100755 index 000000000000..db77bb4b7b09 Binary files /dev/null and b/packages/firebase_storage/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/firebase_storage/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/firebase_storage/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100755 index 000000000000..17987b79bb8a Binary files /dev/null and b/packages/firebase_storage/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/firebase_storage/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/firebase_storage/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100755 index 000000000000..09d4391482be Binary files /dev/null and b/packages/firebase_storage/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/firebase_storage/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/firebase_storage/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100755 index 000000000000..d5f1c8d34e7a Binary files /dev/null and b/packages/firebase_storage/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/firebase_storage/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/firebase_storage/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100755 index 000000000000..4d6372eebdb2 Binary files /dev/null and b/packages/firebase_storage/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/firebase_storage/example/android/build.gradle b/packages/firebase_storage/example/android/build.gradle new file mode 100755 index 000000000000..2023b0f5725e --- /dev/null +++ b/packages/firebase_storage/example/android/build.gradle @@ -0,0 +1,30 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.google.gms:google-services:3.0.0' + } +} + +allprojects { + repositories { + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.14.1' +} diff --git a/packages/firebase_storage/example/android/gradle.properties b/packages/firebase_storage/example/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/firebase_storage/example/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/firebase_storage/example/android/settings.gradle b/packages/firebase_storage/example/android/settings.gradle new file mode 100755 index 000000000000..115da6cb4f4d --- /dev/null +++ b/packages/firebase_storage/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/firebase_storage/example/firebase_storage_example.iml b/packages/firebase_storage/example/firebase_storage_example.iml new file mode 100755 index 000000000000..1ae40a0f7f54 --- /dev/null +++ b/packages/firebase_storage/example/firebase_storage_example.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/firebase_storage/example/ios/.gitignore b/packages/firebase_storage/example/ios/.gitignore new file mode 100755 index 000000000000..667cd0925fee --- /dev/null +++ b/packages/firebase_storage/example/ios/.gitignore @@ -0,0 +1,42 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +Pods/ +/Flutter/app.flx +/Flutter/app.zip +/Flutter/App.framework +/Flutter/Flutter.framework +/Flutter/Generated.xcconfig +/ServiceDefinitions.json + +Podfile.lock +/Runner/GeneratedPluginRegistrant.h +/Runner/GeneratedPluginRegistrant.m diff --git a/packages/firebase_storage/example/ios/Flutter/AppFrameworkInfo.plist b/packages/firebase_storage/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100755 index 000000000000..6c2de8086bcd --- /dev/null +++ b/packages/firebase_storage/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/firebase_storage/example/ios/Flutter/Debug.xcconfig b/packages/firebase_storage/example/ios/Flutter/Debug.xcconfig new file mode 100755 index 000000000000..9803018ca79d --- /dev/null +++ b/packages/firebase_storage/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/firebase_storage/example/ios/Flutter/Release.xcconfig b/packages/firebase_storage/example/ios/Flutter/Release.xcconfig new file mode 100755 index 000000000000..a4a8c604e13d --- /dev/null +++ b/packages/firebase_storage/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/firebase_storage/example/ios/Podfile b/packages/firebase_storage/example/ios/Podfile new file mode 100755 index 000000000000..90b5f651fb63 --- /dev/null +++ b/packages/firebase_storage/example/ios/Podfile @@ -0,0 +1,36 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +if ENV['FLUTTER_FRAMEWORK_DIR'] == nil + abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework') +end + +target 'Runner' do + # Pods for Runner + + # Flutter Pods + pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR'] + + if File.exists? '../.flutter-plugins' + flutter_root = File.expand_path('..') + File.foreach('../.flutter-plugins') { |line| + plugin = line.split(pattern='=') + if plugin.length == 2 + name = plugin[0].strip() + path = plugin[1].strip() + resolved_path = File.expand_path("#{path}/ios", flutter_root) + pod name, :path => resolved_path + else + puts "Invalid plugin specification: #{line}" + end + } + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/packages/firebase_storage/example/ios/Runner.xcodeproj/project.pbxproj b/packages/firebase_storage/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100755 index 000000000000..1ec2a01a07dc --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,498 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 5C6F5A711EC3CCCC008D64B5 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C6F5A701EC3CCCC008D64B5 /* GeneratedPluginRegistrant.m */; }; + 7A1ECC911E8EDB6900309407 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7A1ECC901E8EDB6900309407 /* GoogleService-Info.plist */; }; + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; }; + 9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; }; + 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 */; }; + CE57DC9C9240FBD15E358E24 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E13AAF33B0B411D7B2D38642 /* libPods-Runner.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 5C6F5A6F1EC3CCCC008D64B5 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 5C6F5A701EC3CCCC008D64B5 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 7A1ECC901E8EDB6900309407 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.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 = ""; }; + 9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = ""; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; 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 = ""; }; + E13AAF33B0B411D7B2D38642 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + CE57DC9C9240FBD15E358E24 /* libPods-Runner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 9740EEB71CF902C7004384FC /* app.flx */, + 3B80C3931E831B6300D905FE /* App.framework */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 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 = ( + 5C6F5A6F1EC3CCCC008D64B5 /* GeneratedPluginRegistrant.h */, + 5C6F5A701EC3CCCC008D64B5 /* GeneratedPluginRegistrant.m */, + 7A1ECC901E8EDB6900309407 /* GoogleService-Info.plist */, + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 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 = ( + E13AAF33B0B411D7B2D38642 /* 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 = 0830; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = 3GRKCVVJ22; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + 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 = ( + 9740EEBB1CF902C7004384FC /* app.flx in Resources */, + 7A1ECC911E8EDB6900309407 /* GoogleService-Info.plist in Resources */, + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 9740EEB41CF90195004384FC /* Debug.xcconfig 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\" thin"; + }; + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/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 = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../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"; + 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 */, + 5C6F5A711EC3CCCC008D64B5 /* 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; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + 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_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + 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_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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 = { + ARCHS = arm64; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 3GRKCVVJ22; + 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 = com.yourcompany.firebaseStorageExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ARCHS = arm64; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 3GRKCVVJ22; + 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 = com.yourcompany.firebaseStorageExample; + 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/firebase_storage/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/firebase_storage/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/firebase_storage/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/firebase_storage/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100755 index 000000000000..1c9580788197 --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_storage/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/firebase_storage/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/firebase_storage/example/ios/Runner/AppDelegate.h b/packages/firebase_storage/example/ios/Runner/AppDelegate.h new file mode 100755 index 000000000000..cf210d213f27 --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/packages/firebase_storage/example/ios/Runner/AppDelegate.m b/packages/firebase_storage/example/ios/Runner/AppDelegate.m new file mode 100755 index 000000000000..ce9c30f9f812 --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner/AppDelegate.m @@ -0,0 +1,12 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application +didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 000000000000..d22f10b2ab63 --- /dev/null +++ b/packages/firebase_storage/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/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100755 index 000000000000..28c6bf03016f Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100755 index 000000000000..2ccbfd967d96 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100755 index 000000000000..f091b6b0bca8 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100755 index 000000000000..4cde12118dda Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100755 index 000000000000..d0ef06e7edb8 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100755 index 000000000000..dcdc2306c285 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100755 index 000000000000..2ccbfd967d96 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100755 index 000000000000..c8f9ed8f5cee Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100755 index 000000000000..a6d6b8609df0 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100755 index 000000000000..a6d6b8609df0 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100755 index 000000000000..75b2d164a5a9 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100755 index 000000000000..c4df70d39da7 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100755 index 000000000000..6a84f41e14e2 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100755 index 000000000000..d0e1f5853602 Binary files /dev/null and b/packages/firebase_storage/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/firebase_storage/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/firebase_storage/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100755 index 000000000000..ebf48f603974 --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_storage/example/ios/Runner/Base.lproj/Main.storyboard b/packages/firebase_storage/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100755 index 000000000000..f3c28516fb38 --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/firebase_storage/example/ios/Runner/GoogleService-Info.plist b/packages/firebase_storage/example/ios/Runner/GoogleService-Info.plist new file mode 100755 index 000000000000..6b1998d1ec03 --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,40 @@ + + + + + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 + CLIENT_ID + 297855924061-vomqkcsig8q6r4d6uajt4aa0hg614u91.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.297855924061-vomqkcsig8q6r4d6uajt4aa0hg614u91 + API_KEY + AIzaSyBq6mcufFXfyqr79uELCiqM_O_1-G72PVU + GCM_SENDER_ID + 297855924061 + PLIST_VERSION + 1 + BUNDLE_ID + com.yourcompany.firebaseStorageExample + PROJECT_ID + flutterfire-cd2f7 + STORAGE_BUCKET + flutterfire-cd2f7.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:297855924061:ios:0daa9b9f7336fbc2 + DATABASE_URL + https://flutterfire-cd2f7.firebaseio.com + + \ No newline at end of file diff --git a/packages/firebase_storage/example/ios/Runner/Info.plist b/packages/firebase_storage/example/ios/Runner/Info.plist new file mode 100755 index 000000000000..6e4ed61c7cbc --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + firebase_storage_example + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/firebase_storage/example/ios/Runner/main.m b/packages/firebase_storage/example/ios/Runner/main.m new file mode 100755 index 000000000000..1bdb8e28d1db --- /dev/null +++ b/packages/firebase_storage/example/ios/Runner/main.m @@ -0,0 +1,10 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, + NSStringFromClass([AppDelegate class])); + } +} diff --git a/packages/firebase_storage/example/lib/main.dart b/packages/firebase_storage/example/lib/main.dart new file mode 100755 index 000000000000..14ad1a83e6ef --- /dev/null +++ b/packages/firebase_storage/example/lib/main.dart @@ -0,0 +1,74 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:firebase_storage/firebase_storage.dart'; +import 'package:http/http.dart' as http; + +void main() { + runApp(new MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'Flutter Storage Example', + home: new MyHomePage(), + ); + } +} + +class MyHomePage extends StatefulWidget { + @override + _MyHomePageState createState() => new _MyHomePageState(); +} + +const String kTestString = "Hello world!"; + +class _MyHomePageState extends State { + String _fileContents; + + Future _uploadFile() async { + Directory systemTempDir = Directory.systemTemp; + File file = await new File('${systemTempDir.path}/foo.txt').create(); + file.writeAsString(kTestString); + assert(await file.readAsString() == kTestString); + String rand = "${new Random().nextInt(10000)}"; + StorageReference ref = FirebaseStorage.instance.ref().child("foo$rand.txt"); + StorageUploadTask uploadTask = ref.put(file); + Uri downloadUrl = (await uploadTask.future).downloadUrl; + http.Response downloadData = await http.get(downloadUrl); + setState(() { + _fileContents = downloadData.body; + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text('Flutter Storage Example'), + ), + body: new Center( + child: new Column( + mainAxisSize: MainAxisSize.min, + children: [ + _fileContents == null ? + new Text('Press the button to upload a file') : + new Text( + 'Success!\n\nFile contents: "$_fileContents"', + style: const TextStyle(color: const Color.fromARGB(255, 0, 155, 0)), + ) + ], + ), + ), + floatingActionButton: new FloatingActionButton( + onPressed: _uploadFile, + tooltip: 'Upload', + child: new Icon(Icons.file_upload), + ), + ); + } +} diff --git a/packages/firebase_storage/example/pubspec.yaml b/packages/firebase_storage/example/pubspec.yaml new file mode 100755 index 000000000000..51c2914e95f2 --- /dev/null +++ b/packages/firebase_storage/example/pubspec.yaml @@ -0,0 +1,43 @@ +name: firebase_storage_example +description: Demonstrates how to use the firebase_storage plugin. + +dependencies: + flutter: + sdk: flutter + firebase_storage: + path: ../ + http: ^0.11.3 + +# For information on the generic Dart part of this file, see the +# following page: https://www.dartlang.org/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section here, in + # this "flutter" section, as in: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 diff --git a/packages/firebase_storage/ios/.gitignore b/packages/firebase_storage/ios/.gitignore new file mode 100755 index 000000000000..956c87f3aa28 --- /dev/null +++ b/packages/firebase_storage/ios/.gitignore @@ -0,0 +1,31 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + diff --git a/packages/firebase_storage/ios/Assets/.gitkeep b/packages/firebase_storage/ios/Assets/.gitkeep new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.h b/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.h new file mode 100755 index 000000000000..7038def5afab --- /dev/null +++ b/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.h @@ -0,0 +1,4 @@ +#import + +@interface FirebaseStoragePlugin : NSObject +@end diff --git a/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m b/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m new file mode 100755 index 000000000000..042ba9a7b2d4 --- /dev/null +++ b/packages/firebase_storage/ios/Classes/FirebaseStoragePlugin.m @@ -0,0 +1,64 @@ +#import "FirebaseStoragePlugin.h" + +#import + +@interface NSError (FlutterError) +@property(readonly, nonatomic) FlutterError *flutterError; +@end + +@implementation NSError (FlutterError) +- (FlutterError *)flutterError { + return [FlutterError + errorWithCode:[NSString stringWithFormat:@"Error %ld", (long)self.code] + message:self.domain + details:self.localizedDescription]; +} +@end + +@implementation FirebaseStoragePlugin { +} + ++ (void)registerWithRegistrar:(NSObject *)registrar { + FlutterMethodChannel *channel = + [FlutterMethodChannel methodChannelWithName:@"firebase_storage" + binaryMessenger:[registrar messenger]]; + FirebaseStoragePlugin *instance = [[FirebaseStoragePlugin alloc] init]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + + +- (instancetype)init { + self = [super init]; + if (self) { + if (![FIRApp defaultApp]) { + [FIRApp configure]; + } + } + return self; +} + +- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { + if ([@"StorageReference#putFile" isEqualToString:call.method]) { + NSData *data = + [NSData dataWithContentsOfFile:call.arguments[@"filename"]]; + NSString *path = call.arguments[@"path"]; + FIRStorageReference *fileRef = + [[FIRStorage storage].reference child:path]; + [fileRef putData:data + metadata:nil + completion:^(FIRStorageMetadata *metadata, NSError *error) { + if (error != nil) { + result(error.flutterError); + } else { + // Metadata contains file metadata such as size, + // content-type, and download URL. + NSURL *downloadURL = metadata.downloadURL; + result(downloadURL.absoluteString); + } + }]; + } else { + result(FlutterMethodNotImplemented); + } +} + +@end diff --git a/packages/firebase_storage/ios/firebase_storage.podspec b/packages/firebase_storage/ios/firebase_storage.podspec new file mode 100755 index 000000000000..dd24e36c3117 --- /dev/null +++ b/packages/firebase_storage/ios/firebase_storage.podspec @@ -0,0 +1,21 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'firebase_storage' + s.version = '0.0.1' + s.summary = 'Firebase Storage plugin for Flutter.' + s.description = <<-DESC +Firebase Storage plugin for Flutter. + DESC + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/firebase_storage' + 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.ios.deployment_target = '6.0' + s.dependency 'Flutter' + s.dependency 'Firebase/Storage' +end + diff --git a/packages/firebase_storage/lib/firebase_storage.dart b/packages/firebase_storage/lib/firebase_storage.dart new file mode 100755 index 000000000000..7242802cfdd4 --- /dev/null +++ b/packages/firebase_storage/lib/firebase_storage.dart @@ -0,0 +1,55 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/services.dart'; + +class FirebaseStorage { + static const MethodChannel _channel = const MethodChannel('firebase_storage'); + + static FirebaseStorage get instance => new FirebaseStorage(); + + StorageReference ref() { + return const StorageReference._(const []); + } +} + +class StorageReference { + const StorageReference._(this._pathComponents); + final List _pathComponents; + + StorageReference child(String path) { + List childPath = new List.from(_pathComponents)..addAll(path.split("/")); + return new StorageReference._(childPath); + } + + StorageUploadTask put(File file) { + StorageUploadTask task = new StorageUploadTask._(file, _pathComponents.join("/")); + task._start(); + return task; + } +} + +class StorageUploadTask { + StorageUploadTask._(this.file, this.path); + final File file; + final String path; + + Completer _completer = new Completer(); + Future get future => _completer.future; + + Future _start() async { + String downloadUrl = await FirebaseStorage._channel.invokeMethod( + "StorageReference#putFile", + { + 'filename': file.absolute.path, + 'path': path, + }, + ); + _completer.complete(new UploadTaskSnapshot(downloadUrl: Uri.parse(downloadUrl))); + } +} + +class UploadTaskSnapshot { + UploadTaskSnapshot({ this.downloadUrl }); + final Uri downloadUrl; +} diff --git a/packages/firebase_storage/pubspec.yaml b/packages/firebase_storage/pubspec.yaml new file mode 100755 index 000000000000..adaedf35c766 --- /dev/null +++ b/packages/firebase_storage/pubspec.yaml @@ -0,0 +1,11 @@ +name: firebase_storage +description: Firebase Storage plugin for Flutter. + +flutter: + plugin: + androidPackage: io.flutter.plugins.firebase.storage + pluginClass: FirebaseStoragePlugin + +dependencies: + flutter: + sdk: flutter diff --git a/packages/google_sign_in/.gitignore b/packages/google_sign_in/.gitignore new file mode 100755 index 000000000000..14c7d4c3f73e --- /dev/null +++ b/packages/google_sign_in/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock diff --git a/packages/google_sign_in/LICENSE b/packages/google_sign_in/LICENSE new file mode 100755 index 000000000000..4da9688730d1 --- /dev/null +++ b/packages/google_sign_in/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/google_sign_in/README.md b/packages/google_sign_in/README.md new file mode 100755 index 000000000000..cca77246d58b --- /dev/null +++ b/packages/google_sign_in/README.md @@ -0,0 +1,83 @@ +# google_sign_in + +A Flutter plugin for [Google Sign In](https://developers.google.com/identity/). + +Note: This is a work-in-progress, and is not fully supported by the Flutter team. +(For example, we don't have this under continuous integration and testing.) + +## Android integration + +To access Google Sign-In, you'll need to make sure to [register your +application](https://developers.google.com/mobile/add?platform=android). + +You don't need to include the google-services.json file in your app unless you +are using Google services that require it. You do need to enable the OAuth APIs +that you want, using the [Google Cloud Platform API +manager](https://console.developers.google.com/). For example, if you +want to mimic the behavior of the Google Sign-In sample app, you'll need to +enable the [Google People API](https://developers.google.com/people/). + +# iOS integration + +To access Google Sign-In, you'll need to make sure to [register your +application](https://developers.google.com/mobile/add?platform=ios). Add +the generated GoogleService-Info.plist to root of your Runner project in Xcode, +so that the Google Sign-In framework can determine your client id. + +You'll need to add this to the main dictionary of your application's Info.plist: + +``` + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + + com.yourcompany.myapp + + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + + com.googleusercontent.apps.861823949799-11qfr04mrfh2mndp3el2vgc0e357a2t6 + + + +``` + +## Usage + +Add the following import to your Dart code: + +``` +import 'package:google_sign_in/google_sign_in.dart'; +``` + +Initialize GoogleSignIn with the scopes you want: + +``` +GoogleSignIn.initialize( + scopes: [ + 'email', + 'https://www.googleapis.com/auth/contacts.readonly', + ], +); +``` + +You can now use the `GoogleSignIn` class to authenticate in your Dart code, e.g. + +``` +GoogleSignInAccount account = await (await GoogleSignIn.instance).signIn(); +``` + +See google_sign_in.dart for more API details. + +## 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/android/.gitignore b/packages/google_sign_in/android/.gitignore new file mode 100755 index 000000000000..5c4ef82869b5 --- /dev/null +++ b/packages/google_sign_in/android/.gitignore @@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/google_sign_in/android/build.gradle b/packages/google_sign_in/android/build.gradle new file mode 100755 index 000000000000..72bee7414eda --- /dev/null +++ b/packages/google_sign_in/android/build.gradle @@ -0,0 +1,37 @@ +group 'io.flutter.plugins.googlesignin' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.0' + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.2' + + defaultConfig { + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + lintOptions { + disable 'InvalidPackage' + } +} + +dependencies { + compile 'com.google.android.gms:play-services-auth:10.2.1' + compile 'com.google.guava:guava:20.0' +} diff --git a/packages/google_sign_in/android/gradle.properties b/packages/google_sign_in/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/google_sign_in/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/google_sign_in/android/settings.gradle b/packages/google_sign_in/android/settings.gradle new file mode 100755 index 000000000000..d943fae5ece0 --- /dev/null +++ b/packages/google_sign_in/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'googlesignin' diff --git a/packages/google_sign_in/android/src/main/AndroidManifest.xml b/packages/google_sign_in/android/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..0f8cbeb9c969 --- /dev/null +++ b/packages/google_sign_in/android/src/main/AndroidManifest.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java b/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java new file mode 100755 index 000000000000..0fdc28ee7cc0 --- /dev/null +++ b/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java @@ -0,0 +1,93 @@ +// Copyright 2017, the Flutter 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. + +package io.flutter.plugins.googlesignin; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** A class for running tasks in a background thread. + * + * TODO(jackson): If this class is useful for other plugins, consider including + * it in a shared library or in the Flutter engine + */ +public final class BackgroundTaskRunner { + + /** + * Interface that callers of this API can implement to be notified when a {@link + * #runInBackground(Callable,Callback) background task} has completed. + */ + public interface Callback { + /** + * Invoked on the UI thread when the specified future has completed (calling {@code get()} on + * the future is guaranteed not to block). If the future completed with an exception, then + * {@code get()} will throw an {@code ExecutionException}. + */ + void run(Future future); + } + + private final ThreadPoolExecutor executor; + + /** + * Creates a new background processor with the given number of threads. + * + * @param threads The fixed number of threads in ther pool. + */ + public BackgroundTaskRunner(int threads) { + BlockingQueue workQueue = new LinkedBlockingQueue<>(); + // Only keeps idle threads open for 1 second if we've got more threads than cores. + executor = new ThreadPoolExecutor(threads, threads, 1, TimeUnit.SECONDS, workQueue); + } + + /** + * Executes the specified task in a background thread and notifies the specified callback once the + * task has completed (either successfully or with an exception). + * + *

The callback will be notified on the UI thread. + */ + public void runInBackground(Callable task, final Callback callback) { + final ListenableFuture future = runInBackground(task); + future.addListener( + new Runnable() { + @Override + public void run() { + callback.run(future); + } + }, + Executors.uiThreadExecutor()); + } + + /** + * Executes the specified task in a background thread and returns a future with which the caller + * can be notified of task completion. + * + *

Note: the future will be notified on the background thread. To be notified on the UI thread, + * use {@link #runInBackground(Callable,Callback)}. + */ + public ListenableFuture runInBackground(final Callable task) { + final SettableFuture future = SettableFuture.create(); + + executor.execute( + new Runnable() { + @Override + public void run() { + if (!future.isCancelled()) { + try { + future.set(task.call()); + } catch (Throwable t) { + future.setException(t); + } + } + } + }); + + return future; + } +} diff --git a/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java b/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java new file mode 100755 index 000000000000..1887b4356da5 --- /dev/null +++ b/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java @@ -0,0 +1,34 @@ +// Copyright 2017, the Flutter 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. + +package io.flutter.plugins.googlesignin; + +import android.os.Handler; +import android.os.Looper; +import java.util.concurrent.Executor; + +/** Factory and utility methods for {@code Executor}. + * + * TODO(jackson): If this class is useful for other plugins, consider including + * it in a shared library or in the Flutter engine + */ +public final class Executors { + + private static final class UiThreadExecutor implements Executor { + private static final Handler UI_THREAD = new Handler(Looper.getMainLooper()); + + @Override + public void execute(Runnable command) { + UI_THREAD.post(command); + } + } + + /** Returns an {@code Executor} that will post commands to the UI thread. */ + public static Executor uiThreadExecutor() { + return new UiThreadExecutor(); + } + + // Should never be instantiated. + private Executors() {} +} diff --git a/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java new file mode 100755 index 000000000000..e1ecc009f7cf --- /dev/null +++ b/packages/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -0,0 +1,476 @@ +// Copyright 2017, the Flutter 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. + +package io.flutter.plugins.googlesignin; + +import android.accounts.Account; +import android.app.Activity; +import android.app.Application.ActivityLifecycleCallbacks; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.util.Log; +import com.google.android.gms.auth.GoogleAuthUtil; +import com.google.android.gms.auth.api.Auth; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.auth.api.signin.GoogleSignInResult; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.OptionalPendingResult; +import com.google.android.gms.common.api.ResultCallback; +import com.google.android.gms.common.api.Scope; +import com.google.android.gms.common.api.Status; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.PluginRegistry; + +import java.util.HashMap; + +/** + * Google sign-in plugin for Flutter. + */ +public class GoogleSignInPlugin + implements MethodCallHandler, + PluginRegistry.ActivityResultListener, + GoogleApiClient.ConnectionCallbacks, + GoogleApiClient.OnConnectionFailedListener { + + private Activity activity; + private static final String CHANNEL = "plugins.flutter.io/google_sign_in"; + + private static final int REQUEST_CODE = 53293; + + private static final String TAG = "flutter"; + + private static final String ERROR_REASON_EXCEPTION = "exception"; + private static final String ERROR_REASON_CANCELED = "canceled"; + private static final String ERROR_REASON_OPERATION_IN_PROGRESS = "operation_in_progress"; + private static final String ERROR_REASON_CONNECTION_FAILED = "connection_failed"; + + private static final String METHOD_INIT = "init"; + private static final String METHOD_SIGN_IN_SILENTLY = "signInSilently"; + private static final String METHOD_SIGN_IN = "signIn"; + private static final String METHOD_GET_TOKENS = "getTokens"; + private static final String METHOD_SIGN_OUT = "signOut"; + private static final String METHOD_DISCONNECT = "disconnect"; + + private static final class PendingOperation { + + final String method; + final Queue resultQueue = Lists.newLinkedList(); + + PendingOperation(String method, Result result) { + this.method = Preconditions.checkNotNull(method); + resultQueue.add(Preconditions.checkNotNull(result)); + } + } + + private final BackgroundTaskRunner backgroundTaskRunner; + private final int requestCode; + + private GoogleApiClient googleApiClient; + private List requestedScopes; + private PendingOperation pendingOperation; + + public static void registerWith(PluginRegistry.Registrar registrar) { + final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL); + final GoogleSignInPlugin instance = new GoogleSignInPlugin(registrar.activity(), new BackgroundTaskRunner(1), REQUEST_CODE); + registrar.addActivityResultListener(instance); + channel.setMethodCallHandler(instance); + } + + @VisibleForTesting + private GoogleSignInPlugin( + Activity activity, + BackgroundTaskRunner backgroundTaskRunner, + int requestCode) { + this.activity = activity; + this.backgroundTaskRunner = backgroundTaskRunner; + this.requestCode = requestCode; + activity.getApplication() + .registerActivityLifecycleCallbacks(new GoogleApiClientConnectionManager()); + } + + @Override + public void onMethodCall(MethodCall call, Result result) { + @SuppressWarnings({"unchecked"}) + HashMap arguments = (HashMap) call.arguments; + switch (call.method) { + case METHOD_INIT: + @SuppressWarnings({"unchecked"}) + List scopes = (List) arguments.get("scopes"); + init(result, scopes, (String) arguments.get("hostedDomain")); + break; + + case METHOD_SIGN_IN_SILENTLY: + signInSilently(result); + break; + + case METHOD_SIGN_IN: + signIn(result); + break; + + case METHOD_GET_TOKENS: + getTokens(result, (String) arguments.get("email")); + break; + + case METHOD_SIGN_OUT: + signOut(result); + break; + + case METHOD_DISCONNECT: + disconnect(result); + break; + + default: + throw new IllegalArgumentException("Unknown method " + call.method); + } + } + + /** + * Initializes this listener so that it is ready to perform other operations. The Dart code + * guarantees that this will be called and completed before any other methods are invoked. + */ + private void init(Result result, List requestedScopes, String hostedDomain) { + try { + if (googleApiClient != null) { + // This can happen if the scopes change, or a full restart hot reload + googleApiClient = null; + } + GoogleSignInOptions.Builder optionsBuilder = + new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail(); + // Only requests a clientId if google-services.json was present and parsed + // by the google-services Gradle script. + // TODO(jackson): Perhaps we should provide a mechanism to override this + // behavior. + int clientIdIdentifier = activity.getResources().getIdentifier( + "default_web_client_id", "string", activity.getPackageName()); + if (clientIdIdentifier != 0) { + optionsBuilder.requestIdToken(activity.getString(clientIdIdentifier)); + } + for (String scope : requestedScopes) { + optionsBuilder.requestScopes(new Scope(scope)); + } + if (!Strings.isNullOrEmpty(hostedDomain)) { + optionsBuilder.setHostedDomain(hostedDomain); + } + + this.requestedScopes = requestedScopes; + this.googleApiClient = + new GoogleApiClient.Builder(activity) + .addApi(Auth.GOOGLE_SIGN_IN_API, optionsBuilder.build()) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + this.googleApiClient.connect(); + } catch (Exception e) { + Log.e(TAG, "Initialization error", e); + result.error(ERROR_REASON_EXCEPTION, e.getMessage(), null); + } + + // We're not initialized until we receive `onConnected`. + // If initialization fails, we'll receive `onConnectionFailed` + pendingOperation = new PendingOperation(METHOD_INIT, result); + } + + /** + * Handles the case of a concurrent operation already in progress. + * + *

Only one type of operation is allowed to be executed at a time, so if there's a pending + * operation for a method type other than the current invocation, this will report failure on the + * specified result object. Alternatively, if there's a pending operation for the same method + * type, this will signal that the method is already being handled and add the specified result + * to the pending operation's result queue. + * + *

If there's no pending operation, this method will set the pending operation to the current + * invocation. + * + * @param currentMethod The current invocation. + * @param result receives the result of the current invocation. + * @return true iff an operation is already in progress (and thus the response is already being + * handled). + */ + private boolean checkAndSetPendingOperation(String currentMethod, Result result) { + if (pendingOperation == null) { + pendingOperation = new PendingOperation(currentMethod, result); + return false; + } + + if (pendingOperation.method.equals(currentMethod)) { + // This method is already being handled + pendingOperation.resultQueue.add(result); + } else { + // Only one type of operation can be in progress at a time + result.error(ERROR_REASON_OPERATION_IN_PROGRESS, pendingOperation.method, null); + } + + return true; + } + + /** + * Returns the account information for the user who is signed in to this app. If no user is signed + * in, tries to sign the user in without displaying any user interface. + */ + private void signInSilently(Result result) { + if (checkAndSetPendingOperation(METHOD_SIGN_IN, result)) { + return; + } + + OptionalPendingResult pendingResult = + Auth.GoogleSignInApi.silentSignIn(googleApiClient); + if (pendingResult.isDone()) { + onSignInResult(pendingResult.get()); + } else { + pendingResult.setResultCallback( + new ResultCallback() { + @Override + public void onResult(@NonNull GoogleSignInResult signInResult) { + onSignInResult(signInResult); + } + }); + } + } + + /** + * Signs the user in via the sign-in user interface, including the OAuth consent flow if scopes + * were requested. + */ + private void signIn(Result result) { + if (checkAndSetPendingOperation(METHOD_SIGN_IN, result)) { + return; + } + + Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient); + activity.startActivityForResult(signInIntent, requestCode); + } + + /** + * Gets an OAuth access token with the scopes that were specified during {@link + * #init(Result, List, String) initialization} for the user with the specified email + * address. + */ + private void getTokens(Result result, final String email) { + if (email == null) { + result.error(ERROR_REASON_EXCEPTION, "Email is null", null); + return; + } + + if (checkAndSetPendingOperation(METHOD_GET_TOKENS, result)) { + return; + } + + Callable getTokenTask = + new Callable() { + @Override + public String call() throws Exception { + Account account = new Account(email, "com.google"); + String scopesStr = "oauth2:" + Joiner.on(' ').join(requestedScopes); + return GoogleAuthUtil.getToken(activity.getApplication(), account, scopesStr); + } + }; + + backgroundTaskRunner.runInBackground( + getTokenTask, + new BackgroundTaskRunner.Callback() { + @Override + public void run(Future tokenFuture) { + try { + String token = tokenFuture.get(); + HashMap result = new HashMap<>(); + result.put("accessToken", token); + // TODO(jackson): If we had a way to get the current user at this + // point, we could use that to obtain an up-to-date idToken here + // instead of the value we cached during sign in. At least, that's + // how it works on iOS. + finishWithSuccess(result); + } catch (ExecutionException e) { + Log.e(TAG, "Exception getting access token", e); + finishWithError(ERROR_REASON_EXCEPTION, e.getCause().getMessage()); + } catch (InterruptedException e) { + finishWithError(ERROR_REASON_EXCEPTION, e.getMessage()); + } + } + }); + } + + /** + * Signs the user out. Their credentials may remain valid, meaning they'll be able to silently + * sign back in. + */ + private void signOut(Result result) { + if (checkAndSetPendingOperation(METHOD_SIGN_OUT, result)) { + return; + } + + Auth.GoogleSignInApi.signOut(googleApiClient) + .setResultCallback( + new ResultCallback() { + @Override + public void onResult(@NonNull Status status) { + // TODO(tvolkert): communicate status back to user + finishWithSuccess(null); + } + }); + } + + /** + * Signs the user out, and revokes their credentials. + */ + private void disconnect(Result result) { + if (checkAndSetPendingOperation(METHOD_DISCONNECT, result)) { + return; + } + + Auth.GoogleSignInApi.revokeAccess(googleApiClient) + .setResultCallback( + new ResultCallback() { + @Override + public void onResult(@NonNull Status status) { + // TODO(tvolkert): communicate status back to user + finishWithSuccess(null); + } + }); + } + + /** + * Invoked when the GMS client has successfully connected to the GMS server. This signals that + * this listener is properly initialized. + */ + @Override + public void onConnected(Bundle connectionHint) { + // We can get reconnected if, e.g. the activity is paused and resumed. + if (pendingOperation != null && pendingOperation.method.equals(METHOD_INIT)) { + finishWithSuccess(null); + } + } + + /** + * Invoked when the GMS client was unable to connect to the GMS server, either because of an error + * the user was unable to resolve, or because the user canceled the resolution (e.g. cancelling a + * dialog instructing them to upgrade Google Play Services). This signals that we were unable to + * properly initialize this listener. + */ + @Override + public void onConnectionFailed(@NonNull ConnectionResult result) { + // We can attempt to reconnect if, e.g. the activity is paused and resumed. + if (pendingOperation != null && pendingOperation.method.equals(METHOD_INIT)) { + finishWithError(ERROR_REASON_CONNECTION_FAILED, result.toString()); + } + } + + @Override + public void onConnectionSuspended(int cause) { + // TODO(jackson): implement + Log.w(TAG, "The GMS server connection has been suspended (" + cause + ")"); + } + + @Override + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode != this.requestCode) { + // We're only interested in the "sign in" activity result + return false; + } + + if (pendingOperation == null || !pendingOperation.method.equals(METHOD_SIGN_IN)) { + Log.w(TAG, "Unexpected activity result; sign-in not in progress"); + return false; + } + + if (resultCode != Activity.RESULT_OK) { + finishWithError(ERROR_REASON_CANCELED, String.valueOf(resultCode)); + return true; + } + + onSignInResult(Auth.GoogleSignInApi.getSignInResultFromIntent(data)); + return true; + } + + private void onSignInResult(GoogleSignInResult result) { + if (result.isSuccess()) { + finishWithSuccess(getSignInResponse(result.getSignInAccount())); + } else { + finishWithSuccess(null); + // TODO(jackson): Communicate status about reason for failure, e.g. + // finishWithError(ERROR_REASON_STATUS, result.getStatus().toString()); + } + } + + private static HashMap getSignInResponse(GoogleSignInAccount account) { + HashMap result = new HashMap<>(); + result.put("displayName", account.getDisplayName()); + result.put("email", account.getEmail()); + result.put("id", account.getId()); + result.put("idToken", account.getIdToken()); + Uri photoUrl = account.getPhotoUrl(); + result.put("photoUrl", photoUrl != null ? photoUrl.toString() : null); + return result; + } + + private void finishWithSuccess(Object data) { + for (Result result : pendingOperation.resultQueue) { + result.success(data); + } + pendingOperation = null; + } + + private void finishWithError(String errorCode, String errorMessage) { + for (Result result : pendingOperation.resultQueue) { + result.error(errorCode, errorMessage, null); + } + pendingOperation = null; + } + + private class GoogleApiClientConnectionManager implements ActivityLifecycleCallbacks { + @Override + public void onActivityCreated(Activity activity, Bundle bundle) { + } + + @Override + public void onActivityDestroyed(Activity activity) { + } + + @Override + public void onActivityPaused(Activity activity) { + } + + @Override + public void onActivityResumed(Activity activity) { + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + } + + @Override + public void onActivityStarted(Activity activity) { + if (activity == GoogleSignInPlugin.this.activity && googleApiClient != null) { + googleApiClient.connect(); + } + } + + @Override + public void onActivityStopped(Activity activity) { + if (activity == GoogleSignInPlugin.this.activity && googleApiClient != null) { + googleApiClient.disconnect(); + } + } + } + +} diff --git a/packages/google_sign_in/example/.gitignore b/packages/google_sign_in/example/.gitignore new file mode 100755 index 000000000000..eb15c3d27cab --- /dev/null +++ b/packages/google_sign_in/example/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock +.flutter-plugins diff --git a/packages/google_sign_in/example/README.md b/packages/google_sign_in/example/README.md new file mode 100755 index 000000000000..78b7274ad37f --- /dev/null +++ b/packages/google_sign_in/example/README.md @@ -0,0 +1,8 @@ +# google_sign_in_example + +Demonstrates how to use the google_sign_in plugin. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/google_sign_in/example/android.iml b/packages/google_sign_in/example/android.iml new file mode 100755 index 000000000000..462b903e05b6 --- /dev/null +++ b/packages/google_sign_in/example/android.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/google_sign_in/example/android/.gitignore b/packages/google_sign_in/example/android/.gitignore new file mode 100755 index 000000000000..e6a9f0678cf1 --- /dev/null +++ b/packages/google_sign_in/example/android/.gitignore @@ -0,0 +1,13 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +PluginRegistry.java + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/google_sign_in/example/android/app/build.gradle b/packages/google_sign_in/example/android/app/build.gradle new file mode 100755 index 000000000000..6d9d2f106790 --- /dev/null +++ b/packages/google_sign_in/example/android/app/build.gradle @@ -0,0 +1,41 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withInputStream { stream -> + localProperties.load(stream) + } +} + +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.") +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.2' + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + applicationId "io.flutter.plugins.google_sign_in_example" + testInstrumentationRunner "android.support.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 + } + } +} + +flutter { + source '../..' +} diff --git a/packages/google_sign_in/example/android/app/google-services.json b/packages/google_sign_in/example/android/app/google-services.json new file mode 100755 index 000000000000..b2e729b93a3a --- /dev/null +++ b/packages/google_sign_in/example/android/app/google-services.json @@ -0,0 +1,204 @@ +{ + "project_info": { + "project_number": "861823949799", + "project_id": "tensile-market-126823" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:861823949799:android:ac633ff55751026b", + "android_client_info": { + "package_name": "com.google.google_sign_in.example" + } + }, + "oauth_client": [ + { + "client_id": "861823949799-b79ooadae3620tevk9fuevahrict0j83.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.google.google_sign_in.example", + "certificate_hash": "c3adef7e7773e40e777d5c236dbba7461cbea5f0" + } + }, + { + "client_id": "861823949799-ib268r6ni4s6hief8bmh78sfnr63t8ja.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBeNYObyAbBwc6EIfVwUKRihZTRSbxgS9M" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 1 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:861823949799:android:267a23c68c23f34f", + "android_client_info": { + "package_name": "com.example.flutter.google_sign_in" + } + }, + "oauth_client": [ + { + "client_id": "861823949799-jgmubfm8604lngvm9lt8fil9f4nefp5t.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.example.flutter.google_sign_in", + "certificate_hash": "8a4e194f5bfc3fb1075e7daae8dcddd526fde207" + } + }, + { + "client_id": "861823949799-ib268r6ni4s6hief8bmh78sfnr63t8ja.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBeNYObyAbBwc6EIfVwUKRihZTRSbxgS9M" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 1 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:861823949799:android:84a1951f08b82133", + "android_client_info": { + "package_name": "com.example.google_sign_in" + } + }, + "oauth_client": [ + { + "client_id": "861823949799-en18k5ut51ehp64chfifrlk52pojaqjo.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.example.google_sign_in", + "certificate_hash": "eda6413c3e3a95492114fe07cd953ad897e40d1a" + } + }, + { + "client_id": "861823949799-ib268r6ni4s6hief8bmh78sfnr63t8ja.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBeNYObyAbBwc6EIfVwUKRihZTRSbxgS9M" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 1 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:861823949799:android:27717105cac89fff", + "android_client_info": { + "package_name": "com.yourcompany.googlesignin.example" + } + }, + "oauth_client": [ + { + "client_id": "861823949799-jo91u6af10qflkh9gtk61gbu9rekeqin.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.yourcompany.googlesignin.example", + "certificate_hash": "8a4e194f5bfc3fb1075e7daae8dcddd526fde207" + } + }, + { + "client_id": "861823949799-ib268r6ni4s6hief8bmh78sfnr63t8ja.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBeNYObyAbBwc6EIfVwUKRihZTRSbxgS9M" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 1 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:861823949799:android:24b94c3718c846a6", + "android_client_info": { + "package_name": "io.flutter.plugins.google_sign_in_example" + } + }, + "oauth_client": [ + { + "client_id": "861823949799-19gil347tgrk0l0k694196i1m1uef404.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "io.flutter.plugins.google_sign_in_example", + "certificate_hash": "c3adef7e7773e40e777d5c236dbba7461cbea5f0" + } + }, + { + "client_id": "861823949799-ib268r6ni4s6hief8bmh78sfnr63t8ja.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBeNYObyAbBwc6EIfVwUKRihZTRSbxgS9M" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 1 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/packages/google_sign_in/example/android/app/src/main/AndroidManifest.xml b/packages/google_sign_in/example/android/app/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..32c085be74f8 --- /dev/null +++ b/packages/google_sign_in/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/.gitignore b/packages/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/.gitignore new file mode 100755 index 000000000000..9eb4563d2ae1 --- /dev/null +++ b/packages/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/.gitignore @@ -0,0 +1 @@ +GeneratedPluginRegistrant.java diff --git a/packages/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/google_sign_in_example/MainActivity.java b/packages/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/google_sign_in_example/MainActivity.java new file mode 100755 index 000000000000..459a06fdf837 --- /dev/null +++ b/packages/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/google_sign_in_example/MainActivity.java @@ -0,0 +1,13 @@ +package io.flutter.plugins.google_sign_in_example; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class MainActivity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/packages/google_sign_in/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/google_sign_in/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100755 index 000000000000..db77bb4b7b09 Binary files /dev/null and b/packages/google_sign_in/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/google_sign_in/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/google_sign_in/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100755 index 000000000000..17987b79bb8a Binary files /dev/null and b/packages/google_sign_in/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/google_sign_in/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/google_sign_in/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100755 index 000000000000..09d4391482be Binary files /dev/null and b/packages/google_sign_in/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/google_sign_in/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/google_sign_in/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100755 index 000000000000..d5f1c8d34e7a Binary files /dev/null and b/packages/google_sign_in/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/google_sign_in/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/google_sign_in/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100755 index 000000000000..4d6372eebdb2 Binary files /dev/null and b/packages/google_sign_in/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/google_sign_in/example/android/build.gradle b/packages/google_sign_in/example/android/build.gradle new file mode 100755 index 000000000000..3053745fdcb0 --- /dev/null +++ b/packages/google_sign_in/example/android/build.gradle @@ -0,0 +1,28 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.2.3' + } +} + +allprojects { + repositories { + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.14.1' +} diff --git a/packages/google_sign_in/example/android/gradle.properties b/packages/google_sign_in/example/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/google_sign_in/example/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/google_sign_in/example/android/settings.gradle b/packages/google_sign_in/example/android/settings.gradle new file mode 100755 index 000000000000..115da6cb4f4d --- /dev/null +++ b/packages/google_sign_in/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/example/example.iml b/packages/google_sign_in/example/example.iml new file mode 100755 index 000000000000..c4447024fe3c --- /dev/null +++ b/packages/google_sign_in/example/example.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/google_sign_in/example/google_sign_in_example.iml b/packages/google_sign_in/example/google_sign_in_example.iml new file mode 100755 index 000000000000..9d5dae19540c --- /dev/null +++ b/packages/google_sign_in/example/google_sign_in_example.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/google_sign_in/example/ios/.gitignore b/packages/google_sign_in/example/ios/.gitignore new file mode 100755 index 000000000000..3e933cc36aaa --- /dev/null +++ b/packages/google_sign_in/example/ios/.gitignore @@ -0,0 +1,44 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ +PluginRegistry.h +PluginRegistry.m + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/app.flx +/Flutter/app.zip +/Flutter/App.framework +/Flutter/Flutter.framework +/Flutter/Generated.xcconfig +/ServiceDefinitions.json + +Pods/ +Podfile.lock +/Runner/GeneratedPluginRegistrant.h +/Runner/GeneratedPluginRegistrant.m diff --git a/packages/google_sign_in/example/ios/Flutter/AppFrameworkInfo.plist b/packages/google_sign_in/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100755 index 000000000000..6c2de8086bcd --- /dev/null +++ b/packages/google_sign_in/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/example/ios/Flutter/Debug.xcconfig b/packages/google_sign_in/example/ios/Flutter/Debug.xcconfig new file mode 100755 index 000000000000..9803018ca79d --- /dev/null +++ b/packages/google_sign_in/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/example/ios/Flutter/Release.xcconfig b/packages/google_sign_in/example/ios/Flutter/Release.xcconfig new file mode 100755 index 000000000000..a4a8c604e13d --- /dev/null +++ b/packages/google_sign_in/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/example/ios/Podfile b/packages/google_sign_in/example/ios/Podfile new file mode 100755 index 000000000000..d4dc61cf4f57 --- /dev/null +++ b/packages/google_sign_in/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +if ENV['FLUTTER_FRAMEWORK_DIR'] == nil + abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework') +end + +target 'Runner' do + # use_frameworks! + + # Pods for Runner + + # Flutter Pods + pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR'] + + if File.exists? '../.flutter-plugins' + flutter_root = File.expand_path('..') + File.foreach('../.flutter-plugins') { |line| + plugin = line.split(pattern='=') + if plugin.length == 2 + name = plugin[0].strip() + path = plugin[1].strip() + resolved_path = File.expand_path("#{path}/ios", flutter_root) + pod name, :path => resolved_path + else + puts "Invalid plugin specification: #{line}" + end + } + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/packages/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100755 index 000000000000..175566ee3c9e --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,498 @@ +// !$*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 */; }; + 7ACDFB091E89442200BE2D00 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7ACDFB081E89442200BE2D00 /* App.framework */; }; + 7ACDFB0A1E89442200BE2D00 /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7ACDFB081E89442200BE2D00 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 7ACDFB0E1E8944C400BE2D00 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7ACDFB0D1E8944C400BE2D00 /* AppFrameworkInfo.plist */; }; + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; }; + 9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; }; + 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 */; }; + C16B660CC74FAEC583237BE3 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E788135933A58DA16E5983F /* libPods-Runner.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 7ACDFB0A1E89442200BE2D00 /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 2E788135933A58DA16E5983F /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 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 = ""; }; + 7ACDFB081E89442200BE2D00 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; 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 = ""; }; + 9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = ""; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; 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 = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 7ACDFB091E89442200BE2D00 /* App.framework in Frameworks */, + C16B660CC74FAEC583237BE3 /* libPods-Runner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 7ACDFB0D1E8944C400BE2D00 /* AppFrameworkInfo.plist */, + 9740EEB71CF902C7004384FC /* app.flx */, + 7ACDFB081E89442200BE2D00 /* App.framework */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 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 = ( + 2E788135933A58DA16E5983F /* 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 = 0830; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = 3GRKCVVJ22; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + 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 */, + 9740EEBB1CF902C7004384FC /* app.flx in Resources */, + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, + 7ACDFB0E1E8944C400BE2D00 /* AppFrameworkInfo.plist in Resources */, + 9740EEB41CF90195004384FC /* Debug.xcconfig 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\" thin"; + }; + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/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 = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../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"; + 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; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + 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_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + 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_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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 = { + ARCHS = arm64; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 3GRKCVVJ22; + 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 = com.yourcompany.googlesignin.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ARCHS = arm64; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 3GRKCVVJ22; + 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 = com.yourcompany.googlesignin.example; + 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/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/google_sign_in/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/google_sign_in/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/google_sign_in/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100755 index 000000000000..1c9580788197 --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_sign_in/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/google_sign_in/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/google_sign_in/example/ios/Runner/AppDelegate.h b/packages/google_sign_in/example/ios/Runner/AppDelegate.h new file mode 100755 index 000000000000..cf210d213f27 --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/packages/google_sign_in/example/ios/Runner/AppDelegate.m b/packages/google_sign_in/example/ios/Runner/AppDelegate.m new file mode 100755 index 000000000000..0e94ecd7e4e8 --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner/AppDelegate.m @@ -0,0 +1,12 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 000000000000..d22f10b2ab63 --- /dev/null +++ b/packages/google_sign_in/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100755 index 000000000000..28c6bf03016f Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100755 index 000000000000..2ccbfd967d96 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100755 index 000000000000..f091b6b0bca8 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100755 index 000000000000..4cde12118dda Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100755 index 000000000000..d0ef06e7edb8 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100755 index 000000000000..dcdc2306c285 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100755 index 000000000000..2ccbfd967d96 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100755 index 000000000000..c8f9ed8f5cee Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100755 index 000000000000..a6d6b8609df0 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100755 index 000000000000..a6d6b8609df0 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100755 index 000000000000..75b2d164a5a9 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100755 index 000000000000..c4df70d39da7 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100755 index 000000000000..6a84f41e14e2 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100755 index 000000000000..d0e1f5853602 Binary files /dev/null and b/packages/google_sign_in/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/google_sign_in/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/google_sign_in/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100755 index 000000000000..ebf48f603974 --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_sign_in/example/ios/Runner/Base.lproj/Main.storyboard b/packages/google_sign_in/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100755 index 000000000000..f3c28516fb38 --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_sign_in/example/ios/Runner/GoogleService-Info.plist b/packages/google_sign_in/example/ios/Runner/GoogleService-Info.plist new file mode 100755 index 000000000000..1fa6d38e85ad --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,28 @@ + + + + + CLIENT_ID + 861823949799-vc35cprkp249096uujjn0vvnmcvjppkn.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn + PLIST_VERSION + 1 + BUNDLE_ID + com.yourcompany.googlesignin.example + PROJECT_ID + tensile-market-126823 + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:861823949799:ios:27717105cac89fff + + \ No newline at end of file diff --git a/packages/google_sign_in/example/ios/Runner/Info.plist b/packages/google_sign_in/example/ios/Runner/Info.plist new file mode 100755 index 000000000000..a19cdf7472c9 --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner/Info.plist @@ -0,0 +1,63 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleSignInExample + CFBundlePackageType + APPL + CFBundleDisplayName + Google Sign-In Example + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + com.yourcompany.googlesignin.example + com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn + + + + 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/example/ios/Runner/main.m b/packages/google_sign_in/example/ios/Runner/main.m new file mode 100755 index 000000000000..1bdb8e28d1db --- /dev/null +++ b/packages/google_sign_in/example/ios/Runner/main.m @@ -0,0 +1,10 @@ +#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/example/lib/main.dart b/packages/google_sign_in/example/lib/main.dart new file mode 100755 index 000000000000..23a1e9d79d85 --- /dev/null +++ b/packages/google_sign_in/example/lib/main.dart @@ -0,0 +1,151 @@ +import 'dart:async'; +import 'dart:convert' show JSON; + +import "package:http/http.dart" as http; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:google_sign_in/google_sign_in.dart'; + +GoogleSignIn _googleSignIn = new GoogleSignIn( + scopes: [ + 'email', + 'https://www.googleapis.com/auth/contacts.readonly', + ], +); + +void main() { + runApp( + new MaterialApp( + title: 'Google Sign In', + home: new SignInDemo(), + ), + ); +} + +class SignInDemo extends StatefulWidget { + @override + State createState() => new 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..."; + }); + http.Response response = await http.get( + 'https://people.googleapis.com/v1/people/me/connections', + headers: await _currentUser.authHeaders, + ); + if (response.statusCode != 200) { + setState(() { + _contactText = "People API gave a ${response.statusCode} " + + "response. Check logs for details."; + }); + print('People API ${response.statusCode} response: ${response.body}'); + return; + } + Map data = JSON.decode(response.body); + String namedContact = _pickFirstNamedContact(data); + setState(() { + if (namedContact != null) { + _contactText = "I see you know $namedContact!"; + } else { + _contactText = "No contacts to display."; + } + }); + } + + String _pickFirstNamedContact(Map data) { + List> connections = data['connections']; + Map contact = connections?.firstWhere( + (Map contact) => contact['names'] != null, + orElse: () => null, + ); + if (contact != null) { + Map name = contact['names'].firstWhere( + (Map name) => name['displayName'] != null, + orElse: () => null, + ); + if (name != null) { + return name['displayName']; + } + } + return null; + } + + Future _handleSignIn() async { + try { + await _googleSignIn.signIn(); + } catch (error) { + print(error); + } + } + + Future _handleSignOut() async { + _googleSignIn.disconnect(); + } + + Widget _buildBody() { + if (_currentUser != null) { + return new Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + new ListTile( + leading: new GoogleUserCircleAvatar(_currentUser.photoUrl), + title: new Text(_currentUser.displayName), + subtitle: new Text(_currentUser.email), + ), + new Text("Signed in successfully."), + new Text(_contactText), + new RaisedButton( + child: new Text('SIGN OUT'), + onPressed: _handleSignOut, + ), + new RaisedButton( + child: new Text('REFRESH'), + onPressed: _handleGetContact, + ), + ], + ); + } else { + return new Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + new Text("You are not currently signed in."), + new RaisedButton( + child: new Text('SIGN IN'), + onPressed: _handleSignIn, + ), + ], + ); + } + } + + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text('Google Sign In'), + ), + body: new ConstrainedBox( + constraints: const BoxConstraints.expand(), + child: _buildBody(), + )); + } +} diff --git a/packages/google_sign_in/example/pubspec.yaml b/packages/google_sign_in/example/pubspec.yaml new file mode 100755 index 000000000000..950ca3437f53 --- /dev/null +++ b/packages/google_sign_in/example/pubspec.yaml @@ -0,0 +1,12 @@ +name: example +description: Example of Google Sign-In plugin. + +dependencies: + flutter: + sdk: flutter + google_sign_in: + path: ../ + http: ^0.11.3 + +flutter: + uses-material-design: true diff --git a/packages/google_sign_in/ios/.gitignore b/packages/google_sign_in/ios/.gitignore new file mode 100755 index 000000000000..956c87f3aa28 --- /dev/null +++ b/packages/google_sign_in/ios/.gitignore @@ -0,0 +1,31 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + diff --git a/packages/google_sign_in/ios/Assets/.gitkeep b/packages/google_sign_in/ios/Assets/.gitkeep new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/packages/google_sign_in/ios/Classes/GoogleSignInPlugin.h b/packages/google_sign_in/ios/Classes/GoogleSignInPlugin.h new file mode 100755 index 000000000000..bc19fd167437 --- /dev/null +++ b/packages/google_sign_in/ios/Classes/GoogleSignInPlugin.h @@ -0,0 +1,8 @@ +// Copyright 2017, the Flutter 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 + +@interface GoogleSignInPlugin : NSObject +@end diff --git a/packages/google_sign_in/ios/Classes/GoogleSignInPlugin.m b/packages/google_sign_in/ios/Classes/GoogleSignInPlugin.m new file mode 100755 index 000000000000..8d0702dc0b64 --- /dev/null +++ b/packages/google_sign_in/ios/Classes/GoogleSignInPlugin.m @@ -0,0 +1,133 @@ +// Copyright 2017, the Flutter 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 "GoogleSignInPlugin.h" +#import + +@interface NSError(FlutterError) +@property (readonly, nonatomic) FlutterError *flutterError; +@end + +@implementation NSError(FlutterError) +- (FlutterError *)flutterError { + return [FlutterError errorWithCode:[NSString stringWithFormat:@"Error %ld", (long)self.code] + message:self.domain + details:self.localizedDescription]; +} +@end + +@interface GoogleSignInPlugin () +@end + +@implementation GoogleSignInPlugin { + NSMutableArray* _accountRequests; +} + ++ (void)registerWithRegistrar:(NSObject *)registrar { + FlutterMethodChannel *channel = + [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/google_sign_in" + binaryMessenger:[registrar messenger]]; + // TODO(goderbauer): cast is workaround for https://github.com/flutter/flutter/issues/9961. + UIViewController *viewController = (UIViewController *)registrar.messenger; + GoogleSignInPlugin *instance = [[GoogleSignInPlugin alloc] initWithViewController: viewController]; + [registrar addApplicationDelegate:instance]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (instancetype)initWithViewController:(UIViewController *)viewController { + self = [super init]; + if (self) { + _accountRequests = [[NSMutableArray alloc] init]; + [GIDSignIn sharedInstance].delegate = self; + [GIDSignIn sharedInstance].uiDelegate = (id)viewController; + } + return self; +} + +- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { + if ([call.method isEqualToString:@"init"]) { + NSError *error; + [[GGLContext sharedInstance] configureWithError:&error]; + [GIDSignIn sharedInstance].scopes = call.arguments[@"scopes"]; + [GIDSignIn sharedInstance].hostedDomain = call.arguments[@"hostedDomain"]; + result(error.flutterError); + } else if ([call.method isEqualToString:@"signInSilently"]) { + [_accountRequests insertObject:result atIndex:0]; + [[GIDSignIn sharedInstance] signInSilently]; + } else if ([call.method isEqualToString:@"signIn"]) { + [_accountRequests insertObject:result atIndex:0]; + [[GIDSignIn sharedInstance] signIn]; + } else if ([call.method isEqualToString:@"getTokens"]) { + GIDGoogleUser *currentUser = [GIDSignIn sharedInstance].currentUser; + GIDAuthentication *auth = currentUser.authentication; + [auth getTokensWithHandler:^void(GIDAuthentication* authentication, + NSError* error) { + result(error != nil ? error.flutterError : @{ + @"idToken": authentication.idToken, + @"accessToken": authentication.accessToken, + }); + }]; + } else if ([call.method isEqualToString:@"signOut"]) { + [[GIDSignIn sharedInstance] signOut]; + result(nil); + } else if ([call.method isEqualToString:@"disconnect"]) { + [_accountRequests insertObject:result atIndex:0]; + [[GIDSignIn sharedInstance] disconnect]; + } else { + result(FlutterMethodNotImplemented); + } +} + +- (BOOL)application:(UIApplication*)application + openURL:(NSURL*)url + sourceApplication:(NSString*)sourceApplication + annotation:(id)annotation { + return [[GIDSignIn sharedInstance] handleURL:url + sourceApplication:sourceApplication + annotation:annotation]; +} + +- (void)signIn:(GIDSignIn*)signIn +didSignInForUser:(GIDGoogleUser*)user + withError:(NSError*)error { + if (error != nil) { + if (error.code == -4) { + // Occurs when silent sign-in is not possible, return an empty user in this case + [self respondWithAccount:nil error:nil]; + } else { + [self respondWithAccount:nil error:error]; + } + } else { + NSURL* photoUrl; + if (user.profile.hasImage) { + // Placeholder that will be replaced by on the Dart side based on screen size + photoUrl = [user.profile imageURLWithDimension:1337]; + } + [self respondWithAccount:@{ + @"displayName" : user.profile.name ?: [NSNull null], + @"email" : user.profile.email ?: [NSNull null], + @"id" : user.userID ?: [NSNull null], + @"photoUrl" : [photoUrl absoluteString] ?: [NSNull null], + } + error:nil]; + } +} + +- (void)signIn:(GIDSignIn *)signIn +didDisconnectWithUser:(GIDGoogleUser *)user + withError:(NSError *)error { + [self respondWithAccount:@{} error:nil]; +} + +- (void)respondWithAccount:(id)account + error:(NSError *)error +{ + NSArray *requests = _accountRequests; + _accountRequests = [[NSMutableArray alloc] init]; + for (FlutterResult accountRequest in requests) { + accountRequest(error != nil ? error.flutterError : account); + } +} + +@end diff --git a/packages/google_sign_in/ios/google_sign_in.podspec b/packages/google_sign_in/ios/google_sign_in.podspec new file mode 100755 index 000000000000..3fcdb3913aaf --- /dev/null +++ b/packages/google_sign_in/ios/google_sign_in.podspec @@ -0,0 +1,19 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'google_sign_in' + s.version = '0.0.1' + s.summary = 'Google Sign-In plugin for Flutter' + s.description = <<-DESC +Enables Google Sign-In in Flutter apps. + DESC + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/google_sign_in' + 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.dependency 'Google/SignIn', '~> 3.0' +end diff --git a/packages/google_sign_in/lib/google_sign_in.dart b/packages/google_sign_in/lib/google_sign_in.dart new file mode 100755 index 000000000000..94cec79986af --- /dev/null +++ b/packages/google_sign_in/lib/google_sign_in.dart @@ -0,0 +1,192 @@ +// Copyright 2017, the Flutter 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 'package:flutter/services.dart' show MethodChannel; +import 'package:flutter/material.dart'; +import 'package:meta/meta.dart'; + +class GoogleSignInAuthentication { + final Map _data; + GoogleSignInAuthentication._(this._data); + + /// An OpenID Connect ID token that identifies the user. + String get idToken => _data['idToken']; + + /// The OAuth2 access token to access Google services. + String get accessToken => _data['accessToken']; + + @override + String toString() => 'GoogleSignInAuthentication:$_data'; +} + +class GoogleSignInAccount { + final String displayName; + final String email; + final String id; + final String photoUrl; + final String _idToken; + final GoogleSignIn _googleSignIn; + + GoogleSignInAccount._(this._googleSignIn, Map data) + : displayName = data['displayName'], + email = data['email'], + id = data['id'], + photoUrl = data['photoUrl'], + _idToken = data['idToken'] { + assert(displayName != null); + assert(id != null); + } + + + Future get authentication async { + if (_googleSignIn.currentUser != this) { + throw new StateError('User is no longer signed in.'); + } + + Map response = await _googleSignIn._channel.invokeMethod( + 'getTokens', + {'email': email}, + ); + // On Android, there isn't an API for refreshing the idToken, so re-use + // the one we obtained on login. + if (response['idToken'] == null) + response['idToken'] = _idToken; + return new GoogleSignInAuthentication._(response); + } + + Future> get authHeaders async { + String token = (await authentication).accessToken; + return { + "Authorization": "Bearer $token", + "X-Goog-AuthUser": "0", + }; + } + + @override + String toString() { + Map data = { + 'displayName': displayName, + 'email': email, + 'id': id, + 'photoUrl': photoUrl, + }; + return 'GoogleSignInAccount:$data'; + } +} + +/// GoogleSignIn allows you to authenticate Google users. +class GoogleSignIn { + final MethodChannel _channel; + + /// The list of [scopes] are OAuth scope codes requested when signing in. + final List scopes; + + /// Domain to restrict sign-in to. + final String hostedDomain; + + /// Initializes global sign-in configuration settings. + /// + /// The list of [scopes] are OAuth scope codes to request when signing in. + /// These scope codes will determine the level of data access that is granted + /// to your application by the user. + /// + /// The [hostedDomain] argument specifies a hosted domain restriction. By + /// setting this, sign in will be restricted to accounts of the user in the + /// specified domain. By default, the list of accounts will not be restricted. + GoogleSignIn({ this.scopes, this.hostedDomain }) + : _channel = const MethodChannel('plugins.flutter.io/google_sign_in'); + + @visibleForTesting + GoogleSignIn.private({ this.scopes, this.hostedDomain, MethodChannel channel }) + : _channel = channel; + + StreamController _streamController = + new StreamController.broadcast(); + + /// Subscribe to this stream to be notified when the current user changes + Stream get onCurrentUserChanged => + _streamController.stream; + + // Future that completes when we've finished calling init on the native side + Future _initialization; + + Future _callMethod(String method) async { + if (_initialization == null) { + _initialization = _channel.invokeMethod( + "init", + { + 'scopes': scopes ?? [], + 'hostedDomain': hostedDomain, + }, + ); + } + await _initialization; + Map response = await _channel.invokeMethod(method); + _currentUser = response != null ? new GoogleSignInAccount._(this, response) : null; + _streamController.add(_currentUser); + return _currentUser; + } + + /// The currently signed in account, or null if the user is signed out + GoogleSignInAccount _currentUser; + GoogleSignInAccount get currentUser => _currentUser; + + /// Attempts to sign in a previously authenticated user without interaction. + Future signInSilently() => _callMethod('signInSilently'); + + /// Starts the sign-in process. + Future signIn() => _callMethod('signIn'); + + /// Marks current user as being in the signed out state. + Future signOut() => _callMethod('signOut'); + + /// Disconnects the current user from the app and revokes previous + /// authentication. + Future disconnect() => _callMethod('disconnect'); +} + +/// Builds a CircleAvatar profile image of the appropriate resolution +class GoogleUserCircleAvatar extends StatelessWidget { + const GoogleUserCircleAvatar(this._primaryProfileImageUrl); + final String _primaryProfileImageUrl; + + Widget build(BuildContext context) { + return new CircleAvatar( + child: new LayoutBuilder(builder: _buildClippedImage), + ); + } + + /// Adds sizing information to the URL, inserted as the last + /// directory before the image filename. The format is "/sNN-c/", + /// where NN is the max width/height of the image, and "c" indicates we + /// want the image cropped. + String _sizedProfileImageUrl(double size) { + if (_primaryProfileImageUrl == null) return null; + Uri profileUri = Uri.parse(_primaryProfileImageUrl); + List pathSegments = new List.from(profileUri.pathSegments); + pathSegments.remove("s1337"); // placeholder value added by iOS plugin + return new Uri( + scheme: profileUri.scheme, + host: profileUri.host, + pathSegments: pathSegments, + query: "sz=${size.round()}", + ).toString(); + } + + Widget _buildClippedImage(BuildContext context, BoxConstraints constraints) { + assert(constraints.maxWidth == constraints.maxHeight); + String url = _sizedProfileImageUrl( + MediaQuery.of(context).devicePixelRatio * constraints.maxWidth, + ); + if (url == null) + return new Container(); + return new ClipOval( + child: new Image( + image: new NetworkImage(url), + ), + ); + } +} diff --git a/packages/google_sign_in/pubspec.yaml b/packages/google_sign_in/pubspec.yaml new file mode 100755 index 000000000000..af8d12d45b02 --- /dev/null +++ b/packages/google_sign_in/pubspec.yaml @@ -0,0 +1,16 @@ +name: google_sign_in +description: Google Sign-In plugin for Flutter. + +flutter: + plugin: + androidPackage: io.flutter.plugins.googlesignin + pluginClass: GoogleSignInPlugin + +dependencies: + flutter: + sdk: flutter + meta: ^1.0.4 + +dev_dependencies: + mockito: ^2.0.2 + test: ^0.12.20 diff --git a/packages/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/test/google_sign_in_test.dart new file mode 100755 index 000000000000..ba04dc416786 --- /dev/null +++ b/packages/google_sign_in/test/google_sign_in_test.dart @@ -0,0 +1,55 @@ +// 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 'dart:async'; + +import 'package:mockito/mockito.dart'; +import 'package:test/test.dart'; + +import 'package:flutter/services.dart'; + +import 'package:google_sign_in/google_sign_in.dart'; + +void main() { + group('$GoogleSignIn', () { + GoogleSignIn googleSignIn; + + List invokedMethods = []; + + setUp(() { + MockPlatformChannel mockChannel = new MockPlatformChannel(); + + invokedMethods = []; + + when(mockChannel.invokeMethod(any, any)).thenAnswer((Invocation invocation) { + invokedMethods.add(invocation.positionalArguments[0]); + return new Future.value(null); + }); + + googleSignIn = new GoogleSignIn.private(channel: mockChannel); + }); + + test('signInSilently', () async { + await googleSignIn.signIn(); + expect(invokedMethods, ['init', 'signInSilently']); + }); + + test('setUserId', () async { + await googleSignIn.signIn(); + expect(invokedMethods, ['init', 'signIn']); + }); + + test('signOut', () async { + await googleSignIn.signIn(); + expect(invokedMethods, ['init', 'signOut']); + }); + + test('disconnect', () async { + await googleSignIn.signIn(); + expect(invokedMethods, ['init', 'disconnect']); + }); + }); +} + +class MockPlatformChannel extends Mock implements MethodChannel { } diff --git a/packages/image_picker/.gitignore b/packages/image_picker/.gitignore new file mode 100755 index 000000000000..14c7d4c3f73e --- /dev/null +++ b/packages/image_picker/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/.generated/ +packages +pubspec.lock diff --git a/packages/image_picker/LICENSE b/packages/image_picker/LICENSE new file mode 100755 index 000000000000..282a0f51aa4a --- /dev/null +++ b/packages/image_picker/LICENSE @@ -0,0 +1,26 @@ +Copyright 2017, 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/image_picker/README.md b/packages/image_picker/README.md new file mode 100755 index 000000000000..d6b8d1adb316 --- /dev/null +++ b/packages/image_picker/README.md @@ -0,0 +1,8 @@ +A Flutter wrapper for the native image picker. + +Note: This is a work-in-progress, and is not fully supported by the Flutter team. + +## 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/image_picker/android/.gitignore b/packages/image_picker/android/.gitignore new file mode 100755 index 000000000000..5c4ef82869b5 --- /dev/null +++ b/packages/image_picker/android/.gitignore @@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/image_picker/android/build.gradle b/packages/image_picker/android/build.gradle new file mode 100755 index 000000000000..418c4472df37 --- /dev/null +++ b/packages/image_picker/android/build.gradle @@ -0,0 +1,40 @@ +group 'com.yourcompany.image_picker' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.0' + } +} + +allprojects { + repositories { + jcenter() + maven { url "https://jitpack.io" } + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.0' + + defaultConfig { + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + lintOptions { + disable 'InvalidPackage' + } +} + +dependencies { + compile 'com.github.bumptech.glide:glide:3.7.0' + compile 'com.github.esafirm.android-image-picker:imagepicker:1.3.4@aar' + compile 'com.android.support:appcompat-v7:25.0.1' + compile 'com.android.support:recyclerview-v7:25.0.1' +} diff --git a/packages/image_picker/android/gradle.properties b/packages/image_picker/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/image_picker/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/image_picker/android/settings.gradle b/packages/image_picker/android/settings.gradle new file mode 100755 index 000000000000..5b9496172108 --- /dev/null +++ b/packages/image_picker/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'imagepicker' diff --git a/packages/image_picker/android/src/main/AndroidManifest.xml b/packages/image_picker/android/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..42708dad6f17 --- /dev/null +++ b/packages/image_picker/android/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java b/packages/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java new file mode 100755 index 000000000000..b90ce8068c49 --- /dev/null +++ b/packages/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java @@ -0,0 +1,97 @@ +package io.flutter.plugins.imagepicker; + +import android.app.Activity; +import android.content.Intent; +import io.flutter.plugin.common.PluginRegistry; +import io.flutter.plugin.common.PluginRegistry.ActivityResultListener; +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.MethodCall; +import com.esafirm.imagepicker.features.ImagePicker; +import com.esafirm.imagepicker.features.camera.DefaultCameraModule; +import com.esafirm.imagepicker.features.camera.OnImageReadyListener; +import com.esafirm.imagepicker.model.Image; +import java.util.ArrayList; +import java.util.List; + +/** + * Location Plugin + */ +public class ImagePickerPlugin implements MethodCallHandler, ActivityResultListener { + private static String TAG = "flutter"; + private static final String CHANNEL = "image_picker"; + + public static final int REQUEST_CODE_PICK = 2342; + public static final int REQUEST_CODE_CAMERA = 2343; + + private Activity activity; + + private static final DefaultCameraModule cameraModule = new DefaultCameraModule(); + + // Pending method call to obtain an image + private Result pendingResult; + + public static void registerWith(PluginRegistry.Registrar registrar) { + final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL); + final ImagePickerPlugin instance = new ImagePickerPlugin(registrar.activity()); + registrar.addActivityResultListener(instance); + channel.setMethodCallHandler(instance); + } + + private ImagePickerPlugin(Activity activity) { + this.activity = activity; + } + + @Override + public void onMethodCall(MethodCall call, Result result) { + if (pendingResult != null) { + result.error("ALREADY_ACTIVE", "Image picker is already active", null); + return; + } + pendingResult = result; + if (call.method.equals("pickImage")) { + ImagePicker.create(activity) + .single() + .start(REQUEST_CODE_PICK); + } else if (call.method.equals("captureImage")) { + activity.startActivityForResult(cameraModule.getCameraIntent(activity), REQUEST_CODE_CAMERA); + } else { + throw new IllegalArgumentException("Unknown method " + call.method); + } + } + + @Override + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_PICK) { + if (resultCode == Activity.RESULT_OK && data != null) { + ArrayList images = (ArrayList) ImagePicker.getImages(data); + handleResult(images.get(0)); + } else { + pendingResult.error("PICK_ERROR", "Error picking image", null); + pendingResult = null; + } + return true; + } + if (requestCode == REQUEST_CODE_CAMERA) { + if (resultCode == Activity.RESULT_OK && data != null) + cameraModule.getImage(activity, data, new OnImageReadyListener() { + @Override + public void onImageReady(List images) { + handleResult(images.get(0)); + } + }); + return true; + } + return false; + } + + private void handleResult(Image image) { + if (pendingResult != null) { + pendingResult.success(image.getPath()); + pendingResult = null; + } else { + throw new IllegalStateException("Received images from picker that were not requested"); + } + } +} diff --git a/packages/image_picker/example/.gitignore b/packages/image_picker/example/.gitignore new file mode 100755 index 000000000000..25b918079d1a --- /dev/null +++ b/packages/image_picker/example/.gitignore @@ -0,0 +1,12 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +build/ +ios/Pods +ios/Podfile.lock +ios/.generated/ +packages +pubspec.lock +.flutter-plugins diff --git a/packages/image_picker/example/README.md b/packages/image_picker/example/README.md new file mode 100755 index 000000000000..4a33db1ce92d --- /dev/null +++ b/packages/image_picker/example/README.md @@ -0,0 +1,8 @@ +# image_picker_example + +Demonstrates how to use the image_picker plugin. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). diff --git a/packages/image_picker/example/android.iml b/packages/image_picker/example/android.iml new file mode 100755 index 000000000000..462b903e05b6 --- /dev/null +++ b/packages/image_picker/example/android.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/image_picker/example/android/.gitignore b/packages/image_picker/example/android/.gitignore new file mode 100755 index 000000000000..5c4ef82869b5 --- /dev/null +++ b/packages/image_picker/example/android/.gitignore @@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures + +/gradle +/gradlew +/gradlew.bat diff --git a/packages/image_picker/example/android/app/build.gradle b/packages/image_picker/example/android/app/build.gradle new file mode 100755 index 000000000000..60585c69ae9a --- /dev/null +++ b/packages/image_picker/example/android/app/build.gradle @@ -0,0 +1,47 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withInputStream { stream -> + localProperties.load(stream) + } +} + +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.") +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 25 + buildToolsVersion '25.0.2' + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + applicationId "io.flutter.plugins.image_picker.example" + testInstrumentationRunner "android.support.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 + } + } +} + +flutter { + source '../..' +} + +dependencies { + androidTestCompile 'com.android.support:support-annotations:25.0.0' + androidTestCompile 'com.android.support.test:runner:0.5' + androidTestCompile 'com.android.support.test:rules:0.5' +} diff --git a/packages/image_picker/example/android/app/src/main/AndroidManifest.xml b/packages/image_picker/example/android/app/src/main/AndroidManifest.xml new file mode 100755 index 000000000000..5a2aa384f4dc --- /dev/null +++ b/packages/image_picker/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/image_picker/example/android/app/src/main/java/io/flutter/plugins/.gitignore b/packages/image_picker/example/android/app/src/main/java/io/flutter/plugins/.gitignore new file mode 100755 index 000000000000..9eb4563d2ae1 --- /dev/null +++ b/packages/image_picker/example/android/app/src/main/java/io/flutter/plugins/.gitignore @@ -0,0 +1 @@ +GeneratedPluginRegistrant.java diff --git a/packages/image_picker/example/android/app/src/main/java/io/flutter/plugins/image_picker_example/MainActivity.java b/packages/image_picker/example/android/app/src/main/java/io/flutter/plugins/image_picker_example/MainActivity.java new file mode 100755 index 000000000000..c61ef1705593 --- /dev/null +++ b/packages/image_picker/example/android/app/src/main/java/io/flutter/plugins/image_picker_example/MainActivity.java @@ -0,0 +1,14 @@ +package io.flutter.plugins.image_picker_example; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class MainActivity extends FlutterActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/packages/image_picker/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/image_picker/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100755 index 000000000000..db77bb4b7b09 Binary files /dev/null and b/packages/image_picker/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/image_picker/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/image_picker/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100755 index 000000000000..17987b79bb8a Binary files /dev/null and b/packages/image_picker/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/image_picker/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/image_picker/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100755 index 000000000000..09d4391482be Binary files /dev/null and b/packages/image_picker/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/image_picker/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/image_picker/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100755 index 000000000000..d5f1c8d34e7a Binary files /dev/null and b/packages/image_picker/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/image_picker/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/image_picker/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100755 index 000000000000..4d6372eebdb2 Binary files /dev/null and b/packages/image_picker/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/image_picker/example/android/build.gradle b/packages/image_picker/example/android/build.gradle new file mode 100755 index 000000000000..ac9f2fee5bcd --- /dev/null +++ b/packages/image_picker/example/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.2.3' + } +} + +allprojects { + repositories { + jcenter() + maven { url "https://jitpack.io" } + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.14.1' +} diff --git a/packages/image_picker/example/android/gradle.properties b/packages/image_picker/example/android/gradle.properties new file mode 100755 index 000000000000..8bd86f680510 --- /dev/null +++ b/packages/image_picker/example/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/packages/image_picker/example/android/settings.gradle b/packages/image_picker/example/android/settings.gradle new file mode 100755 index 000000000000..115da6cb4f4d --- /dev/null +++ b/packages/image_picker/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/image_picker/example/image_picker_example.iml b/packages/image_picker/example/image_picker_example.iml new file mode 100755 index 000000000000..1ae40a0f7f54 --- /dev/null +++ b/packages/image_picker/example/image_picker_example.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/image_picker/example/ios/.gitignore b/packages/image_picker/example/ios/.gitignore new file mode 100755 index 000000000000..ffef8dafa738 --- /dev/null +++ b/packages/image_picker/example/ios/.gitignore @@ -0,0 +1,40 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +Pods/ +/Flutter/app.flx +/Flutter/app.zip +/Flutter/App.framework +/Flutter/Flutter.framework +/Flutter/Generated.xcconfig +/ServiceDefinitions.json + +Podfile.lock diff --git a/packages/image_picker/example/ios/Flutter/AppFrameworkInfo.plist b/packages/image_picker/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100755 index 000000000000..6c2de8086bcd --- /dev/null +++ b/packages/image_picker/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/image_picker/example/ios/Flutter/Debug.xcconfig b/packages/image_picker/example/ios/Flutter/Debug.xcconfig new file mode 100755 index 000000000000..9803018ca79d --- /dev/null +++ b/packages/image_picker/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/image_picker/example/ios/Flutter/Release.xcconfig b/packages/image_picker/example/ios/Flutter/Release.xcconfig new file mode 100755 index 000000000000..a4a8c604e13d --- /dev/null +++ b/packages/image_picker/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/image_picker/example/ios/Podfile b/packages/image_picker/example/ios/Podfile new file mode 100755 index 000000000000..74b3de064932 --- /dev/null +++ b/packages/image_picker/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +if ENV['FLUTTER_FRAMEWORK_DIR'] == nil + abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework') +end + +target 'Runner' do + use_frameworks! + + # Pods for Runner + + # Flutter Pods + pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR'] + + if File.exists? '../.flutter-plugins' + flutter_root = File.expand_path('..') + File.foreach('../.flutter-plugins') { |line| + plugin = line.split(pattern='=') + if plugin.length == 2 + name = plugin[0].strip() + path = plugin[1].strip() + resolved_path = File.expand_path("#{path}/ios", flutter_root) + pod name, :path => resolved_path + else + puts "Invalid plugin specification: #{line}" + end + } + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/packages/image_picker/example/ios/Runner.xcodeproj/project.pbxproj b/packages/image_picker/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100755 index 000000000000..846b061a60be --- /dev/null +++ b/packages/image_picker/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,494 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 3E15FEC43344A77097B00440 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01A6711EF19E90303F1F55DC /* Pods_Runner.framework */; }; + 5C9513011EC38BD300040975 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C9513001EC38BD300040975 /* GeneratedPluginRegistrant.m */; }; + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; }; + 9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; }; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 01A6711EF19E90303F1F55DC /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 5C9512FF1EC38BD300040975 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 5C9513001EC38BD300040975 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; 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 = ""; }; + 9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = ""; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; 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 = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + 3E15FEC43344A77097B00440 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 9740EEB71CF902C7004384FC /* app.flx */, + 3B80C3931E831B6300D905FE /* App.framework */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 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 = ( + 5C9512FF1EC38BD300040975 /* GeneratedPluginRegistrant.h */, + 5C9513001EC38BD300040975 /* GeneratedPluginRegistrant.m */, + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 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 = ( + 01A6711EF19E90303F1F55DC /* Pods_Runner.framework */, + ); + 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 = 0830; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = 3GRKCVVJ22; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + 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 = ( + 9740EEBB1CF902C7004384FC /* app.flx in Resources */, + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 9740EEB41CF90195004384FC /* Debug.xcconfig 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\" thin"; + }; + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/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 = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../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"; + 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 */, + 5C9513011EC38BD300040975 /* 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; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + 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_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + 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_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_OBJC_ROOT_CLASS = YES_ERROR; + 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 = { + ARCHS = arm64; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 3GRKCVVJ22; + 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 = com.yourcompany.imagePickerExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ARCHS = arm64; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 3GRKCVVJ22; + 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 = com.yourcompany.imagePickerExample; + 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/image_picker/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/image_picker/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/image_picker/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100755 index 000000000000..1c9580788197 --- /dev/null +++ b/packages/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/image_picker/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/image_picker/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100755 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/image_picker/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/image_picker/example/ios/Runner/.gitignore b/packages/image_picker/example/ios/Runner/.gitignore new file mode 100755 index 000000000000..0cab08d0bdd7 --- /dev/null +++ b/packages/image_picker/example/ios/Runner/.gitignore @@ -0,0 +1,2 @@ +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m diff --git a/packages/image_picker/example/ios/Runner/AppDelegate.h b/packages/image_picker/example/ios/Runner/AppDelegate.h new file mode 100755 index 000000000000..cf210d213f27 --- /dev/null +++ b/packages/image_picker/example/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/packages/image_picker/example/ios/Runner/AppDelegate.m b/packages/image_picker/example/ios/Runner/AppDelegate.m new file mode 100755 index 000000000000..ce9c30f9f812 --- /dev/null +++ b/packages/image_picker/example/ios/Runner/AppDelegate.m @@ -0,0 +1,12 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application +didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 000000000000..d22f10b2ab63 --- /dev/null +++ b/packages/image_picker/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/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100755 index 000000000000..28c6bf03016f Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100755 index 000000000000..2ccbfd967d96 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100755 index 000000000000..f091b6b0bca8 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100755 index 000000000000..4cde12118dda Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100755 index 000000000000..d0ef06e7edb8 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100755 index 000000000000..dcdc2306c285 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100755 index 000000000000..2ccbfd967d96 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100755 index 000000000000..c8f9ed8f5cee Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100755 index 000000000000..a6d6b8609df0 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100755 index 000000000000..a6d6b8609df0 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100755 index 000000000000..75b2d164a5a9 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100755 index 000000000000..c4df70d39da7 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100755 index 000000000000..6a84f41e14e2 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100755 index 000000000000..d0e1f5853602 Binary files /dev/null and b/packages/image_picker/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/image_picker/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/image_picker/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100755 index 000000000000..ebf48f603974 --- /dev/null +++ b/packages/image_picker/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/image_picker/example/ios/Runner/Base.lproj/Main.storyboard b/packages/image_picker/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100755 index 000000000000..f3c28516fb38 --- /dev/null +++ b/packages/image_picker/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/image_picker/example/ios/Runner/Info.plist b/packages/image_picker/example/ios/Runner/Info.plist new file mode 100755 index 000000000000..780303c86d1c --- /dev/null +++ b/packages/image_picker/example/ios/Runner/Info.plist @@ -0,0 +1,53 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + image_picker_example + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + NSCameraUsageDescription + Used to demonstrate image picker plugin + NSPhotoLibraryUsageDescription + Used to demonstrate image picker plugin + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/image_picker/example/ios/Runner/main.m b/packages/image_picker/example/ios/Runner/main.m new file mode 100755 index 000000000000..1bdb8e28d1db --- /dev/null +++ b/packages/image_picker/example/ios/Runner/main.m @@ -0,0 +1,10 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, + NSStringFromClass([AppDelegate class])); + } +} diff --git a/packages/image_picker/example/lib/main.dart b/packages/image_picker/example/lib/main.dart new file mode 100755 index 000000000000..16592644b9c5 --- /dev/null +++ b/packages/image_picker/example/lib/main.dart @@ -0,0 +1,64 @@ +import 'dart:io'; +import 'dart:async'; +import 'dart:math'; + +import 'package:flutter/services.dart'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; + +void main() { + runApp(new MyApp()); +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'Image Picker Demo', + home: new MyHomePage(title: 'Image Picker Example'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => new _MyHomePageState(); +} + +class _MyHomePageState extends State { + Future _imageFile; + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text('Image Picker Example'), + ), + body: new Center( + child: new FutureBuilder( + future: _imageFile, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + return new Image.file(snapshot.data); + } else { + return new Text('You have not yet picked an image.'); + } + } + ) + ), + floatingActionButton: new FloatingActionButton( + onPressed: () { + setState(() { + _imageFile = ImagePicker.pickImage(); + }); + }, + tooltip: 'Pick Image', + child: new Icon(Icons.add_a_photo), + ), + ); + } +} diff --git a/packages/image_picker/example/pubspec.yaml b/packages/image_picker/example/pubspec.yaml new file mode 100755 index 000000000000..919751f68148 --- /dev/null +++ b/packages/image_picker/example/pubspec.yaml @@ -0,0 +1,42 @@ +name: image_picker_example +description: Demonstrates how to use the image_picker plugin. + +dependencies: + flutter: + sdk: flutter + image_picker: + path: ../ + +# For information on the generic Dart part of this file, see the +# following page: https://www.dartlang.org/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section here, in + # this "flutter" section, as in: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 diff --git a/packages/image_picker/ios/.gitignore b/packages/image_picker/ios/.gitignore new file mode 100755 index 000000000000..956c87f3aa28 --- /dev/null +++ b/packages/image_picker/ios/.gitignore @@ -0,0 +1,31 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + diff --git a/packages/image_picker/ios/Assets/.gitkeep b/packages/image_picker/ios/Assets/.gitkeep new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/packages/image_picker/ios/Classes/ImagePickerPlugin.h b/packages/image_picker/ios/Classes/ImagePickerPlugin.h new file mode 100755 index 000000000000..9878e2f5e1bc --- /dev/null +++ b/packages/image_picker/ios/Classes/ImagePickerPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface ImagePickerPlugin : NSObject +@end diff --git a/packages/image_picker/ios/Classes/ImagePickerPlugin.m b/packages/image_picker/ios/Classes/ImagePickerPlugin.m new file mode 100755 index 000000000000..465b3d391488 --- /dev/null +++ b/packages/image_picker/ios/Classes/ImagePickerPlugin.m @@ -0,0 +1,129 @@ +@import UIKit; + +#import "ImagePickerPlugin.h" + +@interface ImagePickerPlugin () +@end + +@implementation ImagePickerPlugin { + FlutterResult _result; + UIImagePickerController *_imagePickerController; + UIViewController* _viewController; +} + ++ (void)registerWithRegistrar:(NSObject *)registrar { + FlutterMethodChannel *channel = + [FlutterMethodChannel methodChannelWithName:@"image_picker" + binaryMessenger:[registrar messenger]]; + // TODO(goderbauer): cast is workaround for https://github.com/flutter/flutter/issues/9961. + UIViewController *viewController = (UIViewController *)registrar.messenger; + ImagePickerPlugin *instance = [[ImagePickerPlugin alloc] initWithViewController:viewController]; + [registrar addMethodCallDelegate:instance channel:channel]; +} + +- (instancetype)initWithViewController:(UIViewController *)viewController { + self = [super init]; + if (self) { + _viewController = viewController; + _imagePickerController = [[UIImagePickerController alloc] init]; + } + return self; +} + +- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { + if (_result) { + + _result([FlutterError errorWithCode:@"multiple_request" + message:@"Cancelled by a second request" + details:nil]); + _result = nil; + } + if ([@"pickImage" isEqualToString:call.method]) { + _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; + _imagePickerController.delegate = self; + _result = result; + + UIAlertController *alert = + [UIAlertController alertControllerWithTitle:nil + message:nil + preferredStyle:UIAlertControllerStyleActionSheet]; + UIAlertAction *camera = + [UIAlertAction actionWithTitle:@"Take Photo" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) { + _imagePickerController.sourceType = + UIImagePickerControllerSourceTypeCamera; + [_viewController presentViewController:_imagePickerController + animated:YES + completion:nil]; + }]; + UIAlertAction *library = + [UIAlertAction actionWithTitle:@"Choose Photo" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) { + _imagePickerController.sourceType = + UIImagePickerControllerSourceTypePhotoLibrary; + [_viewController presentViewController:_imagePickerController + animated:YES + completion:nil]; + }]; + UIAlertAction *cancel = + [UIAlertAction actionWithTitle:@"Cancel" + style:UIAlertActionStyleCancel + handler:nil]; + [alert addAction:camera]; + [alert addAction:library]; + [alert addAction:cancel]; + [_viewController presentViewController:alert animated:YES completion:nil]; + } else { + result(FlutterMethodNotImplemented); + } +} + +- (void)imagePickerController:(UIImagePickerController *)picker + didFinishPickingMediaWithInfo:(NSDictionary *)info { + [_imagePickerController dismissViewControllerAnimated:YES completion:nil]; + UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage]; + if (image == nil) { + image = [info objectForKey:UIImagePickerControllerOriginalImage]; + } + if (image == nil) { + image = [info objectForKey:UIImagePickerControllerCropRect]; + } + image = [self normalizedImage: image]; + NSData *data = UIImageJPEGRepresentation(image, 1.0); + NSString *tmpDirectory = NSTemporaryDirectory(); + NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString]; + // TODO(jackson): Using the cache directory might be better than temporary + // directory. + NSString *tmpFile = [NSString stringWithFormat:@"image_picker_%@.jpg", guid]; + NSString *tmpPath = [tmpDirectory stringByAppendingPathComponent:tmpFile]; + if ([[NSFileManager defaultManager] createFileAtPath:tmpPath + contents:data + attributes:nil]) { + _result(tmpPath); + } else { + _result([FlutterError errorWithCode:@"create_error" + message:@"Temporary file could not be created" + details:nil]); + } + _result = nil; +} + +// The way we save images to the tmp dir currently throws away all EXIF data +// (including the orientation of the image). That means, pics taken in portrait +// will not be orientated correctly as is. To avoid that, we rotate the actual +// image data. +// TODO(goderbauer): investigate how to preserve EXIF data. +- (UIImage *)normalizedImage: (UIImage *)image { + if (image.imageOrientation == UIImageOrientationUp) return image; + + UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale); + [image drawInRect:(CGRect){0, 0, image.size}]; + UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return normalizedImage; +} + +@end diff --git a/packages/image_picker/ios/image_picker.podspec b/packages/image_picker/ios/image_picker.podspec new file mode 100755 index 000000000000..1a0f2d4c8024 --- /dev/null +++ b/packages/image_picker/ios/image_picker.podspec @@ -0,0 +1,18 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'image_picker' + s.version = '0.0.1' + s.summary = 'Flutter plugin that shows an image picker.' + s.description = <<-DESC +Flutter plugin that shows an image picker. + DESC + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/image_picker' + 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' +end diff --git a/packages/image_picker/lib/image_picker.dart b/packages/image_picker/lib/image_picker.dart new file mode 100755 index 000000000000..90ebb8d90f3d --- /dev/null +++ b/packages/image_picker/lib/image_picker.dart @@ -0,0 +1,15 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/services.dart'; + +class ImagePicker { + static const MethodChannel _channel = + const MethodChannel('image_picker'); + + // Returns the URL of the picked image + static Future pickImage() async { + String path = await _channel.invokeMethod('pickImage'); + return new File(path); + } +} diff --git a/packages/image_picker/pubspec.yaml b/packages/image_picker/pubspec.yaml new file mode 100755 index 000000000000..ab29aa592726 --- /dev/null +++ b/packages/image_picker/pubspec.yaml @@ -0,0 +1,11 @@ +name: image_picker +description: Flutter plugin that shows an image picker. + +flutter: + plugin: + androidPackage: io.flutter.plugins.imagepicker + pluginClass: ImagePickerPlugin + +dependencies: + flutter: + sdk: flutter