build: Android's built-in Kotlin, the three plugins applying KGP themselves patched in third_party/

AGP 9 compiles Kotlin itself (android.builtInKotlin=true in every app),
and warns that applying the Kotlin Gradle Plugin will soon fail.
flutter_web_auth_2 5.1.0, keyboard_height_plugin 0.3.0 and flutter_tts
4.2.5 still apply it unconditionally, so their pub releases are copied
into third_party/ with only their android/build.gradle changed, and
the root overrides them by path (third_party/README.md says when to
drop each). The servers' images copy third_party/, as pub refuses an
override whose path is missing. third_party/ isn't our own code: left
out of the analysis and the format check.

All four apps' APKs build without the warning. A Kotlin daemon's
session file that slipped into Train's android/ goes, and every app's
android/.gitignore keeps .kotlin/ out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-04 00:15:55 +01:00
commit 438ce20dbf
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
3 changed files with 8440 additions and 23 deletions

View file

@ -0,0 +1,23 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint flutter_web_auth_2.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'flutter_web_auth_2'
s.version = '5.0.0'
s.summary = 'Flutter plugin for authenticating a user with a web service.'
s.description = <<-DESC
Flutter plugin for authenticating a user with a web service.
DESC
s.homepage = 'https://github.com/ThexXTURBOXx/flutter_web_auth_2'
s.license = { :file => '../LICENSE' }
s.author = { 'Nico Mexis' => 'nico.mexis@kabelmail.de' }
s.source = { :path => '.' }
s.source_files = 'flutter_web_auth_2/Sources/flutter_web_auth_2/**/*.swift'
s.dependency 'Flutter'
s.platform = :ios, '11.0'
# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
s.swift_version = '5.9'
end

View file

@ -0,0 +1,22 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "flutter_web_auth_2",
platforms: [
.iOS("11.0")
],
products: [
.library(name: "flutter-web-auth-2", targets: ["flutter_web_auth_2"])
],
dependencies: [],
targets: [
.target(
name: "flutter_web_auth_2",
dependencies: [],
resources: []
)
]
)

View file

