😰

Firebaseのメールアドレスを変更する

2023/02/01に公開

メールアドレス変わったら変更しないと...

スマホのメールアドレス変わっちゃった!
メールアドレスの変更が必要ですよね😅
Firebaseだと、簡単に変更できる便利な機能がありました!
こちらの記事を参考にさせていたただきました!
https://zenn.dev/taku_zenn/articles/e2ee90d9c69bec

FlutterFireの公式によると

https://firebase.flutter.dev/docs/auth/manage-users#re-authenticate_a_user

ユーザーのメールアドレスを設定する

ユーザーのメールアドレスを設定するには、updateEmail() メソッドを使用します。たとえば

await user?.updateEmail("janeq@example.com");

Formの値を引数で渡してあげればOKですね。


Demoアプリを作る

完成品のソースコード

https://github.com/sakurakotubaki/UpdateEmailApp

まずは、Firebaseのプロジェクトを作りましよう。Google Analyticsはなしで良いです。








Flutterのプロジェクトを作成する

以下のpackageを追加して、認証機能に必要なファイルを作成してください。

pabspec.yaml
name: email_update
description: A new Flutter project.

# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev

# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1

environment:
  sdk: '>=2.18.0 <3.0.0'

# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  firebase_core: ^2.4.1
  firebase_auth: ^4.2.5
  flutter_riverpod: ^2.1.3

dev_dependencies:
  flutter_test:
    sdk: flutter

  # The "flutter_lints" package below contains a set of recommended lints to
  # encourage good coding practices. The lint set provided by the package is
  # activated in the `analysis_options.yaml` file located at the root of your
  # package. See that file for information about deactivating specific lint
  # rules and activating additional ones.
  flutter_lints: ^2.0.0

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

# The following section is specific to Flutter packages.
flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  # To add assets to your application, add an assets section, like this:
  # assets:
  #   - images/a_dot_burr.jpeg
  #   - images/a_dot_ham.jpeg

  # An image asset can refer to one or more resolution-specific "variants", see
  # https://flutter.dev/assets-and-images/#resolution-aware

  # For details regarding adding assets from package dependencies, see
  # https://flutter.dev/assets-and-images/#from-packages

  # To add custom fonts to your application, add a fonts section here,
  # in this "flutter" section. Each entry in this list should have a
  # "family" key with the font family name, and a "fonts" key with a
  # list giving the asset and other descriptors for the font. For
  # example:
  # fonts:
  #   - family: Schyler
  #     fonts:
  #       - asset: fonts/Schyler-Regular.ttf
  #       - asset: fonts/Schyler-Italic.ttf
  #         style: italic
  #   - family: Trajan Pro
  #     fonts:
  #       - asset: fonts/TrajanPro.ttf
  #       - asset: fonts/TrajanPro_Bold.ttf
  #         weight: 700
  #
  # For details regarding fonts from package dependencies,
  # see https://flutter.dev/custom-fonts/#from-packages
lib
├── main.dart
├── ui
│   ├── email_reset.dart
│   └── signin_page.dart
└── utils
    ├── auth_provider.dart
    └── auth_state.dart

utilsディレクトリを作成して、FirebaseAuenticationを使用するためのProviderとロジックを作成しましよう。

FirebaseAuthenticationと、TextEditingControllerを使うためのProviderを作成。

utils/auth_provider.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final firebaseAuthProvider =
    Provider<FirebaseAuth>((ref) => FirebaseAuth.instance);

final emailProvider = StateProvider.autoDispose((ref) {
  return TextEditingController(text: '');
});

final passwordProvider = StateProvider.autoDispose((ref) {
  return TextEditingController(text: '');
});

ユーザーの登録、ログイン、ログアウト、メールアドレスの変更ができるロジック

utils/auth_state.dart
import 'package:email_update/ui/email_reset.dart';
import 'package:email_update/ui/signin_page.dart';
import 'package:email_update/utils/auth_provider.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final authStateProvider = StateNotifierProvider<AuthState, dynamic>((ref) {
  return AuthState(ref);
});

class AuthState extends StateNotifier<dynamic> {
  final Ref _ref;

