0
0

Flutterのurl_lanucherとuni_linksでOAuth

Last updated at Posted at 2024-01-29

この記事の補足記事になります。

認証部分は読んだ前提で話を進めるので、読んでください!

webviewを使ったGoogleのOAuthがセキュリティ的にちょっとアレなため、url_launcherとuni_linksを使用した正攻法(?)で実装してみます。

サンプルのリポジトリは同じです。
https://github.com/Taichiro-S/notion_sample

使用するFlutterパッケージ

  • url_launcher : 端末のデフォルトブラウザでWebページを開く
  • uni_links : deeplinkするやつ

実装

修正箇所は以下の2点です。

  1. 「連携」ボタンクリック時にnotionの認証ページをurl_launcherで開くようにする
  2. uni_liksのlinkStream.listenで自分のアプリへのリクエストをlistenする

修正が必要なのはmain.dartのみです。

まず連携ボタンを修正。

main.dart
child: ElevatedButton(
    onPressed: () async {
        if (await canLaunchUrl(Uri.parse(Env.notionOauthUrl))) {
         launchUrl(Uri.parse(Env.notionOauthUrl));
        }
    },
    child: const Text('Notionと連携する'),
)

次にlistenerを設定
MyAppをConsumerWidgetからConsumerStatefulWidgetに変更します。
linkStream.listen内で、自分のアプリに対するリクエストで、URLにcodeパラメータを含むものを検知してauthenticateメソッドを実行し、providerを更新します。

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

  @override
  ConsumerState<MyApp> createState() => _MyApp();
}

class _MyApp extends ConsumerState<MyApp> {
  StreamSubscription? _sub;
  @override
  void initState() {
    super.initState();
    initUniLinks();
  }

  Future<void> initUniLinks() async {
    _sub = linkStream.listen((link) async {
      if (link != null &&
          link.startsWith('notionsample://oauth/callback?code')) {
        await ref.read(notionOauthApiProvider).authenticate(link);
        ref.invalidate(notionAuthProvider);
      }
    }, onError: (e) {
      print(e.toString());
    });
  }

// build以降はそのまま
}

これで一応実装できました。

動かしてみるとこんな感じ。

2つほど気になるところが...

1. 二度目以降の連携では最初に連携をしたアカウントの連携ページに飛ばされてしまう

ブラウザに初回ログイン時の情報が残っているため?
webviewでは毎回ページを開く前にキャッシュを削除していた(clearCache: trueに設定)が、url_launcherではできないみたい。
Githubに同様のissueがあったが、

url_launcher is intended to have a minimal API for launching, and the API of SFViewController is extremely limited so this couldn't be implemented on iOS anyway. Use cases that need detailed control of the webview should build on webview_flutter instead.

Closing as out of scope.

webviewを使わないと無理っぽい。

2. 認証完了後に自動でブラウザを閉じることができない

ので、ユーザーに手動で閉じてもらう必要がある。
こちらちょっとめんどい程度の問題なのでまあ許せるが、1つ目は今のところ解決策が思い浮かばない。

ということで、いい解決方法知ってる人、教えてください!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0