Refactor Live Activity creation to return success status and handle push token updates asynchronously

This commit is contained in:
2026-03-06 12:28:38 +01:00
parent fe33bb2db0
commit 55035b535c
4 changed files with 39 additions and 50 deletions

View File

@@ -90,15 +90,11 @@ import Security
}
if #available(iOS 16.2, *) {
LiveActivityManager.create { [weak self] pushToken in
guard let self = self, let token = pushToken else {
result(nil)
return
}
LiveActivityManager.create { success in
let deviceId = self.getOrCreateDeviceId()
let bundleId = Bundle.main.bundleIdentifier ?? ""
result([
"pushToken": token,
"success": success,
"deviceId": deviceId,
"bundleId": bundleId,
])

View File

@@ -26,8 +26,10 @@ final class LiveActivityManager {
static let shared = LiveActivityManager()
var currentActivity: Activity<LiveActivitiesAppAttributes>?
/// Létrehozza a Live Activity-t pushType: .token-nel, majd visszaadja az APNs push tokent.
class func create(completion: @escaping (String?) -> Void) {
/// Létrehozza a Live Activity-t pushType: .token-nel.
/// A completion azonnal meghívódik a létrehozás után (success/fail).
/// A push token később érkezik a pushTokenUpdates-en keresztül.
class func create(completion: @escaping (Bool) -> Void) {
Task {
// Előző activity-k eltakarítása, hogy ne legyen dupla
for activity in Activity<LiveActivitiesAppAttributes>.activities {
@@ -64,22 +66,28 @@ final class LiveActivityManager {
activityID = activity.id
print("Live Activity létrehozva. Azonosító: \(activity.id)")
// Azonnal visszatérünk a LA látszik
completion(true)
// Dismiss/end figyelése háttérben
Task { await monitorActivityState(activity: activity) }
// Az APNs token aszinkron érkezik megvárjuk az elsőt
for await tokenData in activity.pushTokenUpdates {
let tokenHex = tokenData.map { String(format: "%02x", $0) }.joined()
activityPushToken = tokenHex
print("Live Activity push token: \(tokenHex)")
completion(tokenHex)
// Token rotation figyelése a háttérben
Task { await monitorTokenRotation(activity: activity) }
break
// Push token figyelése háttérben az első és a rotation is
// a LiveActivityTokenUpdated notification-ön keresztül megy Flutter felé
Task {
for await tokenData in activity.pushTokenUpdates {
let tokenHex = tokenData.map { String(format: "%02x", $0) }.joined()
activityPushToken = tokenHex
print("Live Activity push token: \(tokenHex)")
NotificationCenter.default.post(
name: NSNotification.Name("LiveActivityTokenUpdated"),
object: tokenHex
)
}
}
} catch {
print("Hiba történt a Live Activity létrehozásakor: \(error)")
completion(nil)
completion(false)
}
}
}
@@ -103,19 +111,8 @@ final class LiveActivityManager {
}
/// Token rotation figyelése: ha az APNs új tokent ad ki, értesítjük a Flutter oldalt.
private class func monitorTokenRotation(activity: Activity<LiveActivitiesAppAttributes>) async {
var isFirst = true
for await tokenData in activity.pushTokenUpdates {
if isFirst { isFirst = false; continue } // Az első tokent már kezeltük
let tokenHex = tokenData.map { String(format: "%02x", $0) }.joined()
activityPushToken = tokenHex
print("Live Activity push token frissítve (rotation): \(tokenHex)")
NotificationCenter.default.post(
name: NSNotification.Name("LiveActivityTokenUpdated"),
object: tokenHex
)
}
}
/// MEGJEGYZÉS: Már nem használjuk külön a create() maga figyeli a pushTokenUpdates-t
/// és minden tokent (elsőt is, rotation-t is) a LiveActivityTokenUpdated notification-ön küld.
class func update() {
Task {

View File

@@ -63,12 +63,15 @@ class LiveCardProvider extends ChangeNotifier {
? Duration(seconds: settings.bellDelay)
: Duration.zero;
// Token rotation figyelése: ha iOS új APNs tokent ad ki, szinkronizáljuk a szerverrel
// Token figyelése: amikor az APNs tokent ad (első vagy rotation), regisztráljuk a szerverrel
PlatformChannel.onTokenUpdated = (pushToken, deviceId, bundleId) {
serverSync.refreshToken(
debugPrint("Push token érkezett: $pushToken");
serverSync.registerAndSync(
deviceId: deviceId,
pushToken: pushToken,
bundleId: bundleId,
liveActivityColor: '#${settings.liveActivityColor.toHexString().substring(2)}',
todayLessons: _today(_timetable),
);
};
@@ -413,20 +416,13 @@ class LiveCardProvider extends ChangeNotifier {
Future<void> _createAndSync() async {
final result = await PlatformChannel.createLiveActivity(toMap());
if (result != null) {
final pushToken = result['pushToken'] ?? '';
final deviceId = result['deviceId'] ?? '';
final bundleId = result['bundleId'] ?? '';
if (pushToken.isNotEmpty && deviceId.isNotEmpty) {
await serverSync.registerAndSync(
deviceId: deviceId,
pushToken: pushToken,
bundleId: bundleId,
liveActivityColor:
'#${_settings.liveActivityColor.toHexString().substring(2)}',
todayLessons: _today(_timetable),
);
}
if (result != null && result['success'] == 'true') {
debugPrint("Live Activity létrehozva, várunk a push tokenre...");
// A regisztráció az onTokenUpdated callback-ben történik,
// amikor az APNs elküldi a push tokent.
} else {
debugPrint("Live Activity létrehozás sikertelen");
hasActivityStarted = false;
}
}

View File

@@ -32,8 +32,8 @@ class PlatformChannel {
});
}
/// Létrehozza a Live Activity-t és visszaadja az APNs push tokent,
/// a device ID-t (Keychain UUID) és a bundle ID-t.
/// Létrehozza a Live Activity-t. Azonnal visszatér deviceId/bundleId-vel.
/// A push token később érkezik az onTokenUpdated callback-en.
static Future<Map<String, String>?> createLiveActivity(
Map<String, dynamic> activityData) async {
if (Platform.isIOS) {
@@ -44,7 +44,7 @@ class PlatformChannel {
'createLiveActivity', activityData);
if (result == null) return null;
return {
'pushToken': result['pushToken'] as String? ?? '',
'success': (result['success'] as bool? ?? false).toString(),
'deviceId': result['deviceId'] as String? ?? '',
'bundleId': result['bundleId'] as String? ?? '',
};