Skip to content
Draft
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
5 changes: 1 addition & 4 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Gradle cache
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0
- name: AVD cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
id: avd-cache
Expand All @@ -75,9 +75,6 @@ jobs:
melos-version: "^7.5.0"
- name: "Bootstrap package"
run: melos bootstrap --scope tests
# needed because twitter_login plugin doesn't have a namespace defined and he hasn't released a new version yet: https://github.com/0maru/twitter_login/issues/139
- name: Patch twitter_login plugin
run: ./scripts/patch-twitter-login.sh
- name: Start Firebase Emulator
run: |
cd functions/
Expand Down
1 change: 0 additions & 1 deletion packages/firebase_ui_auth/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ dependencies:
firebase_ui_oauth_google: ^2.1.0
firebase_ui_oauth_twitter: ^2.1.0
# This and twitter oauth package need to depend on git main directly due to namespace build error on android.
twitter_login: ^4.4.2
dev_dependencies:
drive: ^1.0.0-1.0.nullsafety.5
firebase_ui_shared: ^1.5.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class TwitterSignInButton extends _TwitterSignInButton {
const TwitterSignInButton({
super.key,
required super.loadingIndicator,
required super.apiKey,
required super.apiSecretKey,
super.apiKey,
super.apiSecretKey,
super.redirectUri,
super.action = null,
super.auth,
Expand All @@ -35,8 +35,8 @@ class TwitterSignInButton extends _TwitterSignInButton {
class TwitterSignInIconButton extends _TwitterSignInButton {
const TwitterSignInIconButton({
super.key,
required super.apiKey,
required super.apiSecretKey,
super.apiKey,
super.apiSecretKey,
required super.loadingIndicator,
super.action = null,
super.auth,
Expand Down Expand Up @@ -74,16 +74,16 @@ class _TwitterSignInButton extends StatelessWidget {
final DifferentProvidersFoundCallback? onDifferentProvidersFound;
final SignedInCallback? onSignedIn;
final double size;
final String apiKey;
final String apiSecretKey;
final String? apiKey;
final String? apiSecretKey;
final String? redirectUri;
final void Function(Exception exception)? onError;
final VoidCallback? onCanceled;

const _TwitterSignInButton({
super.key,
required this.apiKey,
required this.apiSecretKey,
this.apiKey,
this.apiSecretKey,
required this.loadingIndicator,
String? label,
bool? overrideDefaultTapAction,
Expand Down
167 changes: 120 additions & 47 deletions packages/firebase_ui_oauth_twitter/lib/src/provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,65 +5,137 @@
import 'package:firebase_auth/firebase_auth.dart' hide OAuthProvider;
import 'package:flutter/foundation.dart';
import 'package:firebase_ui_oauth/firebase_ui_oauth.dart';
import 'package:twitter_login/twitter_login.dart';

import 'theme.dart';

/// A Firebase UI Auth provider which should be used to add Twitter Sign In
/// to your app.
///
/// On Android and iOS the sign in flow is handled by Firebase itself via
/// [FirebaseAuth.signInWithProvider], so [apiKey] and [apiSecretKey] are not
/// needed: configure the Twitter provider in the Firebase console instead.
///
/// macOS and Windows still perform the OAuth 1.0a flow in-process and do
/// require [apiKey] and [apiSecretKey]. `signInWithProvider` rejects every
/// provider except Apple and Game Center on macOS, so the desktop flow stays
/// in place there.
class TwitterProvider extends OAuthProvider {
@override
final providerId = 'twitter.com';
final String apiKey;
final String apiSecretKey;

/// The Twitter API key.
///
/// Only required on macOS and Windows, which perform the OAuth 1.0a flow
/// in-process.
final String? apiKey;

/// The Twitter API secret key.
///
/// Only required on macOS and Windows, which perform the OAuth 1.0a flow
/// in-process.
final String? apiSecretKey;

final String? redirectUri;

@override
final style = const TwitterProviderButtonStyle();

@override
late final desktopSignInArgs = TwitterSignInArgs(
apiKey: apiKey,
apiSecretKey: apiSecretKey,
redirectUri: redirectUri ?? defaultRedirectUri,
);

late TwitterLogin provider = TwitterLogin(
apiKey: apiKey,
apiSecretKey: apiSecretKey,
redirectURI: redirectUri ?? defaultRedirectUri,
);

TwitterProvider({
required this.apiKey,
required this.apiSecretKey,
this.redirectUri,
});
TwitterAuthProvider firebaseAuthProvider = TwitterAuthProvider();

@override
TwitterSignInArgs get desktopSignInArgs {
final apiKey = this.apiKey;
final apiSecretKey = this.apiSecretKey;

if (apiKey == null || apiSecretKey == null) {
throw ArgumentError(
'TwitterProvider.apiKey and TwitterProvider.apiSecretKey are required '
'on $defaultTargetPlatform, which signs in using the OAuth 1.0a flow. '
'Android and iOS use the Firebase native provider flow and do not '
'need them.',
);
}

return TwitterSignInArgs(
apiKey: apiKey,
apiSecretKey: apiSecretKey,
redirectUri: redirectUri ?? defaultRedirectUri,
);
}

TwitterProvider({this.apiKey, this.apiSecretKey, this.redirectUri});

bool _warnedAboutIgnoredKeys = false;

/// Warns once, in debug builds, that [apiKey] and [apiSecretKey] no longer
/// take part in sign in on the platforms that use the Firebase provider
/// flow. Without this the change is silent: the app still compiles, and the
/// first signal the developer gets is a sign in that fails in the browser.
void _warnIfKeysAreIgnored() {
if (!kDebugMode || _warnedAboutIgnoredKeys) return;
if (apiKey == null && apiSecretKey == null) return;

_warnedAboutIgnoredKeys = true;

debugPrint(
'TwitterProvider: apiKey and apiSecretKey are ignored on '
'$defaultTargetPlatform. Sign in is now performed by Firebase, which '
'reads the Twitter API key and secret from the Firebase console. They '
'are still used on macOS and Windows.\n'
'If sign in fails, check that the Twitter app callback URL is '
'"${redirectUri ?? defaultRedirectUri}", and that you have added the '
'Encoded App ID URL scheme (iOS) or your SHA-1 fingerprint '
'(Android). See '
'https://github.com/firebase/FirebaseUI-Flutter/blob/main/docs/firebase-ui-auth/providers/oauth.md#twitter-login',
);
}

@override
void mobileSignIn(AuthAction action) {
final result = provider.login();

result
.then((value) {
switch (value.status!) {
case TwitterLoginStatus.loggedIn:
final credential = TwitterAuthProvider.credential(
accessToken: value.authToken!,
secret: value.authTokenSecret!,
);

onCredentialReceived(credential, action);
break;
case TwitterLoginStatus.cancelledByUser:
authListener.onError(AuthCancelledException());
break;
case TwitterLoginStatus.error:
authListener.onError(Exception(value.errorMessage));
break;
}
})
.catchError((err) {
authListener.onError(err);
});
if (action == AuthAction.none) {
throw UnsupportedError(
'AuthAction.none is not supported by TwitterProvider on '
'$defaultTargetPlatform. Firebase signs the user in as part of '
'obtaining the credential, so the credential cannot be returned '
'without also creating a session.',
);
}

_warnIfKeysAreIgnored();

// Linking is also used to upgrade an anonymous user, so that the
// anonymous uid survives the sign in.
if (action == AuthAction.link || shouldUpgradeAnonymous) {
final currentUser = auth.currentUser;

// Only AuthAction.link can reach this with no user, since
// shouldUpgradeAnonymous is false when currentUser is null. Reporting it
// matters because a null-shorting call would leave the flow stuck in its
// loading state with no error and no completion.
if (currentUser == null) {
authListener.onError(
FirebaseAuthException(
code: 'no-current-user',
message:
'AuthAction.link requires a signed in user to link the '
'Twitter credential to, but FirebaseAuth.currentUser is null.',
),
);
return;
}

currentUser
.linkWithProvider(firebaseAuthProvider)
.then(_onLinked)
.catchError(authListener.onError);
return;
}
Comment thread
demolaf marked this conversation as resolved.

auth
.signInWithProvider(firebaseAuthProvider)
.then(authListener.onSignedIn)
.catchError(authListener.onError);
}

@override
Expand All @@ -74,9 +146,6 @@ class TwitterProvider extends OAuthProvider {
);
}

@override
TwitterAuthProvider get firebaseAuthProvider => TwitterAuthProvider();

@override
Future<void> logOutProvider() {
return SynchronousFuture(null);
Expand All @@ -86,4 +155,8 @@ class TwitterProvider extends OAuthProvider {
bool supportsPlatform(TargetPlatform platform) {
return true;
}

void _onLinked(UserCredential userCredential) {
authListener.onCredentialLinked(userCredential.credential!);
}
}
1 change: 0 additions & 1 deletion packages/firebase_ui_oauth_twitter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ dependencies:
sdk: flutter
firebase_auth: ^6.5.4
firebase_ui_oauth: ^2.1.0
twitter_login: ^4.4.2

dev_dependencies:
flutter_test:
Expand Down
51 changes: 0 additions & 51 deletions scripts/patch-twitter-login.sh

This file was deleted.

3 changes: 1 addition & 2 deletions tests/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ plugins {

android {
namespace = "io.flutter.plugins.firebase.tests"
// use "flutter.compileSdkVersion" and bump AGP once twitter_login has released v4.4.3: https://github.com/0maru/twitter_login/issues/139
compileSdk 36
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion

compileOptions {
Expand Down
2 changes: 1 addition & 1 deletion tests/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pluginManagement {

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.7.3" apply false
id "com.android.application" version "8.9.1" apply false
id "org.jetbrains.kotlin.android" version "2.3.0" apply false
id "com.google.gms.google-services" version "4.4.2" apply false
}
Expand Down
Loading
Loading