feat: background streaming of responses
This commit is contained in:
@@ -59,6 +59,8 @@ PODS:
|
||||
- SwiftyGif (5.4.5)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- wakelock_plus (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
@@ -72,6 +74,7 @@ DEPENDENCIES:
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
@@ -103,6 +106,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
wakelock_plus:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
@@ -120,6 +125,7 @@ SPEC CHECKSUMS:
|
||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||
|
||||
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e
|
||||
|
||||
|
||||
@@ -1,13 +1,166 @@
|
||||
import Flutter
|
||||
import UIKit
|
||||
|
||||
// Background streaming handler class
|
||||
class BackgroundStreamingHandler: NSObject {
|
||||
private var backgroundTask: UIBackgroundTaskIdentifier = .invalid
|
||||
private var activeStreams: Set<String> = []
|
||||
private var channel: FlutterMethodChannel?
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
setupNotifications()
|
||||
}
|
||||
|
||||
func setup(with channel: FlutterMethodChannel) {
|
||||
self.channel = channel
|
||||
}
|
||||
|
||||
private func setupNotifications() {
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(appDidEnterBackground),
|
||||
name: UIApplication.didEnterBackgroundNotification,
|
||||
object: nil
|
||||
)
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(appWillEnterForeground),
|
||||
name: UIApplication.willEnterForegroundNotification,
|
||||
object: nil
|
||||
)
|
||||
}
|
||||
|
||||
@objc private func appDidEnterBackground() {
|
||||
if !activeStreams.isEmpty {
|
||||
startBackgroundTask()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func appWillEnterForeground() {
|
||||
endBackgroundTask()
|
||||
}
|
||||
|
||||
func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "startBackgroundExecution":
|
||||
if let args = call.arguments as? [String: Any],
|
||||
let streamIds = args["streamIds"] as? [String] {
|
||||
startBackgroundExecution(streamIds: streamIds)
|
||||
result(nil)
|
||||
} else {
|
||||
result(FlutterError(code: "INVALID_ARGS", message: "Invalid arguments", details: nil))
|
||||
}
|
||||
|
||||
case "stopBackgroundExecution":
|
||||
if let args = call.arguments as? [String: Any],
|
||||
let streamIds = args["streamIds"] as? [String] {
|
||||
stopBackgroundExecution(streamIds: streamIds)
|
||||
result(nil)
|
||||
} else {
|
||||
result(FlutterError(code: "INVALID_ARGS", message: "Invalid arguments", details: nil))
|
||||
}
|
||||
|
||||
case "keepAlive":
|
||||
keepAlive()
|
||||
result(nil)
|
||||
|
||||
case "saveStreamStates":
|
||||
if let args = call.arguments as? [String: Any],
|
||||
let states = args["states"] as? [[String: Any]] {
|
||||
saveStreamStates(states)
|
||||
result(nil)
|
||||
} else {
|
||||
result(FlutterError(code: "INVALID_ARGS", message: "Invalid arguments", details: nil))
|
||||
}
|
||||
|
||||
case "recoverStreamStates":
|
||||
result(recoverStreamStates())
|
||||
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
private func startBackgroundExecution(streamIds: [String]) {
|
||||
activeStreams = Set(streamIds)
|
||||
|
||||
if UIApplication.shared.applicationState == .background {
|
||||
startBackgroundTask()
|
||||
}
|
||||
}
|
||||
|
||||
private func stopBackgroundExecution(streamIds: [String]) {
|
||||
streamIds.forEach { activeStreams.remove($0) }
|
||||
|
||||
if activeStreams.isEmpty {
|
||||
endBackgroundTask()
|
||||
}
|
||||
}
|
||||
|
||||
private func startBackgroundTask() {
|
||||
guard backgroundTask == .invalid else { return }
|
||||
|
||||
backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "ConduitStreaming") { [weak self] in
|
||||
self?.endBackgroundTask()
|
||||
}
|
||||
}
|
||||
|
||||
private func endBackgroundTask() {
|
||||
guard backgroundTask != .invalid else { return }
|
||||
|
||||
UIApplication.shared.endBackgroundTask(backgroundTask)
|
||||
backgroundTask = .invalid
|
||||
}
|
||||
|
||||
private func keepAlive() {
|
||||
if backgroundTask != .invalid {
|
||||
endBackgroundTask()
|
||||
startBackgroundTask()
|
||||
}
|
||||
}
|
||||
|
||||
private func saveStreamStates(_ states: [[String: Any]]) {
|
||||
UserDefaults.standard.set(states, forKey: "ConduitActiveStreams")
|
||||
}
|
||||
|
||||
private func recoverStreamStates() -> [[String: Any]] {
|
||||
return UserDefaults.standard.array(forKey: "ConduitActiveStreams") as? [[String: Any]] ?? []
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
endBackgroundTask()
|
||||
}
|
||||
}
|
||||
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
private var backgroundStreamingHandler: BackgroundStreamingHandler?
|
||||
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
|
||||
// Setup background streaming handler manually
|
||||
if let controller = window?.rootViewController as? FlutterViewController {
|
||||
let channel = FlutterMethodChannel(
|
||||
name: "conduit/background_streaming",
|
||||
binaryMessenger: controller.binaryMessenger
|
||||
)
|
||||
|
||||
backgroundStreamingHandler = BackgroundStreamingHandler()
|
||||
backgroundStreamingHandler?.setup(with: channel)
|
||||
|
||||
// Register method call handler
|
||||
channel.setMethodCallHandler { [weak self] (call, result) in
|
||||
self?.backgroundStreamingHandler?.handle(call, result: result)
|
||||
}
|
||||
}
|
||||
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user