Skip to content

Fix dynamic links #59

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
65BCA432225697F5006B0132 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 65BCA431225697F5006B0132 /* GoogleService-Info.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
Expand All @@ -29,8 +25,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -44,7 +38,6 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
659289A922F326CA00141BCB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
65BCA431225697F5006B0132 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
Expand All @@ -53,7 +46,6 @@
9509D4FB0A3AE83891A59C6C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
Expand All @@ -66,8 +58,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
D86CE457489221BB4884DE05 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -96,9 +86,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
Expand Down Expand Up @@ -260,7 +248,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
554449AE36070DC848C03225 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
Expand Down

This file was deleted.

9 changes: 5 additions & 4 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'package:apple_sign_in/apple_sign_in.dart';
import 'package:firebase_auth_demo_flutter/app/auth_widget_builder.dart';
import 'package:firebase_auth_demo_flutter/app/email_link_error_presenter.dart';
import 'package:firebase_auth_demo_flutter/app/auth_widget.dart';
Expand All @@ -7,6 +6,7 @@ import 'package:firebase_auth_demo_flutter/services/auth_service.dart';
import 'package:firebase_auth_demo_flutter/services/auth_service_adapter.dart';
import 'package:firebase_auth_demo_flutter/services/firebase_email_link_handler.dart';
import 'package:firebase_auth_demo_flutter/services/email_secure_store.dart';
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:provider/provider.dart';
Expand Down Expand Up @@ -45,10 +45,11 @@ class MyApp extends StatelessWidget {
),
ProxyProvider2<AuthService, EmailSecureStore, FirebaseEmailLinkHandler>(
update: (_, AuthService authService, EmailSecureStore storage, __) =>
FirebaseEmailLinkHandler.createAndConfigure(
FirebaseEmailLinkHandler(
auth: authService,
userCredentialsStorage: storage,
),
emailStore: storage,
firebaseDynamicLinks: FirebaseDynamicLinks.instance,
)..init(),
dispose: (_, linkHandler) => linkHandler.dispose(),
),
],
Expand Down
105 changes: 33 additions & 72 deletions lib/services/firebase_email_link_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,45 +48,39 @@ class EmailLinkError {
}

/// Checks incoming dynamic links and uses them to sign in the user with Firebase
class FirebaseEmailLinkHandler with WidgetsBindingObserver {
class FirebaseEmailLinkHandler {
FirebaseEmailLinkHandler({
@required this.auth,
@required this.widgetsBinding,
@required this.emailStore,
}) {
// Register WidgetsBinding observer so that we can detect when the app is resumed.
// See [didChangeAppLifecycleState].
widgetsBinding.addObserver(this);
}
@required this.firebaseDynamicLinks,
});
final AuthService auth;
final WidgetsBinding widgetsBinding;
final EmailSecureStore emailStore;
final FirebaseDynamicLinks firebaseDynamicLinks;

/// Sets up listeners to process all links from [FirebaseDynamicLinks.instance.getInitialLink()] and [FirebaseDynamicLinks.instance.onLink]
Future<void> init() async {
try {
// Listen to incoming links when the app is open
firebaseDynamicLinks.onLink(
onSuccess: (linkData) => _processDynamicLink(linkData?.link),
onError: (error) => _handleLinkError(PlatformException(
code: error.code,
message: error.message,
details: error.details,
)),
);

static FirebaseEmailLinkHandler createAndConfigure({
@required AuthService auth,
@required EmailSecureStore userCredentialsStorage,
}) {
final linkHandler = FirebaseEmailLinkHandler(
auth: auth,
widgetsBinding: WidgetsBinding.instance,
emailStore: userCredentialsStorage,
);
// Check dynamic link once on app startup. This is required to process any dynamic links that may have opened
// the app when it was closed.
FirebaseDynamicLinks.instance
.getInitialLink()
.then((link) => linkHandler._processDynamicLink(link?.link));
// Listen to subsequent links
FirebaseDynamicLinks.instance.onLink(
onSuccess: (linkData) => linkHandler.handleLink(linkData?.link),
// convert to PlatformException as OnLinkErrorCallback has private constructor and can't be tested
onError: (error) => linkHandler.handleLinkError(PlatformException(
code: error.code,
message: error.message,
details: error.details,
)),
);
return linkHandler;
// Check dynamic link once on app startup.
// This is required to process any dynamic links that are opened when the app was closed
final linkData = await firebaseDynamicLinks.getInitialLink();
final link = linkData?.link?.toString();
if (link != null) {
await _processDynamicLink(linkData?.link);
}
} on PlatformException catch (e) {
_handleLinkError(e);
}
}

/// Clients can listen to this stream and show error alerts when dynamic link processing fails
Expand All @@ -99,51 +93,18 @@ class FirebaseEmailLinkHandler with WidgetsBindingObserver {

Future<String> getEmail() => emailStore.getEmail();

/// last link data received from FirebaseDynamicLinks
Uri _lastUnprocessedLink;

/// last link error received from FirebaseDynamicLinks
PlatformException _lastUnprocessedLinkError;

Future<dynamic> handleLink(Uri link) {
_lastUnprocessedLink = link;
_lastUnprocessedLinkError = null;
return Future<dynamic>.value();
}
Future<dynamic> _handleLinkError(PlatformException error) {
_errorController.add(EmailLinkError(
error: EmailLinkErrorType.linkError,
description: error.message,
));

Future<dynamic> handleLinkError(PlatformException error) {
_lastUnprocessedLink = null;
_lastUnprocessedLinkError = error;
return Future<dynamic>.value();
}

void dispose() {
_errorController.close();
isLoading.dispose();
widgetsBinding.removeObserver(this);
}

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
// When the application comes into focus
if (state == AppLifecycleState.resumed) {
_checkUnprocessedLinks();
}
}

/// Checks for a dynamic link, and tries to use it to sign in with email (passwordless)
Future<void> _checkUnprocessedLinks() async {
if (_lastUnprocessedLink != null) {
await _processDynamicLink(_lastUnprocessedLink);
_lastUnprocessedLink = null;
}
if (_lastUnprocessedLinkError != null) {
_errorController.add(EmailLinkError(
error: EmailLinkErrorType.linkError,
description: _lastUnprocessedLinkError.message,
));
_lastUnprocessedLinkError = null;
}
}

Future<void> _processDynamicLink(Uri deepLink) async {
Expand Down Expand Up @@ -212,7 +173,7 @@ class FirebaseEmailLinkHandler with WidgetsBindingObserver {
androidInstallIfNotAvailable: androidInstallIfNotAvailable,
androidMinimumVersion: androidMinimumVersion,
);
} on PlatformException catch (e) {
} on PlatformException catch (_) {
rethrow;
} finally {
isLoading.value = false;
Expand Down
6 changes: 5 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ dependencies:
flutter_facebook_login: ^3.0.0
apple_sign_in: ^0.1.0
provider: ^4.0.1
firebase_dynamic_links: ^0.5.0+9
firebase_dynamic_links:
git:
url: https://github.com/mrmilu/flutterfire
path: packages/firebase_dynamic_links
ref: firebase_dynamic_links
rxdart: ^0.23.1
flutter_secure_storage: ^3.3.1+1
package_info: ^0.4.0+13
Expand Down
Loading