/// <summary>
        /// Called at the end of each batch.
        /// Has to be run on the dispatcher thread corresponding to the <see cref="UIManager.NativeViewHierarchyManager"/> processing the batch.
        /// </summary>
        internal static void OnBatchComplete()
        {
            // Exit fast if no dirty node exists at all
            if (!s_treeContext.Value.Dirty)
            {
                return;
            }

#if PERF_LOG
            s_treeContext.Value.ProcessedNodesCount = 0;
            var savedDirtyNodesCount = s_treeContext.Value.DirtyNodesCount;
#endif

            // Recurse through all known roots
            foreach (var root in s_treeContext.Value.RootViews)
            {
                UpdateAccessibilityPropertiesForTree(root);
            }

            // Not dirty anymore
            s_treeContext.Value.Dirty = false;

#if PERF_LOG
            RnLog.Info(ReactConstants.RNW, $"Stats: ElementCount: {s_treeContext.Value.ElementCount}, " +
                       $"MarkedDirtyNodesCount: {s_treeContext.Value.MarkedDirtyNodesCount}, " +
                       $"DirtyNodesCount(before): {savedDirtyNodesCount}, " +
                       $"DirtyNodesCount(after): {s_treeContext.Value.DirtyNodesCount}, " +
                       $"ProcessedNodesCount: {s_treeContext.Value.ProcessedNodesCount}");
            s_treeContext.Value.MarkedDirtyNodesCount = 0;
#endif
        }
示例#2
0
        public void getCurrentAppState(ICallback success, ICallback error)
        {
            var currentAppState = _appState;

            RnLog.Info(ReactConstants.RNW, $"AppStateModule: getCurrentAppState returned {currentAppState}");
            success.Invoke(CreateAppStateEventMap(currentAppState));
        }
示例#3
0
        private async Task StartReactApplicationAsync(ReactInstanceManager reactInstanceManager, string moduleName, JObject initialProps)
        {
            RnLog.Info(ReactConstants.RNW, $"ReactRootView: StartReactApplicationAsync ({moduleName}) - entry");
            // This is called under the dispatcher associated with the view.
            DispatcherHelpers.AssertOnDispatcher(this);

            if (_reactInstanceManager != null)
            {
                throw new InvalidOperationException("This root view has already been attached to an instance manager.");
            }

            _reactInstanceManager = reactInstanceManager;
            _jsModuleName         = moduleName;
            _initialProps         = initialProps;

            var getReactContextTaskTask =
                DispatcherHelpers.CallOnDispatcher(async() => await _reactInstanceManager.GetOrCreateReactContextAsync(CancellationToken.None), true);

            await getReactContextTaskTask.Unwrap();

            // We need to wait for the initial `Measure` call, if this view has
            // not yet been measured, we set the `_attachScheduled` flag, which
            // will enable deferred attachment of the root node.
            if (_wasMeasured)
            {
                await _reactInstanceManager.AttachMeasuredRootViewAsync(this);
            }
            else
            {
                _attachScheduled = true;
            }

            RnLog.Info(ReactConstants.RNW, $"ReactRootView: StartReactApplicationAsync ({moduleName}) - done ({(_attachScheduled ? "with scheduled work" : "completely")})");
        }
示例#4
0
        public async void clear(ICallback callback)
        {
            var error = default(JObject);

            await _mutex.WaitAsync().ConfigureAwait(false);

            try
            {
                var storageFolder = await GetAsyncStorageFolder(false).ConfigureAwait(false);

                if (storageFolder != null)
                {
                    await storageFolder.DeleteAsync().ConfigureAwait(false);
                }
            }
            catch (Exception ex)
            {
                error = AsyncStorageHelpers.GetError(ex);
            }
            finally
            {
                _mutex.Release();
            }

            if (error != null)
            {
                RnLog.Warn(ReactConstants.RNW, $"Error in AsyncStorageModule.clear: {error}");
                callback.Invoke(error);
            }
            else
            {
                callback.Invoke();
            }
        }
