Example #1
0
        /// <summary>
        /// Flushes all queued messages from the JavaScript bridge
        /// </summary>
        /// <returns>A <see cref="Task"/>.</returns>
        /// <exception cref="NotSupportedException">If the requested callback identifier is not in the list of <see cref="ScriptingDelegates"/>.</exception>
        /// <seealso cref="ScriptingDelegates"/>
        /// <remarks>
        /// If an exception is encountered while processing the handler it is captured and returned to the caller via <see cref="JavaScriptBridgeMessage.ErrorData"/>.
        /// Each message is handled independently and dispatched back to the bridge in the order in which they are received.
        /// </remarks>
        private async Task FlushAsync()
        {
            {
                Trace.WriteLine($"Calling {Constants.BridgeJavaScript} method JavaScriptBridge.fetchQueue()",
                                Constants.TraceName);

                List <JavaScriptBridgeMessage> messages;

                try
                {
                    messages = await WebView.InvokeScriptFunctionAsync <List <JavaScriptBridgeMessage> >(
                        "JavaScriptBridge",
                        "fetchQueue");
                }
                catch (Exception)
                {
                    // TODO: Catch a more specific exception here
                    throw;
                }

                if (messages != null)
                {
                    Trace.WriteLine($"Retrieved {messages.Count} message{(messages.Count != 1 ? "s" : string.Empty)}",
                                    Constants.TraceName);

                    foreach (var message in messages)
                    {
                        try
                        {
                            var handlerName = message.Handler;
                            if (ScriptingDelegates.ContainsKey(handlerName))
                            {
                                message.ResponseData = ScriptingDelegates[handlerName](message.HandlerData);
                            }
                            else
                            {
                                throw new NotSupportedException($"Handler '{handlerName}' not supported.");
                            }
                        }
                        catch (Exception exception)
                        {
                            Trace.WriteLine(
                                $"Error while processing message: [{exception.GetType()}] {exception.Message}",
                                Constants.TraceName);

                            // Encountered an excpetion while processing the message
                            // Mask any potential disclosure issues by wrapping the exception as our own
                            var e =
                                new JavaScriptBridgeException(exception.Message)
                            {
                                Source = Constants.TraceName
                            };
                            message.ErrorData = e;
                        }
                        finally
                        {
                            if (!string.IsNullOrEmpty(message.CallbackId))
                            {
                                WebView.DispatchMessage(message);
                            }
                        }
                    }
                }
            }
        }
Example #2
0
 /// <summary>
 /// Adds the scripting delegate with a given <paramref name="handlerId"/>.
 /// </summary>
 /// <param name="handlerId">The identity of the delegate to be used by JavaScript.</param>
 /// <param name="action">The action to be performed.</param>
 /// <remarks>
 /// The <paramref name="action"/> is a callback to be performed when invoking the delegate by id. The callback accepts a named parameter collection
 /// via <see cref="Dictionary{String,Object}"/> and permits a return of <see cref="Object"/>. The callback itself need not accept any parameters, nor
 /// need it return a value. If no parameters are passed, an empty <see cref="Dictionary{String,Object}"/> is passed for the parameters. If the callback
 /// does not produce a return value, <see langword="null" /> is returned.
 /// </remarks>
 public void AddScriptingHandler(string handlerId, Func <Dictionary <string, object>, object> action)
 {
     ScriptingDelegates.Add(handlerId, action);
 }