Skip to content

Commit c40b48e

Browse files
committed
feat: add sign in with Apple on iOS
1 parent d05d5e5 commit c40b48e

File tree

10 files changed

+131
-15
lines changed

10 files changed

+131
-15
lines changed

ios/Podfile.lock

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ PODS:
4646
- SDWebImage (5.21.0):
4747
- SDWebImage/Core (= 5.21.0)
4848
- SDWebImage/Core (5.21.0)
49+
- sign_in_with_apple (0.0.1):
50+
- Flutter
4951
- SwiftyGif (5.4.5)
5052
- url_launcher_ios (0.0.1):
5153
- Flutter
@@ -57,6 +59,7 @@ DEPENDENCIES:
5759
- flutter_web_auth_2 (from `.symlinks/plugins/flutter_web_auth_2/ios`)
5860
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
5961
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
62+
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
6063
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
6164

6265
SPEC REPOS:
@@ -79,21 +82,24 @@ EXTERNAL SOURCES:
7982
:path: ".symlinks/plugins/package_info_plus/ios"
8083
path_provider_foundation:
8184
:path: ".symlinks/plugins/path_provider_foundation/darwin"
85+
sign_in_with_apple:
86+
:path: ".symlinks/plugins/sign_in_with_apple/ios"
8287
url_launcher_ios:
8388
:path: ".symlinks/plugins/url_launcher_ios/ios"
8489

8590
SPEC CHECKSUMS:
8691
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
8792
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
8893
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
89-
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
94+
file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
9095
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
9196
flutter_web_auth_2: 06d500582775790a0d4c323222fcb6d7990f9603
92-
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
97+
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
9398
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
9499
SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
100+
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
95101
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
96-
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
102+
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
97103

98104
PODFILE CHECKSUM: 4305caec6b40dde0ae97be1573c53de1882a07e5
99105

ios/Runner.xcodeproj/project.pbxproj

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6565
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
6666
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
67+
B027785E2E26C14E00185D39 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
6768
E6C6C9E95AAA2FCE085F1F37 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
6869
/* End PBXFileReference section */
6970