示例#5
0
        public void UpdateView()
        {
            if (_connectedViewTag == -1)
            {
                return;
            }

            foreach (var entry in _propNodeMapping)
            {
                var node = _manager.GetNodeById(entry.Value);
                if (node is StyleAnimatedNode styleNode)
                {
                    styleNode.CollectViewUpdates(_propMap);
                }
                else if (node is ValueAnimatedNode valueNode)
                {
                    _propMap[entry.Key] = valueNode.Value;
                }
                else
                {
                    throw new InvalidOperationException($"Unsupported type of node used in property node '{node.GetType()}'.");
                }
            }

            var updated = _uiImplementation.SynchronouslyUpdateViewOnDispatcherThread(
                _connectedViewTag,
                _propMap);

            if (!updated)
            {
                RnLog.Warn(ReactConstants.RNW, $"Native animation workaround, frame lost as result of race condition.");
            }
        }
        private async Task TearDownReactContextAsync(ReactContext reactContext, CancellationToken token)
        {
            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: Tearing down React context - entry");
            token.ThrowIfCancellationRequested();

            DispatcherHelpers.AssertOnDispatcher();

            _lifecycleStateMachine.SetContext(null);

            // Existing root views should be silenced before tearing down the context.
            // Most of the work is done by the tearing down of the context itself, yet the native root views continue to exist,
            // so things like "size changes" or touch handling should be stopped immediately.
            foreach (var rootView in _attachedRootViews)
            {
                // Inlining allowed
                DispatcherHelpers.RunOnDispatcher(rootView.Dispatcher, () =>
                {
                    rootView.RemoveSizeChanged();

                    rootView.StopTouchHandling();
                }, true);
            }

            await reactContext.DisposeAsync();

            _devSupportManager.OnReactContextDestroyed(reactContext);

            // TODO: add memory pressure hooks
            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: Tearing down React context - done");
        }
        private async Task <ReactContext> InitializeReactContextAsync(
            Func <IJavaScriptExecutor> jsExecutorFactory,
            JavaScriptBundleLoader jsBundleLoader,
            CancellationToken token)
        {
            var currentReactContext = _currentReactContext;

            if (currentReactContext != null)
            {
                await TearDownReactContextAsync(currentReactContext, token);

                _currentReactContext = null;
            }

            try
            {
                var reactContext = await CreateReactContextCoreAsync(jsExecutorFactory, jsBundleLoader, token);
                await SetupReactContextAsync(reactContext);

                return(reactContext);
            }
            catch (OperationCanceledException)
                when(token.IsCancellationRequested)
                {
                    RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: Creating React context has been canceled");
                    throw;
                }
            catch (Exception ex)
            {
                RnLog.Error(ReactConstants.RNW, ex, $"ReactInstanceManager: Exception when creating React context: {ex.Message}");
                _devSupportManager.HandleException(ex);
            }

            return(null);
        }
        /// <summary>
        /// Parse a <see cref="DebugServerException"/> from the server response.
        /// </summary>
        /// <param name="content">
        /// JSON response returned by the debug server.
        /// </param>
        /// <returns>The exception instance.</returns>
        public static DebugServerException Parse(string content)
        {
            if (!string.IsNullOrEmpty(content))
            {
                try
                {
                    var jsonObject  = JObject.Parse(content);
                    var fileName    = jsonObject.Value <string>("filename");
                    var description = jsonObject.Value <string>("description");
                    if (description != null)
                    {
                        return(new DebugServerException(
                                   jsonObject.Value <string>("description"),
                                   ShortenFileName(fileName),
                                   jsonObject.Value <int>("lineNumber"),
                                   jsonObject.Value <int>("column")));
                    }
                }
                catch (JsonException ex)
                {
                    RnLog.Error(ReactConstants.RNW, ex, $"Failure deserializing debug server exception message.");
                }
            }

            return(null);
        }
