From ef524b8dd0287874894a501a5c4d6606baa3cc84 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Thu, 13 Aug 2026 14:06:15 +0000 Subject: [PATCH 1/3] feat(crashlytics): add Pigeon support Replace stringly-typed MethodChannel RPCs with a generated HostApi so Crashlytics platform calls are type-safe, matching the other FlutterFire plugins. --- .../analysis_options.yaml | 11 + .../FlutterFirebaseCrashlyticsPlugin.kt | 167 ++---- .../GeneratedAndroidFirebaseCrashlytics.g.kt | 542 ++++++++++++++++++ .../FirebaseCrashlyticsMessages.g.swift | 512 +++++++++++++++++ .../FirebaseCrashlyticsPlugin.swift | 167 ++---- .../FirebaseCrashlyticsMessages.g.swift | 1 + .../test/firebase_crashlytics_test.dart | 131 ++--- .../firebase_crashlytics/test/mock.dart | 119 ++-- .../method_channel_crashlytics.dart | 105 ++-- .../lib/src/pigeon/messages.pigeon.dart | 466 +++++++++++++++ .../lib/src/pigeon/test_api.dart | 276 +++++++++ .../lib/test.dart | 10 + .../pigeons/copyright.txt | 3 + .../pigeons/messages.dart | 92 +++ .../pubspec.yaml | 6 +- .../method_channel_crashlytics_test.dart | 397 +++++++------ .../test/mock.dart | 22 +- 17 files changed, 2421 insertions(+), 606 deletions(-) create mode 100644 packages/firebase_crashlytics/analysis_options.yaml create mode 100644 packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/generated/GeneratedAndroidFirebaseCrashlytics.g.kt create mode 100644 packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift create mode 120000 packages/firebase_crashlytics/firebase_crashlytics/macos/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift create mode 100644 packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/messages.pigeon.dart create mode 100644 packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/test_api.dart create mode 100644 packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/test.dart create mode 100644 packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pigeons/copyright.txt create mode 100644 packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pigeons/messages.dart diff --git a/packages/firebase_crashlytics/analysis_options.yaml b/packages/firebase_crashlytics/analysis_options.yaml new file mode 100644 index 000000000000..b451bee6fdb1 --- /dev/null +++ b/packages/firebase_crashlytics/analysis_options.yaml @@ -0,0 +1,11 @@ +# Copyright 2026 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +include: ../../analysis_options.yaml + +analyzer: + exclude: + - firebase_crashlytics_platform_interface/lib/src/pigeon/messages.pigeon.dart + - firebase_crashlytics_platform_interface/lib/src/pigeon/test_api.dart + - firebase_crashlytics_platform_interface/pigeons/messages.dart diff --git a/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/FlutterFirebaseCrashlyticsPlugin.kt b/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/FlutterFirebaseCrashlyticsPlugin.kt index f38f4a3b1fb9..5a621cb44a75 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/FlutterFirebaseCrashlyticsPlugin.kt +++ b/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/FlutterFirebaseCrashlyticsPlugin.kt @@ -20,19 +20,18 @@ import com.google.firebase.crashlytics.internal.Logger import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.EventChannel -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel import io.flutter.plugins.firebase.core.FlutterFirebasePlugin import io.flutter.plugins.firebase.core.FlutterFirebasePlugin.cachedThreadPool import io.flutter.plugins.firebase.core.FlutterFirebasePluginRegistry +import io.flutter.plugins.firebase.crashlytics.generated.CrashlyticsStackFrame +import io.flutter.plugins.firebase.crashlytics.generated.FirebaseCrashlyticsHostApi +import io.flutter.plugins.firebase.crashlytics.generated.RecordErrorRequest +import io.flutter.plugins.firebase.crashlytics.generated.FlutterError as PigeonFlutterError /** FlutterFirebaseCrashlyticsPlugin */ class FlutterFirebaseCrashlyticsPlugin : - FlutterFirebasePlugin, - FlutterPlugin, - MethodChannel.MethodCallHandler, - EventChannel.StreamHandler { - private var channel: MethodChannel? = null + FlutterFirebasePlugin, FlutterPlugin, FirebaseCrashlyticsHostApi, EventChannel.StreamHandler { + private var binaryMessenger: BinaryMessenger? = null private var testEventChannel: EventChannel? = null private var testEventSink: EventChannel.EventSink? = null private lateinit var applicationContext: Context @@ -44,8 +43,9 @@ class FlutterFirebaseCrashlyticsPlugin : private var elfBuildId: String? = null private fun initInstance(messenger: BinaryMessenger) { - channel = MethodChannel(messenger, CHANNEL_NAME).also { it.setMethodCallHandler(this) } FlutterFirebasePluginRegistry.registerPlugin(CHANNEL_NAME, this) + binaryMessenger = messenger + FirebaseCrashlyticsHostApi.setUp(messenger, this) testEventChannel = EventChannel(messenger, TEST_EVENT_CHANNEL_NAME).also { it.setStreamHandler(this) } } @@ -57,68 +57,60 @@ class FlutterFirebaseCrashlyticsPlugin : } override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { - channel?.setMethodCallHandler(null) - channel = null + FirebaseCrashlyticsHostApi.setUp(binding.binaryMessenger, null) + binaryMessenger = null testEventChannel?.setStreamHandler(null) testEventChannel = null } - private fun checkForUnsentReports(): Task> { - val taskCompletionSource = TaskCompletionSource>() + override fun checkForUnsentReports(callback: (Result) -> Unit) { cachedThreadPool.execute { try { val unsentReports = Tasks.await(FirebaseCrashlytics.getInstance().checkForUnsentReports()) - taskCompletionSource.setResult(mapOf(Constants.UNSENT_REPORTS to unsentReports)) + callback(Result.success(unsentReports)) } catch (exception: Exception) { - taskCompletionSource.setException(exception) + handleFailure(callback, exception) } } - return taskCompletionSource.task } - private fun crash() { + override fun crash(callback: (Result) -> Unit) { Handler(Looper.myLooper()!!).postDelayed({ throw FirebaseCrashlyticsTestCrash() }, 50) } - private fun deleteUnsentReports(): Task { - val taskCompletionSource = TaskCompletionSource() + override fun deleteUnsentReports(callback: (Result) -> Unit) { cachedThreadPool.execute { try { FirebaseCrashlytics.getInstance().deleteUnsentReports() - taskCompletionSource.setResult(null) + callback(Result.success(Unit)) } catch (exception: Exception) { - taskCompletionSource.setException(exception) + handleFailure(callback, exception) } } - return taskCompletionSource.task } - private fun didCrashOnPreviousExecution(): Task> { - val taskCompletionSource = TaskCompletionSource>() + override fun didCrashOnPreviousExecution(callback: (Result) -> Unit) { cachedThreadPool.execute { try { val didCrash = FirebaseCrashlytics.getInstance().didCrashOnPreviousExecution() - taskCompletionSource.setResult(mapOf(Constants.DID_CRASH_ON_PREVIOUS_EXECUTION to didCrash)) + callback(Result.success(didCrash)) } catch (exception: Exception) { - taskCompletionSource.setException(exception) + handleFailure(callback, exception) } } - return taskCompletionSource.task } - private fun recordError(arguments: Map): Task { - val taskCompletionSource = TaskCompletionSource() + override fun recordError(request: RecordErrorRequest, callback: (Result) -> Unit) { val mainHandler = Handler(Looper.getMainLooper()) cachedThreadPool.execute { try { val crashlytics = FirebaseCrashlytics.getInstance() - val dartExceptionMessage = arguments[Constants.EXCEPTION]!! as String - val reason = arguments[Constants.REASON] as String? - val information = arguments[Constants.INFORMATION]!! as String - val fatal = arguments[Constants.FATAL]!! as Boolean - val dartBuildId = arguments[Constants.BUILD_ID]!! as String - @Suppress("UNCHECKED_CAST") - val loadingUnits = arguments[Constants.LOADING_UNITS]!! as List + val dartExceptionMessage = request.exception + val reason = request.reason + val information = request.information + val fatal = request.fatal + val dartBuildId = request.buildId + val loadingUnits = request.loadingUnits // Prefer the ELF build ID from libapp.so over the Dart VM's snapshot build ID. // The firebase-crashlytics-buildtools JAR uses the ELF build ID when uploading symbols, @@ -142,9 +134,8 @@ class FlutterFirebaseCrashlyticsPlugin : } crashlytics.setCustomKey(Constants.FLUTTER_ERROR_EXCEPTION, dartExceptionMessage) - @Suppress("UNCHECKED_CAST") - val errorElements = arguments[Constants.STACK_TRACE_ELEMENTS]!! as List> - exception.stackTrace = errorElements.mapNotNull(::generateStackTraceElement).toTypedArray() + exception.stackTrace = + request.stackTraceElements.mapNotNull(::generateStackTraceElement).toTypedArray() if (information.isNotEmpty()) { crashlytics.log(information) @@ -154,128 +145,84 @@ class FlutterFirebaseCrashlyticsPlugin : } else { crashlytics.recordException(exception) } - taskCompletionSource.setResult(null) + callback(Result.success(Unit)) } catch (exception: Exception) { - taskCompletionSource.setException(exception) + handleFailure(callback, exception) } } - return taskCompletionSource.task } - private fun log(arguments: Map): Task { - val taskCompletionSource = TaskCompletionSource() + override fun log(message: String, callback: (Result) -> Unit) { cachedThreadPool.execute { try { - val message = arguments[Constants.MESSAGE]!! as String FirebaseCrashlytics.getInstance().log(message) - taskCompletionSource.setResult(null) + callback(Result.success(Unit)) } catch (exception: Exception) { - taskCompletionSource.setException(exception) + handleFailure(callback, exception) } } - return taskCompletionSource.task } - private fun sendUnsentReports(): Task { - val taskCompletionSource = TaskCompletionSource() + override fun sendUnsentReports(callback: (Result) -> Unit) { cachedThreadPool.execute { try { FirebaseCrashlytics.getInstance().sendUnsentReports() - taskCompletionSource.setResult(null) + callback(Result.success(Unit)) } catch (exception: Exception) { - taskCompletionSource.setException(exception) + handleFailure(callback, exception) } } - return taskCompletionSource.task } - private fun setCrashlyticsCollectionEnabled(arguments: Map): Task> { - val taskCompletionSource = TaskCompletionSource>() + override fun setCrashlyticsCollectionEnabled( + enabled: Boolean, + callback: (Result) -> Unit + ) { cachedThreadPool.execute { try { - val enabled = arguments[Constants.ENABLED]!! as Boolean FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(enabled) - taskCompletionSource.setResult( - mapOf( - Constants.IS_CRASHLYTICS_COLLECTION_ENABLED to - isCrashlyticsCollectionEnabled(FirebaseApp.getInstance()))) + callback(Result.success(isCrashlyticsCollectionEnabled(FirebaseApp.getInstance()))) } catch (exception: Exception) { - taskCompletionSource.setException(exception) + handleFailure(callback, exception) } } - return taskCompletionSource.task } - private fun setUserIdentifier(arguments: Map): Task { - val taskCompletionSource = TaskCompletionSource() + override fun setUserIdentifier(identifier: String, callback: (Result) -> Unit) { cachedThreadPool.execute { try { - val identifier = arguments[Constants.IDENTIFIER]!! as String FirebaseCrashlytics.getInstance().setUserId(identifier) - taskCompletionSource.setResult(null) + callback(Result.success(Unit)) } catch (exception: Exception) { - taskCompletionSource.setException(exception) + handleFailure(callback, exception) } } - return taskCompletionSource.task } - private fun setCustomKey(arguments: Map): Task { - val taskCompletionSource = TaskCompletionSource() + override fun setCustomKey(key: String, value: String, callback: (Result) -> Unit) { cachedThreadPool.execute { try { - val key = arguments[Constants.KEY]!! as String - val value = arguments[Constants.VALUE]!! as String FirebaseCrashlytics.getInstance().setCustomKey(key, value) - taskCompletionSource.setResult(null) + callback(Result.success(Unit)) } catch (exception: Exception) { - taskCompletionSource.setException(exception) + handleFailure(callback, exception) } } - return taskCompletionSource.task } - override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { - val task: Task<*> = - when (call.method) { - "Crashlytics#checkForUnsentReports" -> checkForUnsentReports() - "Crashlytics#crash" -> { - crash() - return - } - "Crashlytics#deleteUnsentReports" -> deleteUnsentReports() - "Crashlytics#didCrashOnPreviousExecution" -> didCrashOnPreviousExecution() - "Crashlytics#recordError" -> recordError(call.arguments>()!!) - "Crashlytics#log" -> log(call.arguments>()!!) - "Crashlytics#sendUnsentReports" -> sendUnsentReports() - "Crashlytics#setCrashlyticsCollectionEnabled" -> - setCrashlyticsCollectionEnabled(call.arguments>()!!) - "Crashlytics#setUserIdentifier" -> setUserIdentifier(call.arguments>()!!) - "Crashlytics#setCustomKey" -> setCustomKey(call.arguments>()!!) - else -> { - result.notImplemented() - return - } - } - - task.addOnCompleteListener { completedTask -> - if (completedTask.isSuccessful) { - result.success(completedTask.result) - } else { - val message = completedTask.exception?.message ?: "An unknown error occurred" - result.error("firebase_crashlytics", message, null) - } - } + private fun handleFailure(callback: (Result) -> Unit, exception: Exception?) { + val message = exception?.message ?: "An unknown error occurred" + callback(Result.failure(PigeonFlutterError("firebase_crashlytics", message, null))) } /** Extracts a StackTraceElement from a Dart stack trace element. */ - private fun generateStackTraceElement(errorElement: Map): StackTraceElement? = + private fun generateStackTraceElement(errorElement: CrashlyticsStackFrame): StackTraceElement? = try { StackTraceElement( - errorElement[Constants.CLASS] ?: "", - errorElement[Constants.METHOD], - errorElement[Constants.FILE], - errorElement[Constants.LINE]!!.toInt()) + errorElement.className ?: "", + errorElement.method, + errorElement.file, + errorElement.line.toInt()) } catch (_: Exception) { Log.e(TAG, "Unable to generate stack trace element from Dart error.") null diff --git a/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/generated/GeneratedAndroidFirebaseCrashlytics.g.kt b/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/generated/GeneratedAndroidFirebaseCrashlytics.g.kt new file mode 100644 index 000000000000..029c5f402677 --- /dev/null +++ b/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/generated/GeneratedAndroidFirebaseCrashlytics.g.kt @@ -0,0 +1,542 @@ +// Copyright 2026, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. +// See also: https://pub.dev/packages/pigeon +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") + +package io.flutter.plugins.firebase.crashlytics.generated + +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 object GeneratedAndroidFirebaseCrashlyticsPigeonUtils { + + fun wrapResult(result: Any?): List { + return listOf(result) + } + + 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) + ) + } + } + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } + if (a == null || b == null) { + return false + } + if (a is ByteArray && b is ByteArray) { + return a.contentEquals(b) + } + if (a is IntArray && b is IntArray) { + return a.contentEquals(b) + } + if (a is LongArray && b is LongArray) { + return a.contentEquals(b) + } + if (a is DoubleArray && b is DoubleArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true + } + if (a is Array<*> && b is Array<*>) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!deepEquals(a[i], b[i])) return false + } + return true + } + if (a is List<*> && b is List<*>) { + if (a.size != b.size) return false + val iterA = a.iterator() + val iterB = b.iterator() + while (iterA.hasNext() && iterB.hasNext()) { + if (!deepEquals(iterA.next(), iterB.next())) return false + } + return true + } + if (a is Map<*, *> && b is Map<*, *>) { + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false + } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) + } + return a == b + } + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += ((deepHash(entry.key) * 31) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } + +} + +/** + * 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 +) : RuntimeException() + +/** Generated class from Pigeon that represents data sent in messages. */ +data class CrashlyticsStackFrame ( + /** Dart reserved word `class`; native maps this to the historical "class" key. */ + val className: String? = null, + val method: String, + val file: String, + val line: String +) + { + companion object { + fun fromList(pigeonVar_list: List): CrashlyticsStackFrame { + val className = pigeonVar_list[0] as String? + val method = pigeonVar_list[1] as String + val file = pigeonVar_list[2] as String + val line = pigeonVar_list[3] as String + return CrashlyticsStackFrame(className, method, file, line) + } + } + fun toList(): List { + return listOf( + className, + method, + file, + line, + ) + } + override fun equals(other: Any?): Boolean { + if (other == null || other.javaClass != javaClass) { + return false + } + if (this === other) { + return true + } + val other = other as CrashlyticsStackFrame + return GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.className, other.className) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.method, other.method) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.file, other.file) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.line, other.line) + } + + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.className) + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.method) + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.file) + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.line) + return result + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class RecordErrorRequest ( + val exception: String, + val information: String, + val reason: String? = null, + val fatal: Boolean, + val buildId: String, + val loadingUnits: List, + val stackTraceElements: List +) + { + companion object { + fun fromList(pigeonVar_list: List): RecordErrorRequest { + val exception = pigeonVar_list[0] as String + val information = pigeonVar_list[1] as String + val reason = pigeonVar_list[2] as String? + val fatal = pigeonVar_list[3] as Boolean + val buildId = pigeonVar_list[4] as String + val loadingUnits = pigeonVar_list[5] as List + val stackTraceElements = pigeonVar_list[6] as List + return RecordErrorRequest(exception, information, reason, fatal, buildId, loadingUnits, stackTraceElements) + } + } + fun toList(): List { + return listOf( + exception, + information, + reason, + fatal, + buildId, + loadingUnits, + stackTraceElements, + ) + } + override fun equals(other: Any?): Boolean { + if (other == null || other.javaClass != javaClass) { + return false + } + if (this === other) { + return true + } + val other = other as RecordErrorRequest + return GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.exception, other.exception) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.information, other.information) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.reason, other.reason) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.fatal, other.fatal) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.buildId, other.buildId) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.loadingUnits, other.loadingUnits) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.stackTraceElements, other.stackTraceElements) + } + + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.exception) + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.information) + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.reason) + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.fatal) + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.buildId) + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.loadingUnits) + result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.stackTraceElements) + return result + } +} +private open class GeneratedAndroidFirebaseCrashlyticsPigeonCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 129.toByte() -> { + return (readValue(buffer) as? List)?.let { + CrashlyticsStackFrame.fromList(it) + } + } + 130.toByte() -> { + return (readValue(buffer) as? List)?.let { + RecordErrorRequest.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is CrashlyticsStackFrame -> { + stream.write(129) + writeValue(stream, value.toList()) + } + is RecordErrorRequest -> { + stream.write(130) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + + +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ +interface FirebaseCrashlyticsHostApi { + fun checkForUnsentReports(callback: (Result) -> Unit) + fun crash(callback: (Result) -> Unit) + fun deleteUnsentReports(callback: (Result) -> Unit) + fun didCrashOnPreviousExecution(callback: (Result) -> Unit) + fun recordError(request: RecordErrorRequest, callback: (Result) -> Unit) + fun log(message: String, callback: (Result) -> Unit) + fun sendUnsentReports(callback: (Result) -> Unit) + fun setCrashlyticsCollectionEnabled(enabled: Boolean, callback: (Result) -> Unit) + fun setUserIdentifier(identifier: String, callback: (Result) -> Unit) + fun setCustomKey(key: String, value: String, callback: (Result) -> Unit) + + companion object { + /** The codec used by FirebaseCrashlyticsHostApi. */ + val codec: MessageCodec by lazy { + GeneratedAndroidFirebaseCrashlyticsPigeonCodec() + } + /** Sets up an instance of `FirebaseCrashlyticsHostApi` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: FirebaseCrashlyticsHostApi?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.checkForUnsentReports{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.crash{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) + } else { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.deleteUnsentReports{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) + } else { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.didCrashOnPreviousExecution{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as RecordErrorRequest + api.recordError(requestArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) + } else { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val messageArg = args[0] as String + api.log(messageArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) + } else { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.sendUnsentReports{ result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) + } else { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val enabledArg = args[0] as Boolean + api.setCrashlyticsCollectionEnabled(enabledArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val identifierArg = args[0] as String + api.setUserIdentifier(identifierArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) + } else { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val keyArg = args[0] as String + val valueArg = args[1] as String + api.setCustomKey(keyArg, valueArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) + } else { + reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} diff --git a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift new file mode 100644 index 000000000000..13a91db75fbc --- /dev/null +++ b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift @@ -0,0 +1,512 @@ +// Copyright 2026, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v26.3.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: Sendable? + + init(code: String, message: String?, details: Sendable?) { + 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)", + "\(Swift.type(of: error))", + "Stacktrace: \(Thread.callStackSymbols)", + ] +} + +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? +} + +private func doubleEqualsFirebaseCrashlyticsMessages(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashFirebaseCrashlyticsMessages(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8000000000000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + +func deepEqualsFirebaseCrashlyticsMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { + let cleanLhs = nilOrValue(lhs) as Any? + let cleanRhs = nilOrValue(rhs) as Any? + switch (cleanLhs, cleanRhs) { + case (nil, nil): + return true + + case (nil, _), (_, nil): + return false + + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: + return true + + case is (Void, Void): + return true + + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsFirebaseCrashlyticsMessages(element, rhsArray[index]) { + return false + } + } + return true + + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsFirebaseCrashlyticsMessages(element, rhsArray[index]) { + return false + } + } + return true + + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsFirebaseCrashlyticsMessages(lhsKey, rhsKey) { + if deepEqualsFirebaseCrashlyticsMessages(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsFirebaseCrashlyticsMessages(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + + default: + return false + } +} + +func deepHashFirebaseCrashlyticsMessages(value: Any?, hasher: inout Hasher) { + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashFirebaseCrashlyticsMessages(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashFirebaseCrashlyticsMessages(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashFirebaseCrashlyticsMessages(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashFirebaseCrashlyticsMessages(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashFirebaseCrashlyticsMessages(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) + } + } else { + hasher.combine(0) + } +} + + +/// Generated class from Pigeon that represents data sent in messages. +struct CrashlyticsStackFrame: Hashable { + /// Dart reserved word `class`; native maps this to the historical "class" key. + var className: String? = nil + var method: String + var file: String + var line: String + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> CrashlyticsStackFrame? { + let className: String? = nilOrValue(pigeonVar_list[0]) + let method = pigeonVar_list[1] as! String + let file = pigeonVar_list[2] as! String + let line = pigeonVar_list[3] as! String + + return CrashlyticsStackFrame( + className: className, + method: method, + file: file, + line: line + ) + } + func toList() -> [Any?] { + return [ + className, + method, + file, + line, + ] + } + static func == (lhs: CrashlyticsStackFrame, rhs: CrashlyticsStackFrame) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirebaseCrashlyticsMessages(lhs.className, rhs.className) && deepEqualsFirebaseCrashlyticsMessages(lhs.method, rhs.method) && deepEqualsFirebaseCrashlyticsMessages(lhs.file, rhs.file) && deepEqualsFirebaseCrashlyticsMessages(lhs.line, rhs.line) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("CrashlyticsStackFrame") + deepHashFirebaseCrashlyticsMessages(value: className, hasher: &hasher) + deepHashFirebaseCrashlyticsMessages(value: method, hasher: &hasher) + deepHashFirebaseCrashlyticsMessages(value: file, hasher: &hasher) + deepHashFirebaseCrashlyticsMessages(value: line, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct RecordErrorRequest: Hashable { + var exception: String + var information: String + var reason: String? = nil + var fatal: Bool + var buildId: String + var loadingUnits: [String] + var stackTraceElements: [CrashlyticsStackFrame] + + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> RecordErrorRequest? { + let exception = pigeonVar_list[0] as! String + let information = pigeonVar_list[1] as! String + let reason: String? = nilOrValue(pigeonVar_list[2]) + let fatal = pigeonVar_list[3] as! Bool + let buildId = pigeonVar_list[4] as! String + let loadingUnits = pigeonVar_list[5] as! [String] + let stackTraceElements = pigeonVar_list[6] as! [CrashlyticsStackFrame] + + return RecordErrorRequest( + exception: exception, + information: information, + reason: reason, + fatal: fatal, + buildId: buildId, + loadingUnits: loadingUnits, + stackTraceElements: stackTraceElements + ) + } + func toList() -> [Any?] { + return [ + exception, + information, + reason, + fatal, + buildId, + loadingUnits, + stackTraceElements, + ] + } + static func == (lhs: RecordErrorRequest, rhs: RecordErrorRequest) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirebaseCrashlyticsMessages(lhs.exception, rhs.exception) && deepEqualsFirebaseCrashlyticsMessages(lhs.information, rhs.information) && deepEqualsFirebaseCrashlyticsMessages(lhs.reason, rhs.reason) && deepEqualsFirebaseCrashlyticsMessages(lhs.fatal, rhs.fatal) && deepEqualsFirebaseCrashlyticsMessages(lhs.buildId, rhs.buildId) && deepEqualsFirebaseCrashlyticsMessages(lhs.loadingUnits, rhs.loadingUnits) && deepEqualsFirebaseCrashlyticsMessages(lhs.stackTraceElements, rhs.stackTraceElements) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("RecordErrorRequest") + deepHashFirebaseCrashlyticsMessages(value: exception, hasher: &hasher) + deepHashFirebaseCrashlyticsMessages(value: information, hasher: &hasher) + deepHashFirebaseCrashlyticsMessages(value: reason, hasher: &hasher) + deepHashFirebaseCrashlyticsMessages(value: fatal, hasher: &hasher) + deepHashFirebaseCrashlyticsMessages(value: buildId, hasher: &hasher) + deepHashFirebaseCrashlyticsMessages(value: loadingUnits, hasher: &hasher) + deepHashFirebaseCrashlyticsMessages(value: stackTraceElements, hasher: &hasher) + } +} + +private class FirebaseCrashlyticsMessagesPigeonCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 129: + return CrashlyticsStackFrame.fromList(self.readValue() as! [Any?]) + case 130: + return RecordErrorRequest.fromList(self.readValue() as! [Any?]) + default: + return super.readValue(ofType: type) + } + } +} + +private class FirebaseCrashlyticsMessagesPigeonCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? CrashlyticsStackFrame { + super.writeByte(129) + super.writeValue(value.toList()) + } else if let value = value as? RecordErrorRequest { + super.writeByte(130) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class FirebaseCrashlyticsMessagesPigeonCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return FirebaseCrashlyticsMessagesPigeonCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return FirebaseCrashlyticsMessagesPigeonCodecWriter(data: data) + } +} + +class FirebaseCrashlyticsMessagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { + static let shared = FirebaseCrashlyticsMessagesPigeonCodec(readerWriter: FirebaseCrashlyticsMessagesPigeonCodecReaderWriter()) +} + + +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol FirebaseCrashlyticsHostApi { + func checkForUnsentReports(completion: @escaping (Result) -> Void) + func crash(completion: @escaping (Result) -> Void) + func deleteUnsentReports(completion: @escaping (Result) -> Void) + func didCrashOnPreviousExecution(completion: @escaping (Result) -> Void) + func recordError(request: RecordErrorRequest, completion: @escaping (Result) -> Void) + func log(message: String, completion: @escaping (Result) -> Void) + func sendUnsentReports(completion: @escaping (Result) -> Void) + func setCrashlyticsCollectionEnabled(enabled: Bool, completion: @escaping (Result) -> Void) + func setUserIdentifier(identifier: String, completion: @escaping (Result) -> Void) + func setCustomKey(key: String, value: String, completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class FirebaseCrashlyticsHostApiSetup { + static var codec: FlutterStandardMessageCodec { FirebaseCrashlyticsMessagesPigeonCodec.shared } + /// Sets up an instance of `FirebaseCrashlyticsHostApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: FirebaseCrashlyticsHostApi?, messageChannelSuffix: String = "") { + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + let checkForUnsentReportsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + checkForUnsentReportsChannel.setMessageHandler { _, reply in + api.checkForUnsentReports { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + checkForUnsentReportsChannel.setMessageHandler(nil) + } + let crashChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + crashChannel.setMessageHandler { _, reply in + api.crash { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + crashChannel.setMessageHandler(nil) + } + let deleteUnsentReportsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + deleteUnsentReportsChannel.setMessageHandler { _, reply in + api.deleteUnsentReports { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + deleteUnsentReportsChannel.setMessageHandler(nil) + } + let didCrashOnPreviousExecutionChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + didCrashOnPreviousExecutionChannel.setMessageHandler { _, reply in + api.didCrashOnPreviousExecution { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + didCrashOnPreviousExecutionChannel.setMessageHandler(nil) + } + let recordErrorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + recordErrorChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let requestArg = args[0] as! RecordErrorRequest + api.recordError(request: requestArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + recordErrorChannel.setMessageHandler(nil) + } + let logChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + logChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let messageArg = args[0] as! String + api.log(message: messageArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + logChannel.setMessageHandler(nil) + } + let sendUnsentReportsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + sendUnsentReportsChannel.setMessageHandler { _, reply in + api.sendUnsentReports { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + sendUnsentReportsChannel.setMessageHandler(nil) + } + let setCrashlyticsCollectionEnabledChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setCrashlyticsCollectionEnabledChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let enabledArg = args[0] as! Bool + api.setCrashlyticsCollectionEnabled(enabled: enabledArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setCrashlyticsCollectionEnabledChannel.setMessageHandler(nil) + } + let setUserIdentifierChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setUserIdentifierChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let identifierArg = args[0] as! String + api.setUserIdentifier(identifier: identifierArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setUserIdentifierChannel.setMessageHandler(nil) + } + let setCustomKeyChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setCustomKeyChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let keyArg = args[0] as! String + let valueArg = args[1] as! String + api.setCustomKey(key: keyArg, value: valueArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setCustomKeyChannel.setMessageHandler(nil) + } + } +} diff --git a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift index e558b7856a2b..ced1e52e18d6 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift +++ b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift @@ -24,23 +24,10 @@ private let kFLTFirebaseCrashlyticsChannelName = "plugins.flutter.io/firebase_cr private let kFLTFirebaseCrashlyticsTestChannelName = "plugins.flutter.io/firebase_crashlytics_test_stream" -private let kCrashlyticsArgumentException = "exception" -private let kCrashlyticsArgumentInformation = "information" -private let kCrashlyticsArgumentStackTraceElements = "stackTraceElements" -private let kCrashlyticsArgumentReason = "reason" -private let kCrashlyticsArgumentIdentifier = "identifier" -private let kCrashlyticsArgumentKey = "key" -private let kCrashlyticsArgumentValue = "value" -private let kCrashlyticsArgumentFatal = "fatal" -private let kCrashlyticsArgumentFile = "file" -private let kCrashlyticsArgumentLine = "line" -private let kCrashlyticsArgumentMethod = "method" -private let kCrashlyticsArgumentEnabled = "enabled" -private let kCrashlyticsArgumentUnsentReports = "unsentReports" -private let kCrashlyticsArgumentDidCrashOnPreviousExecution = "didCrashOnPreviousExecution" +extension FlutterError: Error {} public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, FlutterPlugin, - FlutterStreamHandler + FlutterStreamHandler, FirebaseCrashlyticsHostApi { private var testEventChannel: FlutterEventChannel? private var testEventSink: FlutterEventSink? @@ -56,15 +43,10 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu binaryMessenger = registrar.messenger() #endif - let channel = FlutterMethodChannel( - name: kFLTFirebaseCrashlyticsChannelName, - binaryMessenger: binaryMessenger - ) - let instance = shared FLTFirebasePluginRegistry.sharedInstance().register(instance) CrashlyticsPlatformHelpers.setDevelopmentPlatformName("Flutter", version: "-1") - registrar.addMethodCallDelegate(instance, channel: channel) + FirebaseCrashlyticsHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: instance) instance.testEventChannel = FlutterEventChannel( name: kFLTFirebaseCrashlyticsTestChannelName, @@ -95,55 +77,46 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu kFLTFirebaseCrashlyticsChannelName } - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - let arguments = call.arguments as? [String: Any] ?? [:] - - switch call.method { - case "Crashlytics#recordError": - recordError(arguments: arguments, result: result) - case "Crashlytics#setUserIdentifier": - setUserIdentifier(arguments: arguments, result: result) - case "Crashlytics#setCustomKey": - setCustomKey(arguments: arguments, result: result) - case "Crashlytics#log": - log(arguments: arguments, result: result) - case "Crashlytics#crash": - NSException( - name: NSExceptionName("FirebaseCrashlyticsTestCrash"), - reason: "This is a test crash caused by calling .crash() in Dart.", - userInfo: nil - ).raise() - case "Crashlytics#setCrashlyticsCollectionEnabled": - setCrashlyticsCollectionEnabled(arguments: arguments, result: result) - case "Crashlytics#checkForUnsentReports": - checkForUnsentReports(result: result) - case "Crashlytics#sendUnsentReports": - sendUnsentReports(result: result) - case "Crashlytics#deleteUnsentReports": - deleteUnsentReports(result: result) - case "Crashlytics#didCrashOnPreviousExecution": - didCrashOnPreviousExecution(result: result) - default: - result(FlutterMethodNotImplemented) + // MARK: - FirebaseCrashlyticsHostApi + + public func checkForUnsentReports(completion: @escaping (Result) -> Void) { + Crashlytics.crashlytics().checkForUnsentReports { unsentReports in + completion(.success(unsentReports)) } } - // MARK: - Firebase Crashlytics API + public func crash(completion: @escaping (Result) -> Void) { + NSException( + name: NSExceptionName("FirebaseCrashlyticsTestCrash"), + reason: "This is a test crash caused by calling .crash() in Dart.", + userInfo: nil + ).raise() + } + + public func deleteUnsentReports(completion: @escaping (Result) -> Void) { + Crashlytics.crashlytics().deleteUnsentReports() + completion(.success(())) + } + + public func didCrashOnPreviousExecution(completion: @escaping (Result) -> Void) { + completion(.success(Crashlytics.crashlytics().didCrashDuringPreviousExecution())) + } - private func recordError(arguments: [String: Any], result: @escaping FlutterResult) { - var reason = arguments[kCrashlyticsArgumentReason] as? String - let information = arguments[kCrashlyticsArgumentInformation] as? String ?? "" - let dartExceptionMessage = arguments[kCrashlyticsArgumentException] as? String ?? "" - let errorElements = - arguments[kCrashlyticsArgumentStackTraceElements] as? [[String: Any]] ?? [] - let fatal = (arguments[kCrashlyticsArgumentFatal] as? NSNumber)?.boolValue ?? false + public func recordError( + request: RecordErrorRequest, + completion: @escaping (Result) -> Void + ) { + var reason = request.reason + let information = request.information + let dartExceptionMessage = request.exception + let fatal = request.fatal if !information.isEmpty { Crashlytics.crashlytics().log(information) } var frames: [StackFrame] = [] - for errorElement in errorElements { + for errorElement in request.stackTraceElements { frames.append(generateFrame(errorElement: errorElement)) } @@ -175,68 +148,52 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu let exception = ExceptionModel(name: "FlutterError", reason: reason ?? "") exception.stackTrace = frames CrashlyticsPlatformHelpers.record(exception, fatal: fatal) - result(nil) + completion(.success(())) } - private func setUserIdentifier(arguments: [String: Any], result: @escaping FlutterResult) { - let identifier = arguments[kCrashlyticsArgumentIdentifier] as? String ?? "" - Crashlytics.crashlytics().setUserID(identifier) - result(nil) - } - - private func setCustomKey(arguments: [String: Any], result: @escaping FlutterResult) { - let key = arguments[kCrashlyticsArgumentKey] as? String ?? "" - let value = arguments[kCrashlyticsArgumentValue] as? String ?? "" - Crashlytics.crashlytics().setCustomValue(value, forKey: key) - result(nil) + public func log(message: String, completion: @escaping (Result) -> Void) { + Crashlytics.crashlytics().log(message) + completion(.success(())) } - private func log(arguments: [String: Any], result: @escaping FlutterResult) { - let message = arguments["message"] as? String ?? "" - Crashlytics.crashlytics().log(message) - result(nil) + public func sendUnsentReports(completion: @escaping (Result) -> Void) { + Crashlytics.crashlytics().sendUnsentReports() + completion(.success(())) } - private func setCrashlyticsCollectionEnabled( - arguments: [String: Any], - result: @escaping FlutterResult + public func setCrashlyticsCollectionEnabled( + enabled: Bool, + completion: @escaping (Result) -> Void ) { - let enabled = (arguments[kCrashlyticsArgumentEnabled] as? NSNumber)?.boolValue ?? false Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(enabled) - result([ - "isCrashlyticsCollectionEnabled": Crashlytics.crashlytics().isCrashlyticsCollectionEnabled() - ]) - } - - private func checkForUnsentReports(result: @escaping FlutterResult) { - Crashlytics.crashlytics().checkForUnsentReports { unsentReports in - result([kCrashlyticsArgumentUnsentReports: unsentReports]) - } + completion(.success(Crashlytics.crashlytics().isCrashlyticsCollectionEnabled())) } - private func sendUnsentReports(result: @escaping FlutterResult) { - Crashlytics.crashlytics().sendUnsentReports() - result(nil) - } - - private func deleteUnsentReports(result: @escaping FlutterResult) { - Crashlytics.crashlytics().deleteUnsentReports() - result(nil) + public func setUserIdentifier( + identifier: String, + completion: @escaping (Result) -> Void + ) { + Crashlytics.crashlytics().setUserID(identifier) + completion(.success(())) } - private func didCrashOnPreviousExecution(result: @escaping FlutterResult) { - let didCrash = Crashlytics.crashlytics().didCrashDuringPreviousExecution() - result([kCrashlyticsArgumentDidCrashOnPreviousExecution: didCrash]) + public func setCustomKey( + key: String, + value: String, + completion: @escaping (Result) -> Void + ) { + Crashlytics.crashlytics().setCustomValue(value, forKey: key) + completion(.success(())) } // MARK: - Utilities - private func generateFrame(errorElement: [String: Any]) -> StackFrame { - let methodName = errorElement[kCrashlyticsArgumentMethod] as? String ?? "" - let className = errorElement["class"] as? String ?? "" + private func generateFrame(errorElement: CrashlyticsStackFrame) -> StackFrame { + let methodName = errorElement.method + let className = errorElement.className ?? "" let symbol = "\(className).\(methodName)" - let file = errorElement[kCrashlyticsArgumentFile] as? String ?? "" - let line = (errorElement[kCrashlyticsArgumentLine] as? NSNumber)?.intValue ?? 0 + let file = errorElement.file + let line = Int(errorElement.line) ?? 0 return StackFrame(symbol: symbol, file: file, line: line) } diff --git a/packages/firebase_crashlytics/firebase_crashlytics/macos/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift b/packages/firebase_crashlytics/firebase_crashlytics/macos/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift new file mode 120000 index 000000000000..39f94bf2d687 --- /dev/null +++ b/packages/firebase_crashlytics/firebase_crashlytics/macos/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift @@ -0,0 +1 @@ +../../../../ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift \ No newline at end of file diff --git a/packages/firebase_crashlytics/firebase_crashlytics/test/firebase_crashlytics_test.dart b/packages/firebase_crashlytics/firebase_crashlytics/test/firebase_crashlytics_test.dart index 77c870c6ec7b..8f0b8eec0416 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/test/firebase_crashlytics_test.dart +++ b/packages/firebase_crashlytics/firebase_crashlytics/test/firebase_crashlytics_test.dart @@ -1,7 +1,7 @@ // ignore_for_file: require_trailing_commas -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. +// Copyright 2020 The Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_crashlytics/firebase_crashlytics.dart'; @@ -23,44 +23,35 @@ void main() { crashlytics = FirebaseCrashlytics.instance; }); - setUp(() async { - methodCallLog.clear(); - }); - - tearDown(methodCallLog.clear); + setUp(hostApi.reset); test('checkForUnsentReports', () async { await crashlytics!.setCrashlyticsCollectionEnabled(false); await crashlytics!.checkForUnsentReports(); - expect(methodCallLog, [ - isMethodCall('Crashlytics#setCrashlyticsCollectionEnabled', - arguments: {'enabled': false}), - isMethodCall('Crashlytics#checkForUnsentReports', arguments: null) + expect(hostApi.calls, [ + 'setCrashlyticsCollectionEnabled', + 'checkForUnsentReports', ]); }); test('crash', () async { crashlytics!.crash(); + await Future.delayed(Duration.zero); - expect(methodCallLog, - [isMethodCall('Crashlytics#crash', arguments: null)]); + expect(hostApi.calls, ['crash']); }); test('deleteUnsentReports', () async { await crashlytics!.deleteUnsentReports(); - expect(methodCallLog, [ - isMethodCall('Crashlytics#deleteUnsentReports', arguments: null) - ]); + expect(hostApi.calls, ['deleteUnsentReports']); }); test('didCrashOnPreviousExecution', () async { await crashlytics!.didCrashOnPreviousExecution(); - expect(methodCallLog, [ - isMethodCall('Crashlytics#didCrashOnPreviousExecution', arguments: null) - ]); + expect(hostApi.calls, ['didCrashOnPreviousExecution']); }); group('recordError', () { @@ -71,22 +62,16 @@ void main() { await crashlytics! .recordError(exception, stack, reason: exceptionReason); - expect(methodCallLog, [ - isMethodCall('Crashlytics#recordError', arguments: { - 'exception': exception, - 'reason': exceptionReason, - 'information': '', - 'fatal': false, - 'stackTraceElements': getStackTraceElements(stack), - 'buildId': '', - 'loadingUnits': [], - }) - ]); - // Confirm that the stack trace contains current stack. + expect(hostApi.calls, ['recordError']); + expect(hostApi.lastRecordError!.exception, exception); + expect(hostApi.lastRecordError!.reason, exceptionReason); + expect(hostApi.lastRecordError!.information, ''); + expect(hostApi.lastRecordError!.fatal, isFalse); + expect(hostApi.lastRecordError!.buildId, ''); + expect(hostApi.lastRecordError!.loadingUnits, isEmpty); expect( - methodCallLog[0].arguments['stackTraceElements'], - contains( - containsPair('file', contains('firebase_crashlytics_test.dart'))), + hostApi.lastRecordError!.stackTraceElements.map((e) => e.file), + contains(contains('firebase_crashlytics_test.dart')), ); }); @@ -96,15 +81,12 @@ void main() { await crashlytics! .recordError(exception, null, reason: exceptionReason); - expect(methodCallLog[0].method, 'Crashlytics#recordError'); - expect(methodCallLog[0].arguments['exception'], exception); - expect(methodCallLog[0].arguments['reason'], exceptionReason); - - // Confirm that the stack trace contains current stack. + expect(hostApi.calls, ['recordError']); + expect(hostApi.lastRecordError!.exception, exception); + expect(hostApi.lastRecordError!.reason, exceptionReason); expect( - methodCallLog[0].arguments['stackTraceElements'], - contains( - containsPair('file', contains('firebase_crashlytics_test.dart'))), + hostApi.lastRecordError!.stackTraceElements.map((e) => e.file), + contains(contains('firebase_crashlytics_test.dart')), ); }); }); @@ -134,17 +116,18 @@ void main() { try { await crashlytics!.recordFlutterError(details); expect(presentedError, true); - expect(methodCallLog, [ - isMethodCall('Crashlytics#recordError', arguments: { - 'exception': exception, - 'reason': exceptionReason, - 'fatal': false, - 'information': '$exceptionFirstMessage\n$exceptionSecondMessage', - 'stackTraceElements': getStackTraceElements(stack), - 'buildId': '', - 'loadingUnits': [], - }) - ]); + expect(hostApi.calls, ['recordError']); + expect(hostApi.lastRecordError!.exception, exception); + expect(hostApi.lastRecordError!.reason, exceptionReason); + expect(hostApi.lastRecordError!.fatal, isFalse); + expect(hostApi.lastRecordError!.information, + '$exceptionFirstMessage\n$exceptionSecondMessage'); + expect(hostApi.lastRecordError!.buildId, ''); + expect(hostApi.lastRecordError!.loadingUnits, isEmpty); + expect( + hostApi.lastRecordError!.stackTraceElements.map((e) => e.file), + contains(contains('firebase_crashlytics_test.dart')), + ); } finally { FlutterError.presentError = oldPresentError; } @@ -154,20 +137,15 @@ void main() { test('should call delegate method', () async { const msg = 'foo'; await crashlytics!.log(msg); - expect(methodCallLog, [ - isMethodCall('Crashlytics#log', arguments: { - 'message': msg, - }) - ]); + expect(hostApi.calls, ['log']); + expect(hostApi.lastLogMessage, msg); }); }); group('sendUnsentReports', () { test('should call delegate method', () async { await crashlytics!.sendUnsentReports(); - expect(methodCallLog, [ - isMethodCall('Crashlytics#sendUnsentReports', arguments: null) - ]); + expect(hostApi.calls, ['sendUnsentReports']); }); }); @@ -177,16 +155,11 @@ void main() { expect(crashlytics!.isCrashlyticsCollectionEnabled, isFalse); await crashlytics!.setCrashlyticsCollectionEnabled(true); expect(crashlytics!.isCrashlyticsCollectionEnabled, isTrue); - expect(methodCallLog, [ - isMethodCall('Crashlytics#setCrashlyticsCollectionEnabled', - arguments: { - 'enabled': false, - }), - isMethodCall('Crashlytics#setCrashlyticsCollectionEnabled', - arguments: { - 'enabled': true, - }) + expect(hostApi.calls, [ + 'setCrashlyticsCollectionEnabled', + 'setCrashlyticsCollectionEnabled', ]); + expect(hostApi.lastCollectionEnabled, isTrue); }); }); @@ -194,11 +167,8 @@ void main() { test('should call delegate method', () async { const id = 'foo'; await crashlytics!.setUserIdentifier(id); - expect(methodCallLog, [ - isMethodCall('Crashlytics#setUserIdentifier', arguments: { - 'identifier': id, - }) - ]); + expect(hostApi.calls, ['setUserIdentifier']); + expect(hostApi.lastUserIdentifier, id); }); }); @@ -214,12 +184,9 @@ void main() { const key = 'foo'; const value = 'bar'; await crashlytics!.setCustomKey(key, value); - expect(methodCallLog, [ - isMethodCall('Crashlytics#setCustomKey', arguments: { - 'key': key, - 'value': value, - }) - ]); + expect(hostApi.calls, ['setCustomKey']); + expect(hostApi.lastCustomKey, key); + expect(hostApi.lastCustomValue, value); }); }); diff --git a/packages/firebase_crashlytics/firebase_crashlytics/test/mock.dart b/packages/firebase_crashlytics/firebase_crashlytics/test/mock.dart index 0a3872e427e3..720960973dde 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/test/mock.dart +++ b/packages/firebase_crashlytics/firebase_crashlytics/test/mock.dart @@ -1,17 +1,15 @@ // ignore_for_file: require_trailing_commas -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. +// Copyright 2020, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'; import 'package:firebase_core_platform_interface/test.dart'; -import 'package:firebase_crashlytics_platform_interface/firebase_crashlytics_platform_interface.dart'; -import 'package:flutter/services.dart'; +import 'package:firebase_crashlytics_platform_interface/test.dart'; import 'package:flutter_test/flutter_test.dart'; -typedef Callback = void Function(MethodCall call); - -final List methodCallLog = []; +final FakeFirebaseCrashlyticsHostApi hostApi = + FakeFirebaseCrashlyticsHostApi(); class MockFirebaseAppWithCollectionEnabled implements TestFirebaseCoreHostApi { @override @@ -66,32 +64,89 @@ class MockFirebaseAppWithCollectionEnabled implements TestFirebaseCoreHostApi { } } -void setupFirebaseCrashlyticsMocks([Callback? customHandlers]) { +void setupFirebaseCrashlyticsMocks() { TestWidgetsFlutterBinding.ensureInitialized(); TestFirebaseCoreHostApi.setUp(MockFirebaseAppWithCollectionEnabled()); + TestFirebaseCrashlyticsHostApi.setUp(hostApi); +} + +class FakeFirebaseCrashlyticsHostApi + implements TestFirebaseCrashlyticsHostApi { + final List calls = []; + RecordErrorRequest? lastRecordError; + String? lastLogMessage; + bool? lastCollectionEnabled; + String? lastUserIdentifier; + String? lastCustomKey; + String? lastCustomValue; + + void reset() { + calls.clear(); + lastRecordError = null; + lastLogMessage = null; + lastCollectionEnabled = null; + lastUserIdentifier = null; + lastCustomKey = null; + lastCustomValue = null; + } + + @override + Future checkForUnsentReports() async { + calls.add('checkForUnsentReports'); + return true; + } + + @override + Future crash() async { + calls.add('crash'); + } + + @override + Future deleteUnsentReports() async { + calls.add('deleteUnsentReports'); + } + + @override + Future didCrashOnPreviousExecution() async { + calls.add('didCrashOnPreviousExecution'); + return true; + } - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(MethodChannelFirebaseCrashlytics.channel, - (MethodCall methodCall) async { - methodCallLog.add(methodCall); - switch (methodCall.method) { - case 'Crashlytics#checkForUnsentReports': - return { - 'unsentReports': true, - }; - case 'Crashlytics#setCrashlyticsCollectionEnabled': - return { - 'isCrashlyticsCollectionEnabled': methodCall.arguments['enabled'] - }; - case 'Crashlytics#didCrashOnPreviousExecution': - return { - 'didCrashOnPreviousExecution': true, - }; - case 'Crashlytics#recordError': - return null; - default: - return false; - } - }); + @override + Future recordError(RecordErrorRequest request) async { + calls.add('recordError'); + lastRecordError = request; + } + + @override + Future log(String message) async { + calls.add('log'); + lastLogMessage = message; + } + + @override + Future sendUnsentReports() async { + calls.add('sendUnsentReports'); + } + + @override + Future setCrashlyticsCollectionEnabled(bool enabled) async { + calls.add('setCrashlyticsCollectionEnabled'); + lastCollectionEnabled = enabled; + return enabled; + } + + @override + Future setUserIdentifier(String identifier) async { + calls.add('setUserIdentifier'); + lastUserIdentifier = identifier; + } + + @override + Future setCustomKey(String key, String value) async { + calls.add('setCustomKey'); + lastCustomKey = key; + lastCustomValue = value; + } } diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/method_channel/method_channel_crashlytics.dart b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/method_channel/method_channel_crashlytics.dart index 42a135d45302..06d27d64db1c 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/method_channel/method_channel_crashlytics.dart +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/method_channel/method_channel_crashlytics.dart @@ -6,6 +6,8 @@ import 'dart:async'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_crashlytics_platform_interface/src/pigeon/messages.pigeon.dart' + as pigeon; import 'package:flutter/services.dart'; import './utils/exception.dart'; @@ -19,16 +21,19 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { MethodChannelFirebaseCrashlytics({required FirebaseApp app}) : super(appInstance: app); - /// The [MethodChannel] used to communicate with the native plugin - static MethodChannel channel = const MethodChannel( + /// Channel name used for [FlutterFirebasePluginRegistry] / pluginConstants. + static const MethodChannel channel = MethodChannel( 'plugins.flutter.io/firebase_crashlytics', ); - bool? _isCrashlyticsCollectionEnabled; + static final pigeon.FirebaseCrashlyticsHostApi pigeonChannel = + pigeon.FirebaseCrashlyticsHostApi(); + + late bool _isCrashlyticsCollectionEnabled; @override bool get isCrashlyticsCollectionEnabled { - return _isCrashlyticsCollectionEnabled!; + return _isCrashlyticsCollectionEnabled; } @override @@ -47,12 +52,8 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { } try { - Map? data = - await channel.invokeMapMethod( - 'Crashlytics#checkForUnsentReports'); - - return data!['unsentReports']; - } on PlatformException catch (e, s) { + return await pigeonChannel.checkForUnsentReports(); + } catch (e, s) { convertPlatformException(e, s); } } @@ -60,8 +61,8 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { @override Future crash() async { try { - await channel.invokeMethod('Crashlytics#crash'); - } on PlatformException catch (e, s) { + await pigeonChannel.crash(); + } catch (e, s) { convertPlatformException(e, s); } } @@ -69,8 +70,8 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { @override Future deleteUnsentReports() async { try { - await channel.invokeMethod('Crashlytics#deleteUnsentReports'); - } on PlatformException catch (e, s) { + await pigeonChannel.deleteUnsentReports(); + } catch (e, s) { convertPlatformException(e, s); } } @@ -78,12 +79,8 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { @override Future didCrashOnPreviousExecution() async { try { - Map? data = - await channel.invokeMapMethod( - 'Crashlytics#didCrashOnPreviousExecution'); - - return data!['didCrashOnPreviousExecution']; - } on PlatformException catch (e, s) { + return await pigeonChannel.didCrashOnPreviousExecution(); + } catch (e, s) { convertPlatformException(e, s); } } @@ -99,17 +96,27 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { List>? stackTraceElements, }) async { try { - await channel - .invokeMethod('Crashlytics#recordError', { - 'exception': exception, - 'information': information, - 'reason': reason, - 'fatal': fatal, - 'buildId': buildId ?? '', - 'loadingUnits': loadingUnits, - 'stackTraceElements': stackTraceElements ?? [], - }); - } on PlatformException catch (e, s) { + await pigeonChannel.recordError( + pigeon.RecordErrorRequest( + exception: exception, + information: information, + reason: reason, + fatal: fatal, + buildId: buildId ?? '', + loadingUnits: loadingUnits, + stackTraceElements: (stackTraceElements ?? []) + .map( + (element) => pigeon.CrashlyticsStackFrame( + className: element['class'], + method: element['method'] ?? '', + file: element['file'] ?? '', + line: element['line'] ?? '0', + ), + ) + .toList(), + ), + ); + } catch (e, s) { convertPlatformException(e, s); } } @@ -117,10 +124,8 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { @override Future log(String message) async { try { - await channel.invokeMethod('Crashlytics#log', { - 'message': message, - }); - } on PlatformException catch (e, s) { + await pigeonChannel.log(message); + } catch (e, s) { convertPlatformException(e, s); } } @@ -128,8 +133,8 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { @override Future sendUnsentReports() async { try { - await channel.invokeMethod('Crashlytics#sendUnsentReports'); - } on PlatformException catch (e, s) { + await pigeonChannel.sendUnsentReports(); + } catch (e, s) { convertPlatformException(e, s); } } @@ -137,14 +142,9 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { @override Future setCrashlyticsCollectionEnabled(bool enabled) async { try { - Map? data = await channel - .invokeMapMethod( - 'Crashlytics#setCrashlyticsCollectionEnabled', { - 'enabled': enabled, - }); - - _isCrashlyticsCollectionEnabled = data!['isCrashlyticsCollectionEnabled']; - } on PlatformException catch (e, s) { + _isCrashlyticsCollectionEnabled = + await pigeonChannel.setCrashlyticsCollectionEnabled(enabled); + } catch (e, s) { convertPlatformException(e, s); } } @@ -152,11 +152,8 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { @override Future setUserIdentifier(String identifier) async { try { - await channel.invokeMethod( - 'Crashlytics#setUserIdentifier', { - 'identifier': identifier, - }); - } on PlatformException catch (e, s) { + await pigeonChannel.setUserIdentifier(identifier); + } catch (e, s) { convertPlatformException(e, s); } } @@ -164,12 +161,8 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform { @override Future setCustomKey(String key, String value) async { try { - await channel - .invokeMethod('Crashlytics#setCustomKey', { - 'key': key, - 'value': value, - }); - } on PlatformException catch (e, s) { + await pigeonChannel.setCustomKey(key, value); + } catch (e, s) { convertPlatformException(e, s); } } diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/messages.pigeon.dart b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/messages.pigeon.dart new file mode 100644 index 000000000000..7df34e10d3a3 --- /dev/null +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/messages.pigeon.dart @@ -0,0 +1,466 @@ +// Copyright 2026, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: unused_import, unused_shown_name +// ignore_for_file: type=lint + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List; + +import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; + +Object? _extractReplyValueOrThrow( + List? replyList, + String channelName, { + required bool isNullValid, +}) { + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } + return replyList.firstOrNull; +} + + +List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { + if (empty) { + return []; + } + if (error == null) { + return [result]; + } + return [error.code, error.message, error.details]; +} +bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } + if (a is List && b is List) { + return a.length == b.length && + a.indexed + .every(((int, dynamic) item) => _deepEquals(item.$2, b[item.$1])); + } + if (a is Map && b is Map) { + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; + } + return a == b; +} + +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + + +class CrashlyticsStackFrame { + CrashlyticsStackFrame({ + this.className, + required this.method, + required this.file, + required this.line, + }); + + /// Dart reserved word `class`; native maps this to the historical "class" key. + String? className; + + String method; + + String file; + + String line; + + List _toList() { + return [ + className, + method, + file, + line, + ]; + } + + Object encode() { + return _toList(); } + + static CrashlyticsStackFrame decode(Object result) { + result as List; + return CrashlyticsStackFrame( + className: result[0] as String?, + method: result[1]! as String, + file: result[2]! as String, + line: result[3]! as String, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! CrashlyticsStackFrame || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(className, other.className) && _deepEquals(method, other.method) && _deepEquals(file, other.file) && _deepEquals(line, other.line); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + +class RecordErrorRequest { + RecordErrorRequest({ + required this.exception, + required this.information, + this.reason, + required this.fatal, + required this.buildId, + required this.loadingUnits, + required this.stackTraceElements, + }); + + String exception; + + String information; + + String? reason; + + bool fatal; + + String buildId; + + List loadingUnits; + + List stackTraceElements; + + List _toList() { + return [ + exception, + information, + reason, + fatal, + buildId, + loadingUnits, + stackTraceElements, + ]; + } + + Object encode() { + return _toList(); } + + static RecordErrorRequest decode(Object result) { + result as List; + return RecordErrorRequest( + exception: result[0]! as String, + information: result[1]! as String, + reason: result[2] as String?, + fatal: result[3]! as bool, + buildId: result[4]! as String, + loadingUnits: (result[5]! as List).cast(), + stackTraceElements: (result[6]! as List).cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! RecordErrorRequest || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(exception, other.exception) && _deepEquals(information, other.information) && _deepEquals(reason, other.reason) && _deepEquals(fatal, other.fatal) && _deepEquals(buildId, other.buildId) && _deepEquals(loadingUnits, other.loadingUnits) && _deepEquals(stackTraceElements, other.stackTraceElements); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + + +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 CrashlyticsStackFrame) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is RecordErrorRequest) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + return CrashlyticsStackFrame.decode(readValue(buffer)!); + case 130: + return RecordErrorRequest.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class FirebaseCrashlyticsHostApi { + /// Constructor for [FirebaseCrashlyticsHostApi]. 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. + FirebaseCrashlyticsHostApi({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 checkForUnsentReports() async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; + return pigeonVar_replyValue! as bool; + } + + Future crash() async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; + } + + Future deleteUnsentReports() async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; + } + + Future didCrashOnPreviousExecution() async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; + return pigeonVar_replyValue! as bool; + } + + Future recordError(RecordErrorRequest request) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([request]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; + } + + Future log(String message) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([message]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; + } + + Future sendUnsentReports() async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; + } + + Future setCrashlyticsCollectionEnabled(bool enabled) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([enabled]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; + return pigeonVar_replyValue! as bool; + } + + Future setUserIdentifier(String identifier) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([identifier]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; + } + + Future setCustomKey(String key, String value) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send([key, value]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; + } +} diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/test_api.dart b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/test_api.dart new file mode 100644 index 000000000000..c18ab5dfe1d8 --- /dev/null +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/test_api.dart @@ -0,0 +1,276 @@ +// Copyright 2026, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v26.3.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, unnecessary_import, no_leading_underscores_for_local_identifiers, omit_obvious_local_variable_types +// ignore_for_file: avoid_relative_lib_imports +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'; +import 'package:flutter_test/flutter_test.dart'; + +import 'messages.pigeon.dart'; + + +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 CrashlyticsStackFrame) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is RecordErrorRequest) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + return CrashlyticsStackFrame.decode(readValue(buffer)!); + case 130: + return RecordErrorRequest.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class TestFirebaseCrashlyticsHostApi { + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => TestDefaultBinaryMessengerBinding.instance; + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + Future checkForUnsentReports(); + + Future crash(); + + Future deleteUnsentReports(); + + Future didCrashOnPreviousExecution(); + + Future recordError(RecordErrorRequest request); + + Future log(String message); + + Future sendUnsentReports(); + + Future setCrashlyticsCollectionEnabled(bool enabled); + + Future setUserIdentifier(String identifier); + + Future setCustomKey(String key, String value); + + static void setUp(TestFirebaseCrashlyticsHostApi? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + try { + final bool output = await api.checkForUnsentReports(); + return [output]; + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + try { + await api.crash(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + try { + await api.deleteUnsentReports(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + try { + final bool output = await api.didCrashOnPreviousExecution(); + return [output]; + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + final List args = message! as List; + final RecordErrorRequest arg_request = args[0]! as RecordErrorRequest; + try { + await api.recordError(arg_request); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + final List args = message! as List; + final String arg_message = args[0]! as String; + try { + await api.log(arg_message); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + try { + await api.sendUnsentReports(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + final List args = message! as List; + final bool arg_enabled = args[0]! as bool; + try { + final bool output = await api.setCrashlyticsCollectionEnabled(arg_enabled); + return [output]; + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + final List args = message! as List; + final String arg_identifier = args[0]! as String; + try { + await api.setUserIdentifier(arg_identifier); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + final List args = message! as List; + final String arg_key = args[0]! as String; + final String arg_value = args[1]! as String; + try { + await api.setCustomKey(arg_key, arg_value); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/test.dart b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/test.dart new file mode 100644 index 000000000000..87aef5dfc6c4 --- /dev/null +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/test.dart @@ -0,0 +1,10 @@ +// ignore_for_file: require_trailing_commas +// Copyright 2026, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Test helpers for this package. +library; + +export 'package:firebase_crashlytics_platform_interface/src/pigeon/messages.pigeon.dart'; +export 'package:firebase_crashlytics_platform_interface/src/pigeon/test_api.dart'; diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pigeons/copyright.txt b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pigeons/copyright.txt new file mode 100644 index 000000000000..c507a9c1b050 --- /dev/null +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pigeons/copyright.txt @@ -0,0 +1,3 @@ +Copyright 2026, the Chromium project authors. Please see the AUTHORS file +for details. All rights reserved. Use of this source code is governed by a +BSD-style license that can be found in the LICENSE file. diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pigeons/messages.dart b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pigeons/messages.dart new file mode 100644 index 000000000000..ee299feeb840 --- /dev/null +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pigeons/messages.dart @@ -0,0 +1,92 @@ +// Copyright 2026 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + dartOut: 'lib/src/pigeon/messages.pigeon.dart', + // Exported via lib/test.dart so firebase_crashlytics package tests can mock it. + dartTestOut: 'lib/src/pigeon/test_api.dart', + dartPackageName: 'firebase_crashlytics_platform_interface', + kotlinOut: + '../firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/generated/GeneratedAndroidFirebaseCrashlytics.g.kt', + kotlinOptions: KotlinOptions( + // Separate package so Pigeon's FlutterError does not collide with + // io.flutter.plugins.firebase.crashlytics.FlutterError (Crashlytics + // console exception type). + package: 'io.flutter.plugins.firebase.crashlytics.generated', + ), + swiftOut: + '../firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift', + copyrightHeader: 'pigeons/copyright.txt', + ), +) +class CrashlyticsStackFrame { + const CrashlyticsStackFrame({ + this.className, + required this.method, + required this.file, + required this.line, + }); + + /// Dart reserved word `class`; native maps this to the historical "class" key. + final String? className; + final String method; + final String file; + final String line; +} + +class RecordErrorRequest { + const RecordErrorRequest({ + required this.exception, + required this.information, + this.reason, + required this.fatal, + required this.buildId, + required this.loadingUnits, + required this.stackTraceElements, + }); + + final String exception; + final String information; + final String? reason; + final bool fatal; + final String buildId; + final List loadingUnits; + final List stackTraceElements; +} + +@HostApi(dartHostTestHandler: 'TestFirebaseCrashlyticsHostApi') +abstract class FirebaseCrashlyticsHostApi { + @async + bool checkForUnsentReports(); + + @async + void crash(); + + @async + void deleteUnsentReports(); + + @async + bool didCrashOnPreviousExecution(); + + @async + void recordError(RecordErrorRequest request); + + @async + void log(String message); + + @async + void sendUnsentReports(); + + @async + bool setCrashlyticsCollectionEnabled(bool enabled); + + @async + void setUserIdentifier(String identifier); + + @async + void setCustomKey(String key, String value); +} diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pubspec.yaml b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pubspec.yaml index dd790a85325b..fedfff9404d9 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pubspec.yaml +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/pubspec.yaml @@ -15,11 +15,13 @@ dependencies: firebase_core: ^4.13.0 flutter: sdk: flutter + # Needed to export the pigeon test HostApi via lib/test.dart + flutter_test: + sdk: flutter meta: ^1.8.0 plugin_platform_interface: ^2.1.3 dev_dependencies: firebase_core_platform_interface: ^8.1.0 - flutter_test: - sdk: flutter mockito: ^5.0.0 + pigeon: 26.3.4 diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/test/method_channel_tests/method_channel_crashlytics_test.dart b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/test/method_channel_tests/method_channel_crashlytics_test.dart index 81a27fd5b00c..b5086952ff65 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/test/method_channel_tests/method_channel_crashlytics_test.dart +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/test/method_channel_tests/method_channel_crashlytics_test.dart @@ -4,6 +4,8 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_crashlytics_platform_interface/firebase_crashlytics_platform_interface.dart'; +import 'package:firebase_crashlytics_platform_interface/src/pigeon/messages.pigeon.dart'; +import 'package:firebase_crashlytics_platform_interface/src/pigeon/test_api.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -11,217 +13,143 @@ import '../mock.dart'; void main() { setupFirebaseCrashlyticsMocks(); - TestMethodChannelFirebaseCrashlytics? mockCrashlytics; - FirebaseCrashlyticsPlatform? crashlytics; - final List logger = []; - - // mock props - bool mockPlatformExceptionThrown = false; - bool mockExceptionThrown = false; - - bool kUnsentReports = false; - - String kMockMessage = 'foo.bar.baz'; - String kMockUserIdentifier = 'user12345'; - - Map kMockError = { - 'exception': 'Test exception', - 'reason': 'MethodChannelTest', - 'fatal': false, - 'information': 'This is a test exception', - 'buildId': '', - 'loadingUnits': [], - 'stackTraceElements': >[ - { - 'declaringClass': 'MethodChannelCrashlyticsTest', - 'methodName': 'recordError', - 'fileName': 'method_channel_crashlytics_test.dart', - 'lineNumber': '99999', - } - ], - }; + + late FirebaseCrashlyticsPlatform crashlytics; + late TestMethodChannelFirebaseCrashlytics mockCrashlytics; + late _TestFirebaseCrashlyticsHostApi hostApi; + + const kMockMessage = 'foo.bar.baz'; + const kMockUserIdentifier = 'user12345'; + + final kMockStackTraceElements = >[ + { + 'class': 'MethodChannelCrashlyticsTest', + 'method': 'recordError', + 'file': 'method_channel_crashlytics_test.dart', + 'line': '99999', + } + ]; group('$MethodChannelFirebaseCrashlytics', () { setUpAll(() async { - FirebaseApp app = await Firebase.initializeApp(); - - handleMethodCall((call) async { - logger.add(call); - - if (mockExceptionThrown) { - throw Exception(); - } else if (mockPlatformExceptionThrown) { - throw PlatformException(code: 'UNKNOWN'); - } - - switch (call.method) { - case 'Crashlytics#recordError': - return null; - case 'Crashlytics#checkForUnsentReports': - return {'unsentReports': kUnsentReports}; - case 'Crashlytics#crash': - return null; - case 'Crashlytics#deleteUnsentReports': - kUnsentReports = false; - return null; - case 'Crashlytics#didCrashOnPreviousExecution': - return {'didCrashOnPreviousExecution': true}; - case 'Crashlytics#log': - return null; - case 'Crashlytics#sendUnsentReports': - return null; - case 'Crashlytics#setCrashlyticsCollectionEnabled': - return {'isCrashlyticsCollectionEnabled': true}; - default: - return true; - } - }); - + final FirebaseApp app = await Firebase.initializeApp(); + hostApi = _TestFirebaseCrashlyticsHostApi(); + TestFirebaseCrashlyticsHostApi.setUp(hostApi); crashlytics = MethodChannelFirebaseCrashlytics(app: app); mockCrashlytics = TestMethodChannelFirebaseCrashlytics(app); }); - setUp(() async { - mockPlatformExceptionThrown = false; - mockExceptionThrown = false; - logger.clear(); + tearDownAll(() { + TestFirebaseCrashlyticsHostApi.setUp(null); }); - tearDown(() async { - mockPlatformExceptionThrown = false; - mockExceptionThrown = false; + setUp(() { + hostApi.reset(); }); group('checkForUnsentReports', () { test('should call delegate method successfully', () async { - kUnsentReports = true; - var isUnsentReports = await mockCrashlytics!.checkForUnsentReports(); + hostApi.unsentReports = true; + final isUnsentReports = await mockCrashlytics.checkForUnsentReports(); expect(isUnsentReports, isTrue); - - // check native method was called - expect(logger, [ - isMethodCall( - 'Crashlytics#checkForUnsentReports', - arguments: null, - ), - ]); - - kUnsentReports = false; + expect(hostApi.checkForUnsentReportsCalled, isTrue); }); test( 'catch a [PlatformException] error and throws a [FirebaseCrashlyticsException] error', () async { - mockPlatformExceptionThrown = true; + hostApi.throwPlatformException = true; await testExceptionHandling( 'PLATFORM', - mockCrashlytics!.checkForUnsentReports, + mockCrashlytics.checkForUnsentReports, ); }); }); group('crash', () { - test('should call delegate method successfully', () { - crashlytics!.crash(); - - // check native method was called - expect(logger, [ - isMethodCall( - 'Crashlytics#crash', - arguments: null, - ), - ]); + test('should call delegate method successfully', () async { + await mockCrashlytics.crash(); + + expect(hostApi.crashCalled, isTrue); }); test( 'catch a [PlatformException] error and throws a [FirebaseCrashlyticsException] error', () async { - mockPlatformExceptionThrown = true; + hostApi.throwPlatformException = true; - await testExceptionHandling('PLATFORM', crashlytics!.crash); + await testExceptionHandling('PLATFORM', crashlytics.crash); }); }); group('deleteUnsentReports', () { test('should call delegate method successfully', () async { - kUnsentReports = true; - await crashlytics!.deleteUnsentReports(); - - expect(kUnsentReports, isFalse); + hostApi.unsentReports = true; + await crashlytics.deleteUnsentReports(); - // check native method was called - expect(logger, [ - isMethodCall( - 'Crashlytics#deleteUnsentReports', - arguments: null, - ), - ]); + expect(hostApi.unsentReports, isFalse); + expect(hostApi.deleteUnsentReportsCalled, isTrue); }); test( 'catch a [PlatformException] error and throws a [FirebaseCrashlyticsException] error', () async { - mockPlatformExceptionThrown = true; + hostApi.throwPlatformException = true; await testExceptionHandling( 'PLATFORM', - crashlytics!.deleteUnsentReports, + crashlytics.deleteUnsentReports, ); }); }); group('didCrashOnPreviousExecution', () { test('should call delegate method successfully', () async { - var didCrash = await crashlytics!.didCrashOnPreviousExecution(); + final didCrash = await crashlytics.didCrashOnPreviousExecution(); expect(didCrash, isTrue); - - // check native method was called - expect(logger, [ - isMethodCall( - 'Crashlytics#didCrashOnPreviousExecution', - arguments: null, - ), - ]); + expect(hostApi.didCrashOnPreviousExecutionCalled, isTrue); }); test( 'catch a [PlatformException] error and throws a [FirebaseCrashlyticsException] error', () async { - mockPlatformExceptionThrown = true; + hostApi.throwPlatformException = true; await testExceptionHandling( 'PLATFORM', - crashlytics!.didCrashOnPreviousExecution, + crashlytics.didCrashOnPreviousExecution, ); }); }); group('recordError', () { test('should call delegate method successfully', () async { - await crashlytics!.recordError( - exception: kMockError['exception'], - fatal: kMockError['fatal'], - reason: kMockError['reason'], - information: kMockError['information'], - stackTraceElements: kMockError['stackTraceElements'], + await crashlytics.recordError( + exception: 'Test exception', + reason: 'MethodChannelTest', + information: 'This is a test exception', + stackTraceElements: kMockStackTraceElements, ); - // check native method was called - expect(logger, [ - isMethodCall( - 'Crashlytics#recordError', - arguments: { - 'exception': kMockError['exception'], - 'reason': kMockError['reason'], - 'fatal': kMockError['fatal'], - 'information': kMockError['information'], - 'stackTraceElements': kMockError['stackTraceElements'], - 'buildId': '', - 'loadingUnits': [], - }, + expect(hostApi.lastRecordError, isNotNull); + expect(hostApi.lastRecordError!.exception, 'Test exception'); + expect(hostApi.lastRecordError!.reason, 'MethodChannelTest'); + expect(hostApi.lastRecordError!.fatal, isFalse); + expect( + hostApi.lastRecordError!.information, + 'This is a test exception', + ); + expect(hostApi.lastRecordError!.buildId, ''); + expect(hostApi.lastRecordError!.loadingUnits, isEmpty); + expect(hostApi.lastRecordError!.stackTraceElements, [ + CrashlyticsStackFrame( + className: 'MethodChannelCrashlyticsTest', + method: 'recordError', + file: 'method_channel_crashlytics_test.dart', + line: '99999', ), ]); }); @@ -229,11 +157,11 @@ void main() { test( 'catch a [PlatformException] error and throws a [FirebaseCrashlyticsException] error', () async { - mockPlatformExceptionThrown = true; + hostApi.throwPlatformException = true; await testExceptionHandling( 'PLATFORM', - () => crashlytics!.recordError( + () => crashlytics.recordError( exception: 'test exception', reason: 'test', information: 'test', @@ -244,119 +172,81 @@ void main() { }); test('log', () async { - await crashlytics!.log(kMockMessage); - - // check native method was called - expect(logger, [ - isMethodCall( - 'Crashlytics#log', - arguments: { - 'message': kMockMessage, - }, - ), - ]); + await crashlytics.log(kMockMessage); + + expect(hostApi.lastLogMessage, kMockMessage); }); group('sendUnsentReports', () { test('should call delegate method successfully', () async { - await crashlytics!.sendUnsentReports(); + await crashlytics.sendUnsentReports(); - // check native method was called - expect(logger, [ - isMethodCall( - 'Crashlytics#sendUnsentReports', - arguments: null, - ), - ]); + expect(hostApi.sendUnsentReportsCalled, isTrue); }); test( 'catch a [PlatformException] error and throws a [FirebaseCrashlyticsException] error', () async { - mockPlatformExceptionThrown = true; + hostApi.throwPlatformException = true; - await testExceptionHandling('PLATFORM', crashlytics!.sendUnsentReports); + await testExceptionHandling('PLATFORM', crashlytics.sendUnsentReports); }); }); group('setCrashlyticsCollectionEnabled', () { test('should call delegate method successfully', () async { - await crashlytics!.setCrashlyticsCollectionEnabled(true); - - // check native method was called - expect(logger, [ - isMethodCall( - 'Crashlytics#setCrashlyticsCollectionEnabled', - arguments: { - 'enabled': true, - }, - ), - ]); + await crashlytics.setCrashlyticsCollectionEnabled(true); + + expect(hostApi.lastCollectionEnabled, isTrue); }); test( 'catch a [PlatformException] error and throws a [FirebaseCrashlyticsException] error', () async { - mockPlatformExceptionThrown = true; + hostApi.throwPlatformException = true; await testExceptionHandling( 'PLATFORM', - () => crashlytics!.setCrashlyticsCollectionEnabled(true), + () => crashlytics.setCrashlyticsCollectionEnabled(true), ); }); }); group('setUserIdentifier', () { test('should call delegate method successfully', () async { - await crashlytics!.setUserIdentifier(kMockUserIdentifier); - - // check native method was called - expect(logger, [ - isMethodCall( - 'Crashlytics#setUserIdentifier', - arguments: { - 'identifier': kMockUserIdentifier, - }, - ), - ]); + await crashlytics.setUserIdentifier(kMockUserIdentifier); + + expect(hostApi.lastUserIdentifier, kMockUserIdentifier); }); test( 'catch a [PlatformException] error and throws a [FirebaseCrashlyticsException] error', () async { - mockPlatformExceptionThrown = true; + hostApi.throwPlatformException = true; await testExceptionHandling( 'PLATFORM', - () => crashlytics!.setUserIdentifier(kMockUserIdentifier), + () => crashlytics.setUserIdentifier(kMockUserIdentifier), ); }); }); group('setCustomKey', () { test('setCustomKey', () async { - await crashlytics!.setCustomKey('foo', 'bar'); - - // check native method was called - expect(logger, [ - isMethodCall( - 'Crashlytics#setCustomKey', - arguments: { - 'key': 'foo', - 'value': 'bar', - }, - ), - ]); + await crashlytics.setCustomKey('foo', 'bar'); + + expect(hostApi.lastCustomKey, 'foo'); + expect(hostApi.lastCustomValue, 'bar'); }); test( 'catch a [PlatformException] error and throws a [FirebaseCrashlyticsException] error', () async { - mockPlatformExceptionThrown = true; + hostApi.throwPlatformException = true; await testExceptionHandling( 'PLATFORM', - () => crashlytics!.setCustomKey('foo', 'bar'), + () => crashlytics.setCustomKey('foo', 'bar'), ); }); }); @@ -369,3 +259,106 @@ class TestMethodChannelFirebaseCrashlytics @override bool get isCrashlyticsCollectionEnabled => false; } + +class _TestFirebaseCrashlyticsHostApi + implements TestFirebaseCrashlyticsHostApi { + bool throwPlatformException = false; + bool unsentReports = false; + bool checkForUnsentReportsCalled = false; + bool crashCalled = false; + bool deleteUnsentReportsCalled = false; + bool didCrashOnPreviousExecutionCalled = false; + bool sendUnsentReportsCalled = false; + RecordErrorRequest? lastRecordError; + String? lastLogMessage; + bool? lastCollectionEnabled; + String? lastUserIdentifier; + String? lastCustomKey; + String? lastCustomValue; + + void reset() { + throwPlatformException = false; + checkForUnsentReportsCalled = false; + crashCalled = false; + deleteUnsentReportsCalled = false; + didCrashOnPreviousExecutionCalled = false; + sendUnsentReportsCalled = false; + lastRecordError = null; + lastLogMessage = null; + lastCollectionEnabled = null; + lastUserIdentifier = null; + lastCustomKey = null; + lastCustomValue = null; + } + + void _maybeThrow() { + if (throwPlatformException) { + throw PlatformException(code: 'UNKNOWN'); + } + } + + @override + Future checkForUnsentReports() async { + _maybeThrow(); + checkForUnsentReportsCalled = true; + return unsentReports; + } + + @override + Future crash() async { + _maybeThrow(); + crashCalled = true; + } + + @override + Future deleteUnsentReports() async { + _maybeThrow(); + deleteUnsentReportsCalled = true; + unsentReports = false; + } + + @override + Future didCrashOnPreviousExecution() async { + _maybeThrow(); + didCrashOnPreviousExecutionCalled = true; + return true; + } + + @override + Future recordError(RecordErrorRequest request) async { + _maybeThrow(); + lastRecordError = request; + } + + @override + Future log(String message) async { + _maybeThrow(); + lastLogMessage = message; + } + + @override + Future sendUnsentReports() async { + _maybeThrow(); + sendUnsentReportsCalled = true; + } + + @override + Future setCrashlyticsCollectionEnabled(bool enabled) async { + _maybeThrow(); + lastCollectionEnabled = enabled; + return enabled; + } + + @override + Future setUserIdentifier(String identifier) async { + _maybeThrow(); + lastUserIdentifier = identifier; + } + + @override + Future setCustomKey(String key, String value) async { + _maybeThrow(); + lastCustomKey = key; + lastCustomValue = value; + } +} diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/test/mock.dart b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/test/mock.dart index 15e42383f03c..cf3d7c6261ea 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/test/mock.dart +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/test/mock.dart @@ -1,30 +1,18 @@ // ignore_for_file: require_trailing_commas -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. +// Copyright 2020, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. -import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core_platform_interface/test.dart'; -import 'package:firebase_crashlytics_platform_interface/src/method_channel/method_channel_crashlytics.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -typedef MethodCallCallback = dynamic Function(MethodCall methodCall); -typedef Callback = void Function(MethodCall call); - -void setupFirebaseCrashlyticsMocks([Callback? customHandlers]) { +void setupFirebaseCrashlyticsMocks() { TestWidgetsFlutterBinding.ensureInitialized(); setupFirebaseCoreMocks(); } -void handleMethodCall(MethodCallCallback methodCallCallback) => - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(MethodChannelFirebaseCrashlytics.channel, - (call) async { - return await methodCallCallback(call); - }); - Future testExceptionHandling(String type, Function testMethod) async { try { await testMethod(); From e5c0ebb089073da915dfa86ce51718b5e9b6da75 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Thu, 13 Aug 2026 14:06:15 +0000 Subject: [PATCH 2/3] fix(crashlytics): drop public from Pigeon HostApi methods RecordErrorRequest is internal generated Swift, so public HostApi methods failed to compile. Format generated Dart/Kotlin/Swift to match CI. --- .../FlutterFirebaseCrashlyticsPlugin.kt | 2 +- .../GeneratedAndroidFirebaseCrashlytics.g.kt | 225 ++++++++++++------ .../FirebaseCrashlyticsMessages.g.swift | 160 +++++++++---- .../FirebaseCrashlyticsPlugin.swift | 49 ++-- .../firebase_crashlytics/test/mock.dart | 6 +- .../lib/src/pigeon/messages.pigeon.dart | 180 +++++++------- .../lib/src/pigeon/test_api.dart | 170 ++++++++----- 7 files changed, 494 insertions(+), 298 deletions(-) diff --git a/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/FlutterFirebaseCrashlyticsPlugin.kt b/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/FlutterFirebaseCrashlyticsPlugin.kt index 5a621cb44a75..256c6645dbbb 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/FlutterFirebaseCrashlyticsPlugin.kt +++ b/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/FlutterFirebaseCrashlyticsPlugin.kt @@ -25,8 +25,8 @@ import io.flutter.plugins.firebase.core.FlutterFirebasePlugin.cachedThreadPool import io.flutter.plugins.firebase.core.FlutterFirebasePluginRegistry import io.flutter.plugins.firebase.crashlytics.generated.CrashlyticsStackFrame import io.flutter.plugins.firebase.crashlytics.generated.FirebaseCrashlyticsHostApi -import io.flutter.plugins.firebase.crashlytics.generated.RecordErrorRequest import io.flutter.plugins.firebase.crashlytics.generated.FlutterError as PigeonFlutterError +import io.flutter.plugins.firebase.crashlytics.generated.RecordErrorRequest /** FlutterFirebaseCrashlyticsPlugin */ class FlutterFirebaseCrashlyticsPlugin : diff --git a/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/generated/GeneratedAndroidFirebaseCrashlytics.g.kt b/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/generated/GeneratedAndroidFirebaseCrashlytics.g.kt index 029c5f402677..bec96ad3ad60 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/generated/GeneratedAndroidFirebaseCrashlytics.g.kt +++ b/packages/firebase_crashlytics/firebase_crashlytics/android/src/main/kotlin/io/flutter/plugins/firebase/crashlytics/generated/GeneratedAndroidFirebaseCrashlytics.g.kt @@ -10,12 +10,11 @@ package io.flutter.plugins.firebase.crashlytics.generated 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 object GeneratedAndroidFirebaseCrashlyticsPigeonUtils { fun wrapResult(result: Any?): List { @@ -24,19 +23,15 @@ private object GeneratedAndroidFirebaseCrashlyticsPigeonUtils { fun wrapError(exception: Throwable): List { return if (exception is FlutterError) { - listOf( - exception.code, - exception.message, - exception.details - ) + listOf(exception.code, exception.message, exception.details) } else { listOf( - exception.javaClass.simpleName, - exception.toString(), - "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) - ) + exception.javaClass.simpleName, + exception.toString(), + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)) } } + fun doubleEquals(a: Double, b: Double): Boolean { // Normalize -0.0 to 0.0 and handle NaN equality. return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) @@ -180,30 +175,29 @@ private object GeneratedAndroidFirebaseCrashlyticsPigeonUtils { else -> value.hashCode() } } - } /** * 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 +class FlutterError( + val code: String, + override val message: String? = null, + val details: Any? = null ) : RuntimeException() /** Generated class from Pigeon that represents data sent in messages. */ -data class CrashlyticsStackFrame ( - /** Dart reserved word `class`; native maps this to the historical "class" key. */ - val className: String? = null, - val method: String, - val file: String, - val line: String -) - { +data class CrashlyticsStackFrame( + /** Dart reserved word `class`; native maps this to the historical "class" key. */ + val className: String? = null, + val method: String, + val file: String, + val line: String +) { companion object { fun fromList(pigeonVar_list: List): CrashlyticsStackFrame { val className = pigeonVar_list[0] as String? @@ -213,14 +207,16 @@ data class CrashlyticsStackFrame ( return CrashlyticsStackFrame(className, method, file, line) } } + fun toList(): List { return listOf( - className, - method, - file, - line, + className, + method, + file, + line, ) } + override fun equals(other: Any?): Boolean { if (other == null || other.javaClass != javaClass) { return false @@ -229,7 +225,11 @@ data class CrashlyticsStackFrame ( return true } val other = other as CrashlyticsStackFrame - return GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.className, other.className) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.method, other.method) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.file, other.file) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.line, other.line) + return GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals( + this.className, other.className) && + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.method, other.method) && + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.file, other.file) && + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.line, other.line) } override fun hashCode(): Int { @@ -243,16 +243,15 @@ data class CrashlyticsStackFrame ( } /** Generated class from Pigeon that represents data sent in messages. */ -data class RecordErrorRequest ( - val exception: String, - val information: String, - val reason: String? = null, - val fatal: Boolean, - val buildId: String, - val loadingUnits: List, - val stackTraceElements: List -) - { +data class RecordErrorRequest( + val exception: String, + val information: String, + val reason: String? = null, + val fatal: Boolean, + val buildId: String, + val loadingUnits: List, + val stackTraceElements: List +) { companion object { fun fromList(pigeonVar_list: List): RecordErrorRequest { val exception = pigeonVar_list[0] as String @@ -262,20 +261,23 @@ data class RecordErrorRequest ( val buildId = pigeonVar_list[4] as String val loadingUnits = pigeonVar_list[5] as List val stackTraceElements = pigeonVar_list[6] as List - return RecordErrorRequest(exception, information, reason, fatal, buildId, loadingUnits, stackTraceElements) + return RecordErrorRequest( + exception, information, reason, fatal, buildId, loadingUnits, stackTraceElements) } } + fun toList(): List { return listOf( - exception, - information, - reason, - fatal, - buildId, - loadingUnits, - stackTraceElements, + exception, + information, + reason, + fatal, + buildId, + loadingUnits, + stackTraceElements, ) } + override fun equals(other: Any?): Boolean { if (other == null || other.javaClass != javaClass) { return false @@ -284,7 +286,17 @@ data class RecordErrorRequest ( return true } val other = other as RecordErrorRequest - return GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.exception, other.exception) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.information, other.information) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.reason, other.reason) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.fatal, other.fatal) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.buildId, other.buildId) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.loadingUnits, other.loadingUnits) && GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.stackTraceElements, other.stackTraceElements) + return GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals( + this.exception, other.exception) && + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals( + this.information, other.information) && + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.reason, other.reason) && + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.fatal, other.fatal) && + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals(this.buildId, other.buildId) && + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals( + this.loadingUnits, other.loadingUnits) && + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepEquals( + this.stackTraceElements, other.stackTraceElements) } override fun hashCode(): Int { @@ -294,28 +306,29 @@ data class RecordErrorRequest ( result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.reason) result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.fatal) result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.buildId) - result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.loadingUnits) - result = 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.stackTraceElements) + result = + 31 * result + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.loadingUnits) + result = + 31 * result + + GeneratedAndroidFirebaseCrashlyticsPigeonUtils.deepHash(this.stackTraceElements) return result } } + private open class GeneratedAndroidFirebaseCrashlyticsPigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { return when (type) { 129.toByte() -> { - return (readValue(buffer) as? List)?.let { - CrashlyticsStackFrame.fromList(it) - } + return (readValue(buffer) as? List)?.let { CrashlyticsStackFrame.fromList(it) } } 130.toByte() -> { - return (readValue(buffer) as? List)?.let { - RecordErrorRequest.fromList(it) - } + return (readValue(buffer) as? List)?.let { RecordErrorRequest.fromList(it) } } else -> super.readValueOfType(type, buffer) } } - override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { when (value) { is CrashlyticsStackFrame -> { stream.write(129) @@ -330,34 +343,52 @@ private open class GeneratedAndroidFirebaseCrashlyticsPigeonCodec : StandardMess } } - /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ interface FirebaseCrashlyticsHostApi { fun checkForUnsentReports(callback: (Result) -> Unit) + fun crash(callback: (Result) -> Unit) + fun deleteUnsentReports(callback: (Result) -> Unit) + fun didCrashOnPreviousExecution(callback: (Result) -> Unit) + fun recordError(request: RecordErrorRequest, callback: (Result) -> Unit) + fun log(message: String, callback: (Result) -> Unit) + fun sendUnsentReports(callback: (Result) -> Unit) + fun setCrashlyticsCollectionEnabled(enabled: Boolean, callback: (Result) -> Unit) + fun setUserIdentifier(identifier: String, callback: (Result) -> Unit) + fun setCustomKey(key: String, value: String, callback: (Result) -> Unit) companion object { /** The codec used by FirebaseCrashlyticsHostApi. */ - val codec: MessageCodec by lazy { - GeneratedAndroidFirebaseCrashlyticsPigeonCodec() - } - /** Sets up an instance of `FirebaseCrashlyticsHostApi` to handle messages through the `binaryMessenger`. */ + val codec: MessageCodec by lazy { GeneratedAndroidFirebaseCrashlyticsPigeonCodec() } + /** + * Sets up an instance of `FirebaseCrashlyticsHostApi` to handle messages through the + * `binaryMessenger`. + */ @JvmOverloads - fun setUp(binaryMessenger: BinaryMessenger, api: FirebaseCrashlyticsHostApi?, messageChannelSuffix: String = "") { - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + fun setUp( + binaryMessenger: BinaryMessenger, + api: FirebaseCrashlyticsHostApi?, + messageChannelSuffix: String = "" + ) { + val separatedMessageChannelSuffix = + if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports$separatedMessageChannelSuffix", codec) + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports$separatedMessageChannelSuffix", + codec) if (api != null) { channel.setMessageHandler { _, reply -> - api.checkForUnsentReports{ result: Result -> + api.checkForUnsentReports { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) @@ -372,10 +403,14 @@ interface FirebaseCrashlyticsHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash$separatedMessageChannelSuffix", codec) + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash$separatedMessageChannelSuffix", + codec) if (api != null) { channel.setMessageHandler { _, reply -> - api.crash{ result: Result -> + api.crash { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) @@ -389,10 +424,14 @@ interface FirebaseCrashlyticsHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports$separatedMessageChannelSuffix", codec) + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports$separatedMessageChannelSuffix", + codec) if (api != null) { channel.setMessageHandler { _, reply -> - api.deleteUnsentReports{ result: Result -> + api.deleteUnsentReports { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) @@ -406,10 +445,14 @@ interface FirebaseCrashlyticsHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution$separatedMessageChannelSuffix", codec) + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution$separatedMessageChannelSuffix", + codec) if (api != null) { channel.setMessageHandler { _, reply -> - api.didCrashOnPreviousExecution{ result: Result -> + api.didCrashOnPreviousExecution { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) @@ -424,7 +467,11 @@ interface FirebaseCrashlyticsHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError$separatedMessageChannelSuffix", codec) + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError$separatedMessageChannelSuffix", + codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List @@ -443,7 +490,11 @@ interface FirebaseCrashlyticsHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log$separatedMessageChannelSuffix", codec) + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log$separatedMessageChannelSuffix", + codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List @@ -462,10 +513,14 @@ interface FirebaseCrashlyticsHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports$separatedMessageChannelSuffix", codec) + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports$separatedMessageChannelSuffix", + codec) if (api != null) { channel.setMessageHandler { _, reply -> - api.sendUnsentReports{ result: Result -> + api.sendUnsentReports { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(GeneratedAndroidFirebaseCrashlyticsPigeonUtils.wrapError(error)) @@ -479,7 +534,11 @@ interface FirebaseCrashlyticsHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled$separatedMessageChannelSuffix", codec) + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled$separatedMessageChannelSuffix", + codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List @@ -499,7 +558,11 @@ interface FirebaseCrashlyticsHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier$separatedMessageChannelSuffix", codec) + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier$separatedMessageChannelSuffix", + codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List @@ -518,7 +581,11 @@ interface FirebaseCrashlyticsHostApi { } } run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey$separatedMessageChannelSuffix", codec) + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey$separatedMessageChannelSuffix", + codec) if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List diff --git a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift index 13a91db75fbc..8295cbb27459 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift +++ b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift @@ -27,13 +27,12 @@ final class PigeonError: Error { } var localizedDescription: String { - return - "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" + "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" } } private func wrapResult(_ result: Any?) -> [Any?] { - return [result] + [result] } private func wrapError(_ error: Any) -> [Any?] { @@ -59,7 +58,7 @@ private func wrapError(_ error: Any) -> [Any?] { } private func isNullish(_ value: Any?) -> Bool { - return value is NSNull || value == nil + value is NSNull || value == nil } private func nilOrValue(_ value: Any?) -> T? { @@ -68,12 +67,12 @@ private func nilOrValue(_ value: Any?) -> T? { } private func doubleEqualsFirebaseCrashlyticsMessages(_ lhs: Double, _ rhs: Double) -> Bool { - return (lhs.isNaN && rhs.isNaN) || lhs == rhs + (lhs.isNaN && rhs.isNaN) || lhs == rhs } private func doubleHashFirebaseCrashlyticsMessages(_ value: Double, _ hasher: inout Hasher) { if value.isNaN { - hasher.combine(0x7FF8000000000000) + hasher.combine(0x7FF8_0000_0000_0000) } else { // Normalize -0.0 to 0.0 hasher.combine(value == 0 ? 0 : value) @@ -145,7 +144,7 @@ func deepEqualsFirebaseCrashlyticsMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { func deepHashFirebaseCrashlyticsMessages(value: Any?, hasher: inout Hasher) { let cleanValue = nilOrValue(value) as Any? - if let cleanValue = cleanValue { + if let cleanValue { if let doubleValue = cleanValue as? Double { doubleHashFirebaseCrashlyticsMessages(doubleValue, &hasher) } else if let valueList = cleanValue as? [Any?] { @@ -176,16 +175,14 @@ func deepHashFirebaseCrashlyticsMessages(value: Any?, hasher: inout Hasher) { } } - /// Generated class from Pigeon that represents data sent in messages. struct CrashlyticsStackFrame: Hashable { /// Dart reserved word `class`; native maps this to the historical "class" key. - var className: String? = nil + var className: String? var method: String var file: String var line: String - // swift-format-ignore: AlwaysUseLowerCamelCase static func fromList(_ pigeonVar_list: [Any?]) -> CrashlyticsStackFrame? { let className: String? = nilOrValue(pigeonVar_list[0]) @@ -200,19 +197,29 @@ struct CrashlyticsStackFrame: Hashable { line: line ) } + func toList() -> [Any?] { - return [ + [ className, method, file, line, ] } + static func == (lhs: CrashlyticsStackFrame, rhs: CrashlyticsStackFrame) -> Bool { if Swift.type(of: lhs) != Swift.type(of: rhs) { return false } - return deepEqualsFirebaseCrashlyticsMessages(lhs.className, rhs.className) && deepEqualsFirebaseCrashlyticsMessages(lhs.method, rhs.method) && deepEqualsFirebaseCrashlyticsMessages(lhs.file, rhs.file) && deepEqualsFirebaseCrashlyticsMessages(lhs.line, rhs.line) + return deepEqualsFirebaseCrashlyticsMessages(lhs.className, rhs.className) && + deepEqualsFirebaseCrashlyticsMessages( + lhs.method, + rhs.method + ) && deepEqualsFirebaseCrashlyticsMessages(lhs.file, rhs.file) && + deepEqualsFirebaseCrashlyticsMessages( + lhs.line, + rhs.line + ) } func hash(into hasher: inout Hasher) { @@ -228,13 +235,12 @@ struct CrashlyticsStackFrame: Hashable { struct RecordErrorRequest: Hashable { var exception: String var information: String - var reason: String? = nil + var reason: String? var fatal: Bool var buildId: String var loadingUnits: [String] var stackTraceElements: [CrashlyticsStackFrame] - // swift-format-ignore: AlwaysUseLowerCamelCase static func fromList(_ pigeonVar_list: [Any?]) -> RecordErrorRequest? { let exception = pigeonVar_list[0] as! String @@ -255,8 +261,9 @@ struct RecordErrorRequest: Hashable { stackTraceElements: stackTraceElements ) } + func toList() -> [Any?] { - return [ + [ exception, information, reason, @@ -266,11 +273,24 @@ struct RecordErrorRequest: Hashable { stackTraceElements, ] } + static func == (lhs: RecordErrorRequest, rhs: RecordErrorRequest) -> Bool { if Swift.type(of: lhs) != Swift.type(of: rhs) { return false } - return deepEqualsFirebaseCrashlyticsMessages(lhs.exception, rhs.exception) && deepEqualsFirebaseCrashlyticsMessages(lhs.information, rhs.information) && deepEqualsFirebaseCrashlyticsMessages(lhs.reason, rhs.reason) && deepEqualsFirebaseCrashlyticsMessages(lhs.fatal, rhs.fatal) && deepEqualsFirebaseCrashlyticsMessages(lhs.buildId, rhs.buildId) && deepEqualsFirebaseCrashlyticsMessages(lhs.loadingUnits, rhs.loadingUnits) && deepEqualsFirebaseCrashlyticsMessages(lhs.stackTraceElements, rhs.stackTraceElements) + return deepEqualsFirebaseCrashlyticsMessages(lhs.exception, rhs.exception) && + deepEqualsFirebaseCrashlyticsMessages( + lhs.information, + rhs.information + ) && deepEqualsFirebaseCrashlyticsMessages(lhs.reason, rhs.reason) && + deepEqualsFirebaseCrashlyticsMessages( + lhs.fatal, + rhs.fatal + ) && deepEqualsFirebaseCrashlyticsMessages(lhs.buildId, rhs.buildId) && + deepEqualsFirebaseCrashlyticsMessages( + lhs.loadingUnits, + rhs.loadingUnits + ) && deepEqualsFirebaseCrashlyticsMessages(lhs.stackTraceElements, rhs.stackTraceElements) } func hash(into hasher: inout Hasher) { @@ -289,9 +309,9 @@ private class FirebaseCrashlyticsMessagesPigeonCodecReader: FlutterStandardReade override func readValue(ofType type: UInt8) -> Any? { switch type { case 129: - return CrashlyticsStackFrame.fromList(self.readValue() as! [Any?]) + return CrashlyticsStackFrame.fromList(readValue() as! [Any?]) case 130: - return RecordErrorRequest.fromList(self.readValue() as! [Any?]) + return RecordErrorRequest.fromList(readValue() as! [Any?]) default: return super.readValue(ofType: type) } @@ -314,19 +334,21 @@ private class FirebaseCrashlyticsMessagesPigeonCodecWriter: FlutterStandardWrite private class FirebaseCrashlyticsMessagesPigeonCodecReaderWriter: FlutterStandardReaderWriter { override func reader(with data: Data) -> FlutterStandardReader { - return FirebaseCrashlyticsMessagesPigeonCodecReader(data: data) + FirebaseCrashlyticsMessagesPigeonCodecReader(data: data) } override func writer(with data: NSMutableData) -> FlutterStandardWriter { - return FirebaseCrashlyticsMessagesPigeonCodecWriter(data: data) + FirebaseCrashlyticsMessagesPigeonCodecWriter(data: data) } } class FirebaseCrashlyticsMessagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { - static let shared = FirebaseCrashlyticsMessagesPigeonCodec(readerWriter: FirebaseCrashlyticsMessagesPigeonCodecReaderWriter()) + static let shared = + FirebaseCrashlyticsMessagesPigeonCodec( + readerWriter: FirebaseCrashlyticsMessagesPigeonCodecReaderWriter() + ) } - /// Generated protocol from Pigeon that represents a handler of messages from Flutter. protocol FirebaseCrashlyticsHostApi { func checkForUnsentReports(completion: @escaping (Result) -> Void) @@ -336,19 +358,29 @@ protocol FirebaseCrashlyticsHostApi { func recordError(request: RecordErrorRequest, completion: @escaping (Result) -> Void) func log(message: String, completion: @escaping (Result) -> Void) func sendUnsentReports(completion: @escaping (Result) -> Void) - func setCrashlyticsCollectionEnabled(enabled: Bool, completion: @escaping (Result) -> Void) + func setCrashlyticsCollectionEnabled(enabled: Bool, + completion: @escaping (Result) -> Void) func setUserIdentifier(identifier: String, completion: @escaping (Result) -> Void) func setCustomKey(key: String, value: String, completion: @escaping (Result) -> Void) } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. class FirebaseCrashlyticsHostApiSetup { - static var codec: FlutterStandardMessageCodec { FirebaseCrashlyticsMessagesPigeonCodec.shared } - /// Sets up an instance of `FirebaseCrashlyticsHostApi` to handle messages through the `binaryMessenger`. - static func setUp(binaryMessenger: FlutterBinaryMessenger, api: FirebaseCrashlyticsHostApi?, messageChannelSuffix: String = "") { + static var codec: FlutterStandardMessageCodec { + FirebaseCrashlyticsMessagesPigeonCodec.shared + } + + /// Sets up an instance of `FirebaseCrashlyticsHostApi` to handle messages through the + /// `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: FirebaseCrashlyticsHostApi?, + messageChannelSuffix: String = "") { let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" - let checkForUnsentReportsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { + let checkForUnsentReportsChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { checkForUnsentReportsChannel.setMessageHandler { _, reply in api.checkForUnsentReports { result in switch result { @@ -362,8 +394,12 @@ class FirebaseCrashlyticsHostApiSetup { } else { checkForUnsentReportsChannel.setMessageHandler(nil) } - let crashChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { + let crashChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { crashChannel.setMessageHandler { _, reply in api.crash { result in switch result { @@ -377,8 +413,12 @@ class FirebaseCrashlyticsHostApiSetup { } else { crashChannel.setMessageHandler(nil) } - let deleteUnsentReportsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { + let deleteUnsentReportsChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { deleteUnsentReportsChannel.setMessageHandler { _, reply in api.deleteUnsentReports { result in switch result { @@ -392,8 +432,12 @@ class FirebaseCrashlyticsHostApiSetup { } else { deleteUnsentReportsChannel.setMessageHandler(nil) } - let didCrashOnPreviousExecutionChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { + let didCrashOnPreviousExecutionChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { didCrashOnPreviousExecutionChannel.setMessageHandler { _, reply in api.didCrashOnPreviousExecution { result in switch result { @@ -407,8 +451,12 @@ class FirebaseCrashlyticsHostApiSetup { } else { didCrashOnPreviousExecutionChannel.setMessageHandler(nil) } - let recordErrorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { + let recordErrorChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { recordErrorChannel.setMessageHandler { message, reply in let args = message as! [Any?] let requestArg = args[0] as! RecordErrorRequest @@ -424,8 +472,12 @@ class FirebaseCrashlyticsHostApiSetup { } else { recordErrorChannel.setMessageHandler(nil) } - let logChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { + let logChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { logChannel.setMessageHandler { message, reply in let args = message as! [Any?] let messageArg = args[0] as! String @@ -441,8 +493,12 @@ class FirebaseCrashlyticsHostApiSetup { } else { logChannel.setMessageHandler(nil) } - let sendUnsentReportsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { + let sendUnsentReportsChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { sendUnsentReportsChannel.setMessageHandler { _, reply in api.sendUnsentReports { result in switch result { @@ -456,8 +512,12 @@ class FirebaseCrashlyticsHostApiSetup { } else { sendUnsentReportsChannel.setMessageHandler(nil) } - let setCrashlyticsCollectionEnabledChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { + let setCrashlyticsCollectionEnabledChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { setCrashlyticsCollectionEnabledChannel.setMessageHandler { message, reply in let args = message as! [Any?] let enabledArg = args[0] as! Bool @@ -473,8 +533,12 @@ class FirebaseCrashlyticsHostApiSetup { } else { setCrashlyticsCollectionEnabledChannel.setMessageHandler(nil) } - let setUserIdentifierChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { + let setUserIdentifierChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { setUserIdentifierChannel.setMessageHandler { message, reply in let args = message as! [Any?] let identifierArg = args[0] as! String @@ -490,8 +554,12 @@ class FirebaseCrashlyticsHostApiSetup { } else { setUserIdentifierChannel.setMessageHandler(nil) } - let setCustomKeyChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { + let setCustomKeyChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { setCustomKeyChannel.setMessageHandler { message, reply in let args = message as! [Any?] let keyArg = args[0] as! String diff --git a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift index ced1e52e18d6..0aa2d7effef1 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift +++ b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift @@ -27,8 +27,7 @@ private let kFLTFirebaseCrashlyticsTestChannelName = extension FlutterError: Error {} public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, FlutterPlugin, - FlutterStreamHandler, FirebaseCrashlyticsHostApi -{ + FlutterStreamHandler, FirebaseCrashlyticsHostApi { private var testEventChannel: FlutterEventChannel? private var testEventSink: FlutterEventSink? @@ -65,7 +64,7 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu public func pluginConstants(for firebaseApp: FirebaseApp) -> [AnyHashable: Any] { [ - "isCrashlyticsCollectionEnabled": Crashlytics.crashlytics().isCrashlyticsCollectionEnabled() + "isCrashlyticsCollectionEnabled": Crashlytics.crashlytics().isCrashlyticsCollectionEnabled(), ] } @@ -79,13 +78,13 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu // MARK: - FirebaseCrashlyticsHostApi - public func checkForUnsentReports(completion: @escaping (Result) -> Void) { + func checkForUnsentReports(completion: @escaping (Result) -> Void) { Crashlytics.crashlytics().checkForUnsentReports { unsentReports in completion(.success(unsentReports)) } } - public func crash(completion: @escaping (Result) -> Void) { + func crash(completion: @escaping (Result) -> Void) { NSException( name: NSExceptionName("FirebaseCrashlyticsTestCrash"), reason: "This is a test crash caused by calling .crash() in Dart.", @@ -93,19 +92,17 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu ).raise() } - public func deleteUnsentReports(completion: @escaping (Result) -> Void) { + func deleteUnsentReports(completion: @escaping (Result) -> Void) { Crashlytics.crashlytics().deleteUnsentReports() completion(.success(())) } - public func didCrashOnPreviousExecution(completion: @escaping (Result) -> Void) { + func didCrashOnPreviousExecution(completion: @escaping (Result) -> Void) { completion(.success(Crashlytics.crashlytics().didCrashDuringPreviousExecution())) } - public func recordError( - request: RecordErrorRequest, - completion: @escaping (Result) -> Void - ) { + func recordError(request: RecordErrorRequest, + completion: @escaping (Result) -> Void) { var reason = request.reason let information = request.information let dartExceptionMessage = request.exception @@ -151,37 +148,31 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu completion(.success(())) } - public func log(message: String, completion: @escaping (Result) -> Void) { + func log(message: String, completion: @escaping (Result) -> Void) { Crashlytics.crashlytics().log(message) completion(.success(())) } - public func sendUnsentReports(completion: @escaping (Result) -> Void) { + func sendUnsentReports(completion: @escaping (Result) -> Void) { Crashlytics.crashlytics().sendUnsentReports() completion(.success(())) } - public func setCrashlyticsCollectionEnabled( - enabled: Bool, - completion: @escaping (Result) -> Void - ) { + func setCrashlyticsCollectionEnabled(enabled: Bool, + completion: @escaping (Result) -> Void) { Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(enabled) completion(.success(Crashlytics.crashlytics().isCrashlyticsCollectionEnabled())) } - public func setUserIdentifier( - identifier: String, - completion: @escaping (Result) -> Void - ) { + func setUserIdentifier(identifier: String, + completion: @escaping (Result) -> Void) { Crashlytics.crashlytics().setUserID(identifier) completion(.success(())) } - public func setCustomKey( - key: String, - value: String, - completion: @escaping (Result) -> Void - ) { + func setCustomKey(key: String, + value: String, + completion: @escaping (Result) -> Void) { Crashlytics.crashlytics().setCustomValue(value, forKey: key) completion(.success(())) } @@ -199,10 +190,8 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu // MARK: - FlutterStreamHandler - public func onListen( - withArguments arguments: Any?, - eventSink events: @escaping FlutterEventSink - ) -> FlutterError? { + public func onListen(withArguments arguments: Any?, + eventSink events: @escaping FlutterEventSink) -> FlutterError? { testEventSink = events return nil } diff --git a/packages/firebase_crashlytics/firebase_crashlytics/test/mock.dart b/packages/firebase_crashlytics/firebase_crashlytics/test/mock.dart index 720960973dde..aac300034597 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/test/mock.dart +++ b/packages/firebase_crashlytics/firebase_crashlytics/test/mock.dart @@ -8,8 +8,7 @@ import 'package:firebase_core_platform_interface/test.dart'; import 'package:firebase_crashlytics_platform_interface/test.dart'; import 'package:flutter_test/flutter_test.dart'; -final FakeFirebaseCrashlyticsHostApi hostApi = - FakeFirebaseCrashlyticsHostApi(); +final FakeFirebaseCrashlyticsHostApi hostApi = FakeFirebaseCrashlyticsHostApi(); class MockFirebaseAppWithCollectionEnabled implements TestFirebaseCoreHostApi { @override @@ -71,8 +70,7 @@ void setupFirebaseCrashlyticsMocks() { TestFirebaseCrashlyticsHostApi.setUp(hostApi); } -class FakeFirebaseCrashlyticsHostApi - implements TestFirebaseCrashlyticsHostApi { +class FakeFirebaseCrashlyticsHostApi implements TestFirebaseCrashlyticsHostApi { final List calls = []; RecordErrorRequest? lastRecordError; String? lastLogMessage; diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/messages.pigeon.dart b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/messages.pigeon.dart index 7df34e10d3a3..fc72df791f61 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/messages.pigeon.dart +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/messages.pigeon.dart @@ -13,9 +13,9 @@ import 'package:flutter/services.dart'; import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; Object? _extractReplyValueOrThrow( - List? replyList, - String channelName, { - required bool isNullValid, + List? replyList, + String channelName, { + required bool isNullValid, }) { if (replyList == null) { throw PlatformException( @@ -37,8 +37,8 @@ Object? _extractReplyValueOrThrow( return replyList.firstOrNull; } - -List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { +List wrapResponse( + {Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -47,6 +47,7 @@ List wrapResponse({Object? result, PlatformException? error, bool empty } return [error.code, error.message, error.details]; } + bool _deepEquals(Object? a, Object? b) { if (identical(a, b)) { return true; @@ -109,7 +110,6 @@ int _deepHash(Object? value) { return value.hashCode; } - class CrashlyticsStackFrame { CrashlyticsStackFrame({ this.className, @@ -137,7 +137,8 @@ class CrashlyticsStackFrame { } Object encode() { - return _toList(); } + return _toList(); + } static CrashlyticsStackFrame decode(Object result) { result as List; @@ -158,7 +159,10 @@ class CrashlyticsStackFrame { if (identical(this, other)) { return true; } - return _deepEquals(className, other.className) && _deepEquals(method, other.method) && _deepEquals(file, other.file) && _deepEquals(line, other.line); + return _deepEquals(className, other.className) && + _deepEquals(method, other.method) && + _deepEquals(file, other.file) && + _deepEquals(line, other.line); } @override @@ -204,7 +208,8 @@ class RecordErrorRequest { } Object encode() { - return _toList(); } + return _toList(); + } static RecordErrorRequest decode(Object result) { result as List; @@ -215,7 +220,8 @@ class RecordErrorRequest { fatal: result[3]! as bool, buildId: result[4]! as String, loadingUnits: (result[5]! as List).cast(), - stackTraceElements: (result[6]! as List).cast(), + stackTraceElements: + (result[6]! as List).cast(), ); } @@ -228,7 +234,13 @@ class RecordErrorRequest { if (identical(this, other)) { return true; } - return _deepEquals(exception, other.exception) && _deepEquals(information, other.information) && _deepEquals(reason, other.reason) && _deepEquals(fatal, other.fatal) && _deepEquals(buildId, other.buildId) && _deepEquals(loadingUnits, other.loadingUnits) && _deepEquals(stackTraceElements, other.stackTraceElements); + return _deepEquals(exception, other.exception) && + _deepEquals(information, other.information) && + _deepEquals(reason, other.reason) && + _deepEquals(fatal, other.fatal) && + _deepEquals(buildId, other.buildId) && + _deepEquals(loadingUnits, other.loadingUnits) && + _deepEquals(stackTraceElements, other.stackTraceElements); } @override @@ -236,7 +248,6 @@ class RecordErrorRequest { int get hashCode => _deepHash([runtimeType, ..._toList()]); } - class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -244,10 +255,10 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is CrashlyticsStackFrame) { + } else if (value is CrashlyticsStackFrame) { buffer.putUint8(129); writeValue(buffer, value.encode()); - } else if (value is RecordErrorRequest) { + } else if (value is RecordErrorRequest) { buffer.putUint8(130); writeValue(buffer, value.encode()); } else { @@ -272,9 +283,11 @@ class FirebaseCrashlyticsHostApi { /// Constructor for [FirebaseCrashlyticsHostApi]. 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. - FirebaseCrashlyticsHostApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + FirebaseCrashlyticsHostApi( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -282,7 +295,8 @@ class FirebaseCrashlyticsHostApi { final String pigeonVar_messageChannelSuffix; Future checkForUnsentReports() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -292,16 +306,16 @@ class FirebaseCrashlyticsHostApi { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as bool; } Future crash() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -311,15 +325,15 @@ class FirebaseCrashlyticsHostApi { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future deleteUnsentReports() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -329,15 +343,15 @@ class FirebaseCrashlyticsHostApi { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future didCrashOnPreviousExecution() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -347,52 +361,54 @@ class FirebaseCrashlyticsHostApi { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as bool; } Future recordError(RecordErrorRequest request) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([request]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([request]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future log(String message) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([message]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([message]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future sendUnsentReports() async { - final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, @@ -402,65 +418,67 @@ class FirebaseCrashlyticsHostApi { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future setCrashlyticsCollectionEnabled(bool enabled) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([enabled]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([enabled]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: false, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); return pigeonVar_replyValue! as bool; } Future setUserIdentifier(String identifier) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([identifier]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([identifier]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future setCustomKey(String key, String value) async { - final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey$pigeonVar_messageChannelSuffix'; + final pigeonVar_channelName = + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send([key, value]); + final Future pigeonVar_sendFuture = + pigeonVar_channel.send([key, value]); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; _extractReplyValueOrThrow( - pigeonVar_replyList, - pigeonVar_channelName, - isNullValid: true, - ) - ; + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } } diff --git a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/test_api.dart b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/test_api.dart index c18ab5dfe1d8..dd171b9bfafe 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/test_api.dart +++ b/packages/firebase_crashlytics/firebase_crashlytics_platform_interface/lib/src/pigeon/test_api.dart @@ -13,7 +13,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'messages.pigeon.dart'; - class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -21,10 +20,10 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is CrashlyticsStackFrame) { + } else if (value is CrashlyticsStackFrame) { buffer.putUint8(129); writeValue(buffer, value.encode()); - } else if (value is RecordErrorRequest) { + } else if (value is RecordErrorRequest) { buffer.putUint8(130); writeValue(buffer, value.encode()); } else { @@ -46,7 +45,8 @@ class _PigeonCodec extends StandardMessageCodec { } abstract class TestFirebaseCrashlyticsHostApi { - static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => TestDefaultBinaryMessengerBinding.instance; + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => + TestDefaultBinaryMessengerBinding.instance; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); Future checkForUnsentReports(); @@ -69,92 +69,121 @@ abstract class TestFirebaseCrashlyticsHostApi { Future setCustomKey(String key, String value); - static void setUp(TestFirebaseCrashlyticsHostApi? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { - messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp( + TestFirebaseCrashlyticsHostApi? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { try { final bool output = await api.checkForUnsentReports(); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { try { await api.crash(); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { try { await api.deleteUnsentReports(); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { try { final bool output = await api.didCrashOnPreviousExecution(); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { final List args = message! as List; final RecordErrorRequest arg_request = args[0]! as RecordErrorRequest; try { @@ -162,20 +191,25 @@ abstract class TestFirebaseCrashlyticsHostApi { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { final List args = message! as List; final String arg_message = args[0]! as String; try { @@ -183,60 +217,76 @@ abstract class TestFirebaseCrashlyticsHostApi { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { try { await api.sendUnsentReports(); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { final List args = message! as List; final bool arg_enabled = args[0]! as bool; try { - final bool output = await api.setCrashlyticsCollectionEnabled(arg_enabled); + final bool output = + await api.setCrashlyticsCollectionEnabled(arg_enabled); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { final List args = message! as List; final String arg_identifier = args[0]! as String; try { @@ -244,20 +294,25 @@ abstract class TestFirebaseCrashlyticsHostApi { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey$messageChannelSuffix', pigeonChannelCodec, + 'dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey$messageChannelSuffix', + pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, null); + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler(pigeonVar_channel, (Object? message) async { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { final List args = message! as List; final String arg_key = args[0]! as String; final String arg_value = args[1]! as String; @@ -266,8 +321,9 @@ abstract class TestFirebaseCrashlyticsHostApi { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); } }); } From 8ae4893569c2473e52b0604426dc340c94df09a7 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Fri, 14 Aug 2026 13:22:51 +0000 Subject: [PATCH 3/3] style(crashlytics,apple): apply SwiftFormat to Pigeon host API sources --- .../FirebaseCrashlyticsMessages.g.swift | 61 +++++++++++-------- .../FirebaseCrashlyticsPlugin.swift | 37 +++++++---- 2 files changed, 61 insertions(+), 37 deletions(-) diff --git a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift index 8295cbb27459..9c2ac737d21e 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift +++ b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsMessages.g.swift @@ -211,12 +211,12 @@ struct CrashlyticsStackFrame: Hashable { if Swift.type(of: lhs) != Swift.type(of: rhs) { return false } - return deepEqualsFirebaseCrashlyticsMessages(lhs.className, rhs.className) && - deepEqualsFirebaseCrashlyticsMessages( + return deepEqualsFirebaseCrashlyticsMessages(lhs.className, rhs.className) + && deepEqualsFirebaseCrashlyticsMessages( lhs.method, rhs.method - ) && deepEqualsFirebaseCrashlyticsMessages(lhs.file, rhs.file) && - deepEqualsFirebaseCrashlyticsMessages( + ) && deepEqualsFirebaseCrashlyticsMessages(lhs.file, rhs.file) + && deepEqualsFirebaseCrashlyticsMessages( lhs.line, rhs.line ) @@ -278,16 +278,16 @@ struct RecordErrorRequest: Hashable { if Swift.type(of: lhs) != Swift.type(of: rhs) { return false } - return deepEqualsFirebaseCrashlyticsMessages(lhs.exception, rhs.exception) && - deepEqualsFirebaseCrashlyticsMessages( + return deepEqualsFirebaseCrashlyticsMessages(lhs.exception, rhs.exception) + && deepEqualsFirebaseCrashlyticsMessages( lhs.information, rhs.information - ) && deepEqualsFirebaseCrashlyticsMessages(lhs.reason, rhs.reason) && - deepEqualsFirebaseCrashlyticsMessages( + ) && deepEqualsFirebaseCrashlyticsMessages(lhs.reason, rhs.reason) + && deepEqualsFirebaseCrashlyticsMessages( lhs.fatal, rhs.fatal - ) && deepEqualsFirebaseCrashlyticsMessages(lhs.buildId, rhs.buildId) && - deepEqualsFirebaseCrashlyticsMessages( + ) && deepEqualsFirebaseCrashlyticsMessages(lhs.buildId, rhs.buildId) + && deepEqualsFirebaseCrashlyticsMessages( lhs.loadingUnits, rhs.loadingUnits ) && deepEqualsFirebaseCrashlyticsMessages(lhs.stackTraceElements, rhs.stackTraceElements) @@ -358,8 +358,9 @@ protocol FirebaseCrashlyticsHostApi { func recordError(request: RecordErrorRequest, completion: @escaping (Result) -> Void) func log(message: String, completion: @escaping (Result) -> Void) func sendUnsentReports(completion: @escaping (Result) -> Void) - func setCrashlyticsCollectionEnabled(enabled: Bool, - completion: @escaping (Result) -> Void) + func setCrashlyticsCollectionEnabled( + enabled: Bool, + completion: @escaping (Result) -> Void) func setUserIdentifier(identifier: String, completion: @escaping (Result) -> Void) func setCustomKey(key: String, value: String, completion: @escaping (Result) -> Void) } @@ -372,11 +373,14 @@ class FirebaseCrashlyticsHostApiSetup { /// Sets up an instance of `FirebaseCrashlyticsHostApi` to handle messages through the /// `binaryMessenger`. - static func setUp(binaryMessenger: FlutterBinaryMessenger, api: FirebaseCrashlyticsHostApi?, - messageChannelSuffix: String = "") { + static func setUp( + binaryMessenger: FlutterBinaryMessenger, api: FirebaseCrashlyticsHostApi?, + messageChannelSuffix: String = "" + ) { let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" let checkForUnsentReportsChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports\(channelSuffix)", + name: + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.checkForUnsentReports\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec ) @@ -395,7 +399,8 @@ class FirebaseCrashlyticsHostApiSetup { checkForUnsentReportsChannel.setMessageHandler(nil) } let crashChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash\(channelSuffix)", + name: + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.crash\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec ) @@ -414,7 +419,8 @@ class FirebaseCrashlyticsHostApiSetup { crashChannel.setMessageHandler(nil) } let deleteUnsentReportsChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports\(channelSuffix)", + name: + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.deleteUnsentReports\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec ) @@ -433,7 +439,8 @@ class FirebaseCrashlyticsHostApiSetup { deleteUnsentReportsChannel.setMessageHandler(nil) } let didCrashOnPreviousExecutionChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution\(channelSuffix)", + name: + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.didCrashOnPreviousExecution\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec ) @@ -452,7 +459,8 @@ class FirebaseCrashlyticsHostApiSetup { didCrashOnPreviousExecutionChannel.setMessageHandler(nil) } let recordErrorChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError\(channelSuffix)", + name: + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.recordError\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec ) @@ -473,7 +481,8 @@ class FirebaseCrashlyticsHostApiSetup { recordErrorChannel.setMessageHandler(nil) } let logChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log\(channelSuffix)", + name: + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.log\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec ) @@ -494,7 +503,8 @@ class FirebaseCrashlyticsHostApiSetup { logChannel.setMessageHandler(nil) } let sendUnsentReportsChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports\(channelSuffix)", + name: + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.sendUnsentReports\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec ) @@ -513,7 +523,8 @@ class FirebaseCrashlyticsHostApiSetup { sendUnsentReportsChannel.setMessageHandler(nil) } let setCrashlyticsCollectionEnabledChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled\(channelSuffix)", + name: + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCrashlyticsCollectionEnabled\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec ) @@ -534,7 +545,8 @@ class FirebaseCrashlyticsHostApiSetup { setCrashlyticsCollectionEnabledChannel.setMessageHandler(nil) } let setUserIdentifierChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier\(channelSuffix)", + name: + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setUserIdentifier\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec ) @@ -555,7 +567,8 @@ class FirebaseCrashlyticsHostApiSetup { setUserIdentifierChannel.setMessageHandler(nil) } let setCustomKeyChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey\(channelSuffix)", + name: + "dev.flutter.pigeon.firebase_crashlytics_platform_interface.FirebaseCrashlyticsHostApi.setCustomKey\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec ) diff --git a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift index 0aa2d7effef1..830bf23784dd 100644 --- a/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift +++ b/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics/Sources/firebase_crashlytics/FirebaseCrashlyticsPlugin.swift @@ -27,7 +27,8 @@ private let kFLTFirebaseCrashlyticsTestChannelName = extension FlutterError: Error {} public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, FlutterPlugin, - FlutterStreamHandler, FirebaseCrashlyticsHostApi { + FlutterStreamHandler, FirebaseCrashlyticsHostApi +{ private var testEventChannel: FlutterEventChannel? private var testEventSink: FlutterEventSink? @@ -64,7 +65,7 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu public func pluginConstants(for firebaseApp: FirebaseApp) -> [AnyHashable: Any] { [ - "isCrashlyticsCollectionEnabled": Crashlytics.crashlytics().isCrashlyticsCollectionEnabled(), + "isCrashlyticsCollectionEnabled": Crashlytics.crashlytics().isCrashlyticsCollectionEnabled() ] } @@ -101,8 +102,10 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu completion(.success(Crashlytics.crashlytics().didCrashDuringPreviousExecution())) } - func recordError(request: RecordErrorRequest, - completion: @escaping (Result) -> Void) { + func recordError( + request: RecordErrorRequest, + completion: @escaping (Result) -> Void + ) { var reason = request.reason let information = request.information let dartExceptionMessage = request.exception @@ -158,21 +161,27 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu completion(.success(())) } - func setCrashlyticsCollectionEnabled(enabled: Bool, - completion: @escaping (Result) -> Void) { + func setCrashlyticsCollectionEnabled( + enabled: Bool, + completion: @escaping (Result) -> Void + ) { Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(enabled) completion(.success(Crashlytics.crashlytics().isCrashlyticsCollectionEnabled())) } - func setUserIdentifier(identifier: String, - completion: @escaping (Result) -> Void) { + func setUserIdentifier( + identifier: String, + completion: @escaping (Result) -> Void + ) { Crashlytics.crashlytics().setUserID(identifier) completion(.success(())) } - func setCustomKey(key: String, - value: String, - completion: @escaping (Result) -> Void) { + func setCustomKey( + key: String, + value: String, + completion: @escaping (Result) -> Void + ) { Crashlytics.crashlytics().setCustomValue(value, forKey: key) completion(.success(())) } @@ -190,8 +199,10 @@ public class FirebaseCrashlyticsPlugin: NSObject, FLTFirebasePluginProtocol, Flu // MARK: - FlutterStreamHandler - public func onListen(withArguments arguments: Any?, - eventSink events: @escaping FlutterEventSink) -> FlutterError? { + public func onListen( + withArguments arguments: Any?, + eventSink events: @escaping FlutterEventSink + ) -> FlutterError? { testEventSink = events return nil }