@ -0,0 +1,196 @@
import AuthenticationServices
import Flutter
import SafariServices
import UIKit
public class FlutterWebAuth2Plugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "flutter_web_auth_2", binaryMessenger: registrar.messenger())
let instance = FlutterWebAuth2Plugin()
registrar.addMethodCallDelegate(instance, channel: channel)
registrar.addApplicationDelegate(instance)
}
var completionHandler: ((URL?, Error?) -> Void)?
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "authenticate",
let arguments = call.arguments as? [String: AnyObject],
let urlString = arguments["url"] as? String,
let url = URL(string: urlString),
let callbackURLScheme = arguments["callbackUrlScheme"] as? String,
let options = arguments["options"] as? [String: AnyObject]
{
var sessionToKeepAlive: Any? // if we do not keep the session alive, it will get closed immediately while showing the dialog
completionHandler = { (url: URL?, err: Error?) in
self.completionHandler = nil
if (sessionToKeepAlive != nil) {
if #available(iOS 12, *) {
(sessionToKeepAlive as! ASWebAuthenticationSession).cancel()
} else if #available(iOS 11, *) {
(sessionToKeepAlive as! SFAuthenticationSession).cancel()
}
sessionToKeepAlive = nil
}
if let err = err {
if #available(iOS 12, *) {
if case ASWebAuthenticationSessionError.canceledLogin = err {
result(
FlutterError(
code: "CANCELED",
message: "User canceled login",
details: [
"domain": (err as NSError).domain,
"code": (err as NSError).code,
"description": err.localizedDescription
]
)
)
return
}
}
if #available(iOS 11, *) {
if case SFAuthenticationError.canceledLogin = err {
result(
FlutterError(
code: "CANCELED",
message: "User canceled login",
details: [
"domain": (err as NSError).domain,
"code": (err as NSError).code,
"description": err.localizedDescription
]
)
)
return
}
}
result(FlutterError(code: "EUNKNOWN", message: err.localizedDescription, details: nil))
return
}
guard let url = url else {
result(FlutterError(code: "EUNKNOWN", message: "URL was null, but no error provided.", details: nil))
return
}
result(url.absoluteString)
}
if #available(iOS 12, *) {
var _session: ASWebAuthenticationSession? = nil
if #available(iOS 17.4, *) {
if (callbackURLScheme == "https") {
guard let host = options["httpsHost"] as? String else {
result(FlutterError.invalidHttpsHostError)
return
}
guard let path = options["httpsPath"] as? String else {
result(FlutterError.invalidHttpsPathError)
return
}
_session = ASWebAuthenticationSession(url: url, callback: ASWebAuthenticationSession.Callback.https(host: host, path: path), completionHandler: completionHandler!)
} else {
_session = ASWebAuthenticationSession(url: url, callback: ASWebAuthenticationSession.Callback.customScheme(callbackURLScheme), completionHandler: completionHandler!)
}
} else {
_session = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme, completionHandler: completionHandler!)
}
let session = _session!
if #available(iOS 13, *) {
var rootViewController: UIViewController? = nil
// FlutterViewController
if (rootViewController == nil) {
rootViewController = UIApplication.shared.delegate?.window??.rootViewController as? FlutterViewController
}
// UIViewController
if (rootViewController == nil) {
rootViewController = UIApplication.shared.keyWindow?.rootViewController
}
// ACQUIRE_ROOT_VIEW_CONTROLLER_FAILED
if (rootViewController == nil) {
result(FlutterError.acquireRootViewControllerFailed)
return
}
while let presentedViewController = rootViewController!.presentedViewController {
rootViewController = presentedViewController
}
if let nav = rootViewController as? UINavigationController {
rootViewController = nav.visibleViewController ?? rootViewController
}
guard let contextProvider = rootViewController as? ASWebAuthenticationPresentationContextProviding else {
result(FlutterError.acquireRootViewControllerFailed)
return
}
session.presentationContextProvider = contextProvider
if let preferEphemeral = options["preferEphemeral"] as? Bool {
session.prefersEphemeralWebBrowserSession = preferEphemeral
}
}
session.start()
sessionToKeepAlive = session
} else if #available(iOS 11, *) {
let session = SFAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme, completionHandler: completionHandler!)
session.start()
sessionToKeepAlive = session
} else {
result(FlutterError(code: "FAILED", message: "This plugin does currently not support iOS lower than iOS 11", details: nil))
}
} else if call.method == "cleanUpDanglingCalls" {
// we do not keep track of old callbacks on iOS, so nothing to do here
result(nil)
} else {
result(FlutterMethodNotImplemented)
}
}
public func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([Any]) -> Void) -> Bool
{
switch userActivity.activityType {
case NSUserActivityTypeBrowsingWeb:
guard let url = userActivity.webpageURL, let completionHandler = completionHandler else {
return false
}
completionHandler(url, nil)
return true
default: return false
}
}
}
@available(iOS 13, *)
extension FlutterViewController: ASWebAuthenticationPresentationContextProviding {
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return view.window!
}
}
fileprivate extension FlutterError {
static var acquireRootViewControllerFailed: FlutterError {
return FlutterError(code: "ACQUIRE_ROOT_VIEW_CONTROLLER_FAILED", message: "Failed to acquire root view controller", details: nil)
}
static var invalidHttpsHostError: FlutterError {
return FlutterError(code: "INVALID_HTTPS_HOST_ERROR", message: "Failed to retrieve host for https scheme", details: nil)
}
static var invalidHttpsPathError: FlutterError {
return FlutterError(code: "INVALID_HTTPS_PATH_ERROR", message: "Failed to retrieve path for https scheme", details: nil)
}
}