feat(ios): run verification and OAuth through ASWebAuthenticationSession

The captcha/OAuth flow relied on the OS routing the spotiflac://
callback back into the app. In sideload containers (LiveContainer)
the guest app's URL scheme is never registered with iOS, so after
solving the challenge the redirect went nowhere and the user could
not return to the app (LiveContainer#242/#162 — unresolved upstream).

ASWebAuthenticationSession intercepts the callback scheme in-process,
so no OS-level scheme registration is involved: the session sheet
closes itself on completion and the callback URL is fed into the same
deep-link handler the OS path uses. Verification challenges, the help
dialog's open-browser action, and extension OAuth logins all prefer
the session on iOS, falling back to url_launcher if it fails to start.
Safari's cookie store is shared so captcha providers see an
established browsing context.
This commit is contained in:
zarzet
2026-07-10 11:25:55 +07:00
parent b28e8a83a8
commit 196fd0f651
4 changed files with 109 additions and 3 deletions
+21
View File
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -299,7 +300,27 @@ String? _firstRegexGroup(String input, RegExp regex) {
return match?.group(1);
}
/// Opens an extension auth/verification page. On iOS this prefers an
/// ASWebAuthenticationSession, which captures the spotiflac:// callback
/// in-process — required for environments where the app's URL scheme is not
/// registered with the OS (sideload containers like LiveContainer) and nicer
/// everywhere else (the sheet closes itself once the challenge completes).
Future<bool> launchExtensionAuthUrl(Uri uri, {required String browserMode}) {
return _launchVerificationUrl(uri, browserMode);
}
Future<bool> _launchVerificationUrl(Uri uri, String browserMode) async {
if (Platform.isIOS && uri.scheme == 'https') {
try {
if (await PlatformBridge.startIosWebAuthSession(uri.toString())) {
return true;
}
_log.w('Web auth session did not start, falling back to browser');
} catch (e) {
_log.w('Web auth session failed, falling back to browser: $e');
}
}
final preferInApp = browserMode.trim().toLowerCase() == 'in_app_first';
final firstMode = preferInApp
? LaunchMode.inAppBrowserView