示例#9
0
        private void SendAppStateChangeEvent()
        {
            var currentAppState = _appState;

            RnLog.Info(ReactConstants.RNW, $"AppStateModule: appStateDidChange to {currentAppState}");
            Context.GetJavaScriptModule <RCTDeviceEventEmitter>()
            .emit("appStateDidChange", CreateAppStateEventMap(currentAppState));
        }
示例#10
0
 private static void Forget(Task task)
 {
     task.ContinueWith(
         t =>
     {
         RnLog.Fatal(ReactConstants.RNW, t.Exception, $"Exception in fire and forget asynchronous function");
     },
         TaskContinuationOptions.OnlyOnFaulted);
 }
 /// <summary>
 /// Awaits the currently initializing React context, or returns null if context fails to initialize.
 /// </summary>
 /// <param name="token">A token to cancel the request.</param>
 /// <returns>
 /// A task to await the React context.
 /// </returns>
 public async Task <ReactContext> TryGetReactContextAsync(CancellationToken token)
 {
     RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: TryGetReactContextAsync - entry");
     DispatcherHelpers.AssertOnDispatcher();
     using (await _lock.LockAsync())
     {
         // By this point context has already been created due to the serialized aspect of context initialization.
         RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: TryGetReactContextAsync - execute/returning existing {(_currentReactContext == null ? "null" : "valid")} context");
         return(_currentReactContext);
     }
 }
示例#12
0
 public void HandleException(Exception exception)
 {
     if (IsEnabled)
     {
         ShowNewNativeError(exception.Message, exception);
     }
     else
     {
         RnLog.Fatal(ReactConstants.RNW, exception, $"Exception caught in top handler");
     }
 }
