From cf36d1cf258a78031e3bcef9ae70322c023c009c Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Thu, 16 Nov 2017 12:22:01 -0500 Subject: [PATCH] Enable CodePush for react-native-windows v0.50+ (#1051) In react-native-windows v0.50+, we added ReactNativeHost, which has better support for running React Native in the background as well as embedding React Native in other controls besides XAML Pages. --- docs/setup-windows.md | 8 +- windows/.gitignore | 78 +++++++++++++++++++ windows/.npmignore | 8 ++ .../CodePush.Shared/CodePushNativeModule.cs | 15 +--- .../CodePush.Shared/CodePushReactPackage.cs | 59 +++++++++++++- 5 files changed, 149 insertions(+), 19 deletions(-) create mode 100644 windows/.gitignore create mode 100644 windows/.npmignore diff --git a/docs/setup-windows.md b/docs/setup-windows.md index 515aec7..12052ee 100644 --- a/docs/setup-windows.md +++ b/docs/setup-windows.md @@ -22,14 +22,14 @@ Once you've acquired the CodePush plugin, you need to integrate it into the Visu ### Plugin Configuration (Windows) -After installing the plugin, you need to configure your app to consult CodePush for the location of your JS bundle, since it will "take control" of managing the current and all future versions. To do this, update the `AppReactPage.cs` file to use CodePush via the following changes: +After installing the plugin, you need to configure your app to consult CodePush for the location of your JS bundle, since it will "take control" of managing the current and all future versions. To do this, update the `MainReactNativeHost.cs` file to use CodePush via the following changes: ```c# ... // 1. Import the CodePush namespace using CodePush.ReactNative; ... -class AppReactPage : ReactPage +class MainReactNativeHost : ReactNativeHost { // 2. Declare a private instance variable for the CodePushModule instance. private CodePushReactPackage codePushReactPackage; @@ -38,7 +38,7 @@ class AppReactPage : ReactPage // specifying the right deployment key, then use it to return the bundle URL from // CodePush instead of statically from the binary. If you don't already have your // deployment key, you can run "code-push deployment ls -k" to retrieve it. - public override string JavaScriptBundleFile + protected override string JavaScriptBundleFile { get { @@ -48,7 +48,7 @@ class AppReactPage : ReactPage } // 4. Add the codePushReactPackage instance to the list of existing packages. - public override List Packages + protected override List Packages { get { diff --git a/windows/.gitignore b/windows/.gitignore new file mode 100644 index 0000000..cbf7e7f --- /dev/null +++ b/windows/.gitignore @@ -0,0 +1,78 @@ +*AppPackages* +*BundleArtifacts* +*ReactAssets* + +#OS junk files +[Tt]humbs.db +*.DS_Store + +#Visual Studio files +*.[Oo]bj +*.user +*.aps +*.pch +*.vspscc +*.vssscc +*_i.c +*_p.c +*.ncb +*.suo +*.tlb +*.tlh +*.bak +*.[Cc]ache +*.ilk +*.log +*.lib +*.sbr +*.sdf +*.opensdf +*.opendb +*.unsuccessfulbuild +ipch/ +[Oo]bj/ +[Bb]in +[Dd]ebug*/ +[Rr]elease*/ +Ankh.NoLoad + +#MonoDevelop +*.pidb +*.userprefs + +#Tooling +_ReSharper*/ +*.resharper +[Tt]est[Rr]esult* +*.sass-cache + +#Project files +[Bb]uild/ + +#Subversion files +.svn + +# Office Temp Files +~$* + +# vim Temp Files +*~ + +#NuGet +packages/ +*.nupkg + +#ncrunch +*ncrunch* +*crunch*.local.xml + +# visual studio database projects +*.dbmdl + +#Test files +*.testsettings + +#Other files +*.DotSettings +.vs/ +*project.lock.json diff --git a/windows/.npmignore b/windows/.npmignore new file mode 100644 index 0000000..93c1e27 --- /dev/null +++ b/windows/.npmignore @@ -0,0 +1,8 @@ +# Make sure we don't publish build artifacts to NPM +ARM/ +Debug/ +x64/ +x86/ +bin/ +obj/ +.vs/ diff --git a/windows/CodePush.Shared/CodePushNativeModule.cs b/windows/CodePush.Shared/CodePushNativeModule.cs index e2b0cb7..4d4c25a 100644 --- a/windows/CodePush.Shared/CodePushNativeModule.cs +++ b/windows/CodePush.Shared/CodePushNativeModule.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Reflection; +using System.Threading; using System.Threading.Tasks; #if WINDOWS_UWP using Windows.Web.Http; @@ -312,17 +313,7 @@ namespace CodePush.ReactNative { // #1) Get the private ReactInstanceManager, which is what includes // the logic to reload the current React context. - FieldInfo info = typeof(ReactPage) - .GetField("_reactInstanceManager", BindingFlags.NonPublic | BindingFlags.Instance); -#if WINDOWS_UWP - var reactInstanceManager = (ReactInstanceManager)typeof(ReactPage) - .GetField("_reactInstanceManager", BindingFlags.NonPublic | BindingFlags.Instance) - .GetValue(_codePush.MainPage); -#else - var reactInstanceManager = ((Lazy)typeof(ReactPage) - .GetField("_reactInstanceManager", BindingFlags.NonPublic | BindingFlags.Instance) - .GetValue(_codePush.MainPage)).Value as ReactInstanceManager; -#endif + var reactInstanceManager = _codePush.ReactInstanceManager; // #2) Update the locally stored JS bundle file path Type reactInstanceManagerType = typeof(ReactInstanceManager); @@ -332,7 +323,7 @@ namespace CodePush.ReactNative .SetValue(reactInstanceManager, latestJSBundleFile); // #3) Get the context creation method and fire it on the UI thread (which RN enforces) - Context.RunOnDispatcherQueueThread(reactInstanceManager.RecreateReactContextInBackground); + Context.RunOnDispatcherQueueThread(() => reactInstanceManager.RecreateReactContextAsync(CancellationToken.None)); } } } \ No newline at end of file diff --git a/windows/CodePush.Shared/CodePushReactPackage.cs b/windows/CodePush.Shared/CodePushReactPackage.cs index a14bf96..57ce5fc 100644 --- a/windows/CodePush.Shared/CodePushReactPackage.cs +++ b/windows/CodePush.Shared/CodePushReactPackage.cs @@ -5,6 +5,7 @@ using ReactNative.Modules.Core; using ReactNative.UIManager; using System; using System.Collections.Generic; +using System.Reflection; using System.Threading.Tasks; @@ -20,10 +21,47 @@ namespace CodePush.ReactNative internal bool NeedToReportRollback { get; set; } = false; internal bool DidUpdate { get; private set; } = false; internal bool IsRunningBinaryVersion { get; private set; } = false; +#pragma warning disable CS0618 // Keeping for backward compatibility internal ReactPage MainPage { get; private set; } +#pragma warning restore CS0618 // Keeping for backward compatibility + internal ReactNativeHost Host { get; private set; } internal UpdateManager UpdateManager { get; private set; } + internal ReactInstanceManager ReactInstanceManager + { + get + { + if (Host != null) + { + return Host.ReactInstanceManager; + } + +#if WINDOWS_UWP +#pragma warning disable CS0618 // Keeping for backward compatibility + return (ReactInstanceManager)typeof(ReactPage) +#pragma warning restore CS0618 // Keeping for backward compatibility + .GetField("_reactInstanceManager", BindingFlags.NonPublic | BindingFlags.Instance) + .GetValue(MainPage); +#else + return ((Lazy)typeof(ReactPage) + .GetField("_reactInstanceManager", BindingFlags.NonPublic | BindingFlags.Instance) + .GetValue(MainPage)).Value as ReactInstanceManager; +#endif + } + } + + internal bool UseDeveloperSupport + { + get + { + return Host?.UseDeveloperSupport ?? MainPage.UseDeveloperSupport; + } + } + + +#pragma warning disable CS0618 // Keeping for backward compatibility public CodePushReactPackage(string deploymentKey, ReactPage mainPage) +#pragma warning restore CS0618 // Keeping for backward compatibility { AppVersion = CodePushUtils.GetAppVersion(); DeploymentKey = deploymentKey; @@ -38,7 +76,22 @@ namespace CodePush.ReactNative CurrentInstance = this; } - #region Public methods + public CodePushReactPackage(string deploymentKey, ReactNativeHost host) + { + AppVersion = CodePushUtils.GetAppVersion(); + DeploymentKey = deploymentKey; + Host = host; + UpdateManager = new UpdateManager(); + + if (CurrentInstance != null) + { + CodePushUtils.Log("More than one CodePush instance has been initialized. Please use the instance method codePush.getBundleUrlInternal() to get the correct bundleURL for a particular instance."); + } + + CurrentInstance = this; + } + +#region Public methods public IReadOnlyList CreateJavaScriptModulesConfig() { return new List(); @@ -110,7 +163,7 @@ namespace CodePush.ReactNative { // The binary version is newer. DidUpdate = false; - if (!MainPage.UseDeveloperSupport || !AppVersion.Equals(packageAppVersion)) + if (!UseDeveloperSupport || !AppVersion.Equals(packageAppVersion)) { await ClearUpdatesAsync().ConfigureAwait(false); } @@ -147,7 +200,7 @@ namespace CodePush.ReactNative { DidUpdate = true; // Clear the React dev bundle cache so that new updates can be loaded. - if (MainPage.UseDeveloperSupport) + if (UseDeveloperSupport) { FileUtils.ClearReactDevBundleCacheAsync().Wait(); }