diff --git a/melos.yaml b/melos.yaml index 64dece9..8fad648 100644 --- a/melos.yaml +++ b/melos.yaml @@ -15,3 +15,7 @@ scripts: generate:dart: run: melos exec -c 1 --depends-on="build_runner" --no-flutter -- "dart run build_runner build --delete-conflicting-outputs" description: Build all generated files for Dart packages in this project. + + generate:pigeon: + run: cd workmanager_platform_interface && dart run pigeon --input pigeons/workmanager_api.dart + description: Generate Pigeon type-safe platform channel code for workmanager_platform_interface. diff --git a/workmanager_android/lib/workmanager_android.dart b/workmanager_android/lib/workmanager_android.dart index bdafbfe..1abc0d8 100644 --- a/workmanager_android/lib/workmanager_android.dart +++ b/workmanager_android/lib/workmanager_android.dart @@ -47,7 +47,7 @@ class WorkmanagerAndroid extends WorkmanagerPlatform { 'taskName': taskName, 'inputData': inputData, 'initialDelaySeconds': initialDelay?.inSeconds, - 'networkType': constraints?.networkType.name, + 'networkType': constraints?.networkType?.name, 'requiresBatteryNotLow': constraints?.requiresBatteryNotLow, 'requiresCharging': constraints?.requiresCharging, 'requiresDeviceIdle': constraints?.requiresDeviceIdle, @@ -81,7 +81,7 @@ class WorkmanagerAndroid extends WorkmanagerPlatform { 'frequencySeconds': frequency?.inSeconds, 'flexIntervalSeconds': flexInterval?.inSeconds, 'initialDelaySeconds': initialDelay?.inSeconds, - 'networkType': constraints?.networkType.name, + 'networkType': constraints?.networkType?.name, 'requiresBatteryNotLow': constraints?.requiresBatteryNotLow, 'requiresCharging': constraints?.requiresCharging, 'requiresDeviceIdle': constraints?.requiresDeviceIdle, diff --git a/workmanager_apple/lib/workmanager_apple.dart b/workmanager_apple/lib/workmanager_apple.dart index 009c7b4..9c70ead 100644 --- a/workmanager_apple/lib/workmanager_apple.dart +++ b/workmanager_apple/lib/workmanager_apple.dart @@ -85,7 +85,7 @@ class WorkmanagerApple extends WorkmanagerPlatform { 'taskName': taskName, 'inputData': inputData, 'initialDelaySeconds': initialDelay?.inSeconds, - 'networkType': constraints?.networkType.name, + 'networkType': constraints?.networkType?.name, 'requiresCharging': constraints?.requiresCharging, }); } diff --git a/workmanager_platform_interface/android/src/main/kotlin/dev/fluttercommunity/workmanager/pigeon/WorkmanagerApi.g.kt b/workmanager_platform_interface/android/src/main/kotlin/dev/fluttercommunity/workmanager/pigeon/WorkmanagerApi.g.kt new file mode 100644 index 0000000..8460e10 --- /dev/null +++ b/workmanager_platform_interface/android/src/main/kotlin/dev/fluttercommunity/workmanager/pigeon/WorkmanagerApi.g.kt @@ -0,0 +1,686 @@ +// // Copyright 2024 The Flutter Workmanager Authors. All rights reserved. +// // Use of this source code is governed by a MIT-style license that can be +// // found in the LICENSE file. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. +// See also: https://pub.dev/packages/pigeon +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") + +package dev.fluttercommunity.workmanager.pigeon + +import android.util.Log +import io.flutter.plugin.common.BasicMessageChannel +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.MessageCodec +import io.flutter.plugin.common.StandardMethodCodec +import io.flutter.plugin.common.StandardMessageCodec +import java.io.ByteArrayOutputStream +import java.nio.ByteBuffer + +private fun wrapResult(result: Any?): List { + return listOf(result) +} + +private fun wrapError(exception: Throwable): List { + return if (exception is FlutterError) { + listOf( + exception.code, + exception.message, + exception.details + ) + } else { + listOf( + exception.javaClass.simpleName, + exception.toString(), + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) + ) + } +} + +private fun createConnectionError(channelName: String): FlutterError { + return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "")} + +/** + * Error class for passing custom error details to Flutter via a thrown PlatformException. + * @property code The error code. + * @property message The error message. + * @property details The error details. Must be a datatype supported by the api codec. + */ +class FlutterError ( + val code: String, + override val message: String? = null, + val details: Any? = null +) : Throwable() + +/** + * An enumeration of various network types that can be used as Constraints for work. + * + * Fully supported on Android. + * + * On iOS, this enumeration is used to define whether a piece of work requires + * internet connectivity, by checking for either [NetworkType.connected] or + * [NetworkType.metered]. + */ +enum class NetworkType(val raw: Int) { + /** Any working network connection is required for this work. */ + CONNECTED(0), + /** A metered network connection is required for this work. */ + METERED(1), + /** Default value. A network is not required for this work. */ + NOT_REQUIRED(2), + /** A non-roaming network connection is required for this work. */ + NOT_ROAMING(3), + /** An unmetered network connection is required for this work. */ + UNMETERED(4), + /** + * A temporarily unmetered Network. This capability will be set for + * networks that are generally metered, but are currently unmetered. + * + * Android API 30+ + */ + TEMPORARILY_UNMETERED(5); + + companion object { + fun ofRaw(raw: Int): NetworkType? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** + * An enumeration of backoff policies when retrying work. + * These policies are used when you have a return ListenableWorker.Result.retry() from a worker to determine the correct backoff time. + * Backoff policies are set in WorkRequest.Builder.setBackoffCriteria(BackoffPolicy, long, TimeUnit) or one of its variants. + */ +enum class BackoffPolicy(val raw: Int) { + /** Used to indicate that WorkManager should increase the backoff time exponentially */ + EXPONENTIAL(0), + /** Used to indicate that WorkManager should increase the backoff time linearly */ + LINEAR(1); + + companion object { + fun ofRaw(raw: Int): BackoffPolicy? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** An enumeration of the conflict resolution policies in case of a collision. */ +enum class ExistingWorkPolicy(val raw: Int) { + /** If there is existing pending (uncompleted) work with the same unique name, append the newly-specified work as a child of all the leaves of that work sequence. */ + APPEND(0), + /** If there is existing pending (uncompleted) work with the same unique name, do nothing. */ + KEEP(1), + /** If there is existing pending (uncompleted) work with the same unique name, cancel and delete it. */ + REPLACE(2), + /** + * If there is existing pending (uncompleted) work with the same unique name, it will be updated the new specification. + * Note: This maps to appendOrReplace in the native implementation. + */ + UPDATE(3); + + companion object { + fun ofRaw(raw: Int): ExistingWorkPolicy? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** + * An enumeration of policies that help determine out of quota behavior for expedited jobs. + * + * Only supported on Android. + */ +enum class OutOfQuotaPolicy(val raw: Int) { + /** + * When the app does not have any expedited job quota, the expedited work request will + * fallback to a regular work request. + */ + RUN_AS_NON_EXPEDITED_WORK_REQUEST(0), + /** + * When the app does not have any expedited job quota, the expedited work request will + * we dropped and no work requests are enqueued. + */ + DROP_WORK_REQUEST(1); + + companion object { + fun ofRaw(raw: Int): OutOfQuotaPolicy? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class Constraints ( + val networkType: NetworkType? = null, + val requiresBatteryNotLow: Boolean? = null, + val requiresCharging: Boolean? = null, + val requiresDeviceIdle: Boolean? = null, + val requiresStorageNotLow: Boolean? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): Constraints { + val networkType = pigeonVar_list[0] as NetworkType? + val requiresBatteryNotLow = pigeonVar_list[1] as Boolean? + val requiresCharging = pigeonVar_list[2] as Boolean? + val requiresDeviceIdle = pigeonVar_list[3] as Boolean? + val requiresStorageNotLow = pigeonVar_list[4] as Boolean? + return Constraints(networkType, requiresBatteryNotLow, requiresCharging, requiresDeviceIdle, requiresStorageNotLow) + } + } + fun toList(): List { + return listOf( + networkType, + requiresBatteryNotLow, + requiresCharging, + requiresDeviceIdle, + requiresStorageNotLow, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class BackoffPolicyConfig ( + val backoffPolicy: BackoffPolicy? = null, + val backoffDelayMillis: Long? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): BackoffPolicyConfig { + val backoffPolicy = pigeonVar_list[0] as BackoffPolicy? + val backoffDelayMillis = pigeonVar_list[1] as Long? + return BackoffPolicyConfig(backoffPolicy, backoffDelayMillis) + } + } + fun toList(): List { + return listOf( + backoffPolicy, + backoffDelayMillis, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class InitializeRequest ( + val callbackHandle: Long, + val isInDebugMode: Boolean +) + { + companion object { + fun fromList(pigeonVar_list: List): InitializeRequest { + val callbackHandle = pigeonVar_list[0] as Long + val isInDebugMode = pigeonVar_list[1] as Boolean + return InitializeRequest(callbackHandle, isInDebugMode) + } + } + fun toList(): List { + return listOf( + callbackHandle, + isInDebugMode, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class OneOffTaskRequest ( + val uniqueName: String, + val taskName: String, + val inputData: Map? = null, + val initialDelaySeconds: Long? = null, + val constraints: Constraints? = null, + val backoffPolicy: BackoffPolicyConfig? = null, + val tag: String? = null, + val existingWorkPolicy: ExistingWorkPolicy? = null, + val outOfQuotaPolicy: OutOfQuotaPolicy? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): OneOffTaskRequest { + val uniqueName = pigeonVar_list[0] as String + val taskName = pigeonVar_list[1] as String + val inputData = pigeonVar_list[2] as Map? + val initialDelaySeconds = pigeonVar_list[3] as Long? + val constraints = pigeonVar_list[4] as Constraints? + val backoffPolicy = pigeonVar_list[5] as BackoffPolicyConfig? + val tag = pigeonVar_list[6] as String? + val existingWorkPolicy = pigeonVar_list[7] as ExistingWorkPolicy? + val outOfQuotaPolicy = pigeonVar_list[8] as OutOfQuotaPolicy? + return OneOffTaskRequest(uniqueName, taskName, inputData, initialDelaySeconds, constraints, backoffPolicy, tag, existingWorkPolicy, outOfQuotaPolicy) + } + } + fun toList(): List { + return listOf( + uniqueName, + taskName, + inputData, + initialDelaySeconds, + constraints, + backoffPolicy, + tag, + existingWorkPolicy, + outOfQuotaPolicy, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class PeriodicTaskRequest ( + val uniqueName: String, + val taskName: String, + val frequencySeconds: Long, + val flexIntervalSeconds: Long? = null, + val inputData: Map? = null, + val initialDelaySeconds: Long? = null, + val constraints: Constraints? = null, + val backoffPolicy: BackoffPolicyConfig? = null, + val tag: String? = null, + val existingWorkPolicy: ExistingWorkPolicy? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): PeriodicTaskRequest { + val uniqueName = pigeonVar_list[0] as String + val taskName = pigeonVar_list[1] as String + val frequencySeconds = pigeonVar_list[2] as Long + val flexIntervalSeconds = pigeonVar_list[3] as Long? + val inputData = pigeonVar_list[4] as Map? + val initialDelaySeconds = pigeonVar_list[5] as Long? + val constraints = pigeonVar_list[6] as Constraints? + val backoffPolicy = pigeonVar_list[7] as BackoffPolicyConfig? + val tag = pigeonVar_list[8] as String? + val existingWorkPolicy = pigeonVar_list[9] as ExistingWorkPolicy? + return PeriodicTaskRequest(uniqueName, taskName, frequencySeconds, flexIntervalSeconds, inputData, initialDelaySeconds, constraints, backoffPolicy, tag, existingWorkPolicy) + } + } + fun toList(): List { + return listOf( + uniqueName, + taskName, + frequencySeconds, + flexIntervalSeconds, + inputData, + initialDelaySeconds, + constraints, + backoffPolicy, + tag, + existingWorkPolicy, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class ProcessingTaskRequest ( + val uniqueName: String, + val taskName: String, + val inputData: Map? = null, + val initialDelaySeconds: Long? = null, + val networkType: NetworkType? = null, + val requiresCharging: Boolean? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): ProcessingTaskRequest { + val uniqueName = pigeonVar_list[0] as String + val taskName = pigeonVar_list[1] as String + val inputData = pigeonVar_list[2] as Map? + val initialDelaySeconds = pigeonVar_list[3] as Long? + val networkType = pigeonVar_list[4] as NetworkType? + val requiresCharging = pigeonVar_list[5] as Boolean? + return ProcessingTaskRequest(uniqueName, taskName, inputData, initialDelaySeconds, networkType, requiresCharging) + } + } + fun toList(): List { + return listOf( + uniqueName, + taskName, + inputData, + initialDelaySeconds, + networkType, + requiresCharging, + ) + } +} +private open class WorkmanagerApiPigeonCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 129.toByte() -> { + return (readValue(buffer) as Long?)?.let { + NetworkType.ofRaw(it.toInt()) + } + } + 130.toByte() -> { + return (readValue(buffer) as Long?)?.let { + BackoffPolicy.ofRaw(it.toInt()) + } + } + 131.toByte() -> { + return (readValue(buffer) as Long?)?.let { + ExistingWorkPolicy.ofRaw(it.toInt()) + } + } + 132.toByte() -> { + return (readValue(buffer) as Long?)?.let { + OutOfQuotaPolicy.ofRaw(it.toInt()) + } + } + 133.toByte() -> { + return (readValue(buffer) as? List)?.let { + Constraints.fromList(it) + } + } + 134.toByte() -> { + return (readValue(buffer) as? List)?.let { + BackoffPolicyConfig.fromList(it) + } + } + 135.toByte() -> { + return (readValue(buffer) as? List)?.let { + InitializeRequest.fromList(it) + } + } + 136.toByte() -> { + return (readValue(buffer) as? List)?.let { + OneOffTaskRequest.fromList(it) + } + } + 137.toByte() -> { + return (readValue(buffer) as? List)?.let { + PeriodicTaskRequest.fromList(it) + } + } + 138.toByte() -> { + return (readValue(buffer) as? List)?.let { + ProcessingTaskRequest.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is NetworkType -> { + stream.write(129) + writeValue(stream, value.raw) + } + is BackoffPolicy -> { + stream.write(130) + writeValue(stream, value.raw) + } + is ExistingWorkPolicy -> { + stream.write(131) + writeValue(stream, value.raw) + } + is OutOfQuotaPolicy -> { + stream.write(132) + writeValue(stream, value.raw) + } + is Constraints -> { + stream.write(133) + writeValue(stream, value.toList()) + } + is BackoffPolicyConfig -> { + stream.write(134) + writeValue(stream, value.toList()) + } + is InitializeRequest -> { + stream.write(135) + writeValue(stream, value.toList()) + } + is OneOffTaskRequest -> { + stream.write(136) + writeValue(stream, value.toList()) + } + is PeriodicTaskRequest -> { + stream.write(137) + writeValue(stream, value.toList()) + } + is ProcessingTaskRequest -> { + stream.write(138) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + + +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ +interface WorkmanagerHostApi { + fun initialize(request: InitializeRequest, callback: (Result) -> Unit) + fun registerOneOffTask(request: OneOffTaskRequest, callback: (Result) -> Unit) + fun registerPeriodicTask(request: PeriodicTaskRequest, callback: (Result) -> Unit) + fun registerProcessingTask(request: ProcessingTaskRequest, callback: (Result) -> Unit) + fun cancelByUniqueName(uniqueName: String, callback: (Result) -> Unit) + fun cancelByTag(tag: String, callback: (Result) -> Unit) + fun cancelAll(callback: (Result) -> Unit) + fun isScheduledByUniqueName(uniqueName: String, callback: (Result) -> Unit) + fun printScheduledTasks(callback: (Result) -> Unit) + + companion object { + /** The codec used by WorkmanagerHostApi. */ + val codec: MessageCodec by lazy { + WorkmanagerApiPigeonCodec() + } + /** Sets up an instance of `WorkmanagerHostApi` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: WorkmanagerHostApi?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.initialize$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as InitializeRequest + api.initialize(requestArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.registerOneOffTask$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as OneOffTaskRequest + api.registerOneOffTask(requestArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.registerPeriodicTask$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as PeriodicTaskRequest + api.registerPeriodicTask(requestArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.registerProcessingTask$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as ProcessingTaskRequest + api.registerProcessingTask(requestArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.cancelByUniqueName$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val uniqueNameArg = args[0] as String + api.cancelByUniqueName(uniqueNameArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.cancelByTag$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val tagArg = args[0] as String + api.cancelByTag(tagArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.cancelAll$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.cancelAll{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.isScheduledByUniqueName$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val uniqueNameArg = args[0] as String + api.isScheduledByUniqueName(uniqueNameArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.printScheduledTasks$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.printScheduledTasks{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ +class WorkmanagerFlutterApi(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { + companion object { + /** The codec used by WorkmanagerFlutterApi. */ + val codec: MessageCodec by lazy { + WorkmanagerApiPigeonCodec() + } + } + fun backgroundChannelInitialized(callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerFlutterApi.backgroundChannelInitialized$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(null) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } + fun executeTask(taskNameArg: String, inputDataArg: Map?, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerFlutterApi.executeTask$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(taskNameArg, inputDataArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else if (it[0] == null) { + callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", ""))) + } else { + val output = it[0] as Boolean + callback(Result.success(output)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } +} diff --git a/workmanager_platform_interface/ios/Classes/pigeon/WorkmanagerApi.g.swift b/workmanager_platform_interface/ios/Classes/pigeon/WorkmanagerApi.g.swift new file mode 100644 index 0000000..8c29c61 --- /dev/null +++ b/workmanager_platform_interface/ios/Classes/pigeon/WorkmanagerApi.g.swift @@ -0,0 +1,688 @@ +// // Copyright 2024 The Flutter Workmanager Authors. All rights reserved. +// // Use of this source code is governed by a MIT-style license that can be +// // found in the LICENSE file. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +import Foundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#else + #error("Unsupported platform.") +#endif + +/// Error class for passing custom error details to Dart side. +final class PigeonError: Error { + let code: String + let message: String? + let details: Any? + + init(code: String, message: String?, details: Any?) { + self.code = code + self.message = message + self.details = details + } + + var localizedDescription: String { + return + "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" + } +} + +private func wrapResult(_ result: Any?) -> [Any?] { + return [result] +} + +private func wrapError(_ error: Any) -> [Any?] { + if let pigeonError = error as? PigeonError { + return [ + pigeonError.code, + pigeonError.message, + pigeonError.details, + ] + } + if let flutterError = error as? FlutterError { + return [ + flutterError.code, + flutterError.message, + flutterError.details, + ] + } + return [ + "\(error)", + "\(type(of: error))", + "Stacktrace: \(Thread.callStackSymbols)", + ] +} + +private func createConnectionError(withChannelName channelName: String) -> PigeonError { + return PigeonError(code: "channel-error", message: "Unable to establish connection on channel: '\(channelName)'.", details: "") +} + +private func isNullish(_ value: Any?) -> Bool { + return value is NSNull || value == nil +} + +private func nilOrValue(_ value: Any?) -> T? { + if value is NSNull { return nil } + return value as! T? +} + +/// An enumeration of various network types that can be used as Constraints for work. +/// +/// Fully supported on Android. +/// +/// On iOS, this enumeration is used to define whether a piece of work requires +/// internet connectivity, by checking for either [NetworkType.connected] or +/// [NetworkType.metered]. +enum NetworkType: Int { + /// Any working network connection is required for this work. + case connected = 0 + /// A metered network connection is required for this work. + case metered = 1 + /// Default value. A network is not required for this work. + case notRequired = 2 + /// A non-roaming network connection is required for this work. + case notRoaming = 3 + /// An unmetered network connection is required for this work. + case unmetered = 4 + /// A temporarily unmetered Network. This capability will be set for + /// networks that are generally metered, but are currently unmetered. + /// + /// Android API 30+ + case temporarilyUnmetered = 5 +} + +/// An enumeration of backoff policies when retrying work. +/// These policies are used when you have a return ListenableWorker.Result.retry() from a worker to determine the correct backoff time. +/// Backoff policies are set in WorkRequest.Builder.setBackoffCriteria(BackoffPolicy, long, TimeUnit) or one of its variants. +enum BackoffPolicy: Int { + /// Used to indicate that WorkManager should increase the backoff time exponentially + case exponential = 0 + /// Used to indicate that WorkManager should increase the backoff time linearly + case linear = 1 +} + +/// An enumeration of the conflict resolution policies in case of a collision. +enum ExistingWorkPolicy: Int { + /// If there is existing pending (uncompleted) work with the same unique name, append the newly-specified work as a child of all the leaves of that work sequence. + case append = 0 + /// If there is existing pending (uncompleted) work with the same unique name, do nothing. + case keep = 1 + /// If there is existing pending (uncompleted) work with the same unique name, cancel and delete it. + case replace = 2 + /// If there is existing pending (uncompleted) work with the same unique name, it will be updated the new specification. + /// Note: This maps to appendOrReplace in the native implementation. + case update = 3 +} + +/// An enumeration of policies that help determine out of quota behavior for expedited jobs. +/// +/// Only supported on Android. +enum OutOfQuotaPolicy: Int { + /// When the app does not have any expedited job quota, the expedited work request will + /// fallback to a regular work request. + case runAsNonExpeditedWorkRequest = 0 + /// When the app does not have any expedited job quota, the expedited work request will + /// we dropped and no work requests are enqueued. + case dropWorkRequest = 1 +} + +/// Generated class from Pigeon that represents data sent in messages. +struct Constraints { + var networkType: NetworkType? = nil + var requiresBatteryNotLow: Bool? = nil + var requiresCharging: Bool? = nil + var requiresDeviceIdle: Bool? = nil + var requiresStorageNotLow: Bool? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> Constraints? { + let networkType: NetworkType? = nilOrValue(pigeonVar_list[0]) + let requiresBatteryNotLow: Bool? = nilOrValue(pigeonVar_list[1]) + let requiresCharging: Bool? = nilOrValue(pigeonVar_list[2]) + let requiresDeviceIdle: Bool? = nilOrValue(pigeonVar_list[3]) + let requiresStorageNotLow: Bool? = nilOrValue(pigeonVar_list[4]) + + return Constraints( + networkType: networkType, + requiresBatteryNotLow: requiresBatteryNotLow, + requiresCharging: requiresCharging, + requiresDeviceIdle: requiresDeviceIdle, + requiresStorageNotLow: requiresStorageNotLow + ) + } + func toList() -> [Any?] { + return [ + networkType, + requiresBatteryNotLow, + requiresCharging, + requiresDeviceIdle, + requiresStorageNotLow, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct BackoffPolicyConfig { + var backoffPolicy: BackoffPolicy? = nil + var backoffDelayMillis: Int64? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> BackoffPolicyConfig? { + let backoffPolicy: BackoffPolicy? = nilOrValue(pigeonVar_list[0]) + let backoffDelayMillis: Int64? = nilOrValue(pigeonVar_list[1]) + + return BackoffPolicyConfig( + backoffPolicy: backoffPolicy, + backoffDelayMillis: backoffDelayMillis + ) + } + func toList() -> [Any?] { + return [ + backoffPolicy, + backoffDelayMillis, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InitializeRequest { + var callbackHandle: Int64 + var isInDebugMode: Bool + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InitializeRequest? { + let callbackHandle = pigeonVar_list[0] as! Int64 + let isInDebugMode = pigeonVar_list[1] as! Bool + + return InitializeRequest( + callbackHandle: callbackHandle, + isInDebugMode: isInDebugMode + ) + } + func toList() -> [Any?] { + return [ + callbackHandle, + isInDebugMode, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct OneOffTaskRequest { + var uniqueName: String + var taskName: String + var inputData: [String?: Any?]? = nil + var initialDelaySeconds: Int64? = nil + var constraints: Constraints? = nil + var backoffPolicy: BackoffPolicyConfig? = nil + var tag: String? = nil + var existingWorkPolicy: ExistingWorkPolicy? = nil + var outOfQuotaPolicy: OutOfQuotaPolicy? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> OneOffTaskRequest? { + let uniqueName = pigeonVar_list[0] as! String + let taskName = pigeonVar_list[1] as! String + let inputData: [String?: Any?]? = nilOrValue(pigeonVar_list[2]) + let initialDelaySeconds: Int64? = nilOrValue(pigeonVar_list[3]) + let constraints: Constraints? = nilOrValue(pigeonVar_list[4]) + let backoffPolicy: BackoffPolicyConfig? = nilOrValue(pigeonVar_list[5]) + let tag: String? = nilOrValue(pigeonVar_list[6]) + let existingWorkPolicy: ExistingWorkPolicy? = nilOrValue(pigeonVar_list[7]) + let outOfQuotaPolicy: OutOfQuotaPolicy? = nilOrValue(pigeonVar_list[8]) + + return OneOffTaskRequest( + uniqueName: uniqueName, + taskName: taskName, + inputData: inputData, + initialDelaySeconds: initialDelaySeconds, + constraints: constraints, + backoffPolicy: backoffPolicy, + tag: tag, + existingWorkPolicy: existingWorkPolicy, + outOfQuotaPolicy: outOfQuotaPolicy + ) + } + func toList() -> [Any?] { + return [ + uniqueName, + taskName, + inputData, + initialDelaySeconds, + constraints, + backoffPolicy, + tag, + existingWorkPolicy, + outOfQuotaPolicy, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct PeriodicTaskRequest { + var uniqueName: String + var taskName: String + var frequencySeconds: Int64 + var flexIntervalSeconds: Int64? = nil + var inputData: [String?: Any?]? = nil + var initialDelaySeconds: Int64? = nil + var constraints: Constraints? = nil + var backoffPolicy: BackoffPolicyConfig? = nil + var tag: String? = nil + var existingWorkPolicy: ExistingWorkPolicy? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PeriodicTaskRequest? { + let uniqueName = pigeonVar_list[0] as! String + let taskName = pigeonVar_list[1] as! String + let frequencySeconds = pigeonVar_list[2] as! Int64 + let flexIntervalSeconds: Int64? = nilOrValue(pigeonVar_list[3]) + let inputData: [String?: Any?]? = nilOrValue(pigeonVar_list[4]) + let initialDelaySeconds: Int64? = nilOrValue(pigeonVar_list[5]) + let constraints: Constraints? = nilOrValue(pigeonVar_list[6]) + let backoffPolicy: BackoffPolicyConfig? = nilOrValue(pigeonVar_list[7]) + let tag: String? = nilOrValue(pigeonVar_list[8]) + let existingWorkPolicy: ExistingWorkPolicy? = nilOrValue(pigeonVar_list[9]) + + return PeriodicTaskRequest( + uniqueName: uniqueName, + taskName: taskName, + frequencySeconds: frequencySeconds, + flexIntervalSeconds: flexIntervalSeconds, + inputData: inputData, + initialDelaySeconds: initialDelaySeconds, + constraints: constraints, + backoffPolicy: backoffPolicy, + tag: tag, + existingWorkPolicy: existingWorkPolicy + ) + } + func toList() -> [Any?] { + return [ + uniqueName, + taskName, + frequencySeconds, + flexIntervalSeconds, + inputData, + initialDelaySeconds, + constraints, + backoffPolicy, + tag, + existingWorkPolicy, + ] + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct ProcessingTaskRequest { + var uniqueName: String + var taskName: String + var inputData: [String?: Any?]? = nil + var initialDelaySeconds: Int64? = nil + var networkType: NetworkType? = nil + var requiresCharging: Bool? = nil + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> ProcessingTaskRequest? { + let uniqueName = pigeonVar_list[0] as! String + let taskName = pigeonVar_list[1] as! String + let inputData: [String?: Any?]? = nilOrValue(pigeonVar_list[2]) + let initialDelaySeconds: Int64? = nilOrValue(pigeonVar_list[3]) + let networkType: NetworkType? = nilOrValue(pigeonVar_list[4]) + let requiresCharging: Bool? = nilOrValue(pigeonVar_list[5]) + + return ProcessingTaskRequest( + uniqueName: uniqueName, + taskName: taskName, + inputData: inputData, + initialDelaySeconds: initialDelaySeconds, + networkType: networkType, + requiresCharging: requiresCharging + ) + } + func toList() -> [Any?] { + return [ + uniqueName, + taskName, + inputData, + initialDelaySeconds, + networkType, + requiresCharging, + ] + } +} + +private class WorkmanagerApiPigeonCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 129: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return NetworkType(rawValue: enumResultAsInt) + } + return nil + case 130: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return BackoffPolicy(rawValue: enumResultAsInt) + } + return nil + case 131: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return ExistingWorkPolicy(rawValue: enumResultAsInt) + } + return nil + case 132: + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return OutOfQuotaPolicy(rawValue: enumResultAsInt) + } + return nil + case 133: + return Constraints.fromList(self.readValue() as! [Any?]) + case 134: + return BackoffPolicyConfig.fromList(self.readValue() as! [Any?]) + case 135: + return InitializeRequest.fromList(self.readValue() as! [Any?]) + case 136: + return OneOffTaskRequest.fromList(self.readValue() as! [Any?]) + case 137: + return PeriodicTaskRequest.fromList(self.readValue() as! [Any?]) + case 138: + return ProcessingTaskRequest.fromList(self.readValue() as! [Any?]) + default: + return super.readValue(ofType: type) + } + } +} + +private class WorkmanagerApiPigeonCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? NetworkType { + super.writeByte(129) + super.writeValue(value.rawValue) + } else if let value = value as? BackoffPolicy { + super.writeByte(130) + super.writeValue(value.rawValue) + } else if let value = value as? ExistingWorkPolicy { + super.writeByte(131) + super.writeValue(value.rawValue) + } else if let value = value as? OutOfQuotaPolicy { + super.writeByte(132) + super.writeValue(value.rawValue) + } else if let value = value as? Constraints { + super.writeByte(133) + super.writeValue(value.toList()) + } else if let value = value as? BackoffPolicyConfig { + super.writeByte(134) + super.writeValue(value.toList()) + } else if let value = value as? InitializeRequest { + super.writeByte(135) + super.writeValue(value.toList()) + } else if let value = value as? OneOffTaskRequest { + super.writeByte(136) + super.writeValue(value.toList()) + } else if let value = value as? PeriodicTaskRequest { + super.writeByte(137) + super.writeValue(value.toList()) + } else if let value = value as? ProcessingTaskRequest { + super.writeByte(138) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class WorkmanagerApiPigeonCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return WorkmanagerApiPigeonCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return WorkmanagerApiPigeonCodecWriter(data: data) + } +} + +class WorkmanagerApiPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { + static let shared = WorkmanagerApiPigeonCodec(readerWriter: WorkmanagerApiPigeonCodecReaderWriter()) +} + + +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol WorkmanagerHostApi { + func initialize(request: InitializeRequest, completion: @escaping (Result) -> Void) + func registerOneOffTask(request: OneOffTaskRequest, completion: @escaping (Result) -> Void) + func registerPeriodicTask(request: PeriodicTaskRequest, completion: @escaping (Result) -> Void) + func registerProcessingTask(request: ProcessingTaskRequest, completion: @escaping (Result) -> Void) + func cancelByUniqueName(uniqueName: String, completion: @escaping (Result) -> Void) + func cancelByTag(tag: String, completion: @escaping (Result) -> Void) + func cancelAll(completion: @escaping (Result) -> Void) + func isScheduledByUniqueName(uniqueName: String, completion: @escaping (Result) -> Void) + func printScheduledTasks(completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class WorkmanagerHostApiSetup { + static var codec: FlutterStandardMessageCodec { WorkmanagerApiPigeonCodec.shared } + /// Sets up an instance of `WorkmanagerHostApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: WorkmanagerHostApi?, messageChannelSuffix: String = "") { + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + let initializeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.initialize\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + initializeChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let requestArg = args[0] as! InitializeRequest + api.initialize(request: requestArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + initializeChannel.setMessageHandler(nil) + } + let registerOneOffTaskChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.registerOneOffTask\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + registerOneOffTaskChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let requestArg = args[0] as! OneOffTaskRequest + api.registerOneOffTask(request: requestArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + registerOneOffTaskChannel.setMessageHandler(nil) + } + let registerPeriodicTaskChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.registerPeriodicTask\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + registerPeriodicTaskChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let requestArg = args[0] as! PeriodicTaskRequest + api.registerPeriodicTask(request: requestArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + registerPeriodicTaskChannel.setMessageHandler(nil) + } + let registerProcessingTaskChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.registerProcessingTask\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + registerProcessingTaskChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let requestArg = args[0] as! ProcessingTaskRequest + api.registerProcessingTask(request: requestArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + registerProcessingTaskChannel.setMessageHandler(nil) + } + let cancelByUniqueNameChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.cancelByUniqueName\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + cancelByUniqueNameChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let uniqueNameArg = args[0] as! String + api.cancelByUniqueName(uniqueName: uniqueNameArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + cancelByUniqueNameChannel.setMessageHandler(nil) + } + let cancelByTagChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.cancelByTag\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + cancelByTagChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let tagArg = args[0] as! String + api.cancelByTag(tag: tagArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + cancelByTagChannel.setMessageHandler(nil) + } + let cancelAllChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.cancelAll\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + cancelAllChannel.setMessageHandler { _, reply in + api.cancelAll { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + cancelAllChannel.setMessageHandler(nil) + } + let isScheduledByUniqueNameChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.isScheduledByUniqueName\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + isScheduledByUniqueNameChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let uniqueNameArg = args[0] as! String + api.isScheduledByUniqueName(uniqueName: uniqueNameArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + isScheduledByUniqueNameChannel.setMessageHandler(nil) + } + let printScheduledTasksChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.printScheduledTasks\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + printScheduledTasksChannel.setMessageHandler { _, reply in + api.printScheduledTasks { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + printScheduledTasksChannel.setMessageHandler(nil) + } + } +} +/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. +protocol WorkmanagerFlutterApiProtocol { + func backgroundChannelInitialized(completion: @escaping (Result) -> Void) + func executeTask(taskName taskNameArg: String, inputData inputDataArg: [String?: Any?]?, completion: @escaping (Result) -> Void) +} +class WorkmanagerFlutterApi: WorkmanagerFlutterApiProtocol { + private let binaryMessenger: FlutterBinaryMessenger + private let messageChannelSuffix: String + init(binaryMessenger: FlutterBinaryMessenger, messageChannelSuffix: String = "") { + self.binaryMessenger = binaryMessenger + self.messageChannelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + } + var codec: WorkmanagerApiPigeonCodec { + return WorkmanagerApiPigeonCodec.shared + } + func backgroundChannelInitialized(completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerFlutterApi.backgroundChannelInitialized\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } + func executeTask(taskName taskNameArg: String, inputData inputDataArg: [String?: Any?]?, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerFlutterApi.executeTask\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([taskNameArg, inputDataArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(PigeonError(code: code, message: message, details: details))) + } else if listResponse[0] == nil { + completion(.failure(PigeonError(code: "null-error", message: "Flutter api returned null value for non-null return value.", details: ""))) + } else { + let result = listResponse[0] as! Bool + completion(.success(result)) + } + } + } +} diff --git a/workmanager_platform_interface/lib/src/enums.dart b/workmanager_platform_interface/lib/src/enums.dart deleted file mode 100644 index 0254126..0000000 --- a/workmanager_platform_interface/lib/src/enums.dart +++ /dev/null @@ -1,26 +0,0 @@ -/// Enum for specifying the frequency at which periodic work repeats. -enum Frequency { - /// When no frequency is given. - never, - - /// Work repeats with a minimal interval of 15 minutes. - min15minutes, - - /// Work repeats with an interval of 30 minutes. - min30minutes, - - /// Work repeats with an interval of 1 hour. - hourly, - - /// Work repeats with an interval of 6 hours. - sixHourly, - - /// Work repeats with an interval of 12 hours. - twelveHourly, - - /// Work repeats with an interval of 1 day. - daily, - - /// Work repeats with an interval of 1 week. - weekly, -} diff --git a/workmanager_platform_interface/lib/src/options.dart b/workmanager_platform_interface/lib/src/options.dart deleted file mode 100644 index b23ec4c..0000000 --- a/workmanager_platform_interface/lib/src/options.dart +++ /dev/null @@ -1,103 +0,0 @@ -/// An enumeration of the conflict resolution policies in case of a collision. -enum ExistingWorkPolicy { - /// If there is existing pending (uncompleted) work with the same unique name, append the newly-specified work as a child of all the leaves of that work sequence. - append, - - /// If there is existing pending (uncompleted) work with the same unique name, it will be updated the new specification. - update, - - /// If there is existing pending (uncompleted) work with the same unique name, do nothing. - keep, - - /// If there is existing pending (uncompleted) work with the same unique name, cancel and delete it. - replace -} - -/// An enumeration of various network types that can be used as Constraints for work. -/// -/// Fully supported on Android. -/// -/// On iOS, this enumeration is used to define whether a piece of work requires -/// internet connectivity, by checking for either [NetworkType.connected] or -/// [NetworkType.metered]. -enum NetworkType { - /// Any working network connection is required for this work. - connected, - - /// A metered network connection is required for this work. - metered, - - /// Default value. A network is not required for this work. - notRequired, - - /// A non-roaming network connection is required for this work. - notRoaming, - - /// An unmetered network connection is required for this work. - unmetered, - - /// A temporarily unmetered Network. This capability will be set for - /// networks that are generally metered, but are currently unmetered. - /// - /// Android API 30+ - temporarilyUnmetered, -} - -/// An enumeration of policies that help determine out of quota behavior for expedited jobs. -/// -/// Only supported on Android. -enum OutOfQuotaPolicy { - /// When the app does not have any expedited job quota, the expedited work request will - /// fallback to a regular work request. - runAsNonExpeditedWorkRequest, - - /// When the app does not have any expedited job quota, the expedited work request will - /// we dropped and no work requests are enqueued. - dropWorkRequest, -} - -/// An enumeration of backoff policies when retrying work. -/// These policies are used when you have a return ListenableWorker.Result.retry() from a worker to determine the correct backoff time. -/// Backoff policies are set in WorkRequest.Builder.setBackoffCriteria(BackoffPolicy, long, TimeUnit) or one of its variants. -enum BackoffPolicy { - /// Used to indicate that WorkManager should increase the backoff time exponentially - exponential, - - /// Used to indicate that WorkManager should increase the backoff time linearly - linear -} - -/// A specification of the requirements that need to be met before a WorkRequest can run. -/// By default, WorkRequests do not have any requirements and can run immediately. -/// By adding requirements, you can make sure that work only runs in certain situations - -/// for example, when you have an unmetered network and are charging. -class Constraints { - /// An enumeration of various network types that can be used as Constraints for work. - final NetworkType networkType; - - /// `true` if the work should only execute when the battery isn't low. - /// - /// Only supported on Android. - final bool? requiresBatteryNotLow; - - /// `true` if the work should only execute while the device is charging. - final bool? requiresCharging; - - /// `true` if the work should only execute while the device is idle. - /// - /// Only supported on Android. - final bool? requiresDeviceIdle; - - /// `true` if the work should only execute when the storage isn't low. - /// - /// Only supported on Android. - final bool? requiresStorageNotLow; - - Constraints({ - required this.networkType, - this.requiresBatteryNotLow, - this.requiresCharging, - this.requiresDeviceIdle, - this.requiresStorageNotLow, - }); -} diff --git a/workmanager_platform_interface/lib/src/pigeon/workmanager_api.g.dart b/workmanager_platform_interface/lib/src/pigeon/workmanager_api.g.dart new file mode 100644 index 0000000..2ecbfe1 --- /dev/null +++ b/workmanager_platform_interface/lib/src/pigeon/workmanager_api.g.dart @@ -0,0 +1,710 @@ +// // Copyright 2024 The Flutter Workmanager Authors. All rights reserved. +// // Use of this source code is governed by a MIT-style license that can be +// // found in the LICENSE file. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + +List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { + if (empty) { + return []; + } + if (error == null) { + return [result]; + } + return [error.code, error.message, error.details]; +} + +/// An enumeration of various network types that can be used as Constraints for work. +/// +/// Fully supported on Android. +/// +/// On iOS, this enumeration is used to define whether a piece of work requires +/// internet connectivity, by checking for either [NetworkType.connected] or +/// [NetworkType.metered]. +enum NetworkType { + /// Any working network connection is required for this work. + connected, + /// A metered network connection is required for this work. + metered, + /// Default value. A network is not required for this work. + notRequired, + /// A non-roaming network connection is required for this work. + notRoaming, + /// An unmetered network connection is required for this work. + unmetered, + /// A temporarily unmetered Network. This capability will be set for + /// networks that are generally metered, but are currently unmetered. + /// + /// Android API 30+ + temporarilyUnmetered, +} + +/// An enumeration of backoff policies when retrying work. +/// These policies are used when you have a return ListenableWorker.Result.retry() from a worker to determine the correct backoff time. +/// Backoff policies are set in WorkRequest.Builder.setBackoffCriteria(BackoffPolicy, long, TimeUnit) or one of its variants. +enum BackoffPolicy { + /// Used to indicate that WorkManager should increase the backoff time exponentially + exponential, + /// Used to indicate that WorkManager should increase the backoff time linearly + linear, +} + +/// An enumeration of the conflict resolution policies in case of a collision. +enum ExistingWorkPolicy { + /// If there is existing pending (uncompleted) work with the same unique name, append the newly-specified work as a child of all the leaves of that work sequence. + append, + /// If there is existing pending (uncompleted) work with the same unique name, do nothing. + keep, + /// If there is existing pending (uncompleted) work with the same unique name, cancel and delete it. + replace, + /// If there is existing pending (uncompleted) work with the same unique name, it will be updated the new specification. + /// Note: This maps to appendOrReplace in the native implementation. + update, +} + +/// An enumeration of policies that help determine out of quota behavior for expedited jobs. +/// +/// Only supported on Android. +enum OutOfQuotaPolicy { + /// When the app does not have any expedited job quota, the expedited work request will + /// fallback to a regular work request. + runAsNonExpeditedWorkRequest, + /// When the app does not have any expedited job quota, the expedited work request will + /// we dropped and no work requests are enqueued. + dropWorkRequest, +} + +class Constraints { + Constraints({ + this.networkType, + this.requiresBatteryNotLow, + this.requiresCharging, + this.requiresDeviceIdle, + this.requiresStorageNotLow, + }); + + NetworkType? networkType; + + bool? requiresBatteryNotLow; + + bool? requiresCharging; + + bool? requiresDeviceIdle; + + bool? requiresStorageNotLow; + + Object encode() { + return [ + networkType, + requiresBatteryNotLow, + requiresCharging, + requiresDeviceIdle, + requiresStorageNotLow, + ]; + } + + static Constraints decode(Object result) { + result as List; + return Constraints( + networkType: result[0] as NetworkType?, + requiresBatteryNotLow: result[1] as bool?, + requiresCharging: result[2] as bool?, + requiresDeviceIdle: result[3] as bool?, + requiresStorageNotLow: result[4] as bool?, + ); + } +} + +class BackoffPolicyConfig { + BackoffPolicyConfig({ + this.backoffPolicy, + this.backoffDelayMillis, + }); + + BackoffPolicy? backoffPolicy; + + int? backoffDelayMillis; + + Object encode() { + return [ + backoffPolicy, + backoffDelayMillis, + ]; + } + + static BackoffPolicyConfig decode(Object result) { + result as List; + return BackoffPolicyConfig( + backoffPolicy: result[0] as BackoffPolicy?, + backoffDelayMillis: result[1] as int?, + ); + } +} + +class InitializeRequest { + InitializeRequest({ + required this.callbackHandle, + required this.isInDebugMode, + }); + + int callbackHandle; + + bool isInDebugMode; + + Object encode() { + return [ + callbackHandle, + isInDebugMode, + ]; + } + + static InitializeRequest decode(Object result) { + result as List; + return InitializeRequest( + callbackHandle: result[0]! as int, + isInDebugMode: result[1]! as bool, + ); + } +} + +class OneOffTaskRequest { + OneOffTaskRequest({ + required this.uniqueName, + required this.taskName, + this.inputData, + this.initialDelaySeconds, + this.constraints, + this.backoffPolicy, + this.tag, + this.existingWorkPolicy, + this.outOfQuotaPolicy, + }); + + String uniqueName; + + String taskName; + + Map? inputData; + + int? initialDelaySeconds; + + Constraints? constraints; + + BackoffPolicyConfig? backoffPolicy; + + String? tag; + + ExistingWorkPolicy? existingWorkPolicy; + + OutOfQuotaPolicy? outOfQuotaPolicy; + + Object encode() { + return [ + uniqueName, + taskName, + inputData, + initialDelaySeconds, + constraints, + backoffPolicy, + tag, + existingWorkPolicy, + outOfQuotaPolicy, + ]; + } + + static OneOffTaskRequest decode(Object result) { + result as List; + return OneOffTaskRequest( + uniqueName: result[0]! as String, + taskName: result[1]! as String, + inputData: (result[2] as Map?)?.cast(), + initialDelaySeconds: result[3] as int?, + constraints: result[4] as Constraints?, + backoffPolicy: result[5] as BackoffPolicyConfig?, + tag: result[6] as String?, + existingWorkPolicy: result[7] as ExistingWorkPolicy?, + outOfQuotaPolicy: result[8] as OutOfQuotaPolicy?, + ); + } +} + +class PeriodicTaskRequest { + PeriodicTaskRequest({ + required this.uniqueName, + required this.taskName, + required this.frequencySeconds, + this.flexIntervalSeconds, + this.inputData, + this.initialDelaySeconds, + this.constraints, + this.backoffPolicy, + this.tag, + this.existingWorkPolicy, + }); + + String uniqueName; + + String taskName; + + int frequencySeconds; + + int? flexIntervalSeconds; + + Map? inputData; + + int? initialDelaySeconds; + + Constraints? constraints; + + BackoffPolicyConfig? backoffPolicy; + + String? tag; + + ExistingWorkPolicy? existingWorkPolicy; + + Object encode() { + return [ + uniqueName, + taskName, + frequencySeconds, + flexIntervalSeconds, + inputData, + initialDelaySeconds, + constraints, + backoffPolicy, + tag, + existingWorkPolicy, + ]; + } + + static PeriodicTaskRequest decode(Object result) { + result as List; + return PeriodicTaskRequest( + uniqueName: result[0]! as String, + taskName: result[1]! as String, + frequencySeconds: result[2]! as int, + flexIntervalSeconds: result[3] as int?, + inputData: (result[4] as Map?)?.cast(), + initialDelaySeconds: result[5] as int?, + constraints: result[6] as Constraints?, + backoffPolicy: result[7] as BackoffPolicyConfig?, + tag: result[8] as String?, + existingWorkPolicy: result[9] as ExistingWorkPolicy?, + ); + } +} + +class ProcessingTaskRequest { + ProcessingTaskRequest({ + required this.uniqueName, + required this.taskName, + this.inputData, + this.initialDelaySeconds, + this.networkType, + this.requiresCharging, + }); + + String uniqueName; + + String taskName; + + Map? inputData; + + int? initialDelaySeconds; + + NetworkType? networkType; + + bool? requiresCharging; + + Object encode() { + return [ + uniqueName, + taskName, + inputData, + initialDelaySeconds, + networkType, + requiresCharging, + ]; + } + + static ProcessingTaskRequest decode(Object result) { + result as List; + return ProcessingTaskRequest( + uniqueName: result[0]! as String, + taskName: result[1]! as String, + inputData: (result[2] as Map?)?.cast(), + initialDelaySeconds: result[3] as int?, + networkType: result[4] as NetworkType?, + requiresCharging: result[5] as bool?, + ); + } +} + + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is NetworkType) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is BackoffPolicy) { + buffer.putUint8(130); + writeValue(buffer, value.index); + } else if (value is ExistingWorkPolicy) { + buffer.putUint8(131); + writeValue(buffer, value.index); + } else if (value is OutOfQuotaPolicy) { + buffer.putUint8(132); + writeValue(buffer, value.index); + } else if (value is Constraints) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else if (value is BackoffPolicyConfig) { + buffer.putUint8(134); + writeValue(buffer, value.encode()); + } else if (value is InitializeRequest) { + buffer.putUint8(135); + writeValue(buffer, value.encode()); + } else if (value is OneOffTaskRequest) { + buffer.putUint8(136); + writeValue(buffer, value.encode()); + } else if (value is PeriodicTaskRequest) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); + } else if (value is ProcessingTaskRequest) { + buffer.putUint8(138); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final int? value = readValue(buffer) as int?; + return value == null ? null : NetworkType.values[value]; + case 130: + final int? value = readValue(buffer) as int?; + return value == null ? null : BackoffPolicy.values[value]; + case 131: + final int? value = readValue(buffer) as int?; + return value == null ? null : ExistingWorkPolicy.values[value]; + case 132: + final int? value = readValue(buffer) as int?; + return value == null ? null : OutOfQuotaPolicy.values[value]; + case 133: + return Constraints.decode(readValue(buffer)!); + case 134: + return BackoffPolicyConfig.decode(readValue(buffer)!); + case 135: + return InitializeRequest.decode(readValue(buffer)!); + case 136: + return OneOffTaskRequest.decode(readValue(buffer)!); + case 137: + return PeriodicTaskRequest.decode(readValue(buffer)!); + case 138: + return ProcessingTaskRequest.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class WorkmanagerHostApi { + /// Constructor for [WorkmanagerHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + WorkmanagerHostApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future initialize(InitializeRequest request) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.initialize$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([request]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future registerOneOffTask(OneOffTaskRequest request) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.registerOneOffTask$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([request]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future registerPeriodicTask(PeriodicTaskRequest request) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.registerPeriodicTask$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([request]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future registerProcessingTask(ProcessingTaskRequest request) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.registerProcessingTask$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([request]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future cancelByUniqueName(String uniqueName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.cancelByUniqueName$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([uniqueName]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future cancelByTag(String tag) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.cancelByTag$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([tag]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future cancelAll() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.cancelAll$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + Future isScheduledByUniqueName(String uniqueName) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.isScheduledByUniqueName$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([uniqueName]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future printScheduledTasks() async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerHostApi.printScheduledTasks$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as String?)!; + } + } +} + +abstract class WorkmanagerFlutterApi { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + Future backgroundChannelInitialized(); + + Future executeTask(String taskName, Map? inputData); + + static void setUp(WorkmanagerFlutterApi? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerFlutterApi.backgroundChannelInitialized$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + await api.backgroundChannelInitialized(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerFlutterApi.executeTask$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerFlutterApi.executeTask was null.'); + final List args = (message as List?)!; + final String? arg_taskName = (args[0] as String?); + assert(arg_taskName != null, + 'Argument for dev.flutter.pigeon.workmanager_platform_interface.WorkmanagerFlutterApi.executeTask was null, expected non-null String.'); + final Map? arg_inputData = (args[1] as Map?)?.cast(); + try { + final bool output = await api.executeTask(arg_taskName!, arg_inputData); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} diff --git a/workmanager_platform_interface/lib/src/workmanager_platform_interface.dart b/workmanager_platform_interface/lib/src/workmanager_platform_interface.dart index 0551beb..c76bf46 100644 --- a/workmanager_platform_interface/lib/src/workmanager_platform_interface.dart +++ b/workmanager_platform_interface/lib/src/workmanager_platform_interface.dart @@ -1,6 +1,6 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'options.dart'; +import 'pigeon/workmanager_api.g.dart'; /// The interface that implementations of workmanager must implement. /// diff --git a/workmanager_platform_interface/lib/workmanager_platform_interface.dart b/workmanager_platform_interface/lib/workmanager_platform_interface.dart index 5efa30a..8bae37c 100644 --- a/workmanager_platform_interface/lib/workmanager_platform_interface.dart +++ b/workmanager_platform_interface/lib/workmanager_platform_interface.dart @@ -1,5 +1,4 @@ library workmanager_platform_interface; export 'src/workmanager_platform_interface.dart'; -export 'src/options.dart'; -export 'src/enums.dart'; +export 'src/pigeon/workmanager_api.g.dart'; diff --git a/workmanager_platform_interface/pigeons/copyright.txt b/workmanager_platform_interface/pigeons/copyright.txt new file mode 100644 index 0000000..177dbcb --- /dev/null +++ b/workmanager_platform_interface/pigeons/copyright.txt @@ -0,0 +1,3 @@ +// Copyright 2024 The Flutter Workmanager Authors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. \ No newline at end of file diff --git a/workmanager_platform_interface/pigeons/workmanager_api.dart b/workmanager_platform_interface/pigeons/workmanager_api.dart new file mode 100644 index 0000000..5c0fa4b --- /dev/null +++ b/workmanager_platform_interface/pigeons/workmanager_api.dart @@ -0,0 +1,230 @@ +import 'package:pigeon/pigeon.dart'; + +// Pigeon configuration +@ConfigurePigeon(PigeonOptions( + dartOut: 'lib/src/pigeon/workmanager_api.g.dart', + dartOptions: DartOptions(), + kotlinOut: 'android/src/main/kotlin/dev/fluttercommunity/workmanager/pigeon/WorkmanagerApi.g.kt', + kotlinOptions: KotlinOptions( + package: 'dev.fluttercommunity.workmanager.pigeon', + ), + swiftOut: 'ios/Classes/pigeon/WorkmanagerApi.g.swift', + copyrightHeader: 'pigeons/copyright.txt', + dartPackageName: 'workmanager_platform_interface', +)) + +// Enums - Moved from platform interface for Pigeon compatibility + +/// An enumeration of various network types that can be used as Constraints for work. +/// +/// Fully supported on Android. +/// +/// On iOS, this enumeration is used to define whether a piece of work requires +/// internet connectivity, by checking for either [NetworkType.connected] or +/// [NetworkType.metered]. +enum NetworkType { + /// Any working network connection is required for this work. + connected, + + /// A metered network connection is required for this work. + metered, + + /// Default value. A network is not required for this work. + notRequired, + + /// A non-roaming network connection is required for this work. + notRoaming, + + /// An unmetered network connection is required for this work. + unmetered, + + /// A temporarily unmetered Network. This capability will be set for + /// networks that are generally metered, but are currently unmetered. + /// + /// Android API 30+ + temporarilyUnmetered, +} + +/// An enumeration of backoff policies when retrying work. +/// These policies are used when you have a return ListenableWorker.Result.retry() from a worker to determine the correct backoff time. +/// Backoff policies are set in WorkRequest.Builder.setBackoffCriteria(BackoffPolicy, long, TimeUnit) or one of its variants. +enum BackoffPolicy { + /// Used to indicate that WorkManager should increase the backoff time exponentially + exponential, + + /// Used to indicate that WorkManager should increase the backoff time linearly + linear, +} + +/// An enumeration of the conflict resolution policies in case of a collision. +enum ExistingWorkPolicy { + /// If there is existing pending (uncompleted) work with the same unique name, append the newly-specified work as a child of all the leaves of that work sequence. + append, + + /// If there is existing pending (uncompleted) work with the same unique name, do nothing. + keep, + + /// If there is existing pending (uncompleted) work with the same unique name, cancel and delete it. + replace, + + /// If there is existing pending (uncompleted) work with the same unique name, it will be updated the new specification. + /// Note: This maps to appendOrReplace in the native implementation. + update, +} + +/// An enumeration of policies that help determine out of quota behavior for expedited jobs. +/// +/// Only supported on Android. +enum OutOfQuotaPolicy { + /// When the app does not have any expedited job quota, the expedited work request will + /// fallback to a regular work request. + runAsNonExpeditedWorkRequest, + + /// When the app does not have any expedited job quota, the expedited work request will + /// we dropped and no work requests are enqueued. + dropWorkRequest, +} + +// Data classes +class Constraints { + Constraints({ + this.networkType, + this.requiresBatteryNotLow, + this.requiresCharging, + this.requiresDeviceIdle, + this.requiresStorageNotLow, + }); + + NetworkType? networkType; + bool? requiresBatteryNotLow; + bool? requiresCharging; + bool? requiresDeviceIdle; + bool? requiresStorageNotLow; +} + +class BackoffPolicyConfig { + BackoffPolicyConfig({ + this.backoffPolicy, + this.backoffDelayMillis, + }); + + BackoffPolicy? backoffPolicy; + int? backoffDelayMillis; +} + +class InitializeRequest { + InitializeRequest({required this.callbackHandle, required this.isInDebugMode}); + + int callbackHandle; + bool isInDebugMode; +} + +class OneOffTaskRequest { + OneOffTaskRequest({ + required this.uniqueName, + required this.taskName, + this.inputData, + this.initialDelaySeconds, + this.constraints, + this.backoffPolicy, + this.tag, + this.existingWorkPolicy, + this.outOfQuotaPolicy, + }); + + String uniqueName; + String taskName; + Map? inputData; + int? initialDelaySeconds; + Constraints? constraints; + BackoffPolicyConfig? backoffPolicy; + String? tag; + ExistingWorkPolicy? existingWorkPolicy; + OutOfQuotaPolicy? outOfQuotaPolicy; +} + +class PeriodicTaskRequest { + PeriodicTaskRequest({ + required this.uniqueName, + required this.taskName, + required this.frequencySeconds, + this.flexIntervalSeconds, + this.inputData, + this.initialDelaySeconds, + this.constraints, + this.backoffPolicy, + this.tag, + this.existingWorkPolicy, + }); + + String uniqueName; + String taskName; + int frequencySeconds; + int? flexIntervalSeconds; + Map? inputData; + int? initialDelaySeconds; + Constraints? constraints; + BackoffPolicyConfig? backoffPolicy; + String? tag; + ExistingWorkPolicy? existingWorkPolicy; +} + +// iOS specific request +class ProcessingTaskRequest { + ProcessingTaskRequest({ + required this.uniqueName, + required this.taskName, + this.inputData, + this.initialDelaySeconds, + this.networkType, + this.requiresCharging, + }); + + String uniqueName; + String taskName; + Map? inputData; + int? initialDelaySeconds; + NetworkType? networkType; + bool? requiresCharging; +} + +// Host API (Flutter calls native) +@HostApi() +abstract class WorkmanagerHostApi { + @async + void initialize(InitializeRequest request); + + @async + void registerOneOffTask(OneOffTaskRequest request); + + @async + void registerPeriodicTask(PeriodicTaskRequest request); + + @async + void registerProcessingTask(ProcessingTaskRequest request); + + @async + void cancelByUniqueName(String uniqueName); + + @async + void cancelByTag(String tag); + + @async + void cancelAll(); + + @async + bool isScheduledByUniqueName(String uniqueName); + + @async + String printScheduledTasks(); +} + +// Flutter API (Native calls Flutter) +@FlutterApi() +abstract class WorkmanagerFlutterApi { + @async + void backgroundChannelInitialized(); + + @async + bool executeTask(String taskName, Map? inputData); +} \ No newline at end of file diff --git a/workmanager_platform_interface/pubspec.yaml b/workmanager_platform_interface/pubspec.yaml index 8123707..5a0ce94 100644 --- a/workmanager_platform_interface/pubspec.yaml +++ b/workmanager_platform_interface/pubspec.yaml @@ -20,4 +20,5 @@ dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^6.0.0 + pigeon: ^22.6.0