  AuthState(this._ref) : super([]);
  // ユーザーの新規登録.
  Future<void> userSignUp(
      String emailC, String passwordC, BuildContext context) async {
    try {
      final credential = await _ref
          .read(firebaseAuthProvider)
          .createUserWithEmailAndPassword(email: emailC, password: passwordC);
      Navigator.pushReplacement(
          context, MaterialPageRoute(builder: (context) => EmailRest()));
    } on FirebaseAuthException catch (e) {
      if (e.code == 'weak-password') {
        print('提供されたパスワードが弱すぎる。');
      } else if (e.code == 'email-already-in-use') {
        print('その電子メールにはすでにアカウントが存在します。');
      }
    } catch (e) {
      print(e);
    }
  }

  // ユーザーのログイン.
  Future<void> userSignIn(
      String emailC, String passwordC, BuildContext context) async {
    try {
      final credential = await _ref
          .read(firebaseAuthProvider)
          .signInWithEmailAndPassword(email: emailC, password: passwordC);
      Navigator.pushReplacement(
          context, MaterialPageRoute(builder: (context) => EmailRest()));
    } on FirebaseAuthException catch (e) {
      if (e.code == 'user-not-found') {
        print('そのメールに該当するユーザーは見つかりませんでした。');
      } else if (e.code == 'wrong-password') {
        print('そのユーザーに対して提供されたパスワードが間違っている。');
      }
    }
  }

  // ユーザーのログアウト.
  Future<void> userSignOut(BuildContext context) async {
    final credential = await _ref.read(firebaseAuthProvider).signOut();
    Navigator.pushReplacement(
        context, MaterialPageRoute(builder: (context) => SignInPage()));
  }

  // ユーザーのメールアドレスの変更.
  Future<void> emailUpdate(String emailC) async {
    final ref =
        await _ref.read(firebaseAuthProvider).currentUser?.updateEmail(emailC);
  }
}

メールアドレスを変更するページ

今回は、メールアドレスを変更する方法を学ぶのが目的なので、画面はこのページだけです🙇‍♂️
uiディレクトリを作成してその中にemail_reset.dartを作成。

ui/email_reset.dart
import 'package:email_update/utils/auth_provider.dart';
import 'package:email_update/utils/auth_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class EmailRest extends ConsumerWidget {
  const EmailRest({
    Key? key,
  }) : super(key: key);

  
  Widget build(BuildContext context, WidgetRef ref) {
    final emailC = ref.watch(emailProvider);

    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(
              onPressed: () async {
                ref.read(authStateProvider.notifier).userSignOut(context);
              },
              icon: Icon(Icons.logout))
        ],
        title: const Text('SignIn'),
      ),
      body: Center(
        child: Container(
          padding: const EdgeInsets.all(24),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              // メールアドレス入力用テキストフィールド
              TextFormField(
                controller: emailC,
                decoration: const InputDecoration(labelText: 'メールアドレス'),
              ),
              ElevatedButton(
                  child: const Text('メールアドレスを変更する'),
                  onPressed: () async {
                    ref
                        .read(authStateProvider.notifier)
                        .emailUpdate(emailC.text);
                  }),
            ],
          ),
        ),
      ),
    );
  }
}

アプリを実行するコード

main.dart
import 'package:email_update/ui/signin_page.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(
    // Adding ProviderScope enables Riverpod for the entire project
    const ProviderScope(child: MyApp()),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blueGrey,
      ),
      home: const SignInPage(),
    );
  }
}

ユーザーを登録しておきます

メールアドレスを変更する場合は、ログインしてから、一定時間経過していると、エラーになるので、再ログインが必要です!
Firebase側から、送信されるメールのメッセージを英語から日本語に変更することができるので、設定しておきます。
メールアドレスは、変更してもメールのリンクから、最初に登録したメールアドレスに戻すことができます。
便利ですね。











まとめ

あまりメールアドレスの変更をする情報がないので、動くものを作ってみたいなと思ってDemoアプリを作ってみました。やってみた感想はそんなに難しくはないなと思いましたが、ログインから、時間が経っていると、再ログインが必要なところは注意が必要ですね!

Discussion