示例#13
0
        public async void multiRemove(string[] keys, ICallback callback)
        {
            if (keys == null || keys.Length == 0)
            {
                callback.Invoke(AsyncStorageHelpers.GetInvalidKeyError(null));
                return;
            }

            var error = default(JObject);

            await _mutex.WaitAsync().ConfigureAwait(false);

            try
            {
                foreach (var key in keys)
                {
                    if (key == null)
                    {
                        error = AsyncStorageHelpers.GetInvalidKeyError(null);
                        break;
                    }

                    error = await RemoveAsync(key).ConfigureAwait(false);

                    if (error != null)
                    {
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                error = AsyncStorageHelpers.GetError(ex);
            }
            finally
            {
                _mutex.Release();
            }

            if (error != null)
            {
                RnLog.Warn(ReactConstants.RNW, $"Error in AsyncStorageModule.multiRemove: {error}");
                callback.Invoke(error);
            }
            else
            {
                callback.Invoke();
            }
        }
        /// <summary>
        /// Runs the script at the given path.
        /// </summary>
        /// <param name="sourcePath">The source path.</param>
        /// <param name="sourceUrl">The source URL.</param>
        public void RunScript(string sourcePath, string sourceUrl)
        {
            if (sourcePath == null)
            {
                throw new ArgumentNullException(nameof(sourcePath));
            }
            if (sourceUrl == null)
            {
                throw new ArgumentNullException(nameof(sourceUrl));
            }

            var startupCode = default(string);

            if (IsUnbundle(sourcePath))
            {
                _unbundle = new FileBasedJavaScriptUnbundle(sourcePath);
                InstallNativeRequire();
                startupCode = _unbundle.GetStartupCode();
            }
            else if (IsIndexedUnbundle(sourcePath))
            {
                _unbundle = new IndexedJavaScriptUnbundle(sourcePath);
                InstallNativeRequire();
                startupCode = _unbundle.GetStartupCode();
            }
            else
            {
                startupCode = LoadScript(sourcePath);

                try
                {
                    if (this._modifyBundle != null)
                    {
                        //Modify bundle function returns modified bundle.
                        var updatedBundle = this._modifyBundle(startupCode);
                        startupCode = updatedBundle;
                    }
                }
                catch (Exception ex)
                {
                    RnLog.Error("Native", ex, @"Exception during bundle modification.");
#if DEBUG
                    throw;
#endif
                }
            }

            EvaluateScript(startupCode, sourceUrl);
        }
        public async void removeRootView(int rootViewTag)
        {
            RnLog.Info(ReactConstants.RNW, $"UIManagerModule: removeRootView ({rootViewTag}) - entry");

            // A cleanup task should be waiting here
            if (!_rootViewCleanupTasks.TryRemove(rootViewTag, out var cleanupTask))
            {
                throw new InvalidOperationException("Unexpected removeRootView");
            }

            await _uiImplementation.RemoveRootViewAsync(rootViewTag);

            cleanupTask.SetResult(true);
            RnLog.Info(ReactConstants.RNW, $"UIManagerModule: removeRootView ({rootViewTag}) - done");
        }
示例#16
0
        /// <summary>
        /// Passes the exception to the current
        /// <see cref="NativeModuleCallExceptionHandler"/>, if set, otherwise
        /// rethrows.
        /// </summary>
        /// <param name="exception"></param>
        public void HandleException(Exception exception)
        {
            var nativeModuleCallExceptionHandler = NativeModuleCallExceptionHandler;

            if (_reactInstance != null &&
                !_reactInstance.IsDisposed &&
                nativeModuleCallExceptionHandler != null)
            {
                nativeModuleCallExceptionHandler(exception);
            }
            else
            {
                RnLog.Fatal(ReactConstants.RNW, exception, $"Unhandled Exception in React Context");
            }
        }
        /// <summary>
        /// Method that gives JavaScript the opportunity to consume the back
        /// button event. If JavaScript does not consume the event, the
        /// default back press action will be invoked at the end of the
        /// roundtrip to JavaScript.
        /// </summary>
        public void OnBackPressed()
        {
            DispatcherHelpers.AssertOnDispatcher();
            var reactContext = _currentReactContext;

            if (reactContext == null)
            {
                RnLog.Warn(ReactConstants.RNW, $"ReactInstanceManager: OnBackPressed: Instance detached from instance manager.");
                InvokeDefaultOnBackPressed();
            }
            else
            {
                reactContext.GetNativeModule <DeviceEventManagerModule>().EmitHardwareBackPressed();
            }
        }
 /// <summary>
 /// Invokes an action on a specified dispatcher and priority
 /// </summary>
 /// <param name="dispatcher">The dispatcher.</param>
 /// <param name="priority">The priority.</param>
 /// <param name="action">The action to invoke.</param>
 /// <param name="allowInlining">True if inlining is allowed when calling thread is on the same dispatcher as the one in the parameter.</param>
 public static void RunOnDispatcher(CoreDispatcher dispatcher, CoreDispatcherPriority priority, DispatchedHandler action, bool allowInlining = false)
 {
     if (allowInlining && IsOnDispatcher(dispatcher))
     {
         action();
     }
     else
     {
         dispatcher.RunAsync(priority, action).AsTask().ContinueWith(
             t =>
         {
             RnLog.Fatal(ReactConstants.RNW, t.Exception, $"Exception in fire and forget asynchronous function");
         },
             TaskContinuationOptions.OnlyOnFaulted);
     }
 }
示例#19
0
        /// <summary>
        /// Frees resources associated with this root view.
        /// </summary>
        /// <remarks>
        /// Has to be called under the dispatcher associated with the view.
        /// </remarks>
        /// <returns>Awaitable task.</returns>
        public async Task StopReactApplicationAsync()
        {
            RnLog.Info(ReactConstants.RNW, $"ReactRootView: StopReactApplicationAsync ({JavaScriptModuleName}) - entry");
            DispatcherHelpers.AssertOnDispatcher(this);

            var reactInstanceManager = _reactInstanceManager;
            var attachScheduled      = _attachScheduled;

            _attachScheduled = false;
            if (!attachScheduled && reactInstanceManager != null)
            {
                await reactInstanceManager.DetachRootViewAsync(this);
            }

            RnLog.Info(ReactConstants.RNW, $"ReactRootView: StopReactApplicationAsync ({JavaScriptModuleName}) - done");
        }
示例#20
0
        public async void multiGet(string[] keys, ICallback callback)
        {
            if (keys == null)
            {
                callback.Invoke(AsyncStorageHelpers.GetInvalidKeyError(null), null);
                return;
            }

            var error = default(JObject);
            var data  = new JArray();

            await _mutex.WaitAsync().ConfigureAwait(false);

            try
            {
                foreach (var key in keys)
                {
                    if (key == null)
                    {
                        error = AsyncStorageHelpers.GetInvalidKeyError(null);
                        break;
                    }

                    var value = await GetAsync(key).ConfigureAwait(false);

                    data.Add(new JArray(key, value));
                }
            }
            catch (Exception ex)
            {
                error = AsyncStorageHelpers.GetError(ex);
            }
            finally
            {
                _mutex.Release();
            }

            if (error != null)
            {
                RnLog.Warn(ReactConstants.RNW, $"Error in AsyncStorageModule.multiGet: {error}");
                callback.Invoke(error);
            }
            else
            {
                callback.Invoke(null, data);
            }
        }
        /// <summary>
        /// Awaits the currently initializing React context.
        /// </summary>
        /// <param name="token">A token to cancel the request.</param>
        /// <returns>
        /// A task to await the React context.
        /// </returns>
        public async Task <ReactContext> GetReactContextAsync(CancellationToken token)
        {
            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: GetReactContextAsync - entry");
            DispatcherHelpers.AssertOnDispatcher();
            using (await _lock.LockAsync())
            {
                RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: GetReactContextAsync - execute");
                if (_currentReactContext == null)
                {
                    throw new InvalidOperationException(
                              "Use the create method to start initializing the React context.");
                }

                // By this point context has already been created due to the serialized aspect of context initialization.
                RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: GetReactContextAsync - returning existing {(_currentReactContext == null ? "null" : "valid")} context");
                return(_currentReactContext);
            }
        }
示例#22
0
        public async void getAllKeys(ICallback callback)
        {
            var error = default(JObject);
            var keys  = new JArray();

            await _mutex.WaitAsync().ConfigureAwait(false);

            try
            {
                var storageFolder = await GetAsyncStorageFolder(false).ConfigureAwait(false);

                if (storageFolder != null)
                {
                    var items = await storageFolder.GetItemsAsync().AsTask().ConfigureAwait(false);

                    foreach (var item in items)
                    {
                        var itemName = item.Name;
                        if (itemName.EndsWith(AsyncStorageHelpers.FileExtension))
                        {
                            keys.Add(AsyncStorageHelpers.GetKeyName(itemName));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                error = AsyncStorageHelpers.GetError(ex);
            }
            finally
            {
                _mutex.Release();
            }

            if (error != null)
            {
                RnLog.Warn(ReactConstants.RNW, $"Error in AsyncStorageModule.getAllKeys: {error}");
                callback.Invoke(error);
            }
            else
            {
                callback.Invoke(null, keys);
            }
        }
        internal ReactInstanceManager(
            string jsBundleFile,
            string jsMainModuleName,
            IReadOnlyList <IReactPackage> packages,
            bool useDeveloperSupport,
            LifecycleState initialLifecycleState,
            UIImplementationProvider uiImplementationProvider,
            Func <IJavaScriptExecutor> javaScriptExecutorFactory,
            Action <Exception> nativeModuleCallExceptionHandler,
            bool lazyViewManagersEnabled)
        {
            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: constructor");

            if (packages == null)
            {
                throw new ArgumentNullException(nameof(packages));
            }
            if (uiImplementationProvider == null)
            {
                throw new ArgumentNullException(nameof(uiImplementationProvider));
            }
            if (javaScriptExecutorFactory == null)
            {
                throw new ArgumentNullException(nameof(javaScriptExecutorFactory));
            }

            _jsBundleFile     = jsBundleFile;
            _jsMainModuleName = jsMainModuleName;
            _packages         = packages;

            _useDeveloperSupport = useDeveloperSupport;
            _devSupportManager   = _useDeveloperSupport
                ? (IDevSupportManager) new DevSupportManager(
                new ReactInstanceDevCommandsHandler(this),
                _jsBundleFile == null,
                _jsMainModuleName)
                : new DisabledDevSupportManager();

            _lifecycleStateMachine            = new LifecycleStateMachine(initialLifecycleState);
            _uiImplementationProvider         = uiImplementationProvider;
            _javaScriptExecutorFactory        = javaScriptExecutorFactory;
            _nativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
            _lazyViewManagersEnabled          = lazyViewManagersEnabled;
        }
        /// <summary>
        /// Used by the native animated module to bypass the process of
        /// updating the values through the shadow view hierarchy. This method
        /// will directly update the native views, which means that updates for
        /// layout-related props won't be handled properly.
        /// </summary>
        /// <param name="tag">The view tag.</param>
        /// <param name="props">The props.</param>
        /// <remarks>
        /// Make sure you know what you're doing before calling this method :)
        /// </remarks>
        public bool SynchronouslyUpdateViewOnDispatcherThread(int tag, JObject props)
        {
            // The native animations module is a single threaded implementation affinitized to the "main" dispatcher thread.
            // As a result all calls of this method are on main dispatcher thread.
            // Yet, for secondary views we have to dispatch to correct dispatcher as fast as possible
            DispatcherHelpers.AssertOnDispatcher();

            UIViewOperationQueueInstance queue = GetQueueByTag(tag, true);

            if (queue == null)
            {
                // Returns false as per the caller's expectation
                return(false);
            }

            if (queue == MainUIViewOperationQueue)
            {
                // Main queue case. Just forward.
                if (!MainUIViewOperationQueue.NativeViewHierarchyManager.ViewExists(tag))
                {
                    return(false);
                }

                MainUIViewOperationQueue.NativeViewHierarchyManager.UpdateProps(tag, props);
            }
            else
            {
                // Dispatch to the correct thread.
                DispatcherHelpers.RunOnDispatcher(queue.Dispatcher, CoreDispatcherPriority.High, () =>
                {
                    if (queue.NativeViewHierarchyManager.ViewExists(tag))
                    {
                        queue.NativeViewHierarchyManager.UpdateProps(tag, props);
                    }
                    else
                    {
                        RnLog.Warn(nameof(UIViewOperationQueue), $"View with tag '{tag}' not found due to race condition");
                    }
                });
            }
            return(true);
        }
        /// <summary>
        /// Recreate the React application and context. This should be called
        /// if configuration has changed or the developer has requested the
        /// application to be reloaded.
        /// </summary>
        /// <param name="token">A token to cancel the request.</param>
        /// <returns>A task to await the result.</returns>
        public async Task <ReactContext> RecreateReactContextAsync(CancellationToken token)
        {
            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: RecreateReactContextAsync - entry");
            DispatcherHelpers.AssertOnDispatcher();
            using (await _lock.LockAsync())
            {
                RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: RecreateReactContextAsync - execute");
                if (_currentReactContext == null)
                {
                    throw new InvalidOperationException(
                              "React context re-creation should only be called after the initial " +
                              "create context background call.");
                }

                await CreateReactContextCoreAsync(token);

                RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: RecreateReactContextAsync - returning {(_currentReactContext == null ? "null" : "valid")} context");
                return(_currentReactContext);
            }
        }
        private JavaScriptValue NativeLoggingHook(
            JavaScriptValue callee,
            bool isConstructCall,
            JavaScriptValue[] arguments,
            ushort argumentCount,
            IntPtr callbackData)
        {
            try
            {
                var message  = arguments[1].ToString();
                var logLevel = (LogLevel)(int)arguments[2].ToDouble();
                RnLog.Info("JS", $"{logLevel} {message}");
            }
            catch
            {
                RnLog.Error("JS", $"Unable to process JavaScript console statement");
            }

            return(JavaScriptValue.Undefined);
        }
        /// <summary>
        /// Trigger the React context initialization asynchronously in a
        /// background task. This enables applications to pre-load the
        /// application JavaScript, and execute global core code before the
        /// <see cref="ReactRootView"/> is available and measure. This should
        /// only be called the first time the application is set up, which is
        /// enforced to keep developers from accidentally creating their
        /// applications multiple times.
        /// </summary>
        /// <param name="token">A token to cancel the request.</param>
        /// <returns>A task to await the result.</returns>
        public async Task <ReactContext> CreateReactContextAsync(CancellationToken token)
        {
            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: CreateReactContextAsync - entry");
            DispatcherHelpers.AssertOnDispatcher();
            using (await _lock.LockAsync())
            {
                RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: CreateReactContextAsync - execute");
                if (_currentReactContext != null)
                {
                    throw new InvalidOperationException(
                              "React context creation should only be called when creating the React " +
                              "application for the first time. When reloading JavaScript, e.g., from " +
                              "a new file, explicitly, use the re-create method.");
                }

                await CreateReactContextCoreAsync(token);

                RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: CreateReactContextAsync - returning {(_currentReactContext == null ? "null" : "valid")} context");
                return(_currentReactContext);
            }
        }
        private async Task AttachMeasuredRootViewToInstanceAsync(
            ReactRootView rootView,
            IReactInstance reactInstance)
        {
            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: AttachMeasuredRootViewToInstanceAsync ({rootView.JavaScriptModuleName}) - entry");

            DispatcherHelpers.AssertOnDispatcher();
            var rootTag = await reactInstance.GetNativeModule <UIManagerModule>()
                          .AddMeasuredRootViewAsync(rootView);

            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: AttachMeasuredRootViewToInstanceAsync ({rootView.JavaScriptModuleName}) - added to UIManager (tag: {rootTag}), starting React app");

            var jsAppModuleName = rootView.JavaScriptModuleName;
            var appParameters   = new Dictionary <string, object>
            {
                { "rootTag", rootTag },
                { "initialProps", rootView.InitialProps }
            };

            reactInstance.GetJavaScriptModule <AppRegistry>().runApplication(jsAppModuleName, appParameters);
            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: AttachMeasuredRootViewToInstanceAsync ({rootView.JavaScriptModuleName}) - done");
        }
示例#29
0
        public void InvokeCallback(int callbackId, JArray arguments)
        {
            if (IsDisposed)
            {
                RnLog.Warn(ReactConstants.RNW, $"Invoking JS callback after bridge has been destroyed.");
                return;
            }

            QueueConfiguration.JavaScriptQueue.Dispatch(() =>
            {
                QueueConfiguration.JavaScriptQueue.AssertOnThread();
                if (IsDisposed)
                {
                    return;
                }

                using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "<callback>").Start())
                {
                    _bridge.InvokeCallback(callbackId, arguments);
                }
            });
        }
        private async Task DetachViewFromInstanceAsync(
            ReactRootView rootView,
            IReactInstance reactInstance)
        {
            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: DetachViewFromInstanceAsync ({rootView.JavaScriptModuleName}) - entry");
            DispatcherHelpers.AssertOnDispatcher();

            // Detaches ReactRootView from instance manager root view list and size change monitoring.
            // This has to complete before unmounting the application.
            // Returns a task to await the completion of the `removeRootView` UIManager call (an effect of
            // unmounting the application) and the release of all dispatcher affined UI objects.
            var rootViewRemovedTask = await reactInstance.GetNativeModule <UIManagerModule>()
                                      .DetachRootViewAsync(rootView);

            reactInstance.GetJavaScriptModule <AppRegistry>().unmountApplicationComponentAtRootTag(rootView.GetTag());

            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: DetachViewFromInstanceAsync ({rootView.JavaScriptModuleName}) - waiting for removeRootView({rootView.GetTag()})");

            await rootViewRemovedTask;

            RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: DetachViewFromInstanceAsync ({rootView.JavaScriptModuleName}) - done");
        }