preTesting

This commit is contained in:
2026-05-05 03:56:11 -05:00
parent 14d026841f
commit 39428b4451
12 changed files with 142 additions and 181 deletions

View File

@@ -1,32 +1,83 @@
import Flutter
import Firebase
import FirebaseMessaging
import UIKit
import UserNotifications
// Mirrors LockInBroMobile/Services/NotificationService.swift: pure native APNs,
// no Firebase. The hex device token is forwarded to Dart over a MethodChannel
// (`blindmaster/apns`) which then POSTs it to /register_apns_token.
@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate, UNUserNotificationCenterDelegate {
private var apnsChannel: FlutterMethodChannel?
private var pendingToken: String?
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Explicitly register for remote notifications on every launch so iOS always
// calls didRegisterForRemoteNotificationsWithDeviceToken, ensuring Firebase
// receives a fresh APNs token regardless of whether permission was already granted.
UNUserNotificationCenter.current().delegate = self
// Trigger APNs registration on every launch so iOS calls
// didRegisterForRemoteNotificationsWithDeviceToken with a fresh token.
application.registerForRemoteNotifications()
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
let registrar = engineBridge.pluginRegistry.registrar(forPlugin: "BlindMasterApns")
let channel = FlutterMethodChannel(
name: "blindmaster/apns",
binaryMessenger: registrar.messenger()
)
channel.setMethodCallHandler { [weak self] call, result in
switch call.method {
case "requestPermission":
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if let error = error { print("[APNs] permission error: \(error)") }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
result(granted)
}
case "getToken":
result(self?.pendingToken)
default:
result(FlutterMethodNotImplemented)
}
}
apnsChannel = channel
// If iOS already delivered the token before Dart attached the channel,
// flush it now so the upload still happens.
if let token = pendingToken {
channel.invokeMethod("onToken", arguments: token)
}
}
// FlutterImplicitEngineDelegate can interfere with Firebase's method swizzling,
// preventing it from capturing the APNs token. Forward it explicitly instead.
override func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
Messaging.messaging().apnsToken = deviceToken
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
pendingToken = token
apnsChannel?.invokeMethod("onToken", arguments: token)
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
override func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
print("[APNs] registration failed: \(error)")
super.application(application, didFailToRegisterForRemoteNotificationsWithError: error)
}
// Show banners while the app is in the foreground (matches LockInBroMobile).
override func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
completionHandler([.banner, .sound, .badge])
}
}