@@ -130,6 +131,7 @@
130131
97C146F01CF9000F007C117D /* Runner */ = {
131132
isa = PBXGroup;
132133
children = (
134+
B027785E2E26C14E00185D39 /* Runner.entitlements */,
133135
97C146FA1CF9000F007C117D /* Main.storyboard */,
134136
97C146FD1CF9000F007C117D /* Assets.xcassets */,
135137
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
@@ -352,14 +354,10 @@
352354
inputFileListPaths = (
353355
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
354356
);
355-
inputPaths = (
356-
);
357357
name = "[CP] Embed Pods Frameworks";
358358
outputFileListPaths = (
359359
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
360360
);
361-
outputPaths = (
362-
);
363361
runOnlyForDeploymentPostprocessing = 0;
364362
shellPath = /bin/sh;
365363
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
@@ -473,6 +471,7 @@
473471
buildSettings = {
474472
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
475473
CLANG_ENABLE_MODULES = YES;
474+
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
476475
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
477476
DEVELOPMENT_TEAM = "";
478477
ENABLE_BITCODE = NO;
@@ -656,6 +655,7 @@
656655
buildSettings = {
657656
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
658657
CLANG_ENABLE_MODULES = YES;
658+
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
659659
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
660660
DEVELOPMENT_TEAM = "";
661661
ENABLE_BITCODE = NO;
@@ -679,6 +679,7 @@
679679
buildSettings = {
680680
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
681681
CLANG_ENABLE_MODULES = YES;
682+
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
682683
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
683684
DEVELOPMENT_TEAM = "";
684685
ENABLE_BITCODE = NO;

ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
2930
shouldUseLaunchSchemeArgsEnv = "YES">
3031
<MacroExpansion>
3132
<BuildableReference
@@ -54,6 +55,7 @@
5455
buildConfiguration = "Debug"
5556
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
5657
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
58+
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
5759
launchStyle = "0"
5860
useCustomWorkingDirectory = "NO"
5961
ignoresPersistentStateOnLaunch = "NO"

ios/Runner/Runner.entitlements

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.developer.applesignin</key>
6+
<array>
7+
<string>Default</string>
8+
</array>
9+
</dict>
10+
</plist>

lib/constants.dart.default

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ const userPassword = '';
66
const databaseId = 'default';
77
const bucketId = 'testBucket';
88
const collectionId = 'usernames';
9+
const signInWithAppleFunctionId = 'sign-in-with-apple';

lib/main.dart

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import 'dart:convert';
2+
import 'dart:io';
23

34
import 'package:appwrite/appwrite.dart';
45
import 'package:appwrite/enums.dart';
56
import 'package:appwrite/models.dart';
67
import 'package:file_picker/file_picker.dart';
78
import 'package:flutter/foundation.dart';
89
import 'package:flutter/material.dart';
9-
import 'package:window_location_href/window_location_href.dart';
10+
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
11+
import 'package:window_location_href/window_location_href.dart' hide Platform;
1012

1113
import 'constants.dart';
1214

@@ -17,6 +19,7 @@ void main() {
1719
Account account = Account(client);
1820
Storage storage = Storage(client);
1921
Databases databases = Databases(client);
22+
Functions functions = Functions(client);
2023

2124
client
2225
.setEndpoint(
@@ -35,6 +38,7 @@ void main() {
3538
account: account,
3639
storage: storage,
3740
database: databases,
41+
functions: functions,
3842
),
3943
),
4044
);
@@ -47,11 +51,13 @@ class Playground extends StatefulWidget {
4751
required this.account,
4852
required this.storage,
4953
required this.database,
54+
required this.functions,
5055
}) : super(key: key);
5156
final Client client;
5257
final Account account;
5358
final Storage storage;
5459
final Databases database;
60+
final Functions functions;
5561

5662
@override
5763
PlaygroundState createState() => PlaygroundState();
@@ -303,8 +309,66 @@ class PlaygroundState extends State<Playground> {
303309
style: TextStyle(color: Colors.white, fontSize: 20.0),
304310
),
305311
),
312+
SizedBox(height: 10.0),
313+
if (!kIsWeb && (Platform.isIOS || Platform.isMacOS))
314+
Padding(
315+
padding: const EdgeInsets.only(bottom: 10.0),
316+
child: SizedBox(
317+
width: 280.0,
318+
child: SignInWithAppleButton(
319+
onPressed: () async {
320+
final credential =
321+
await SignInWithApple.getAppleIDCredential(
322+
scopes: [
323+
AppleIDAuthorizationScopes.email,
324+
AppleIDAuthorizationScopes.fullName,
325+
],
326+
);
306327

307-
const SizedBox(height: 20.0),
328+
print(credential);
329+
330+
// Now send the credential (especially `credential.authorizationCode`) to the server to create a session
331+
// after they have been validated with Apple (see `Integration` section for more information on how to do this)
332+
333+
print(credential.authorizationCode);
334+
335+
final body = {'code': credential.authorizationCode};
336+
337+
if (credential.givenName?.isNotEmpty ?? false) {
338+
body['firstName'] = credential.givenName!;
339+
}
340+
341+
if (credential.familyName?.isNotEmpty ?? false) {
342+
body['lastName'] = credential.familyName!;
343+
}
344+
345+
print(body);
346+
final t0 = DateTime.now();
347+
final execution = await widget.functions.createExecution(
348+
functionId: signInWithAppleFunctionId,
349+
method: ExecutionMethod.pOST,
350+
headers: {'Content-Type': 'application/json'},
351+
body: jsonEncode(body),
352+
);
353+
final t1 = DateTime.now();
354+
print('Execution took: ${t1.difference(t0)}');
355+
356+
print(execution.status);
357+
358+
print(execution.responseBody);
359+
360+
final token = json.decode(execution.responseBody);
361+
362+
await widget.account.createSession(
363+
userId: token['userId'],
364+
secret: token['secret'],
365+
);
366+
367+
_getAccount();
368+
},
369+
),
370+
),
371+
),
308372
const Divider(),
309373
const SizedBox(height: 20.0),
310374
Text(

macos/Flutter/GeneratedPluginRegistrant.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import file_picker
1111
import flutter_web_auth_2
1212
import package_info_plus
1313
import path_provider_foundation
14+
import sign_in_with_apple
1415
import url_launcher_macos
1516
import window_to_front
1617

@@ -21,6 +22,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
2122
FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin"))
2223
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
2324
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
25+
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
2426
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
2527
WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin"))
2628
}

pubspec.lock

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,30 @@ packages:
336336
url: "https://pub.dev"
337337
source: hosted
338338
version: "2.1.8"
339+
sign_in_with_apple:
340+
dependency: "direct main"
341+
description:
342+
name: sign_in_with_apple
343+
sha256: "8bd875c8e8748272749eb6d25b896f768e7e9d60988446d543fe85a37a2392b8"
344+
url: "https://pub.dev"
345+
source: hosted
346+
version: "7.0.1"
347+
sign_in_with_apple_platform_interface:
348+
dependency: transitive
349+
description:
350+
name: sign_in_with_apple_platform_interface
351+
sha256: "981bca52cf3bb9c3ad7ef44aace2d543e5c468bb713fd8dda4275ff76dfa6659"
352+
url: "https://pub.dev"
353+
source: hosted
354+
version: "2.0.0"
355+
sign_in_with_apple_web:
356+
dependency: transitive
357+
description:
358+
name: sign_in_with_apple_web
359+
sha256: f316400827f52cafcf50d00e1a2e8a0abc534ca1264e856a81c5f06bd5b10fed
360+
url: "https://pub.dev"
361+
source: hosted
362+
version: "3.0.0"
339363
sky_engine:
340364
dependency: transitive
341365
description: flutter

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ dependencies:
2424
appwrite: ^17.0.1
2525
file_picker: ^10.2.0
2626
window_location_href: ^1.0.1+2
27+
sign_in_with_apple: ^7.0.1
2728

2829
dev_dependencies:
2930
flutter_test:

test/widget_test.dart

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@ void main() {
1616
Account account = Account(client);
1717
Databases databases = Databases(client);
1818
Storage storage = Storage(client);
19+
Functions functions = Functions(client);
1920
// Build our app and trigger a frame.
20-
await tester.pumpWidget(MaterialApp(
21+
await tester.pumpWidget(
22+
MaterialApp(
2123
home: Playground(
22-
client: client,
23-
account: account,
24-
database: databases,
25-
storage: storage,
26-
)));
24+
client: client,
25+
account: account,
26+
database: databases,
27+
storage: storage,
28+
functions: functions,
29+
),
30+
),
31+
);
2732

2833
expect(find.text('Anonymous Login'), findsOneWidget);
2934
});

0 commit comments

Comments
 (0)