private void HandleMethodCall(FlutterMethodCall call, FlutterResult callback) { // Return an error if Flutter is invoking method calls through method channel // when bridge is configured for WebSocket communication if (Mode == FlutnetBridgeMode.WebSocket) { callback(ConstantsEx.FlutterMethodNotImplemented); return; } // Extract target method information from MethodCall.Method FlutnetMethodInfo methodInfo; NSObject dartReturnValue; try { methodInfo = JsonConvert.DeserializeObject <FlutnetMethodInfo>(call.Method, FlutterInterop.JsonSerializerSettings); dartReturnValue = FlutterInterop.ToMethodChannelResult(0); } catch (Exception ex) { callback(FlutterError.Create(FlutnetErrorCode.OperationNotImplemented.ToString(), ex.Message, null)); return; } // Send an empty - successful - response to immediately free Flutter thread callback(dartReturnValue); nint[] taskId = new nint[1]; taskId[0] = UIApplication.SharedApplication.BeginBackgroundTask(() => { FlutnetException error = new FlutnetException(FlutnetErrorCode.OperationCanceled); MainThread.BeginInvokeOnMainThread(() => SendError(methodInfo, error)); UIApplication.SharedApplication.EndBackgroundTask(taskId[0]); }); // Run the call in Background Task.Run(() => { BackgroundHandleMethodCall(methodInfo, call); UIApplication.SharedApplication.EndBackgroundTask(taskId[0]); }); }
/// <summary> /// Invoke a platform operation with the specified arguments. /// </summary> public static PlatformOperationResult Run(FlutnetRuntime.OperationInfo operation, object[] arguments) { // Check if the operation must be invoked on the main (UI) thread bool mainThreadRequired = false; #if __ANDROID__ mainThreadRequired = operation.OperationAttribute.AndroidMainThreadRequired; #elif __IOS__ mainThreadRequired = operation.OperationAttribute.IosMainThreadRequired; #endif object operationResult = null; Exception operationError = null; // 1. Async call on UI Thread if (mainThreadRequired && operation.IsAsyncTask) { ManualResetEvent uiFinishEvent = new ManualResetEvent(false); MainThread.BeginInvokeOnMainThread(() => { Task task = (Task)operation.DelegateWithResult.Invoke(arguments); task.ContinueWith(t => { if (t.IsFaulted) { operationError = t.Exception?.GetBaseException(); } else if (t.IsCanceled) { operationError = new FlutnetException(FlutnetErrorCode.OperationCanceled); } else { operationResult = t.TaskResult(); } uiFinishEvent.Set(); }); }); uiFinishEvent.WaitOne(); } // 2. Sync call on UI Thread else if (mainThreadRequired) { ManualResetEvent uiFinishEvent = new ManualResetEvent(false); MainThread.BeginInvokeOnMainThread(() => { try { if (operation.HasResult) { operationResult = operation.DelegateWithResult.Invoke(arguments); } else { operation.Delegate.Invoke(arguments); operationResult = null; } } catch (Exception ex) { operationError = ex; } finally { uiFinishEvent.Set(); } }); uiFinishEvent.WaitOne(); } // 3. Async call on Background Thread else if (operation.IsAsyncTask) { ManualResetEvent taskFinishEvent = new ManualResetEvent(false); Task task = (Task)operation.DelegateWithResult.Invoke(arguments); task.ContinueWith(t => { if (t.IsFaulted) { operationError = t.Exception?.GetBaseException(); } else if (t.IsCanceled) { operationError = new FlutnetException(FlutnetErrorCode.OperationCanceled); } else { operationResult = t.TaskResult(); } taskFinishEvent.Set(); }); taskFinishEvent.WaitOne(); } // 4. Sync call on Background Thread else { try { if (operation.HasResult) { operationResult = operation.DelegateWithResult.Invoke(arguments); } else { operation.Delegate.Invoke(arguments); operationResult = null; } } catch (Exception ex) { operationError = ex; } } // Return the result return(new PlatformOperationResult { Result = operationResult, Error = operationError }); }