├── ios ├── Assets │ └── .gitkeep ├── Classes │ ├── AppleSignInPlugin.h │ ├── Converters │ │ ├── Utils.m │ │ ├── Utils.h │ │ ├── NSErrorConverter.h │ │ ├── CredentialConverter.h │ │ ├── NSErrorConverter.m │ │ └── CredentialConverter.m │ ├── AppleIDButtonFactory.h │ ├── AuthorizationControllerDelegate.h │ ├── AppleIDButton.h │ ├── AppleIDButtonFactory.m │ ├── AuthorizationControllerDelegate.m │ ├── AppleIDButton.m │ └── AppleSignInPlugin.m ├── .gitignore └── apple_sign_in.podspec ├── android ├── gradle.properties ├── settings.gradle ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── dev │ │ └── gilder │ │ └── tom │ │ └── apple_sign_in │ │ └── AppleSignInPlugin.java ├── .classpath ├── .settings │ └── org.eclipse.buildship.core.prefs ├── .project └── build.gradle ├── example ├── android │ ├── gradle.properties │ ├── .settings │ │ └── org.eclipse.buildship.core.prefs │ ├── app │ │ ├── .settings │ │ │ └── org.eclipse.buildship.core.prefs │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── java │ │ │ │ │ └── dev │ │ │ │ │ │ └── gilder │ │ │ │ │ │ └── tom │ │ │ │ │ │ └── apple_sign_in_example │ │ │ │ │ │ └── MainActivity.java │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ ├── .classpath │ │ ├── .project │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .project │ ├── settings.gradle │ └── build.gradle ├── ios │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ ├── flutter_export_environment.sh │ │ └── AppFrameworkInfo.plist │ ├── Runner │ │ ├── AppDelegate.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ └── Contents.json │ │ ├── main.m │ │ ├── Runner.entitlements │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ └── project.pbxproj │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ ├── Podfile.lock │ └── Podfile ├── lib │ ├── main.dart │ ├── secret_members_only_page.dart │ ├── button_test │ │ ├── native_button.dart │ │ └── button_test_page.dart │ └── sign_in_page.dart ├── .metadata ├── README.md ├── test │ └── widget_test.dart ├── .gitignore └── pubspec.yaml ├── README.md ├── .metadata ├── CHANGELOG.md ├── .gitignore ├── .vscode └── launch.json ├── lib ├── scope.dart ├── open_id_operation.dart ├── apple_id_request.dart ├── apple_id_credential.dart ├── apple_sign_in_button.dart └── apple_sign_in.dart ├── apple_sign_in.iml ├── LICENSE ├── test ├── apple_id_credential_test.dart ├── perform_request_test.dart └── credential_state_test.dart └── pubspec.yaml /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'apple_sign_in' 2 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /example/android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir= 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /example/android/app/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Classes/AppleSignInPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface AppleSignInPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomgilder/flutter_apple_sign_in/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /ios/Classes/Converters/Utils.m: -------------------------------------------------------------------------------- 1 | // 2 | // Utils.m 3 | // apple_sign_in 4 | // 5 | // Created by Tom on 23/06/2019. 6 | // 7 | 8 | #import "Utils.h" 9 | 10 | @implementation Utils 11 | 12 | + (NSObject*)valueOrNSNull:(NSObject*)object { 13 | return object ? object : [NSNull null]; 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NO LONGER MAINTAINED 2 | 3 | Sorry, I haven't had the time to maintain this plugin, and I haven't had a project to test it on. 4 | 5 | A fork of this project is being continued as `the_apple_sign_in` here: 6 | 7 | * https://pub.dev/packages/the_apple_sign_in 8 | * https://github.com/beerstorm-net/the_apple_sign_in 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:apple_sign_in_example/sign_in_page.dart'; 3 | 4 | void main() => runApp(MyApp()); 5 | 6 | class MyApp extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | return MaterialApp(home: SignInPage()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ios/Classes/Converters/Utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // Utils.h 3 | // apple_sign_in 4 | // 5 | // Created by Tom on 23/06/2019. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface Utils : NSObject 13 | 14 | + (NSObject*)valueOrNSNull:(NSObject*)object; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.applesignin 6 | 7 | Default 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /ios/Classes/AppleIDButtonFactory.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppleIDButton.h" 4 | 5 | NS_ASSUME_NONNULL_BEGIN 6 | 7 | @interface AppleIDButtonFactory : NSObject 8 | - (instancetype)initWithMessenger:(NSObject*)messenger; 9 | @end 10 | 11 | NS_ASSUME_NONNULL_END 12 | -------------------------------------------------------------------------------- /android/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Latest 7 | PreviewsEnabled 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Classes/Converters/NSErrorConverter.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSErrorConverter.h 3 | // apple_sign_in 4 | // 5 | // Created by Tom on 23/06/2019. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NSErrorConverter : NSObject 13 | 14 | + (NSDictionary *)dictionaryFromError:(NSError *)error; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /example/android/app/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0 2 | 3 | * Add `CredentialStatus.transferred` 4 | * Added documentation 5 | * API should now be stable 6 | 7 | ## 0.0.3 8 | 9 | * Added `AuthorizationStatus.cancelled` value 10 | * Added `CredentialStatus.transferred` value 11 | 12 | ## 0.0.2 13 | 14 | * Added Flutter `AppleSignInButton` button 15 | * Added `AppleSignIn.isAvailable()` method 16 | 17 | ## 0.0.1 18 | 19 | * Initial preview 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | .pub/ 7 | build/ 8 | # If you're building an application, you may want to check-in your pubspec.lock 9 | pubspec.lock 10 | 11 | # Directory created by dartdoc 12 | # If you don't generate documentation locally you can remove this line. 13 | doc/api/ 14 | .DS_Store 15 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | arguments= 2 | auto.sync=false 3 | build.scans.enabled=false 4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(5.4)) 5 | connection.project.dir=../example/android 6 | eclipse.preferences.version=1 7 | gradle.user.home= 8 | java.home= 9 | jvm.arguments= 10 | offline.mode=false 11 | override.workspace.settings=true 12 | show.console.view=true 13 | show.executions.view=true 14 | -------------------------------------------------------------------------------- /ios/Classes/AuthorizationControllerDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | NS_ASSUME_NONNULL_BEGIN 5 | 6 | typedef void(^CompletionBlock)(NSDictionary*); 7 | 8 | @interface AuthorizationControllerDelegate : NSObject 9 | - (instancetype)initWithCompletion:(CompletionBlock)completition; 10 | @end 11 | 12 | NS_ASSUME_NONNULL_END 13 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Flutter", 9 | "request": "launch", 10 | "type": "dart", 11 | "program": "example/lib/main.dart" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /ios/Classes/AppleIDButton.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | NS_ASSUME_NONNULL_BEGIN 4 | 5 | API_AVAILABLE(ios(13.0)) 6 | @interface AppleIDButton : NSObject 7 | 8 | - (instancetype)initWithFrame:(CGRect)frame 9 | viewIdentifier:(int64_t)viewId 10 | arguments:(id _Nullable)args 11 | binaryMessenger:(NSObject*)messenger ; 12 | 13 | - (UIView*)view; 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/dev/gilder/tom/apple_sign_in_example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package dev.gilder.tom.apple_sign_in_example; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /ios/Classes/Converters/CredentialConverter.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | NS_ASSUME_NONNULL_BEGIN 5 | 6 | @interface CredentialConverter : NSObject 7 | 8 | + (NSDictionary*)dictionaryFromAppleIDCredential:(ASAuthorizationAppleIDCredential*)credential API_AVAILABLE(ios(13.0)); 9 | + (NSString*)stringForCredentialState:(ASAuthorizationAppleIDProviderCredentialState)credentialState API_AVAILABLE(ios(13.0)); 10 | 11 | @end 12 | 13 | NS_ASSUME_NONNULL_END 14 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /example/ios/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/Users/tom/dev/flutter" 4 | export "FLUTTER_APPLICATION_PATH=/Users/tom/repos/flutter_sign_in_with_apple/example" 5 | export "FLUTTER_TARGET=/Users/tom/repos/flutter_sign_in_with_apple/example/lib/main.dart" 6 | export "FLUTTER_BUILD_DIR=build" 7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios" 8 | export "FLUTTER_FRAMEWORK_DIR=/Users/tom/dev/flutter/bin/cache/artifacts/engine/ios" 9 | export "TRACK_WIDGET_CREATION=true" 10 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # apple_sign_in_example 2 | 3 | Demonstrates how to use the apple_sign_in plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | apple_sign_in 4 | Project android_ created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /example/android/app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'dev.gilder.tom.apple_sign_in' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.2.1' 12 | } 13 | } 14 | 15 | rootProject.allprojects { 16 | repositories { 17 | google() 18 | jcenter() 19 | } 20 | } 21 | 22 | apply plugin: 'com.android.library' 23 | 24 | android { 25 | compileSdkVersion 28 26 | 27 | defaultConfig { 28 | minSdkVersion 16 29 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 30 | } 31 | lintOptions { 32 | disable 'InvalidPackage' 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ios/apple_sign_in.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'apple_sign_in' 6 | s.version = '0.0.1' 7 | s.summary = 'A new flutter plugin project.' 8 | s.description = <<-DESC 9 | A new flutter plugin project. 10 | DESC 11 | s.homepage = 'http://example.com' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Your Company' => 'email@example.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | 19 | s.ios.deployment_target = '8.0' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /lib/scope.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | /// The kinds of contact information that can be requested from the user. 4 | @immutable 5 | class Scope { 6 | /// A scope that includes the user’s email address. 7 | static const Scope email = Scope.rawValue('email'); 8 | 9 | /// A scope that includes the user’s full name. 10 | static const Scope fullName = Scope.rawValue('full_name'); 11 | 12 | /// Value of the authorization scope 13 | final String value; 14 | 15 | /// Creates a scope from the given string. 16 | /// Typically you use one of the predefined scopes, like email, instead of initializing one from a string. 17 | const Scope.rawValue(this.value); 18 | 19 | @override 20 | bool operator ==(other) => other is Scope && other.value == value; 21 | 22 | @override 23 | int get hashCode => value.hashCode; 24 | } 25 | -------------------------------------------------------------------------------- /ios/Classes/Converters/NSErrorConverter.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSErrorConverter.m 3 | // apple_sign_in 4 | // 5 | // Created by Tom on 23/06/2019. 6 | // 7 | 8 | #import "NSErrorConverter.h" 9 | 10 | @implementation NSErrorConverter 11 | 12 | + (NSDictionary *)dictionaryFromError:(NSError *)error { 13 | return 14 | @{ 15 | @"code": @(error.code), 16 | @"domain": [self valueOrNSNull:error.domain], 17 | @"localizedDescription": [self valueOrNSNull:error.localizedDescription], 18 | @"localizedRecoverySuggestion": [self valueOrNSNull:error.localizedRecoverySuggestion], 19 | @"localizedFailureReason": [self valueOrNSNull:error.localizedFailureReason] 20 | }; 21 | } 22 | 23 | + (NSObject*)valueOrNSNull:(NSObject*)value { 24 | if (value == nil) { 25 | return [NSNull null]; 26 | } 27 | 28 | return value; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - apple_sign_in (0.0.1): 3 | - Flutter 4 | - Flutter (1.0.0) 5 | - flutter_secure_storage (3.2.0): 6 | - Flutter 7 | 8 | DEPENDENCIES: 9 | - apple_sign_in (from `.symlinks/plugins/apple_sign_in/ios`) 10 | - Flutter (from `.symlinks/flutter/ios`) 11 | - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) 12 | 13 | EXTERNAL SOURCES: 14 | apple_sign_in: 15 | :path: ".symlinks/plugins/apple_sign_in/ios" 16 | Flutter: 17 | :path: ".symlinks/flutter/ios" 18 | flutter_secure_storage: 19 | :path: ".symlinks/plugins/flutter_secure_storage/ios" 20 | 21 | SPEC CHECKSUMS: 22 | apple_sign_in: 7716c7ddfa195aeab7dec0dc374ef4ff45d1adb4 23 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 24 | flutter_secure_storage: 0c5779648ff644110e507909b77a57e620cbbf8b 25 | 26 | PODFILE CHECKSUM: 53753e6df6f108de3dcb6d3894f42b39b585850f 27 | 28 | COCOAPODS: 1.7.1 29 | -------------------------------------------------------------------------------- /lib/open_id_operation.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | /// The kinds of operations that you can perform with OpenID authentication. 4 | @immutable 5 | class OpenIdOperation { 6 | /// An operation that depends on the particular kind of credential provider. 7 | static const operationImplicit = OpenIdOperation.rawValue('implicit'); 8 | 9 | /// An operation used to authenticate a user. 10 | static const operationLogin = OpenIdOperation.rawValue('login'); 11 | 12 | /// An operation that ends an authenticated session. 13 | static const operationLogout = OpenIdOperation.rawValue('logout'); 14 | 15 | /// An operation that refreshes the logged-in user’s credentials. 16 | static const operationRefresh = OpenIdOperation.rawValue('refresh'); 17 | 18 | /// The value of the operation 19 | final String value; 20 | 21 | /// Creates an operation from the given string. 22 | const OpenIdOperation.rawValue(this.value); 23 | } 24 | -------------------------------------------------------------------------------- /apple_sign_in.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:apple_sign_in_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => 22 | widget is Text && widget.data.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /android/src/main/java/dev/gilder/tom/apple_sign_in/AppleSignInPlugin.java: -------------------------------------------------------------------------------- 1 | package dev.gilder.tom.apple_sign_in; 2 | 3 | import io.flutter.plugin.common.MethodCall; 4 | import io.flutter.plugin.common.MethodChannel; 5 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 6 | import io.flutter.plugin.common.MethodChannel.Result; 7 | import io.flutter.plugin.common.PluginRegistry.Registrar; 8 | 9 | /** AppleSignInPlugin */ 10 | public class AppleSignInPlugin implements MethodCallHandler { 11 | /** Plugin registration. */ 12 | public static void registerWith(Registrar registrar) { 13 | final MethodChannel channel = new MethodChannel(registrar.messenger(), "apple_sign_in"); 14 | channel.setMethodCallHandler(new AppleSignInPlugin()); 15 | } 16 | 17 | @Override 18 | public void onMethodCall(MethodCall call, Result result) { 19 | if (call.method.equals("getPlatformVersion")) { 20 | result.success("Android " + android.os.Build.VERSION.RELEASE); 21 | } else { 22 | result.notImplemented(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ios/Classes/AppleIDButtonFactory.m: -------------------------------------------------------------------------------- 1 | #import "AppleIDButtonFactory.h" 2 | 3 | @implementation AppleIDButtonFactory { 4 | NSObject* _messenger; 5 | } 6 | 7 | - (instancetype)initWithMessenger:(NSObject*)messenger { 8 | self = [super init]; 9 | if (self) { 10 | _messenger = messenger; 11 | } 12 | return self; 13 | } 14 | 15 | - (NSObject*)createArgsCodec { 16 | return [FlutterStandardMessageCodec sharedInstance]; 17 | } 18 | 19 | - (NSObject*)createWithFrame:(CGRect)frame 20 | viewIdentifier:(int64_t)viewId 21 | arguments:(id _Nullable)args { 22 | if (@available(iOS 13.0, *)) { 23 | return [[AppleIDButton alloc] initWithFrame:frame 24 | viewIdentifier:viewId 25 | arguments:args 26 | binaryMessenger:_messenger]; 27 | } 28 | 29 | return nil; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Rody Davis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ios/Classes/AuthorizationControllerDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AuthorizationControllerDelegate.h" 2 | #import 3 | #import "Converters/NSErrorConverter.h" 4 | #import "Converters/CredentialConverter.h" 5 | 6 | @implementation AuthorizationControllerDelegate { 7 | CompletionBlock _completion; 8 | } 9 | 10 | - (instancetype)initWithCompletion:(CompletionBlock)completion { 11 | self = [super init]; 12 | if (self) { 13 | _completion = completion; 14 | } 15 | return self; 16 | } 17 | 18 | - (void)authorizationController:(ASAuthorizationController *)controller 19 | didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) { 20 | if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) { 21 | _completion([CredentialConverter dictionaryFromAppleIDCredential:authorization.credential]); 22 | return; 23 | } 24 | 25 | _completion(@{@"status": @"error"}); 26 | } 27 | 28 | - (void)authorizationController:(ASAuthorizationController *)controller 29 | didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)) { 30 | _completion(@ 31 | {@"status": @"error", 32 | @"error": [NSErrorConverter dictionaryFromError:error] 33 | } 34 | ); 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # Exceptions to above rules. 66 | !**/ios/**/default.mode1v3 67 | !**/ios/**/default.mode2v3 68 | !**/ios/**/default.pbxuser 69 | !**/ios/**/default.perspectivev3 70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 71 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/apple_id_credential_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:apple_sign_in/apple_id_credential.dart'; 4 | import 'package:apple_sign_in/apple_sign_in.dart'; 5 | 6 | void main() { 7 | group('AppleIdCredential', () { 8 | test('Creates from map', () async { 9 | final map = { 10 | 'identityToken': Uint8List.fromList([4, 8, 15, 16, 23, 42]), 11 | 'authorizationCode': Uint8List.fromList([1, 2, 3]), 12 | 'state': 'state', 13 | 'authorizedScopes': ['email', 'full_name'], 14 | 'user': 'user', 15 | 'email': 'email', 16 | 'realUserStatus': 2, 17 | 'fullName': { 18 | 'familyName': 'family', 19 | 'givenName': 'given', 20 | 'middleName': 'middle', 21 | 'namePrefix': 'prefix', 22 | 'nameSuffix': 'suffix', 23 | 'nickname': 'nick' 24 | } 25 | }; 26 | 27 | final result = AppleIdCredential.fromMap(map); 28 | 29 | expect(result.identityToken.toList(), [4, 8, 15, 16, 23, 42]); 30 | expect(result.authorizationCode.toList(), [1, 2, 3]); 31 | expect(result.state, 'state'); 32 | expect(result.authorizedScopes, [Scope.email, Scope.fullName]); 33 | expect(result.user, 'user'); 34 | expect(result.email, 'email'); 35 | expect(result.realUserStatus, UserDetectionStatus.likelyReal); 36 | 37 | expect(result.fullName.familyName, 'family'); 38 | expect(result.fullName.givenName, 'given'); 39 | expect(result.fullName.middleName, 'middle'); 40 | expect(result.fullName.namePrefix, 'prefix'); 41 | expect(result.fullName.nameSuffix, 'suffix'); 42 | expect(result.fullName.nickname, 'nick'); 43 | }); 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | Sign In Example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | io.flutter.embedded_views_preview 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /lib/apple_id_request.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'scope.dart'; 3 | import 'open_id_operation.dart'; 4 | 5 | /// A base class for different kinds of authorization requests. 6 | @immutable 7 | abstract class AuthorizationRequest { 8 | final OpenIdOperation requestedOperation; 9 | 10 | final List requestedScopes; 11 | 12 | Map toMap(); 13 | 14 | const AuthorizationRequest({ 15 | this.requestedOperation, 16 | this.requestedScopes, 17 | }); 18 | } 19 | 20 | /// An OpenID authorization request that relies on the user’s Apple ID. 21 | @immutable 22 | class AppleIdRequest extends AuthorizationRequest { 23 | /// An identifier associated with the user’s Apple ID. 24 | /// 25 | /// Typically you leave this property set to null the first time you authenticate a user. Otherwise, if you previously received an authorization containing an ASAuthorizationAppleIDCredential instance, set this property to the value from the credential’s user property. 26 | /// 27 | /// The value is an arbitrary string that’s portable among apps from a single developer, but not between apps from different developers. 28 | final String user; 29 | 30 | const AppleIdRequest({ 31 | this.user, 32 | OpenIdOperation requestedOperation = OpenIdOperation.operationLogin, 33 | List requestedScopes, 34 | }) : super( 35 | requestedOperation: requestedOperation, 36 | requestedScopes: requestedScopes, 37 | ); 38 | 39 | Map toMap() { 40 | return { 41 | 'requestType': 'AppleIdRequest', 42 | 'user': user, 43 | 'requestedOperation': requestedOperation.value, 44 | 'requestedScopes': 45 | requestedScopes?.map((scope) => scope.value)?.toList() ?? [] 46 | }; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/lib/secret_members_only_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_secure_storage/flutter_secure_storage.dart'; 3 | import 'package:apple_sign_in/apple_sign_in.dart'; 4 | import 'package:apple_sign_in_example/sign_in_page.dart'; 5 | 6 | class SecretMembersOnlyPage extends StatelessWidget { 7 | final AppleIdCredential credential; 8 | 9 | const SecretMembersOnlyPage({@required this.credential}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: const Text('🏴‍☠️ SECRET PIRATE CLUB 🏴‍☠️'), 16 | ), 17 | body: SingleChildScrollView( 18 | child: Padding( 19 | padding: const EdgeInsets.all(20.0), 20 | child: Column( 21 | mainAxisAlignment: MainAxisAlignment.center, 22 | crossAxisAlignment: CrossAxisAlignment.center, 23 | children: [ 24 | Text( 25 | "Welcome to the secret pirate club, ${credential.fullName?.givenName}!", 26 | style: TextStyle(fontSize: 25), 27 | textAlign: TextAlign.center, 28 | ), 29 | Text( 30 | "I have your email as '${credential.email}'", 31 | style: TextStyle(fontSize: 15), 32 | textAlign: TextAlign.center, 33 | ), 34 | OutlineButton( 35 | child: Text("Log out"), 36 | onPressed: () async { 37 | await FlutterSecureStorage().deleteAll(); 38 | Navigator.of(context).push( 39 | MaterialPageRoute(builder: (_) => SignInPage())); 40 | }) 41 | ]), 42 | ))); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "dev.gilder.tom.apple_sign_in_example" 37 | minSdkVersion 18 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 61 | } 62 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: apple_sign_in_example 2 | description: Demonstrates how to use the apple_sign_in plugin. 3 | publish_to: 'none' 4 | 5 | environment: 6 | sdk: ">=2.2.2 <3.0.0" 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | 12 | # The following adds the Cupertino Icons font to your application. 13 | # Use with the CupertinoIcons class for iOS style icons. 14 | cupertino_icons: ^0.1.2 15 | flutter_secure_storage: ^3.2.1+1 16 | before_after: ^1.0.1 17 | 18 | dev_dependencies: 19 | flutter_test: 20 | sdk: flutter 21 | 22 | apple_sign_in: 23 | path: ../ 24 | 25 | # For information on the generic Dart part of this file, see the 26 | # following page: https://www.dartlang.org/tools/pub/pubspec 27 | 28 | # The following section is specific to Flutter. 29 | flutter: 30 | 31 | # The following line ensures that the Material Icons font is 32 | # included with your application, so that you can use the icons in 33 | # the material Icons class. 34 | uses-material-design: true 35 | 36 | # To add assets to your application, add an assets section, like this: 37 | # assets: 38 | # - images/a_dot_burr.jpeg 39 | # - images/a_dot_ham.jpeg 40 | 41 | # An image asset can refer to one or more resolution-specific "variants", see 42 | # https://flutter.dev/assets-and-images/#resolution-aware. 43 | 44 | # For details regarding adding assets from package dependencies, see 45 | # https://flutter.dev/assets-and-images/#from-packages 46 | 47 | # To add custom fonts to your application, add a fonts section here, 48 | # in this "flutter" section. Each entry in this list should have a 49 | # "family" key with the font family name, and a "fonts" key with a 50 | # list giving the asset and other descriptors for the font. For 51 | # example: 52 | # fonts: 53 | # - family: Schyler 54 | # fonts: 55 | # - asset: fonts/Schyler-Regular.ttf 56 | # - asset: fonts/Schyler-Italic.ttf 57 | # style: italic 58 | # - family: Trajan Pro 59 | # fonts: 60 | # - asset: fonts/TrajanPro.ttf 61 | # - asset: fonts/TrajanPro_Bold.ttf 62 | # weight: 700 63 | # 64 | # For details regarding fonts from package dependencies, 65 | # see https://flutter.dev/custom-fonts/#from-packages 66 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: apple_sign_in 2 | description: Sign in With Apple for Flutter. Native API bindings and a Flutter implementation of the sign in button. 3 | version: 0.1.0 4 | author: Tom Gilder 5 | homepage: https://github.com/tomgilder/flutter_apple_sign_in 6 | 7 | environment: 8 | sdk: ">=2.2.2 <3.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter 17 | pedantic: ^1.8.0+1 18 | 19 | # For information on the generic Dart part of this file, see the 20 | # following page: https://www.dartlang.org/tools/pub/pubspec 21 | 22 | # The following section is specific to Flutter. 23 | flutter: 24 | # This section identifies this Flutter project as a plugin project. 25 | # The androidPackage and pluginClass identifiers should not ordinarily 26 | # be modified. They are used by the tooling to maintain consistency when 27 | # adding or updating assets for this project. 28 | plugin: 29 | androidPackage: dev.gilder.tom.apple_sign_in 30 | pluginClass: AppleSignInPlugin 31 | 32 | # To add assets to your plugin package, add an assets section, like this: 33 | # assets: 34 | # - images/a_dot_burr.jpeg 35 | # - images/a_dot_ham.jpeg 36 | # 37 | # For details regarding assets in packages, see 38 | # https://flutter.dev/assets-and-images/#from-packages 39 | # 40 | # An image asset can refer to one or more resolution-specific "variants", see 41 | # https://flutter.dev/assets-and-images/#resolution-aware. 42 | 43 | # To add custom fonts to your plugin package, add a fonts section here, 44 | # in this "flutter" section. Each entry in this list should have a 45 | # "family" key with the font family name, and a "fonts" key with a 46 | # list giving the asset and other descriptors for the font. For 47 | # example: 48 | # fonts: 49 | # - family: Schyler 50 | # fonts: 51 | # - asset: fonts/Schyler-Regular.ttf 52 | # - asset: fonts/Schyler-Italic.ttf 53 | # style: italic 54 | # - family: Trajan Pro 55 | # fonts: 56 | # - asset: fonts/TrajanPro.ttf 57 | # - asset: fonts/TrajanPro_Bold.ttf 58 | # weight: 700 59 | # 60 | # For details regarding fonts in packages, see 61 | # https://flutter.dev/custom-fonts/#from-packages 62 | -------------------------------------------------------------------------------- /example/lib/button_test/native_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | import 'package:apple_sign_in/apple_sign_in.dart'; 6 | 7 | /// A control you add to your interface that enables users to initiate the Sign In with Apple flow. 8 | class NativeAppleSignInButton extends StatelessWidget { 9 | /// The callback that is called when the button is tapped or otherwise activated. 10 | /// 11 | /// If this is set to null, the button will be disabled. 12 | final VoidCallback onPressed; 13 | 14 | /// A type for the authorization button. 15 | final ButtonType type; 16 | 17 | /// A style for the authorization button. 18 | final ButtonStyle style; 19 | 20 | /// A custom corner radius to be used by this button. 21 | final double cornerRadius; 22 | 23 | const NativeAppleSignInButton( 24 | {this.onPressed, 25 | this.type = ButtonType.defaultButton, 26 | this.style = ButtonStyle.white, 27 | this.cornerRadius = 4}); 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return ConstrainedBox( 32 | constraints: BoxConstraints(minHeight: 50, maxHeight: 50), 33 | child: UiKitView( 34 | viewType: "dev.gilder.tom/apple_id_button", 35 | creationParamsCodec: const StandardMessageCodec(), 36 | creationParams: _buildCreationParams(), 37 | onPlatformViewCreated: _createMethodChannel), 38 | ); 39 | } 40 | 41 | Map _buildCreationParams() { 42 | return { 43 | "buttonType": type.toString(), 44 | "buttonStyle": style.toString(), 45 | "cornerRadius": cornerRadius, 46 | "enabled": onPressed != null 47 | }; 48 | } 49 | 50 | void _createMethodChannel(int nativeViewId) { 51 | MethodChannel("dev.gilder.tom/apple_sign_in_button_$nativeViewId") 52 | ..setMethodCallHandler(_onMethodCall); 53 | } 54 | 55 | Future _onMethodCall(MethodCall call) async { 56 | switch (call.method) { 57 | case "onTapped": 58 | _onTapped(); 59 | return null; 60 | } 61 | 62 | throw MissingPluginException( 63 | "AppleSignInButton._onMethodCall: no handler for ${call.method}"); 64 | } 65 | 66 | void _onTapped() { 67 | if (onPressed != null) { 68 | onPressed(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /test/perform_request_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/services.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | import 'package:apple_sign_in/open_id_operation.dart'; 6 | import 'package:apple_sign_in/apple_sign_in.dart'; 7 | 8 | void main() { 9 | group('performRequests', () { 10 | const MethodChannel channel = MethodChannel('dev.gilder.tom/apple_sign_in'); 11 | 12 | Future _getPerformRequestsMethodCall() { 13 | final completer = Completer(); 14 | 15 | channel.setMockMethodCallHandler((mc) async { 16 | if (mc.method == 'performRequests') { 17 | completer.complete(mc); 18 | return { 19 | 'status': 'authorized', 20 | 'credentialType': 'ASAuthorizationAppleIDCredential', 21 | 'credential': {'email': 'email@email.com'} 22 | }; 23 | } 24 | 25 | throw 'Unexpected method: ${mc.method}'; 26 | }); 27 | 28 | return completer.future; 29 | } 30 | 31 | test('performRequests sends getCredentialState request to channel', 32 | () async { 33 | final methodCall = _getPerformRequestsMethodCall(); 34 | await AppleSignIn.performRequests([ 35 | AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName]) 36 | ]); 37 | 38 | expect((await methodCall).arguments['requests'], [ 39 | { 40 | 'requestType': 'AppleIdRequest', 41 | 'user': null, 42 | 'requestedOperation': 'login', 43 | 'requestedScopes': ['email', 'full_name'] 44 | } 45 | ]); 46 | }); 47 | 48 | test('AppleIdRequest maps operations', () async { 49 | Future expectOperation(OpenIdOperation operation, String expected) async { 50 | final methodCall = _getPerformRequestsMethodCall(); 51 | await AppleSignIn.performRequests( 52 | [AppleIdRequest(requestedOperation: operation)]); 53 | expect( 54 | (await methodCall).arguments['requests'][0]['requestedOperation'], 55 | expected); 56 | } 57 | 58 | await expectOperation(OpenIdOperation.operationImplicit, 'implicit'); 59 | await expectOperation(OpenIdOperation.operationLogin, 'login'); 60 | await expectOperation(OpenIdOperation.operationLogout, 'logout'); 61 | await expectOperation(OpenIdOperation.operationRefresh, 'refresh'); 62 | }); 63 | }); 64 | } 65 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | pods_ary = [] 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) { |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | pods_ary.push({:name => podname, :path => podpath}); 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | } 32 | return pods_ary 33 | end 34 | 35 | target 'Runner' do 36 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 37 | # referring to absolute paths on developers' machines. 38 | system('rm -rf .symlinks') 39 | system('mkdir -p .symlinks/plugins') 40 | 41 | # Flutter Pods 42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') 43 | if generated_xcode_build_settings.empty? 44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." 45 | end 46 | generated_xcode_build_settings.map { |p| 47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 48 | symlink = File.join('.symlinks', 'flutter') 49 | File.symlink(File.dirname(p[:path]), symlink) 50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) 51 | end 52 | } 53 | 54 | # Plugin Pods 55 | plugin_pods = parse_KV_file('../.flutter-plugins') 56 | plugin_pods.map { |p| 57 | symlink = File.join('.symlinks', 'plugins', p[:name]) 58 | File.symlink(p[:path], symlink) 59 | pod p[:name], :path => File.join(symlink, 'ios') 60 | } 61 | end 62 | 63 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 64 | install! 'cocoapods', :disable_input_output_paths => true 65 | 66 | post_install do |installer| 67 | installer.pods_project.targets.each do |target| 68 | target.build_configurations.each do |config| 69 | config.build_settings['ENABLE_BITCODE'] = 'NO' 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /ios/Classes/Converters/CredentialConverter.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "CredentialConverter.h" 3 | #import "Utils.h" 4 | 5 | @implementation CredentialConverter 6 | 7 | + (NSDictionary*)dictionaryFromAppleIDCredential:(ASAuthorizationAppleIDCredential*)credential API_AVAILABLE(ios(13.0)) { 8 | NSDictionary *dict = @{ 9 | @"status": @"authorized", 10 | @"credentialType": @"ASAuthorizationAppleIDCredential", 11 | @"credential": @{ 12 | @"user": [Utils valueOrNSNull:credential.user], 13 | @"state": [Utils valueOrNSNull:credential.state], 14 | @"authorizedScopes": [Utils valueOrNSNull:credential.authorizedScopes], 15 | @"authorizationCode": credential.authorizationCode ? [FlutterStandardTypedData typedDataWithBytes:credential.authorizationCode] : [NSNull null], 16 | @"identityToken": credential.identityToken ? [FlutterStandardTypedData typedDataWithBytes:credential.identityToken] : [NSNull null], 17 | @"email": [Utils valueOrNSNull:credential.email], 18 | @"fullName": [CredentialConverter dictionaryFromPersonNameComponents:credential.fullName], 19 | @"realUserStatus": @(credential.realUserStatus) 20 | }}; 21 | 22 | NSLog(@"%@", dict); // TODO: Remove debug logging 23 | return dict; 24 | } 25 | 26 | + (NSObject*)dictionaryFromPersonNameComponents:(NSPersonNameComponents*)components API_AVAILABLE(ios(9.0)) { 27 | if (!components) { 28 | return [NSNull null]; 29 | } 30 | 31 | return 32 | @{ 33 | @"namePrefix": [Utils valueOrNSNull:components.namePrefix], 34 | @"givenName": [Utils valueOrNSNull:components.givenName], 35 | @"middleName": [Utils valueOrNSNull:components.middleName], 36 | @"familyName": [Utils valueOrNSNull:components.familyName], 37 | @"nameSuffix": [Utils valueOrNSNull:components.nameSuffix], 38 | @"nickname": [Utils valueOrNSNull:components.nickname], 39 | }; 40 | } 41 | 42 | + (NSString*)stringForCredentialState:(ASAuthorizationAppleIDProviderCredentialState)credentialState API_AVAILABLE(ios(13.0)) { 43 | switch(credentialState) { 44 | case ASAuthorizationAppleIDProviderCredentialAuthorized: 45 | return @"authorized"; 46 | 47 | case ASAuthorizationAppleIDProviderCredentialRevoked: 48 | return @"revoked"; 49 | 50 | case ASAuthorizationAppleIDProviderCredentialTransferred: 51 | return @"transferred"; 52 | 53 | default: // ASAuthorizationAppleIDProviderCredentialNotFound 54 | return @"notFound"; 55 | } 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /ios/Classes/AppleIDButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppleIdButton.m 3 | // apple_sign_in 4 | // 5 | // Created by Tom on 21/06/2019. 6 | // 7 | 8 | #import "AppleIDButton.h" 9 | #import 10 | 11 | @implementation AppleIDButton { 12 | ASAuthorizationAppleIDButton* _button; 13 | int64_t _viewId; 14 | FlutterMethodChannel* _channel; 15 | } 16 | 17 | - (instancetype)initWithFrame:(CGRect)frame 18 | viewIdentifier:(int64_t)viewId 19 | arguments:(id _Nullable)args 20 | binaryMessenger:(NSObject*)messenger { 21 | 22 | if ([super init]) { 23 | NSString* channelName = [NSString stringWithFormat:@"dev.gilder.tom/apple_sign_in_button_%lld", viewId]; 24 | _channel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:messenger]; 25 | 26 | _viewId = viewId; 27 | 28 | ASAuthorizationAppleIDButtonType buttonType = [self buttonTypeFromString:args[@"buttonType"]]; 29 | ASAuthorizationAppleIDButtonStyle buttonStyle = [self buttonStyleFromString:args[@"buttonStyle"]]; 30 | _button = [ASAuthorizationAppleIDButton buttonWithType:buttonType 31 | style:buttonStyle]; 32 | 33 | _button.frame = frame; 34 | _button.enabled = [args[@"enabled"] boolValue]; 35 | _button.cornerRadius = [args[@"cornerRadius"] floatValue]; 36 | 37 | [_button addTarget:self 38 | action:@selector(onTapped) 39 | forControlEvents:UIControlEventTouchUpInside]; 40 | } 41 | return self; 42 | } 43 | 44 | - (UIView*)view { 45 | return _button; 46 | } 47 | 48 | - (void)onTapped { 49 | [_channel invokeMethod:@"onTapped" arguments:nil]; 50 | } 51 | 52 | - (ASAuthorizationAppleIDButtonType)buttonTypeFromString:(NSString*)buttonType { 53 | if ([buttonType isEqualToString:@"ButtonType.continueButton"]) { 54 | return ASAuthorizationAppleIDButtonTypeContinue; 55 | } 56 | 57 | if ([buttonType isEqualToString:@"ButtonType.signIn"]) { 58 | return ASAuthorizationAppleIDButtonTypeSignIn; 59 | } 60 | 61 | // "ButtonType.defaultType" 62 | return ASAuthorizationAppleIDButtonTypeDefault; 63 | } 64 | 65 | 66 | - (ASAuthorizationAppleIDButtonStyle)buttonStyleFromString:(NSString*)buttonStyle { 67 | if ([buttonStyle isEqualToString:@"ButtonStyle.white"]) { 68 | return ASAuthorizationAppleIDButtonStyleWhite; 69 | } 70 | 71 | if ([buttonStyle isEqualToString:@"ButtonStyle.whiteOutline"]) { 72 | return ASAuthorizationAppleIDButtonStyleWhiteOutline; 73 | } 74 | 75 | // "ButtonStyle.black" 76 | return ASAuthorizationAppleIDButtonStyleBlack; 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /test/credential_state_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:apple_sign_in/apple_sign_in.dart'; 4 | 5 | void main() { 6 | group('getCredentialState', () { 7 | const MethodChannel channel = MethodChannel('dev.gilder.tom/apple_sign_in'); 8 | const String USER_ID = 'USER_ID'; 9 | 10 | void _setUpReturn(Map map) { 11 | channel.setMockMethodCallHandler((MethodCall methodCall) async { 12 | if (methodCall.method == 'getCredentialState') { 13 | return map; 14 | } 15 | 16 | throw 'Unknown method: ${methodCall.method}'; 17 | }); 18 | } 19 | 20 | test('getCredentialState sends userId to channel', () async { 21 | MethodCall methodCall; 22 | channel.setMockMethodCallHandler((mc) async { 23 | if (mc.method == 'getCredentialState') { 24 | methodCall = mc; 25 | return {'credentialState': 'authorized'}; 26 | } 27 | 28 | throw 'Unexpected method: ${mc.method}'; 29 | }); 30 | 31 | await AppleSignIn.getCredentialState(USER_ID); 32 | expect(methodCall.arguments['userId'], USER_ID); 33 | }); 34 | 35 | test('getCredentialState returns error', () async { 36 | _setUpReturn({ 37 | 'credentialState': 'error', 38 | 'error': { 39 | 'code': 42, 40 | 'domain': 'domain', 41 | 'localizedDescription': 'localizedDescription', 42 | 'localizedRecoverySuggestion': 'localizedRecoverySuggestion', 43 | 'localizedFailureReason': 'localizedFailureReason' 44 | } 45 | }); 46 | 47 | final result = await AppleSignIn.getCredentialState(USER_ID); 48 | expect(result.status, CredentialStatus.error); 49 | expect(result.error.code, 42); 50 | expect(result.error.localizedDescription, 'localizedDescription'); 51 | expect(result.error.localizedRecoverySuggestion, 52 | 'localizedRecoverySuggestion'); 53 | expect(result.error.localizedFailureReason, 'localizedFailureReason'); 54 | }); 55 | 56 | test('getCredentialState returns authorized', () async { 57 | _setUpReturn({'credentialState': 'authorized'}); 58 | final result = await AppleSignIn.getCredentialState(USER_ID); 59 | expect(result.status, CredentialStatus.authorized); 60 | }); 61 | 62 | test('getCredentialState returns revoked', () async { 63 | _setUpReturn({'credentialState': 'revoked'}); 64 | final result = await AppleSignIn.getCredentialState(USER_ID); 65 | expect(result.status, CredentialStatus.revoked); 66 | }); 67 | 68 | test('getCredentialState returns authorized', () async { 69 | _setUpReturn({'credentialState': 'notFound'}); 70 | final result = await AppleSignIn.getCredentialState(USER_ID); 71 | expect(result.status, CredentialStatus.notFound); 72 | }); 73 | 74 | test('getCredentialState returns transferred', () async { 75 | _setUpReturn({'credentialState': 'transferred'}); 76 | final result = await AppleSignIn.getCredentialState(USER_ID); 77 | expect(result.status, CredentialStatus.transferred); 78 | }); 79 | }); 80 | } 81 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /example/lib/button_test/button_test_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:apple_sign_in/apple_sign_in.dart'; 2 | import 'package:before_after/before_after.dart'; 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'native_button.dart'; 6 | 7 | class ButtonTestPage extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return Scaffold( 11 | appBar: AppBar( 12 | title: const Text('Sign In with Apple Example App'), 13 | ), 14 | backgroundColor: Colors.grey, 15 | body: SingleChildScrollView( 16 | child: Center( 17 | child: SizedBox( 18 | width: 320, 19 | child: Column( 20 | mainAxisAlignment: MainAxisAlignment.center, 21 | crossAxisAlignment: CrossAxisAlignment.center, 22 | children: [ 23 | ButtonComparison( 24 | style: ButtonStyle.whiteOutline, 25 | type: ButtonType.signIn, 26 | ), 27 | ButtonComparison( 28 | style: ButtonStyle.black, 29 | type: ButtonType.signIn, 30 | ), 31 | ButtonComparison( 32 | style: ButtonStyle.white, 33 | type: ButtonType.signIn, 34 | ), 35 | ButtonComparison( 36 | style: ButtonStyle.whiteOutline, 37 | type: ButtonType.continueButton, 38 | ), 39 | ButtonComparison( 40 | style: ButtonStyle.black, 41 | type: ButtonType.continueButton, 42 | ), 43 | ButtonComparison( 44 | style: ButtonStyle.white, 45 | type: ButtonType.continueButton, 46 | ), 47 | ], 48 | ), 49 | ), 50 | ), 51 | ), 52 | ); 53 | } 54 | } 55 | 56 | class ButtonComparison extends StatelessWidget { 57 | final ButtonStyle style; 58 | final ButtonType type; 59 | 60 | ButtonComparison({@required this.style, @required this.type}); 61 | 62 | @override 63 | Widget build(BuildContext context) { 64 | return Card( 65 | child: Padding( 66 | padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), 67 | child: Column( 68 | children: [ 69 | // Text('Native'), 70 | // SizedBox( 71 | // height: 5, 72 | // ), 73 | // NativeAppleSignInButton( 74 | // style: style, 75 | // type: type, 76 | // ), 77 | // SizedBox( 78 | // height: 10, 79 | // ), 80 | // Text('Flutter'), 81 | // SizedBox( 82 | // height: 5, 83 | // ), 84 | // AppleSignInButton( 85 | // style: style, 86 | // type: type, 87 | // ), 88 | Text('Native / Flutter'), 89 | BeforeAfter( 90 | imageCornerRadius: 0, 91 | thumbColor: Colors.blue, 92 | beforeImage: NativeAppleSignInButton( 93 | style: style, 94 | type: type, 95 | ), 96 | afterImage: AppleSignInButton( 97 | style: style, 98 | type: type, 99 | ), 100 | ), 101 | ], 102 | ), 103 | ), 104 | ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /lib/apple_id_credential.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'dart:typed_data'; 3 | import 'scope.dart'; 4 | 5 | @immutable 6 | class AppleIdCredential { 7 | /// A JSON Web Token (JWT) that securely communicates information about the user to your app. Can be null. 8 | final Uint8List identityToken; 9 | 10 | /// A short-lived token used by your app for proof of authorization when interacting with the app’s server counterpart. Can be null. 11 | final Uint8List authorizationCode; 12 | 13 | /// An arbitrary string that your app provided to the request that generated the credential. 14 | final String state; 15 | 16 | /// An identifier associated with the authenticated user. Can be null. 17 | final String user; 18 | 19 | /// The contact information the user authorized your app to access. 20 | final List authorizedScopes; 21 | 22 | /// The user’s name. Can be null. 23 | final PersonNameComponents fullName; 24 | 25 | /// The user’s email address. Can be null. 26 | final String email; 27 | 28 | /// A value that indicates whether the user appears to be a real person. 29 | final UserDetectionStatus realUserStatus; 30 | 31 | const AppleIdCredential({ 32 | this.identityToken, 33 | this.authorizationCode, 34 | this.state, 35 | this.user, 36 | this.authorizedScopes, 37 | this.fullName, 38 | this.email, 39 | this.realUserStatus, 40 | }); 41 | 42 | factory AppleIdCredential.fromMap(Map map) { 43 | assert(map != null); 44 | 45 | return AppleIdCredential( 46 | identityToken: map['identityToken'], 47 | authorizationCode: map['authorizationCode'], 48 | state: map['state'], 49 | user: map['user'], 50 | authorizedScopes: _scopesFromList(map['authorizedScopes']), 51 | email: map['email'], 52 | realUserStatus: map.containsKey('realUserStatus') 53 | ? UserDetectionStatus.values[map['realUserStatus']] 54 | : UserDetectionStatus.unsupported, 55 | fullName: PersonNameComponents.fromMap(map['fullName']), 56 | ); 57 | } 58 | 59 | static List _scopesFromList(List list) { 60 | if (list == null) { 61 | return List(); 62 | } 63 | 64 | return list.map((scope) => Scope.rawValue(scope)).toList(); 65 | } 66 | } 67 | 68 | /// Possible values for the real user indicator. 69 | enum UserDetectionStatus { 70 | /// The system can’t determine this user’s status as a real person. 71 | unsupported, 72 | 73 | /// The system hasn’t determined whether the user might be a real person. 74 | unknown, 75 | 76 | /// The user appears to be a real person. 77 | likelyReal 78 | } 79 | 80 | /// The separate parts of a person's name, allowing locale-aware formatting. 81 | @immutable 82 | class PersonNameComponents { 83 | /// Pre-nominal letters denoting title, salutation, or honorific, e.g. Dr., Mr. Can be null. 84 | final String namePrefix; 85 | 86 | /// Name bestowed upon an individual by one's parents, e.g. Johnathan. Can be null. 87 | final String givenName; 88 | 89 | /// Secondary given name chosen to differentiate those with the same first name, e.g. Maple. Can be null. 90 | final String middleName; 91 | 92 | /// Name passed from one generation to another to indicate lineage, e.g. Appleseed. Can be null. 93 | final String familyName; 94 | 95 | /// Post-nominal letters denoting degree, accreditation, or other honor, e.g. Esq., Jr., Ph.D. Can be null. 96 | final String nameSuffix; 97 | 98 | /// Name substituted for the purposes of familiarity, e.g. 'Johnny'. Can be null. 99 | final String nickname; 100 | 101 | PersonNameComponents({ 102 | this.namePrefix, 103 | this.givenName, 104 | this.middleName, 105 | this.familyName, 106 | this.nameSuffix, 107 | this.nickname, 108 | }); 109 | 110 | factory PersonNameComponents.fromMap(Map map) { 111 | if (map == null) { 112 | return PersonNameComponents(); 113 | } 114 | 115 | return PersonNameComponents( 116 | namePrefix: map['namePrefix'], 117 | givenName: map['givenName'], 118 | middleName: map['middleName'], 119 | familyName: map['familyName'], 120 | nameSuffix: map['nameSuffix'], 121 | nickname: map['nickname'], 122 | ); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /example/lib/sign_in_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:apple_sign_in_example/button_test/button_test_page.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_secure_storage/flutter_secure_storage.dart'; 5 | import 'package:apple_sign_in/apple_sign_in.dart'; 6 | import 'secret_members_only_page.dart'; 7 | 8 | class SignInPage extends StatefulWidget { 9 | @override 10 | State createState() => _SignInPageState(); 11 | } 12 | 13 | class _SignInPageState extends State { 14 | final Future _isAvailableFuture = AppleSignIn.isAvailable(); 15 | 16 | String errorMessage; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | checkLoggedInState(); 22 | 23 | AppleSignIn.onCredentialRevoked.listen((_) { 24 | print("Credentials revoked"); 25 | }); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | appBar: AppBar( 32 | title: const Text('Sign In with Apple Example App'), 33 | ), 34 | backgroundColor: Colors.grey, 35 | body: SingleChildScrollView( 36 | child: Center( 37 | child: SizedBox( 38 | width: 280, 39 | child: FutureBuilder( 40 | future: _isAvailableFuture, 41 | builder: (context, isAvailableSnapshot) { 42 | if (!isAvailableSnapshot.hasData) { 43 | return Container(child: Text('Loading...')); 44 | } 45 | 46 | return isAvailableSnapshot.data 47 | ? Column( 48 | mainAxisAlignment: MainAxisAlignment.center, 49 | crossAxisAlignment: CrossAxisAlignment.center, 50 | children: [ 51 | SizedBox( 52 | height: 10, 53 | ), 54 | AppleSignInButton( 55 | onPressed: logIn, 56 | ), 57 | if (errorMessage != null) Text(errorMessage), 58 | SizedBox( 59 | height: 500, 60 | ), 61 | RaisedButton( 62 | child: Text("Button Test Page"), 63 | onPressed: () { 64 | Navigator.push( 65 | context, 66 | MaterialPageRoute( 67 | builder: (_) => 68 | ButtonTestPage())); 69 | }, 70 | ) 71 | ]) 72 | : Text( 73 | 'Sign in With Apple not available. Must be run on iOS 13+'); 74 | }, 75 | )))), 76 | ); 77 | } 78 | 79 | void logIn() async { 80 | final AuthorizationResult result = await AppleSignIn.performRequests([ 81 | AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName]) 82 | ]); 83 | 84 | switch (result.status) { 85 | case AuthorizationStatus.authorized: 86 | 87 | // Store user ID 88 | await FlutterSecureStorage() 89 | .write(key: "userId", value: result.credential.user); 90 | 91 | // Navigate to secret page (shhh!) 92 | Navigator.of(context).pushReplacement(MaterialPageRoute( 93 | builder: (_) => 94 | SecretMembersOnlyPage(credential: result.credential))); 95 | break; 96 | 97 | case AuthorizationStatus.error: 98 | print("Sign in failed: ${result.error.localizedDescription}"); 99 | setState(() { 100 | errorMessage = "Sign in failed 😿"; 101 | }); 102 | break; 103 | 104 | case AuthorizationStatus.cancelled: 105 | print('User cancelled'); 106 | break; 107 | } 108 | } 109 | 110 | void checkLoggedInState() async { 111 | final userId = await FlutterSecureStorage().read(key: "userId"); 112 | if (userId == null) { 113 | print("No stored user ID"); 114 | return; 115 | } 116 | 117 | final credentialState = await AppleSignIn.getCredentialState(userId); 118 | switch (credentialState.status) { 119 | case CredentialStatus.authorized: 120 | print("getCredentialState returned authorized"); 121 | break; 122 | 123 | case CredentialStatus.error: 124 | print( 125 | "getCredentialState returned an error: ${credentialState.error.localizedDescription}"); 126 | break; 127 | 128 | case CredentialStatus.revoked: 129 | print("getCredentialState returned revoked"); 130 | break; 131 | 132 | case CredentialStatus.notFound: 133 | print("getCredentialState returned not found"); 134 | break; 135 | 136 | case CredentialStatus.transferred: 137 | print("getCredentialState returned not transferred"); 138 | break; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /ios/Classes/AppleSignInPlugin.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "AppleSignInPlugin.h" 3 | #import "AppleIDButtonFactory.h" 4 | #import "AuthorizationControllerDelegate.h" 5 | #import "Converters/NSErrorConverter.h" 6 | #import "Converters/CredentialConverter.h" 7 | 8 | @implementation AppleSignInPlugin 9 | { 10 | FlutterEventSink _eventSink; 11 | } 12 | 13 | typedef void(^CredentialStateCompletionBlock)(ASAuthorizationAppleIDProviderCredentialState credentialState, NSError * _Nullable error) API_AVAILABLE(ios(13.0)); 14 | 15 | + (void)registerWithRegistrar:(NSObject*)registrar { 16 | AppleIDButtonFactory* appleIdButtonFactory = [[AppleIDButtonFactory alloc] initWithMessenger:registrar.messenger]; 17 | [registrar registerViewFactory:appleIdButtonFactory 18 | withId:@"dev.gilder.tom/apple_id_button"]; 19 | 20 | FlutterMethodChannel* methodChannel = [FlutterMethodChannel methodChannelWithName:@"dev.gilder.tom/apple_sign_in" 21 | binaryMessenger:[registrar messenger]]; 22 | 23 | FlutterEventChannel* eventChannel = [FlutterEventChannel eventChannelWithName:@"dev.gilder.tom/apple_sign_in_events" 24 | binaryMessenger:[registrar messenger]]; 25 | 26 | AppleSignInPlugin* plugin = [[AppleSignInPlugin alloc] init]; 27 | [registrar addMethodCallDelegate:plugin channel:methodChannel]; 28 | [eventChannel setStreamHandler:plugin]; 29 | } 30 | 31 | - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { 32 | if (@available(iOS 13.0, *)) { 33 | if ([call.method isEqualToString:@"isAvailable"]) { 34 | result(@{@"isAvailable": @(true)}); 35 | return; 36 | } 37 | else if ([call.method isEqualToString:@"performRequests"]) { 38 | [self performRequests:call result:result]; 39 | return; 40 | } else if ([call.method isEqualToString:@"getCredentialState"]) { 41 | [self getCredentialState:call result:result]; 42 | return; 43 | } 44 | } else { 45 | if ([call.method isEqualToString:@"isAvailable"]) { 46 | result(@{@"isAvailable": @(false)}); 47 | return; 48 | } 49 | } 50 | 51 | result(FlutterMethodNotImplemented); 52 | } 53 | 54 | - (void)performRequests:(FlutterMethodCall*)call result:(FlutterResult)result API_AVAILABLE(ios(13.0)) { 55 | NSArray* requestsInput = call.arguments[@"requests"]; 56 | NSMutableArray* requests = [[NSMutableArray alloc] initWithCapacity:[requestsInput count]]; 57 | 58 | for (NSDictionary* request in requestsInput) { 59 | if ([request[@"requestType"] isEqualToString:@"AppleIdRequest"]) { 60 | [requests addObject:[self createAppleIDRequest:request]]; 61 | } 62 | } 63 | 64 | __block AuthorizationControllerDelegate* delegate; 65 | delegate = [[AuthorizationControllerDelegate alloc] initWithCompletion:^(NSDictionary *delegateResult) { 66 | result(delegateResult); 67 | delegate = nil; 68 | }]; 69 | ASAuthorizationController *controller = [[ASAuthorizationController alloc] initWithAuthorizationRequests:requests]; 70 | controller.delegate = (id)delegate; 71 | [controller performRequests]; 72 | } 73 | 74 | - (ASAuthorizationAppleIDRequest*)createAppleIDRequest:(NSDictionary*)args API_AVAILABLE(ios(13.0)) { 75 | ASAuthorizationAppleIDProvider* appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init]; 76 | ASAuthorizationAppleIDRequest* request = [appleIDProvider createRequest]; 77 | request.requestedScopes = args[@"requestedScopes"]; 78 | return request; 79 | } 80 | 81 | - (void)getCredentialState:(FlutterMethodCall*)call result:(FlutterResult)result API_AVAILABLE(ios(13.0)) { 82 | CredentialStateCompletionBlock completion = ^(ASAuthorizationAppleIDProviderCredentialState credentialState, NSError * _Nullable error) { 83 | if (error != nil) { 84 | result(@{ 85 | @"credentialState": @"error", 86 | @"error": [NSErrorConverter dictionaryFromError:error] 87 | }); 88 | } else { 89 | result(@{@"credentialState": [CredentialConverter stringForCredentialState:credentialState]}); 90 | } 91 | }; 92 | 93 | ASAuthorizationAppleIDProvider* provider = [[ASAuthorizationAppleIDProvider alloc] init]; 94 | [provider getCredentialStateForUserID:call.arguments[@"userId"] 95 | completion:completion]; 96 | } 97 | 98 | 99 | #pragma mark Credentials revoked FlutterStreamHandler 100 | 101 | - (FlutterError*)onListenWithArguments:(id)arguments 102 | eventSink:(FlutterEventSink)eventSink { 103 | if (@available(iOS 13.0, *)) { 104 | _eventSink = eventSink; 105 | [[NSNotificationCenter defaultCenter] addObserver:self 106 | selector:@selector(onCredentialRevokedNotification:) 107 | name:ASAuthorizationAppleIDProviderCredentialRevokedNotification 108 | object:nil]; 109 | } 110 | 111 | return nil; 112 | } 113 | 114 | - (FlutterError*)onCancelWithArguments:(id)arguments { 115 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 116 | _eventSink = nil; 117 | return nil; 118 | } 119 | 120 | - (void)onCredentialRevokedNotification:(NSNotification *)notification API_AVAILABLE(ios(13.0)) { 121 | if (_eventSink != nil) { 122 | _eventSink(ASAuthorizationAppleIDProviderCredentialRevokedNotification); 123 | } 124 | } 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /lib/apple_sign_in_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// A type for the authorization button. 4 | enum ButtonType { defaultButton, continueButton, signIn } 5 | 6 | /// A style for the authorization button. 7 | enum ButtonStyle { black, whiteOutline, white } 8 | 9 | /// A button for Sign in With Apple 10 | class AppleSignInButton extends StatefulWidget { 11 | /// The callback that is called when the button is tapped or otherwise activated. 12 | /// 13 | /// If this is set to null, the button will be disabled. 14 | final VoidCallback onPressed; 15 | 16 | /// A type for the authorization button. 17 | final ButtonType type; 18 | 19 | /// A style for the authorization button. 20 | final ButtonStyle style; 21 | 22 | /// A custom corner radius to be used by this button. 23 | final double cornerRadius; 24 | 25 | const AppleSignInButton({ 26 | this.onPressed, 27 | this.type = ButtonType.defaultButton, 28 | this.style = ButtonStyle.white, 29 | this.cornerRadius = 6, 30 | }) : assert(type != null), 31 | assert(style != null), 32 | assert(cornerRadius != null); 33 | 34 | @override 35 | State createState() => _AppleSignInButtonState(); 36 | } 37 | 38 | class _AppleSignInButtonState extends State { 39 | bool _isTapDown = false; 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | final bgColor = 44 | widget.style == ButtonStyle.black ? Colors.black : Colors.white; 45 | final textColor = 46 | widget.style == ButtonStyle.black ? Colors.white : Colors.black; 47 | final borderColor = 48 | widget.style == ButtonStyle.white ? Colors.white : Colors.black; 49 | 50 | return GestureDetector( 51 | onTapDown: (_) => setState(() => _isTapDown = true), 52 | onTapUp: (_) { 53 | setState(() => _isTapDown = false); 54 | widget?.onPressed(); 55 | }, 56 | onTapCancel: () => setState(() => _isTapDown = false), 57 | child: AnimatedContainer( 58 | duration: Duration(milliseconds: 100), 59 | constraints: BoxConstraints( 60 | minHeight: 32, 61 | maxHeight: 64, 62 | minWidth: 200, 63 | ), 64 | height: 50, 65 | decoration: BoxDecoration( 66 | color: _isTapDown ? Colors.grey : bgColor, 67 | borderRadius: BorderRadius.all( 68 | Radius.circular(widget.cornerRadius), 69 | ), 70 | border: Border.all(width: .7, color: borderColor), 71 | ), 72 | child: Center( 73 | child: Row( 74 | mainAxisSize: MainAxisSize.min, 75 | children: [ 76 | Padding( 77 | padding: const EdgeInsets.only(bottom: 1, left: 2, right: 6), 78 | child: SizedBox( 79 | height: 14, 80 | child: AspectRatio( 81 | aspectRatio: 25 / 31, 82 | child: CustomPaint( 83 | painter: _AppleLogoPainter(color: textColor), 84 | ), 85 | ), 86 | ), 87 | ), 88 | Text( 89 | widget.type == ButtonType.continueButton 90 | ? 'Continue with Apple' 91 | : 'Sign in with Apple', 92 | style: TextStyle( 93 | fontSize: 20, 94 | fontWeight: FontWeight.w500, 95 | letterSpacing: .3, 96 | wordSpacing: -.5, 97 | color: textColor, 98 | ), 99 | ), 100 | ], 101 | )), 102 | ), 103 | ); 104 | } 105 | } 106 | 107 | class _AppleLogoPainter extends CustomPainter { 108 | final Color color; 109 | 110 | _AppleLogoPainter({@required this.color}); 111 | 112 | @override 113 | void paint(Canvas canvas, Size size) { 114 | final paint = Paint()..color = color; 115 | canvas.drawPath(_getApplePath(size.width, size.height), paint); 116 | } 117 | 118 | static Path _getApplePath(double w, double h) { 119 | return Path() 120 | ..moveTo(w * .50779, h * .28732) 121 | ..cubicTo( 122 | w * .4593, h * .28732, w * .38424, h * .24241, w * .30519, h * .24404) 123 | ..cubicTo( 124 | w * .2009, h * .24512, w * .10525, h * .29328, w * .05145, h * .36957) 125 | ..cubicTo(w * -.05683, h * .5227, w * .02355, h * .74888, w * .12916, 126 | h * .87333) 127 | ..cubicTo(w * .18097, h * .93394, w * .24209, h * 1.00211, w * .32313, 128 | h * .99995) 129 | ..cubicTo(w * .40084, h * .99724, w * .43007, h * .95883, w * .52439, 130 | h * .95883) 131 | ..cubicTo(w * .61805, h * .95883, w * .64462, h * .99995, w * .72699, 132 | h * .99833) 133 | ..cubicTo( 134 | w * .81069, h * .99724, w * .86383, h * .93664, w * .91498, h * .8755) 135 | ..cubicTo( 136 | w * .97409, h * .80515, w * .99867, h * .73698, w * 1, h * .73319) 137 | ..cubicTo(w * .99801, h * .73265, w * .83726, h * .68233, w * .83526, 138 | h * .53082) 139 | ..cubicTo( 140 | w * .83394, h * .4042, w * .96214, h * .3436, w * .96812, h * .34089) 141 | ..cubicTo( 142 | w * .89505, h * .25378, w * .78279, h * .24404, w * .7436, h * .24187) 143 | ..cubicTo( 144 | w * .6413, h * .23538, w * .55561, h * .28732, w * .50779, h * .28732) 145 | ..close() 146 | ..moveTo(w * .68049, h * .15962) 147 | ..cubicTo(w * .72367, h * .11742, w * .75223, h * .05844, w * .74426, 0) 148 | ..cubicTo(w * .68249, h * .00216, w * .60809, h * .03355, w * .56359, 149 | h * .07575) 150 | ..cubicTo(w * .52373, h * .11309, w * .48919, h * .17315, w * .49849, 151 | h * .23051) 152 | ..cubicTo(w * .56691, h * .23484, w * .63732, h * .20183, w * .68049, 153 | h * .15962) 154 | ..close(); 155 | } 156 | 157 | @override 158 | bool shouldRepaint(CustomPainter oldDelegate) => false; 159 | } 160 | -------------------------------------------------------------------------------- /lib/apple_sign_in.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | import 'package:flutter/services.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | import 'apple_id_credential.dart'; 6 | import 'apple_id_request.dart'; 7 | export 'scope.dart'; 8 | export 'apple_id_request.dart'; 9 | export 'apple_id_credential.dart'; 10 | export 'open_id_operation.dart'; 11 | export 'apple_sign_in_button.dart'; 12 | 13 | class AppleSignIn { 14 | static const MethodChannel _methodChannel = 15 | const MethodChannel('dev.gilder.tom/apple_sign_in'); 16 | static const EventChannel _eventChannel = 17 | const EventChannel('dev.gilder.tom/apple_sign_in_events'); 18 | 19 | static const _errorCodeCancelled = 1001; 20 | 21 | static Stream _onCredentialRevoked; 22 | 23 | /// A stream that emits an event when Apple ID credentials have been revoked. 24 | static Stream get onCredentialRevoked { 25 | if (_onCredentialRevoked == null) { 26 | _onCredentialRevoked = _eventChannel.receiveBroadcastStream(); 27 | } 28 | 29 | return _onCredentialRevoked; 30 | } 31 | 32 | /// Starts the authorization flow requests provided. 33 | /// Currently the only supported request type is [AppleIdRequest]. 34 | /// 35 | /// ```dart 36 | /// final AuthorizationResult result = await AppleSignIn.performRequests([ 37 | /// AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName]) 38 | /// ]); 39 | /// ``` 40 | static Future performRequests( 41 | List requests) async { 42 | final result = await _methodChannel.invokeMethod( 43 | 'performRequests', 44 | {'requests': requests.map((request) => request.toMap()).toList()}, 45 | ); 46 | final status = result['status']; 47 | 48 | switch (status) { 49 | case 'authorized': 50 | return _makeAuthorizationResult(result); 51 | break; 52 | 53 | case 'error': 54 | final error = NsError.fromMap(result['error']); 55 | 56 | if (error.code == _errorCodeCancelled) { 57 | return AuthorizationResult( 58 | status: AuthorizationStatus.cancelled, 59 | ); 60 | } 61 | 62 | return AuthorizationResult( 63 | status: AuthorizationStatus.error, 64 | error: NsError.fromMap(result['error'])); 65 | break; 66 | } 67 | 68 | throw "performRequests: Unknown status returned: '$status'"; 69 | } 70 | 71 | /// Returns the credential state for the given user. Returns a [CredentialState]. 72 | static Future getCredentialState(String userId) async { 73 | assert(userId != null, 'Must provide userId'); 74 | 75 | final result = await _methodChannel 76 | .invokeMethod('getCredentialState', {'userId': userId}); 77 | final credentialState = result['credentialState']; 78 | 79 | switch (credentialState) { 80 | case 'error': 81 | return CredentialState( 82 | status: CredentialStatus.error, 83 | error: NsError.fromMap(result['error'])); 84 | 85 | case 'revoked': 86 | return CredentialState(status: CredentialStatus.revoked); 87 | 88 | case 'authorized': 89 | return CredentialState(status: CredentialStatus.authorized); 90 | 91 | case 'notFound': 92 | return CredentialState(status: CredentialStatus.notFound); 93 | 94 | case 'transferred': 95 | return CredentialState(status: CredentialStatus.transferred); 96 | } 97 | 98 | throw "Unknown credentialState: '$credentialState'"; 99 | } 100 | 101 | /// Determine if Sign In with Apple is supported on the current device 102 | static Future isAvailable() async { 103 | if (!Platform.isIOS) { 104 | return false; 105 | } 106 | 107 | final result = await _methodChannel.invokeMethod('isAvailable'); 108 | final isAvailable = result['isAvailable'] == 1; 109 | assert(isAvailable != null); 110 | return isAvailable; 111 | } 112 | 113 | static AuthorizationResult _makeAuthorizationResult(Map params) { 114 | switch (params['credentialType']) { 115 | case 'ASAuthorizationAppleIDCredential': 116 | final Map credential = params['credential']; 117 | assert(credential != null); 118 | 119 | return AuthorizationResult( 120 | status: AuthorizationStatus.authorized, 121 | credential: AppleIdCredential.fromMap(credential)); 122 | 123 | break; 124 | 125 | default: 126 | throw 'Unknown credentials type'; 127 | } 128 | } 129 | } 130 | 131 | @immutable 132 | class CredentialState { 133 | final CredentialStatus status; 134 | 135 | final NsError error; 136 | 137 | const CredentialState({@required this.status, this.error}); 138 | } 139 | 140 | @immutable 141 | class NsError { 142 | final int code; 143 | 144 | final String domain; 145 | 146 | final String localizedDescription; 147 | 148 | final String localizedRecoverySuggestion; 149 | 150 | final String localizedFailureReason; 151 | 152 | @override 153 | String toString() => localizedDescription; 154 | 155 | const NsError( 156 | {this.code, 157 | this.domain, 158 | this.localizedDescription, 159 | this.localizedRecoverySuggestion, 160 | this.localizedFailureReason}); 161 | 162 | factory NsError.fromMap(Map map) { 163 | assert(map != null); 164 | 165 | return NsError( 166 | code: map['code'], 167 | domain: map['domain'], 168 | localizedDescription: map['localizedDescription'], 169 | localizedRecoverySuggestion: map['localizedRecoverySuggestion'], 170 | localizedFailureReason: map['localizedFailureReason'], 171 | ); 172 | } 173 | } 174 | 175 | // Possible values for the credential state of a user. 176 | enum CredentialStatus { 177 | // Authorization for the given user has been revoked. 178 | revoked, 179 | 180 | /// The user is authorized. 181 | authorized, 182 | 183 | /// The user can’t be found. 184 | notFound, 185 | 186 | transferred, 187 | 188 | error 189 | } 190 | 191 | /// The result of an [AppleIdRequest] request. 192 | @immutable 193 | class AuthorizationResult { 194 | final AuthorizationStatus status; 195 | 196 | final AppleIdCredential credential; 197 | 198 | final NsError error; 199 | 200 | const AuthorizationResult({ 201 | @required this.status, 202 | this.credential, 203 | this.error, 204 | }); 205 | } 206 | 207 | enum AuthorizationStatus { authorized, cancelled, error } 208 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 6424C87AF993A0F18AB819AB /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C3CBAE930F35752B0BD44F35 /* libPods-Runner.a */; }; 15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 18 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 19 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 20 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 21 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXCopyFilesBuildPhase section */ 25 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 26 | isa = PBXCopyFilesBuildPhase; 27 | buildActionMask = 2147483647; 28 | dstPath = ""; 29 | dstSubfolderSpec = 10; 30 | files = ( 31 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 32 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 33 | ); 34 | name = "Embed Frameworks"; 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXCopyFilesBuildPhase section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 41 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 42 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 43 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 44 | 6779EEE4F5C26118B78296A7 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 45 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 46 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 47 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 48 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 49 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 50 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 51 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 53 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 54 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 55 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 56 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | A86D434E578A04D45E51E330 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 58 | C3CBAE930F35752B0BD44F35 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | D3CF30CFB2EF563721EFE3F5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 60 | E2153ABA22BD01850082EC63 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 61 | /* End PBXFileReference section */ 62 | 63 | /* Begin PBXFrameworksBuildPhase section */ 64 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 69 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 70 | 6424C87AF993A0F18AB819AB /* libPods-Runner.a in Frameworks */, 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | /* End PBXFrameworksBuildPhase section */ 75 | 76 | /* Begin PBXGroup section */ 77 | 7D040D1FCE5611D8EFF1B91F /* Frameworks */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | C3CBAE930F35752B0BD44F35 /* libPods-Runner.a */, 81 | ); 82 | name = Frameworks; 83 | sourceTree = ""; 84 | }; 85 | 9740EEB11CF90186004384FC /* Flutter */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 3B80C3931E831B6300D905FE /* App.framework */, 89 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 90 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 91 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 92 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 93 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 94 | ); 95 | name = Flutter; 96 | sourceTree = ""; 97 | }; 98 | 97C146E51CF9000F007C117D = { 99 | isa = PBXGroup; 100 | children = ( 101 | 9740EEB11CF90186004384FC /* Flutter */, 102 | 97C146F01CF9000F007C117D /* Runner */, 103 | 97C146EF1CF9000F007C117D /* Products */, 104 | BC83A710045C009E46926226 /* Pods */, 105 | 7D040D1FCE5611D8EFF1B91F /* Frameworks */, 106 | ); 107 | sourceTree = ""; 108 | }; 109 | 97C146EF1CF9000F007C117D /* Products */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 97C146EE1CF9000F007C117D /* Runner.app */, 113 | ); 114 | name = Products; 115 | sourceTree = ""; 116 | }; 117 | 97C146F01CF9000F007C117D /* Runner */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | E2153ABA22BD01850082EC63 /* Runner.entitlements */, 121 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 122 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 123 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 124 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 125 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 126 | 97C147021CF9000F007C117D /* Info.plist */, 127 | 97C146F11CF9000F007C117D /* Supporting Files */, 128 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 129 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 130 | ); 131 | path = Runner; 132 | sourceTree = ""; 133 | }; 134 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 97C146F21CF9000F007C117D /* main.m */, 138 | ); 139 | name = "Supporting Files"; 140 | sourceTree = ""; 141 | }; 142 | BC83A710045C009E46926226 /* Pods */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 6779EEE4F5C26118B78296A7 /* Pods-Runner.debug.xcconfig */, 146 | D3CF30CFB2EF563721EFE3F5 /* Pods-Runner.release.xcconfig */, 147 | A86D434E578A04D45E51E330 /* Pods-Runner.profile.xcconfig */, 148 | ); 149 | path = Pods; 150 | sourceTree = ""; 151 | }; 152 | /* End PBXGroup section */ 153 | 154 | /* Begin PBXNativeTarget section */ 155 | 97C146ED1CF9000F007C117D /* Runner */ = { 156 | isa = PBXNativeTarget; 157 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 158 | buildPhases = ( 159 | B0AF2136156D6F087218A811 /* [CP] Check Pods Manifest.lock */, 160 | 9740EEB61CF901F6004384FC /* Run Script */, 161 | 97C146EA1CF9000F007C117D /* Sources */, 162 | 97C146EB1CF9000F007C117D /* Frameworks */, 163 | 97C146EC1CF9000F007C117D /* Resources */, 164 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 165 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 166 | FB7CB0B8310BF0AFC4884F3D /* [CP] Embed Pods Frameworks */, 167 | ); 168 | buildRules = ( 169 | ); 170 | dependencies = ( 171 | ); 172 | name = Runner; 173 | productName = Runner; 174 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 175 | productType = "com.apple.product-type.application"; 176 | }; 177 | /* End PBXNativeTarget section */ 178 | 179 | /* Begin PBXProject section */ 180 | 97C146E61CF9000F007C117D /* Project object */ = { 181 | isa = PBXProject; 182 | attributes = { 183 | LastUpgradeCheck = 1100; 184 | ORGANIZATIONNAME = "The Chromium Authors"; 185 | TargetAttributes = { 186 | 97C146ED1CF9000F007C117D = { 187 | CreatedOnToolsVersion = 7.3.1; 188 | DevelopmentTeam = K87JJRK2CF; 189 | }; 190 | }; 191 | }; 192 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 193 | compatibilityVersion = "Xcode 3.2"; 194 | developmentRegion = en; 195 | hasScannedForEncodings = 0; 196 | knownRegions = ( 197 | en, 198 | Base, 199 | ); 200 | mainGroup = 97C146E51CF9000F007C117D; 201 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 202 | projectDirPath = ""; 203 | projectRoot = ""; 204 | targets = ( 205 | 97C146ED1CF9000F007C117D /* Runner */, 206 | ); 207 | }; 208 | /* End PBXProject section */ 209 | 210 | /* Begin PBXResourcesBuildPhase section */ 211 | 97C146EC1CF9000F007C117D /* Resources */ = { 212 | isa = PBXResourcesBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 216 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 217 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 218 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | /* End PBXResourcesBuildPhase section */ 223 | 224 | /* Begin PBXShellScriptBuildPhase section */ 225 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 226 | isa = PBXShellScriptBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | ); 230 | inputPaths = ( 231 | ); 232 | name = "Thin Binary"; 233 | outputPaths = ( 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | shellPath = /bin/sh; 237 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 238 | }; 239 | 9740EEB61CF901F6004384FC /* Run Script */ = { 240 | isa = PBXShellScriptBuildPhase; 241 | buildActionMask = 2147483647; 242 | files = ( 243 | ); 244 | inputPaths = ( 245 | ); 246 | name = "Run Script"; 247 | outputPaths = ( 248 | ); 249 | runOnlyForDeploymentPostprocessing = 0; 250 | shellPath = /bin/sh; 251 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; 252 | }; 253 | B0AF2136156D6F087218A811 /* [CP] Check Pods Manifest.lock */ = { 254 | isa = PBXShellScriptBuildPhase; 255 | buildActionMask = 2147483647; 256 | files = ( 257 | ); 258 | inputFileListPaths = ( 259 | ); 260 | inputPaths = ( 261 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 262 | "${PODS_ROOT}/Manifest.lock", 263 | ); 264 | name = "[CP] Check Pods Manifest.lock"; 265 | outputFileListPaths = ( 266 | ); 267 | outputPaths = ( 268 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 269 | ); 270 | runOnlyForDeploymentPostprocessing = 0; 271 | shellPath = /bin/sh; 272 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 273 | showEnvVarsInLog = 0; 274 | }; 275 | FB7CB0B8310BF0AFC4884F3D /* [CP] Embed Pods Frameworks */ = { 276 | isa = PBXShellScriptBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | ); 280 | inputPaths = ( 281 | ); 282 | name = "[CP] Embed Pods Frameworks"; 283 | outputPaths = ( 284 | ); 285 | runOnlyForDeploymentPostprocessing = 0; 286 | shellPath = /bin/sh; 287 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 288 | showEnvVarsInLog = 0; 289 | }; 290 | /* End PBXShellScriptBuildPhase section */ 291 | 292 | /* Begin PBXSourcesBuildPhase section */ 293 | 97C146EA1CF9000F007C117D /* Sources */ = { 294 | isa = PBXSourcesBuildPhase; 295 | buildActionMask = 2147483647; 296 | files = ( 297 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 298 | 97C146F31CF9000F007C117D /* main.m in Sources */, 299 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | /* End PBXSourcesBuildPhase section */ 304 | 305 | /* Begin PBXVariantGroup section */ 306 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 307 | isa = PBXVariantGroup; 308 | children = ( 309 | 97C146FB1CF9000F007C117D /* Base */, 310 | ); 311 | name = Main.storyboard; 312 | sourceTree = ""; 313 | }; 314 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 315 | isa = PBXVariantGroup; 316 | children = ( 317 | 97C147001CF9000F007C117D /* Base */, 318 | ); 319 | name = LaunchScreen.storyboard; 320 | sourceTree = ""; 321 | }; 322 | /* End PBXVariantGroup section */ 323 | 324 | /* Begin XCBuildConfiguration section */ 325 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 326 | isa = XCBuildConfiguration; 327 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 328 | buildSettings = { 329 | ALWAYS_SEARCH_USER_PATHS = NO; 330 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 331 | CLANG_ANALYZER_NONNULL = YES; 332 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 333 | CLANG_CXX_LIBRARY = "libc++"; 334 | CLANG_ENABLE_MODULES = YES; 335 | CLANG_ENABLE_OBJC_ARC = YES; 336 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 337 | CLANG_WARN_BOOL_CONVERSION = YES; 338 | CLANG_WARN_COMMA = YES; 339 | CLANG_WARN_CONSTANT_CONVERSION = YES; 340 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 341 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 342 | CLANG_WARN_EMPTY_BODY = YES; 343 | CLANG_WARN_ENUM_CONVERSION = YES; 344 | CLANG_WARN_INFINITE_RECURSION = YES; 345 | CLANG_WARN_INT_CONVERSION = YES; 346 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 347 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 348 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 349 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 350 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 351 | CLANG_WARN_STRICT_PROTOTYPES = YES; 352 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 353 | CLANG_WARN_UNREACHABLE_CODE = YES; 354 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 355 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 356 | COPY_PHASE_STRIP = NO; 357 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 358 | ENABLE_NS_ASSERTIONS = NO; 359 | ENABLE_STRICT_OBJC_MSGSEND = YES; 360 | GCC_C_LANGUAGE_STANDARD = gnu99; 361 | GCC_NO_COMMON_BLOCKS = YES; 362 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 363 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 364 | GCC_WARN_UNDECLARED_SELECTOR = YES; 365 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 366 | GCC_WARN_UNUSED_FUNCTION = YES; 367 | GCC_WARN_UNUSED_VARIABLE = YES; 368 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 369 | MTL_ENABLE_DEBUG_INFO = NO; 370 | SDKROOT = iphoneos; 371 | TARGETED_DEVICE_FAMILY = "1,2"; 372 | VALIDATE_PRODUCT = YES; 373 | }; 374 | name = Profile; 375 | }; 376 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 377 | isa = XCBuildConfiguration; 378 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 379 | buildSettings = { 380 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 381 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 382 | CURRENT_PROJECT_VERSION = 1; 383 | DEVELOPMENT_TEAM = K87JJRK2CF; 384 | ENABLE_BITCODE = NO; 385 | FRAMEWORK_SEARCH_PATHS = ( 386 | "$(inherited)", 387 | "$(PROJECT_DIR)/Flutter", 388 | ); 389 | INFOPLIST_FILE = Runner/Info.plist; 390 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 391 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 392 | LIBRARY_SEARCH_PATHS = ( 393 | "$(inherited)", 394 | "$(PROJECT_DIR)/Flutter", 395 | ); 396 | MARKETING_VERSION = 1; 397 | PRODUCT_BUNDLE_IDENTIFIER = dev.gilder.tom.appleSignIn; 398 | PRODUCT_NAME = "$(TARGET_NAME)"; 399 | VERSIONING_SYSTEM = "apple-generic"; 400 | }; 401 | name = Profile; 402 | }; 403 | 97C147031CF9000F007C117D /* Debug */ = { 404 | isa = XCBuildConfiguration; 405 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 406 | buildSettings = { 407 | ALWAYS_SEARCH_USER_PATHS = NO; 408 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 409 | CLANG_ANALYZER_NONNULL = YES; 410 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 411 | CLANG_CXX_LIBRARY = "libc++"; 412 | CLANG_ENABLE_MODULES = YES; 413 | CLANG_ENABLE_OBJC_ARC = YES; 414 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 415 | CLANG_WARN_BOOL_CONVERSION = YES; 416 | CLANG_WARN_COMMA = YES; 417 | CLANG_WARN_CONSTANT_CONVERSION = YES; 418 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 419 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 420 | CLANG_WARN_EMPTY_BODY = YES; 421 | CLANG_WARN_ENUM_CONVERSION = YES; 422 | CLANG_WARN_INFINITE_RECURSION = YES; 423 | CLANG_WARN_INT_CONVERSION = YES; 424 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 425 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 426 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 427 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 428 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 429 | CLANG_WARN_STRICT_PROTOTYPES = YES; 430 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 431 | CLANG_WARN_UNREACHABLE_CODE = YES; 432 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 433 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 434 | COPY_PHASE_STRIP = NO; 435 | DEBUG_INFORMATION_FORMAT = dwarf; 436 | ENABLE_STRICT_OBJC_MSGSEND = YES; 437 | ENABLE_TESTABILITY = YES; 438 | GCC_C_LANGUAGE_STANDARD = gnu99; 439 | GCC_DYNAMIC_NO_PIC = NO; 440 | GCC_NO_COMMON_BLOCKS = YES; 441 | GCC_OPTIMIZATION_LEVEL = 0; 442 | GCC_PREPROCESSOR_DEFINITIONS = ( 443 | "DEBUG=1", 444 | "$(inherited)", 445 | ); 446 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 447 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 448 | GCC_WARN_UNDECLARED_SELECTOR = YES; 449 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 450 | GCC_WARN_UNUSED_FUNCTION = YES; 451 | GCC_WARN_UNUSED_VARIABLE = YES; 452 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 453 | MTL_ENABLE_DEBUG_INFO = YES; 454 | ONLY_ACTIVE_ARCH = YES; 455 | SDKROOT = iphoneos; 456 | TARGETED_DEVICE_FAMILY = "1,2"; 457 | }; 458 | name = Debug; 459 | }; 460 | 97C147041CF9000F007C117D /* Release */ = { 461 | isa = XCBuildConfiguration; 462 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 463 | buildSettings = { 464 | ALWAYS_SEARCH_USER_PATHS = NO; 465 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 466 | CLANG_ANALYZER_NONNULL = YES; 467 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 468 | CLANG_CXX_LIBRARY = "libc++"; 469 | CLANG_ENABLE_MODULES = YES; 470 | CLANG_ENABLE_OBJC_ARC = YES; 471 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 472 | CLANG_WARN_BOOL_CONVERSION = YES; 473 | CLANG_WARN_COMMA = YES; 474 | CLANG_WARN_CONSTANT_CONVERSION = YES; 475 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 476 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 477 | CLANG_WARN_EMPTY_BODY = YES; 478 | CLANG_WARN_ENUM_CONVERSION = YES; 479 | CLANG_WARN_INFINITE_RECURSION = YES; 480 | CLANG_WARN_INT_CONVERSION = YES; 481 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 482 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 483 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 484 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 485 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 486 | CLANG_WARN_STRICT_PROTOTYPES = YES; 487 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 488 | CLANG_WARN_UNREACHABLE_CODE = YES; 489 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 490 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 491 | COPY_PHASE_STRIP = NO; 492 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 493 | ENABLE_NS_ASSERTIONS = NO; 494 | ENABLE_STRICT_OBJC_MSGSEND = YES; 495 | GCC_C_LANGUAGE_STANDARD = gnu99; 496 | GCC_NO_COMMON_BLOCKS = YES; 497 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 498 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 499 | GCC_WARN_UNDECLARED_SELECTOR = YES; 500 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 501 | GCC_WARN_UNUSED_FUNCTION = YES; 502 | GCC_WARN_UNUSED_VARIABLE = YES; 503 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 504 | MTL_ENABLE_DEBUG_INFO = NO; 505 | SDKROOT = iphoneos; 506 | TARGETED_DEVICE_FAMILY = "1,2"; 507 | VALIDATE_PRODUCT = YES; 508 | }; 509 | name = Release; 510 | }; 511 | 97C147061CF9000F007C117D /* Debug */ = { 512 | isa = XCBuildConfiguration; 513 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 514 | buildSettings = { 515 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 516 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 517 | CURRENT_PROJECT_VERSION = 1; 518 | DEVELOPMENT_TEAM = K87JJRK2CF; 519 | ENABLE_BITCODE = NO; 520 | FRAMEWORK_SEARCH_PATHS = ( 521 | "$(inherited)", 522 | "$(PROJECT_DIR)/Flutter", 523 | ); 524 | INFOPLIST_FILE = Runner/Info.plist; 525 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 526 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 527 | LIBRARY_SEARCH_PATHS = ( 528 | "$(inherited)", 529 | "$(PROJECT_DIR)/Flutter", 530 | ); 531 | MARKETING_VERSION = 1; 532 | PRODUCT_BUNDLE_IDENTIFIER = dev.gilder.tom.appleSignIn; 533 | PRODUCT_NAME = "$(TARGET_NAME)"; 534 | VERSIONING_SYSTEM = "apple-generic"; 535 | }; 536 | name = Debug; 537 | }; 538 | 97C147071CF9000F007C117D /* Release */ = { 539 | isa = XCBuildConfiguration; 540 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 541 | buildSettings = { 542 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 543 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 544 | CURRENT_PROJECT_VERSION = 1; 545 | DEVELOPMENT_TEAM = K87JJRK2CF; 546 | ENABLE_BITCODE = NO; 547 | FRAMEWORK_SEARCH_PATHS = ( 548 | "$(inherited)", 549 | "$(PROJECT_DIR)/Flutter", 550 | ); 551 | INFOPLIST_FILE = Runner/Info.plist; 552 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 553 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 554 | LIBRARY_SEARCH_PATHS = ( 555 | "$(inherited)", 556 | "$(PROJECT_DIR)/Flutter", 557 | ); 558 | MARKETING_VERSION = 1; 559 | PRODUCT_BUNDLE_IDENTIFIER = dev.gilder.tom.appleSignIn; 560 | PRODUCT_NAME = "$(TARGET_NAME)"; 561 | VERSIONING_SYSTEM = "apple-generic"; 562 | }; 563 | name = Release; 564 | }; 565 | /* End XCBuildConfiguration section */ 566 | 567 | /* Begin XCConfigurationList section */ 568 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 569 | isa = XCConfigurationList; 570 | buildConfigurations = ( 571 | 97C147031CF9000F007C117D /* Debug */, 572 | 97C147041CF9000F007C117D /* Release */, 573 | 249021D3217E4FDB00AE95B9 /* Profile */, 574 | ); 575 | defaultConfigurationIsVisible = 0; 576 | defaultConfigurationName = Release; 577 | }; 578 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 579 | isa = XCConfigurationList; 580 | buildConfigurations = ( 581 | 97C147061CF9000F007C117D /* Debug */, 582 | 97C147071CF9000F007C117D /* Release */, 583 | 249021D4217E4FDB00AE95B9 /* Profile */, 584 | ); 585 | defaultConfigurationIsVisible = 0; 586 | defaultConfigurationName = Release; 587 | }; 588 | /* End XCConfigurationList section */ 589 | }; 590 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 591 | } 592 | --------------------------------------------------------------------------------