From be96f07edad4d0bf561de1baab9913462406aef5 Mon Sep 17 00:00:00 2001 From: Alexander Bodalevsky Date: Tue, 14 Feb 2017 02:23:20 +0200 Subject: [PATCH] Added React Native Windows dotNet46 support (#684) Added support react-native-windows dotNet Added example for react-native-windows UWP based Added example for react-native-windows dotNet based Project structure: CodePush.Shared - shared code between UWP and dotNet CodePush - UWP specific code CodePush.Net46 - dotNet specific code For UWP solution it needs to be added the following projects: CodePush.Shared CodePush For dotNet solution it needs to be added the following projects: CodePush.Shared CodePush.Net46 Examples: Examples\CodePushDemoApp\windows\CodePushDemoApp.sln the solution contains both examples (UWP and dotNet). Notes Example for ARM configuration has not been tested. Since there is no changes in UWP part of implementation, there is low risk of failure. In this implementation we tried to reuse UWP library as much as possible. The following issues are relevant for both platforms: ZipFile.ExtractToDirectory is not reliable and throws exception if: folder exists already path is too long (> 250 chars) Un-zipping is quite long operation. Does it make sense for async? await UpdateUtils.UnzipBundleAsync(downloadFile.Path, unzippedFolder.Path); --- .gitignore | 38 ++- .npmignore | 42 +++ Examples/CodePushDemoApp/NuGet.Config | 7 + Examples/CodePushDemoApp/index.windows.js | 1 + Examples/CodePushDemoApp/package.json | 3 +- Examples/CodePushDemoApp/windows/.gitignore | 89 +++++ .../windows/CodePushDemoApp.Wpf/App.config | 6 + .../windows/CodePushDemoApp.Wpf/App.xaml | 5 + .../windows/CodePushDemoApp.Wpf/App.xaml.cs | 107 ++++++ .../CodePushDemoApp.Wpf/AppReactPage.cs | 60 ++++ .../CodePushDemoApp.Wpf.csproj | 184 ++++++++++ .../Properties/AssemblyInfo.cs | 55 +++ .../Properties/Resources.Designer.cs | 63 ++++ .../Properties/Resources.resx | 117 +++++++ .../Properties/Settings.Designer.cs | 26 ++ .../Properties/Settings.settings | 7 + .../CodePushDemoApp.Wpf/packages.config | 5 + .../windows/CodePushDemoApp.sln | 245 ++++++++++++++ .../windows/CodePushDemoApp/App.xaml | 8 + .../windows/CodePushDemoApp/App.xaml.cs | 147 ++++++++ .../Assets/LockScreenLogo.scale-200.png | Bin 0 -> 1430 bytes .../Assets/SplashScreen.scale-200.png | Bin 0 -> 7700 bytes .../Assets/Square150x150Logo.scale-200.png | Bin 0 -> 2937 bytes .../Assets/Square44x44Logo.scale-200.png | Bin 0 -> 1647 bytes ...x44Logo.targetsize-24_altform-unplated.png | Bin 0 -> 1255 bytes .../CodePushDemoApp/Assets/StoreLogo.png | Bin 0 -> 1451 bytes .../Assets/Wide310x150Logo.scale-200.png | Bin 0 -> 3204 bytes .../CodePushDemoApp/CodePushDemoApp.csproj | 230 +++++++++++++ .../CodePushDemoApp.nuget.targets | 9 + .../CodePushDemoApp_TemporaryKey.pfx | Bin 0 -> 2454 bytes .../windows/CodePushDemoApp/MainPage.cs | 62 ++++ .../CodePushDemoApp/Package.appxmanifest | 49 +++ .../Properties/AssemblyInfo.cs | 29 ++ .../CodePushDemoApp/Properties/Default.rd.xml | 31 ++ .../windows/CodePushDemoApp/project.json | 17 + Examples/CodePushDemoApp/windows/nuget.config | 6 + package.json | 6 +- .../ApplicationDataContainerTest.cs | 105 ++++++ .../CodePush.Net46.Test.csproj | 125 +++++++ .../Properties/AssemblyInfo.cs | 36 ++ windows/{ => CodePush.Net46}/.gitignore | 0 .../Adapters/Http/HttpProgress.cs | 28 ++ .../Storage/ApplicationDataContainer.cs | 103 ++++++ windows/CodePush.Net46/CodePush.Net46.csproj | 104 ++++++ windows/CodePush.Net46/CodePushUtils.cs | 53 +++ windows/CodePush.Net46/FileUtils.cs | 55 +++ .../CodePush.Net46/Properties/AssemblyInfo.cs | 36 ++ windows/CodePush.Net46/UpdateManager.cs | 313 ++++++++++++++++++ windows/CodePush.Net46/UpdateUtils.cs | 70 ++++ windows/CodePush.Net46/packages.config | 5 + .../CodePush.Shared/CodePush.Shared.projitems | 21 ++ .../CodePush.Shared/CodePush.Shared.shproj | 13 + .../CodePushConstants.cs | 8 +- .../CodePushNativeModule.cs | 17 +- .../CodePushReactPackage.cs | 47 +-- windows/CodePush.Shared/CodePushUtils.cs | 74 +++++ windows/{ => CodePush.Shared}/InstallMode.cs | 0 .../MinimumBackgroundListener.cs | 0 .../{ => CodePush.Shared}/SettingsManager.cs | 18 +- windows/{ => CodePush.Shared}/UpdateState.cs | 0 windows/{.npmignore => CodePush/.gitignore} | 0 windows/{ => CodePush}/CodePush.csproj | 27 +- windows/{ => CodePush}/CodePushUtils.cs | 15 +- windows/{ => CodePush}/FileUtils.cs | 17 + .../{ => CodePush}/Properties/AssemblyInfo.cs | 0 .../{ => CodePush}/Properties/CodePush.rd.xml | 0 windows/{ => CodePush}/UpdateManager.cs | 9 +- windows/{ => CodePush}/UpdateUtils.cs | 0 windows/{ => CodePush}/project.json | 0 69 files changed, 2866 insertions(+), 87 deletions(-) create mode 100644 Examples/CodePushDemoApp/NuGet.Config create mode 100644 Examples/CodePushDemoApp/index.windows.js create mode 100644 Examples/CodePushDemoApp/windows/.gitignore create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.config create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.xaml create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.xaml.cs create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/AppReactPage.cs create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/CodePushDemoApp.Wpf.csproj create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/AssemblyInfo.cs create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Resources.Designer.cs create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Resources.resx create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Settings.Designer.cs create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Settings.settings create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/packages.config create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp.sln create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/App.xaml create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/App.xaml.cs create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/LockScreenLogo.scale-200.png create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/SplashScreen.scale-200.png create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Square150x150Logo.scale-200.png create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Square44x44Logo.scale-200.png create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/StoreLogo.png create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Wide310x150Logo.scale-200.png create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/CodePushDemoApp.csproj create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/CodePushDemoApp.nuget.targets create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/CodePushDemoApp_TemporaryKey.pfx create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/MainPage.cs create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/Package.appxmanifest create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/Properties/AssemblyInfo.cs create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/Properties/Default.rd.xml create mode 100644 Examples/CodePushDemoApp/windows/CodePushDemoApp/project.json create mode 100644 Examples/CodePushDemoApp/windows/nuget.config create mode 100644 windows/CodePush.Net46.Test/ApplicationDataContainerTest.cs create mode 100644 windows/CodePush.Net46.Test/CodePush.Net46.Test.csproj create mode 100644 windows/CodePush.Net46.Test/Properties/AssemblyInfo.cs rename windows/{ => CodePush.Net46}/.gitignore (100%) create mode 100644 windows/CodePush.Net46/Adapters/Http/HttpProgress.cs create mode 100644 windows/CodePush.Net46/Adapters/Storage/ApplicationDataContainer.cs create mode 100644 windows/CodePush.Net46/CodePush.Net46.csproj create mode 100644 windows/CodePush.Net46/CodePushUtils.cs create mode 100644 windows/CodePush.Net46/FileUtils.cs create mode 100644 windows/CodePush.Net46/Properties/AssemblyInfo.cs create mode 100644 windows/CodePush.Net46/UpdateManager.cs create mode 100644 windows/CodePush.Net46/UpdateUtils.cs create mode 100644 windows/CodePush.Net46/packages.config create mode 100644 windows/CodePush.Shared/CodePush.Shared.projitems create mode 100644 windows/CodePush.Shared/CodePush.Shared.shproj rename windows/{ => CodePush.Shared}/CodePushConstants.cs (95%) rename windows/{ => CodePush.Shared}/CodePushNativeModule.cs (95%) rename windows/{ => CodePush.Shared}/CodePushReactPackage.cs (77%) create mode 100644 windows/CodePush.Shared/CodePushUtils.cs rename windows/{ => CodePush.Shared}/InstallMode.cs (100%) rename windows/{ => CodePush.Shared}/MinimumBackgroundListener.cs (100%) rename windows/{ => CodePush.Shared}/SettingsManager.cs (86%) rename windows/{ => CodePush.Shared}/UpdateState.cs (100%) rename windows/{.npmignore => CodePush/.gitignore} (100%) rename windows/{ => CodePush}/CodePush.csproj (82%) rename windows/{ => CodePush}/CodePushUtils.cs (72%) rename windows/{ => CodePush}/FileUtils.cs (52%) rename windows/{ => CodePush}/Properties/AssemblyInfo.cs (100%) rename windows/{ => CodePush}/Properties/CodePush.rd.xml (100%) rename windows/{ => CodePush}/UpdateManager.cs (97%) rename windows/{ => CodePush}/UpdateUtils.cs (100%) rename windows/{ => CodePush}/project.json (100%) diff --git a/.gitignore b/.gitignore index 4048ad83a..f43ff3530 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +# gitignore contributors: remember to update .npmignore + # OSX # .DS_Store @@ -152,4 +154,38 @@ captures/ code-push-plugin-testing-framework/node_modules # RN New Version App Generation -Examples/testapp_rn \ No newline at end of file +Examples/testapp_rn + +# Windows +windows/.vs/ +windows/obj/ + +#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 \ No newline at end of file diff --git a/.npmignore b/.npmignore index 83a811d0e..a9578543e 100644 --- a/.npmignore +++ b/.npmignore @@ -43,3 +43,45 @@ android/local.properties android/.gradle android/**/*.iml android/.idea + + +# Windows +windows/.vs/ +windows/obj/ + +#Tests +windows/CodePush.Net46.Test + +#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 + +#NuGet +packages/ +*.nupkg diff --git a/Examples/CodePushDemoApp/NuGet.Config b/Examples/CodePushDemoApp/NuGet.Config new file mode 100644 index 000000000..73ee8d8c7 --- /dev/null +++ b/Examples/CodePushDemoApp/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Examples/CodePushDemoApp/index.windows.js b/Examples/CodePushDemoApp/index.windows.js new file mode 100644 index 000000000..8f8f835ee --- /dev/null +++ b/Examples/CodePushDemoApp/index.windows.js @@ -0,0 +1 @@ +require("./demo"); \ No newline at end of file diff --git a/Examples/CodePushDemoApp/package.json b/Examples/CodePushDemoApp/package.json index 8ab24cd6f..7532acab9 100644 --- a/Examples/CodePushDemoApp/package.json +++ b/Examples/CodePushDemoApp/package.json @@ -9,6 +9,7 @@ "babel-preset-react-native-stage-0": "1.0.1", "react": "15.4.0", "react-native": "0.40.0", - "react-native-code-push": "file:../../" + "react-native-code-push": "file:../../", + "react-native-windows": "0.40.0-rc.1" } } diff --git a/Examples/CodePushDemoApp/windows/.gitignore b/Examples/CodePushDemoApp/windows/.gitignore new file mode 100644 index 000000000..33d3fde2b --- /dev/null +++ b/Examples/CodePushDemoApp/windows/.gitignore @@ -0,0 +1,89 @@ +*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 + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +#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/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.config b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.config new file mode 100644 index 000000000..2d2a12d81 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.xaml b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.xaml new file mode 100644 index 000000000..07709dd55 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.xaml @@ -0,0 +1,5 @@ + + + diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.xaml.cs b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.xaml.cs new file mode 100644 index 000000000..8c5c4e489 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/App.xaml.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Navigation; + +namespace CodePushDemoApp.Wpf +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + private readonly AppReactPage _reactPage = new AppReactPage(); + + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + } + + /// + /// Override method fired prior to the Startup event when the Run method of the Application object is called... + /// + /// + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + OnCreate(e.Args); + } + + /// + /// Called whenever the app is opened to initialized... + /// + /// + private void OnCreate(string[] arguments) + { + var shellWindow = Application.Current.MainWindow; + + if (shellWindow == null) + { + shellWindow = new Window + { + ShowActivated = true, + ShowInTaskbar = true, + Title = "CodePushDemoApp.WPF", + Height = 768, + Width = 1024, + WindowStartupLocation = WindowStartupLocation.CenterScreen + }; + + Application.Current.MainWindow = shellWindow; + } + + //Show Window if it is not already active... + if (!shellWindow.IsLoaded) + { + shellWindow.Show(); + } + + var rootFrame = shellWindow.Content as Frame; + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == null) + { + _reactPage.OnCreate(arguments); + + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); + + rootFrame.NavigationFailed += OnNavigationFailed; + + // Place the frame in the current Window + shellWindow.Content = rootFrame; + } + + if (rootFrame.Content == null) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame.Content = _reactPage; + } + + // Ensure the current window is active + shellWindow.Activate(); + } + + /// + /// Invoked when Navigation to a certain page fails + /// + /// The Frame which failed navigation + /// Details about the navigation failure + private void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception("Failed to load Page..."); + } + } +} + diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/AppReactPage.cs b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/AppReactPage.cs new file mode 100644 index 000000000..4fea5bcb3 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/AppReactPage.cs @@ -0,0 +1,60 @@ +using CodePush.ReactNative; +using ReactNative; +using ReactNative.Modules.Core; +using ReactNative.Shell; +using System; +using System.Collections.Generic; + +namespace CodePushDemoApp.Wpf +{ + internal class AppReactPage : ReactPage + { + public override string MainComponentName + { + get + { + return "CodePushDemoApp"; + } + } + + private CodePushReactPackage codePushReactPackage = null; + public override string JavaScriptBundleFile + { + get + { + codePushReactPackage = new CodePushReactPackage("deployment-key-here", this); + +#if BUNDLE + return codePushReactPackage.GetJavaScriptBundleFile(); +#else + return null; +#endif + } + } + + + public override List Packages + { + get + { + return new List + { + new MainReactPackage(), + codePushReactPackage + }; + } + } + + public override bool UseDeveloperSupport + { + get + { +#if !BUNDLE || DEBUG + return true; +#else + return false; +#endif + } + } + } +} diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/CodePushDemoApp.Wpf.csproj b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/CodePushDemoApp.Wpf.csproj new file mode 100644 index 000000000..23dcba70c --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/CodePushDemoApp.Wpf.csproj @@ -0,0 +1,184 @@ + + + + + + Debug + AnyCPU + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA} + WinExe + Properties + CodePushDemoApp.Wpf + CodePushDemoApp.Wpf + v4.6 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + + + + true + bin\x86\Debug\ + TRACE;DEBUG + full + x86 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + true + + + true + bin\x86\DebugBundle\ + TRACE;DEBUG;BUNDLE + full + x86 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x86\ReleaseBundle\ + TRACE;BUNDLE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + true + + + true + bin\x64\Debug\ + TRACE;DEBUG + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + true + bin\x64\DebugBundle\ + TRACE;DEBUG;BUNDLE + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\ReleaseBundle\ + TRACE;BUNDLE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + + False + ..\packages\Facebook.Yoga.1.0.1-pre\lib\netstandard\Facebook.Yoga.dll + True + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + {4dfe3f9f-5e15-4f17-8fd4-33ff0519348e} + CodePush.Net46 + + + {22cbff9c-fe36-43e8-a246-266c7635e662} + ReactNative.Net46 + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + \ No newline at end of file diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/AssemblyInfo.cs b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..1df7e6d7f --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CodePushDemoApp.Wpf")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CodePushDemoApp.Wpf")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Resources.Designer.cs b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Resources.Designer.cs new file mode 100644 index 000000000..abab04ec8 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace CodePushDemoApp.Wpf.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CodePushDemoApp.Wpf.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Resources.resx b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Settings.Designer.cs b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Settings.Designer.cs new file mode 100644 index 000000000..553c4b3a6 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace CodePushDemoApp.Wpf.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Settings.settings b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/packages.config b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/packages.config new file mode 100644 index 000000000..683c93820 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.Wpf/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp.sln b/Examples/CodePushDemoApp/windows/CodePushDemoApp.sln new file mode 100644 index 000000000..9f2ebd919 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp.sln @@ -0,0 +1,245 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodePushDemoApp", "CodePushDemoApp\CodePushDemoApp.csproj", "{3E8198A5-7E41-43F1-880E-E7E2840E5A59}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactNative", "..\node_modules\react-native-windows\ReactWindows\ReactNative\ReactNative.csproj", "{C7673AD5-E3AA-468C-A5FD-FA38154E205C}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ReactNative.Shared", "..\node_modules\react-native-windows\ReactWindows\ReactNative.Shared\ReactNative.Shared.shproj", "{EEA8B852-4D07-48E1-8294-A21AB5909FE5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ChakraBridge", "..\node_modules\react-native-windows\ReactWindows\ChakraBridge\ChakraBridge.vcxproj", "{4B72C796-16D5-4E3A-81C0-3E36F531E578}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodePush", "..\..\..\windows\CodePush\CodePush.csproj", "{446A85D9-55EB-4C7D-8B9D-448306C833D6}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "CodePush.Shared", "..\..\..\windows\CodePush.Shared\CodePush.Shared.shproj", "{4AD4C826-CC26-4F1D-B60D-B97B22F52E90}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactNative.Net46", "..\node_modules\react-native-windows\ReactWindows\ReactNative.Net46\ReactNative.Net46.csproj", "{22CBFF9C-FE36-43E8-A246-266C7635E662}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodePush.Net46", "..\..\..\windows\CodePush.Net46\CodePush.Net46.csproj", "{4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodePushDemoApp.Wpf", "CodePushDemoApp.Wpf\CodePushDemoApp.Wpf.csproj", "{96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodePush.Net46.Test", "..\..\..\windows\CodePush.Net46.Test\CodePush.Net46.Test.csproj", "{BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}" +EndProject +Global + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\node_modules\react-native-windows\ReactWindows\ReactNative.Shared\ReactNative.Shared.projitems*{22cbff9c-fe36-43e8-a246-266c7635e662}*SharedItemsImports = 4 + ..\..\..\windows\CodePush.Shared\CodePush.Shared.projitems*{446a85d9-55eb-4c7d-8b9d-448306c833d6}*SharedItemsImports = 4 + ..\..\..\windows\CodePush.Shared\CodePush.Shared.projitems*{4ad4c826-cc26-4f1d-b60d-b97b22f52e90}*SharedItemsImports = 13 + ..\..\..\windows\CodePush.Shared\CodePush.Shared.projitems*{4dfe3f9f-5e15-4f17-8fd4-33ff0519348e}*SharedItemsImports = 4 + ..\node_modules\react-native-windows\ReactWindows\ReactNative.Shared\ReactNative.Shared.projitems*{c7673ad5-e3aa-468c-a5fd-fa38154e205c}*SharedItemsImports = 4 + ..\node_modules\react-native-windows\ReactWindows\ReactNative.Shared\ReactNative.Shared.projitems*{eea8b852-4d07-48e1-8294-a21ab5909fe5}*SharedItemsImports = 13 + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + DebugBundle|ARM = DebugBundle|ARM + DebugBundle|x64 = DebugBundle|x64 + DebugBundle|x86 = DebugBundle|x86 + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + ReleaseBundle|ARM = ReleaseBundle|ARM + ReleaseBundle|x64 = ReleaseBundle|x64 + ReleaseBundle|x86 = ReleaseBundle|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Debug|ARM.ActiveCfg = Debug|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Debug|ARM.Build.0 = Debug|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Debug|ARM.Deploy.0 = Debug|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Debug|x64.ActiveCfg = Debug|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Debug|x64.Build.0 = Debug|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Debug|x64.Deploy.0 = Debug|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Debug|x86.ActiveCfg = Debug|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Debug|x86.Build.0 = Debug|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Debug|x86.Deploy.0 = Debug|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.DebugBundle|ARM.ActiveCfg = DebugBundle|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.DebugBundle|ARM.Build.0 = DebugBundle|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.DebugBundle|ARM.Deploy.0 = DebugBundle|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.DebugBundle|x64.ActiveCfg = DebugBundle|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.DebugBundle|x64.Build.0 = DebugBundle|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.DebugBundle|x64.Deploy.0 = DebugBundle|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.DebugBundle|x86.ActiveCfg = DebugBundle|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.DebugBundle|x86.Build.0 = DebugBundle|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.DebugBundle|x86.Deploy.0 = DebugBundle|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Release|ARM.ActiveCfg = Release|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Release|ARM.Build.0 = Release|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Release|ARM.Deploy.0 = Release|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Release|x64.ActiveCfg = Release|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Release|x64.Build.0 = Release|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Release|x64.Deploy.0 = Release|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Release|x86.ActiveCfg = Release|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Release|x86.Build.0 = Release|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.Release|x86.Deploy.0 = Release|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.ReleaseBundle|ARM.ActiveCfg = ReleaseBundle|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.ReleaseBundle|ARM.Build.0 = ReleaseBundle|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.ReleaseBundle|ARM.Deploy.0 = ReleaseBundle|ARM + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.ReleaseBundle|x64.ActiveCfg = ReleaseBundle|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.ReleaseBundle|x64.Build.0 = ReleaseBundle|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.ReleaseBundle|x64.Deploy.0 = ReleaseBundle|x64 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.ReleaseBundle|x86.ActiveCfg = ReleaseBundle|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.ReleaseBundle|x86.Build.0 = ReleaseBundle|x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59}.ReleaseBundle|x86.Deploy.0 = ReleaseBundle|x86 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|ARM.ActiveCfg = Debug|ARM + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|ARM.Build.0 = Debug|ARM + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x64.ActiveCfg = Debug|x64 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x64.Build.0 = Debug|x64 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x86.ActiveCfg = Debug|x86 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x86.Build.0 = Debug|x86 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|ARM.ActiveCfg = Debug|ARM + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|ARM.Build.0 = Debug|ARM + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|x64.ActiveCfg = Debug|x64 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|x64.Build.0 = Debug|x64 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|x86.ActiveCfg = Debug|x86 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|x86.Build.0 = Debug|x86 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|ARM.ActiveCfg = Release|ARM + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|ARM.Build.0 = Release|ARM + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x64.ActiveCfg = Release|x64 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x64.Build.0 = Release|x64 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x86.ActiveCfg = Release|x86 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x86.Build.0 = Release|x86 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|ARM.ActiveCfg = Release|ARM + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|ARM.Build.0 = Release|ARM + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|x64.ActiveCfg = Release|x64 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|x64.Build.0 = Release|x64 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|x86.ActiveCfg = Release|x86 + {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|x86.Build.0 = Release|x86 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|ARM.ActiveCfg = Debug|ARM + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|ARM.Build.0 = Debug|ARM + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x64.ActiveCfg = Debug|x64 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x64.Build.0 = Debug|x64 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x86.ActiveCfg = Debug|Win32 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x86.Build.0 = Debug|Win32 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|ARM.ActiveCfg = Debug|ARM + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|ARM.Build.0 = Debug|ARM + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|x64.ActiveCfg = Debug|x64 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|x64.Build.0 = Debug|x64 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|x86.ActiveCfg = Debug|Win32 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|x86.Build.0 = Debug|Win32 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|ARM.ActiveCfg = Release|ARM + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|ARM.Build.0 = Release|ARM + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x64.ActiveCfg = Release|x64 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x64.Build.0 = Release|x64 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x86.ActiveCfg = Release|Win32 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x86.Build.0 = Release|Win32 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|ARM.ActiveCfg = Release|ARM + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|ARM.Build.0 = Release|ARM + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|x64.ActiveCfg = Release|x64 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|x64.Build.0 = Release|x64 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|x86.ActiveCfg = Release|Win32 + {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|x86.Build.0 = Release|Win32 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Debug|ARM.ActiveCfg = Debug|ARM + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Debug|ARM.Build.0 = Debug|ARM + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Debug|x64.ActiveCfg = Debug|x64 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Debug|x64.Build.0 = Debug|x64 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Debug|x86.ActiveCfg = Debug|x86 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Debug|x86.Build.0 = Debug|x86 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.DebugBundle|ARM.ActiveCfg = Debug|ARM + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.DebugBundle|ARM.Build.0 = Debug|ARM + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.DebugBundle|x64.ActiveCfg = Debug|x64 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.DebugBundle|x64.Build.0 = Debug|x64 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.DebugBundle|x86.ActiveCfg = Debug|x86 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.DebugBundle|x86.Build.0 = Debug|x86 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Release|ARM.ActiveCfg = Release|ARM + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Release|ARM.Build.0 = Release|ARM + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Release|x64.ActiveCfg = Release|x64 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Release|x64.Build.0 = Release|x64 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Release|x86.ActiveCfg = Release|x86 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.Release|x86.Build.0 = Release|x86 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.ReleaseBundle|ARM.ActiveCfg = Release|ARM + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.ReleaseBundle|ARM.Build.0 = Release|ARM + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.ReleaseBundle|x64.ActiveCfg = Release|x64 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.ReleaseBundle|x64.Build.0 = Release|x64 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.ReleaseBundle|x86.ActiveCfg = Release|x86 + {446A85D9-55EB-4C7D-8B9D-448306C833D6}.ReleaseBundle|x86.Build.0 = Release|x86 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Debug|ARM.ActiveCfg = Debug|ARM + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Debug|ARM.Build.0 = Debug|ARM + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Debug|x64.ActiveCfg = Debug|x64 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Debug|x64.Build.0 = Debug|x64 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Debug|x86.ActiveCfg = Debug|x86 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Debug|x86.Build.0 = Debug|x86 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.DebugBundle|ARM.ActiveCfg = Debug|ARM + {22CBFF9C-FE36-43E8-A246-266C7635E662}.DebugBundle|ARM.Build.0 = Debug|ARM + {22CBFF9C-FE36-43E8-A246-266C7635E662}.DebugBundle|x64.ActiveCfg = Debug|x64 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.DebugBundle|x64.Build.0 = Debug|x64 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.DebugBundle|x86.ActiveCfg = Debug|x86 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.DebugBundle|x86.Build.0 = Debug|x86 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Release|ARM.ActiveCfg = Release|ARM + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Release|ARM.Build.0 = Release|ARM + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Release|x64.ActiveCfg = Release|x64 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Release|x64.Build.0 = Release|x64 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Release|x86.ActiveCfg = Release|x86 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.Release|x86.Build.0 = Release|x86 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.ReleaseBundle|ARM.ActiveCfg = Release|ARM + {22CBFF9C-FE36-43E8-A246-266C7635E662}.ReleaseBundle|ARM.Build.0 = Release|ARM + {22CBFF9C-FE36-43E8-A246-266C7635E662}.ReleaseBundle|x64.ActiveCfg = Release|x64 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.ReleaseBundle|x64.Build.0 = Release|x64 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.ReleaseBundle|x86.ActiveCfg = Release|x86 + {22CBFF9C-FE36-43E8-A246-266C7635E662}.ReleaseBundle|x86.Build.0 = Release|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.Debug|ARM.ActiveCfg = Debug|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.Debug|x64.ActiveCfg = Debug|x64 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.Debug|x64.Build.0 = Debug|x64 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.Debug|x86.ActiveCfg = Debug|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.Debug|x86.Build.0 = Debug|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.DebugBundle|ARM.ActiveCfg = Debug|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.DebugBundle|x64.ActiveCfg = Debug|x64 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.DebugBundle|x64.Build.0 = Debug|x64 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.DebugBundle|x86.ActiveCfg = Debug|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.DebugBundle|x86.Build.0 = Debug|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.Release|ARM.ActiveCfg = Release|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.Release|x64.ActiveCfg = Release|x64 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.Release|x64.Build.0 = Release|x64 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.Release|x86.ActiveCfg = Release|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.Release|x86.Build.0 = Release|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.ReleaseBundle|ARM.ActiveCfg = Release|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.ReleaseBundle|x64.ActiveCfg = Release|x64 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.ReleaseBundle|x64.Build.0 = Release|x64 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.ReleaseBundle|x86.ActiveCfg = Release|x86 + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}.ReleaseBundle|x86.Build.0 = Release|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.Debug|ARM.ActiveCfg = Debug|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.Debug|x64.ActiveCfg = Debug|x64 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.Debug|x64.Build.0 = Debug|x64 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.Debug|x86.ActiveCfg = Debug|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.Debug|x86.Build.0 = Debug|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.DebugBundle|ARM.ActiveCfg = Debug|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.DebugBundle|x64.ActiveCfg = DebugBundle|x64 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.DebugBundle|x64.Build.0 = DebugBundle|x64 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.DebugBundle|x86.ActiveCfg = DebugBundle|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.DebugBundle|x86.Build.0 = DebugBundle|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.Release|ARM.ActiveCfg = Release|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.Release|x64.ActiveCfg = Release|x64 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.Release|x64.Build.0 = Release|x64 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.Release|x86.ActiveCfg = Release|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.Release|x86.Build.0 = Release|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.ReleaseBundle|ARM.ActiveCfg = Release|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.ReleaseBundle|x64.ActiveCfg = ReleaseBundle|x64 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.ReleaseBundle|x64.Build.0 = ReleaseBundle|x64 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.ReleaseBundle|x86.ActiveCfg = ReleaseBundle|x86 + {96E3B61A-F3CA-4297-97FA-5D45C2DBC2BA}.ReleaseBundle|x86.Build.0 = ReleaseBundle|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.Debug|ARM.ActiveCfg = Debug|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.Debug|x64.ActiveCfg = Debug|x64 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.Debug|x64.Build.0 = Debug|x64 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.Debug|x86.ActiveCfg = Debug|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.Debug|x86.Build.0 = Debug|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.DebugBundle|ARM.ActiveCfg = Debug|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.DebugBundle|x64.ActiveCfg = Debug|x64 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.DebugBundle|x64.Build.0 = Debug|x64 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.DebugBundle|x86.ActiveCfg = Debug|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.DebugBundle|x86.Build.0 = Debug|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.Release|ARM.ActiveCfg = Release|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.Release|x64.ActiveCfg = Release|x64 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.Release|x64.Build.0 = Release|x64 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.Release|x86.ActiveCfg = Release|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.Release|x86.Build.0 = Release|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.ReleaseBundle|ARM.ActiveCfg = Release|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.ReleaseBundle|x64.ActiveCfg = Release|x64 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.ReleaseBundle|x64.Build.0 = Release|x64 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.ReleaseBundle|x86.ActiveCfg = Release|x86 + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}.ReleaseBundle|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/App.xaml b/Examples/CodePushDemoApp/windows/CodePushDemoApp/App.xaml new file mode 100644 index 000000000..e47bd984e --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp/App.xaml @@ -0,0 +1,8 @@ + + + diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/App.xaml.cs b/Examples/CodePushDemoApp/windows/CodePushDemoApp/App.xaml.cs new file mode 100644 index 000000000..5f024f3b0 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp/App.xaml.cs @@ -0,0 +1,147 @@ +using ReactNative; +using ReactNative.Modules.Launch; +using System; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Activation; +using Windows.UI.Core; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace CodePushDemoApp +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + sealed partial class App : Application + { + private readonly ReactPage _reactPage; + + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + this.InitializeComponent(); + this.Suspending += OnSuspending; + this.Resuming += OnResuming; + + _reactPage = new MainPage(); + } + + /// + /// Invoked when the application is launched normally by the end user. Other entry points + /// will be used such as when the application is launched to open a specific file. + /// + /// Details about the launch request and process. + protected override void OnLaunched(LaunchActivatedEventArgs e) + { + base.OnLaunched(e); + OnCreate(e.Arguments); + } + + /// + /// Invoked when the application is activated. + /// + /// The activated event arguments. + protected override void OnActivated(IActivatedEventArgs args) + { + base.OnActivated(args); + + switch (args.Kind) + { + case ActivationKind.Protocol: + case ActivationKind.ProtocolForResults: + var protocolArgs = (IProtocolActivatedEventArgs)args; + LauncherModule.SetActivatedUrl(protocolArgs.Uri.AbsoluteUri); + break; + } + + if (args.PreviousExecutionState != ApplicationExecutionState.Running && + args.PreviousExecutionState != ApplicationExecutionState.Suspended) + { + OnCreate(null); + } + } + + /// + /// Called whenever the app is opened to initia + /// + /// + private void OnCreate(string arguments) + { + _reactPage.OnResume(Exit); + +#if DEBUG + if (System.Diagnostics.Debugger.IsAttached) + { + this.DebugSettings.EnableFrameRateCounter = true; + } + + SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = + AppViewBackButtonVisibility.Visible; +#endif + + Frame rootFrame = Window.Current.Content as Frame; + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == null) + { + _reactPage.OnCreate(arguments); + + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); + + rootFrame.NavigationFailed += OnNavigationFailed; + + // Place the frame in the current Window + Window.Current.Content = rootFrame; + } + + if (rootFrame.Content == null) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame.Content = _reactPage; + } + + // Ensure the current window is active + Window.Current.Activate(); + } + + /// + /// Invoked when Navigation to a certain page fails + /// + /// The Frame which failed navigation + /// Details about the navigation failure + private void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); + } + + /// + /// Invoked when application execution is being suspended. Application state is saved + /// without knowing whether the application will be terminated or resumed with the contents + /// of memory still intact. + /// + /// The source of the suspend request. + /// Details about the suspend request. + private void OnSuspending(object sender, SuspendingEventArgs e) + { + _reactPage.OnSuspend(); + } + + /// + /// Invoked when application execution is being resumed. + /// + /// The source of the resume request. + /// Details about the resume request. + private void OnResuming(object sender, object e) + { + _reactPage.OnResume(Exit); + } + } +} diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/LockScreenLogo.scale-200.png b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/LockScreenLogo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..735f57adb5dfc01886d137b4e493d7e97cf13af3 GIT binary patch literal 1430 zcmaJ>TTC2P7~aKltDttVHYH6u8Io4i*}3fO&d$gd*bA_<3j~&e7%8(eXJLfhS!M@! zKrliY>>6yT4+Kr95$!DoD(Qn-5TP|{V_KS`k~E6(LGS@#`v$hQo&^^BKsw3HIsZBT z_y6C2n`lK@apunKojRQ^(_P}Mgewt$(^BBKCTZ;*xa?J3wQ7~@S0lUvbcLeq1Bg4o zH-bvQi|wt~L7q$~a-gDFP!{&TQfc3fX*6=uHv* zT&1&U(-)L%Xp^djI2?~eBF2cxC@YOP$+9d?P&h?lPy-9M2UT9fg5jKm1t$m#iWE{M zIf%q9@;fyT?0UP>tcw-bLkz;s2LlKl2qeP0w zECS7Ate+Awk|KQ+DOk;fl}Xsy4o^CY=pwq%QAAKKl628_yNPsK>?A>%D8fQG6IgdJ ztnxttBz#NI_a@fk7SU`WtrpsfZsNs9^0(2a z@C3#YO3>k~w7?2hipBf{#b6`}Xw1hlG$yi?;1dDs7k~xDAw@jiI*+tc;t2Lflg&bM)0!Y;0_@=w%`LW^8DsYpS#-bLOklX9r?Ei}TScw|4DbpW%+7 zFgAI)f51s}{y-eWb|vrU-Ya!GuYKP)J7z#*V_k^Xo>4!1Yqj*m)x&0L^tg3GJbVAJ zJ-Pl$R=NAabouV=^z_t;^K*0AvFs!vYU>_<|I^#c?>>CR<(T?=%{;U=aI*SbZADLH z&(f2wz_Y0??Tf|g;?|1Znw6}6U43Q#qNRwv1vp9uFn1)V#*4p&%$mP9x&15^OaBiDS(XppT|z^>;B{PLVEbS3IFYV yGvCsSX*m literal 0 HcmV?d00001 diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/SplashScreen.scale-200.png b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/SplashScreen.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..023e7f1feda78d5100569825acedfd213a0d84e9 GIT binary patch literal 7700 zcmeHLYj~4Yw%(;oxoEH#Kxq-eR|+VkP17b#Vk;?4QwkI+A{L04G+#<<(x#Un1#+h5>eArRq zTw$)ZvTWW_Y?bDho0nPVTh08+s`sp!j74rJTTtXIDww0SILedFv?sZ?yb@@}GN;#8 znk_b~Q(A0YR#uV4ef!osoV1M3;vQ8N$O|fStfgf$S5;ddUNv`tWtGjM;koG#N;7M< zP*84lnx(bn_KF&9Z5Ai$)#Cs3a|$OFw>WKCT$of*L7_CqQEinflT|W{JT+aKp-E0v zsxmYg)1(T>DROm+LN1eQw8}KCTp=C!$H7`PU!t9_Hw@TsTI2`udRZv*!a5`#A9hK6Y95L(CDUX&_@QxKV z_feX{UhA#ZWlvgpL$#w^D#lq`_A4AzDqd|Zv6y9PX&DNcN|l}_D^{q@GG&H^Pg583 z8FI6N8^H7b5WjGp;urW)d7F+_lcp%KsLX0viCmE(OHH+=%ZfD_=`voUuoUxFO^L;- z;!;2{g-YiiO6m4bs89OuF9!p{FGtH-f%8<2gY!h9s)4ciN%{Kh1+`}{^}M~+TDH9N z^Z5PlgVXMC&2&k*Hw^Lb9gny#ro$MOIxIt{+r)EA10$VR3 zanN8D{TUkl+v0CQ_>ZoHP<M-x#8@8ZiT#$Kh`(uRaX1g$Bg|qy$<#7 zSSAi{Nb8Y=lvNVeio+UGLCAtoLBfL`iOv`)yoJMDJBN>4IH@(l7YRF;61@>qq1iM9 zr@b#OC~SAxSle?5Pp8Z78{VO0YFr1x7kZU64Z23eLf2T2#6J_t;-E}DkB?NufZ0Ug zi?J&byXeaB-uTNVhuiM!UVQw}bZrJ3GtAETYp->!{q#zfN7D3AS9@Q7*V^85jGx#R z(QxYV(wW#F0XF9^^s>>H8pPlVJ>)3Oz z&_X8Sf@~?cH_O*cgi$U#`v`RRfv#y3m(ZpKk^5uLup+lVs$~}FZU$r_+}#hl%?g5m z-u-}-666ssp-xWQak~>PPy$mRc|~?pVSs1_@mBEXpPVfLF6(Ktf1S* zPPh@QZ=tFMs?LM2(5P3L2;l_6XX6s&cYsP1ip#eg0`ZEP0HGYh{UmS@o`MihLLvkU zgyAG0G`b1|qjxxh1(ODKFE%AP}Dq=3vK$P7TXP4GrM1kQ72!GUVMDl`rDC&2;TA}*nF z8$nQD&6ys_nc1*E7$*1S@R8$ymy(sQV}imGSedB@{!QR5P&N_H=-^o!?LsWs+2|mH z-e=)T^SvI)=_JIm7}j4;@*Z17=(#}m=~YF~z~CLI+vdAGlJDcdF$TM?CVI1%LhUrN zaa6DJ=Yh$)$k&Oz{-~8yw^GM^8prYxSxo zvI4k#ibryMa%%*8oI-5m61Koa_A_xg=(fwp0aBX{;X4Q;NXUhtaoJDo1>TqhWtn=_ zd5~chq#&6~c%8JZK#t_&J(9EVUU&upYeIovLt1>vaHe}UUq>#RGQj!EN#5+0@T`(@ z^g~>*c`VGRiSt;!$_4+0hk^I!@O3``5=sZ8IwlxWW7km1B&_t&E*u0_9UBa#VqwY* zz>nxv?FAsVnRaD(Bui=6i==BFUw0k4n$>`umU`F2l?7CYTD^)c2X+d9X&ddS9|gj? zM?knGkGCX&W8offw8aLC2$D{PjC3nVZwd4k?eZH8*mZ)U@3Qk8RDFOz_#WUA#vnzy zyP>KrCfKwSXea7}jgJjBc}PGY+4#6%lbZyjhy`5sZd_Vy6Wz;ixa?czkN}J9It1K6 zY!eu>|AwF^fwZlLAYyQI*lM@^>O>Iu6Vf6i>Q$?v!SeUS<{>UYMwz$*%Aq?w^`j{h z!$GZbhu=^D{&ET8;))LL%ZBDZkQqRd2;u~!d9bHGmLRhLDctNgYyjsuvoSZ#iVdoB z2!f--UUA#U;<{je#?cYt^{PIyKa%hW>}uepWMyAI{{Zo7?2>?$c9;whJae%oN|I-kpTQSx_C$Z&;f zi2i)qmEn=y4U0uvk)$m;zKfjPK@oc?I`}1Jzl$Q~aoKBd3kt7L#7gyt|A_qgz6ai< z=X%D1i!d2h?rHR^R8SUj&G||dkC?DT>{o#Yau<@uqVT{Xef&XG}5*E4aPk{}~ zplx&XhaV)&1EfI3Em;Bw#O5SV^c;{twb-1Rw)+=0!e_BLbd7tYmXCH0wrlOSS+~`7He8Iqx0{CN+DVit9;*6L~JAN zD&cyT)2?h}xnYmL?^)<7YyzZ3$FHU^Eg;DLqAV{#wv#Wj7S`Jdl1pX&{3(uZ?!uh} zDc$ZTNV*7le_W6}Hju~GMTxZQ1aWCeUc%!jv3MHAzt>Y-nQK%zfT*3ebDQA5b?iGn; zBjv3B+GhLTexd_(CzZDP4|#n5^~scvB6#Pk%Ho!kQ>yYw((Dv{6=$g3jT1!u6gORW zx5#`7Wy-ZHRa~IxGHdrp(bm%lf>2%J660nj$fCqN(epv@y!l9s7@k6EvxS{AMP>WY zX4$@F8^kayphIx-RGO$+LYl9YdoI5d|4#q9##`_F5Xnx`&GPzp2fB{-{P@ATw=X@~ z_|&^UMWAKD;jjBKTK(~o?cUFRK8EX=6>cXpfzg4ZpMB>*w_^8GSiT-Jp|xBOnzM+j z*09-@-~qJ(eqWq5@R4i^u4^{McCP(!3}C|v_WsTR*bIUxN(Nx`u##3B4{sE`Z`v8w zAwIG`?1~PkID~W{uDzmqH98Pew_1(;x2%8r^vY{)_&J2K)cN{W+h5+g)ZcjP&Ci#O zgy|8K@4kyMfwilHd&6TDlhb%++Pk!>9HRld6HT7gwyZGrxS$}CsD6`>6!!2K1@Mjf z(P0WYB7V_OFZyeWrbOFb>O54BNXf~K&?}3=^v;v_wT{DKr?jN^DtN&DXwX%u?s*c6`%8>WFz z7}YW^tp0bp^NriE)AB6M2l<7rn7fzePtR*omOevpfm9n?}2V*+0iW;S)C zhg`NAjL?D=W#k*$aR{>pGf~lD-rVtD;5jW1_*Jn1j1=es@Kcx4ySM_bwcQCT=d+DV z>Sz~L=Hj@(X%31nK$mWI@7d>}ORB`K(p=+`UD)+99YUGQc7y^bHZ1F(8|tL0 zdK*DT0kSXG_{BKTpP2*2PecdKV9;dq$^ZZDP;Nyq1kp-&GI5eAyZsK!e3V zK@rPy*{(`KIfo+lc878mDKk^V#`VT05}64kBtk%DgwLrOvLMj5-;*GNKv6c6pzMuL z6EP%ob|_0IW}lLRXCP2!9wWhEw3LA7iF#1O1mIZ@Z=6&bz41F;@S_GvYAG-#CW3z{ zP3+6vHhvP&A3$##Vo9$dT^#MoGg^|MDm=Bt1d2RRwSZ<;ZHICpLBv5Xs!D?BH^(9_ z7`H=N&^v|Z-%mP}wNzG{aiFCsRgwzwq!N6obW9+7(R; z(SZ=23`|`>qil!LMGG{_Heq!BD>(Y-zV9wD)}hz25JA37YR%39;kI4y9pgtcUass6 zP24}ZY$vvYeI`zy&)A_X#nY3017ap*0&jx|mVwyGhg3;!keU53a}Uhm3BZI$N$6Se zLWlAmy1S0xKJm4G_U@sN_Tm=`$xWJSEwKU98rZ&)1R^*$$1vA3oG#&*%SMxY_~oGP zP&PFJatFLM-Ps%84IV-+Ow)T{C7cqUAvauy4C z(FRz&?6$Rypj{xO!`y=*J5o4@U8Q-(y5(*=YoKeZ+-1YdljXxkA#B)zo=FeQH#?Le zycNUmEEHWO9a=X^pb#&cOq7-`7UA87#|S22)<7RUtZo|(zibX=w;K3qur9vy#`MNV z6UUcf9ZwEnKCCp+OoBnF@OdbvH)ANXO0o~Pi9l8=x3))}L<#vO0-~O4!~--Ket?d} zJaqsj<@CD1%S2cTW%rOP{Vto%0sGW~1RMa_j^)5nil0Yw- z0EE#bP+l4#P^%PQ+N*oxu1Zq05xZ!bXfYTg>9c{(Iw*lnjR^>kz%lAN^zFce7rppy zY8zA~3GD=A6d*hze&l4D_wA~+O!56)BZTe_rEu}Ezi<4!kG|W#amBZ5{&XS2@6R~H z{9o^y*BkH4$~yX9U&@CgbOzX1bn9xqF|zh$Dh0Y5y*E0e90*$!ObrHY3Ok0`2=O~r zCuke6KrP9KOf?V(YDsM<6pX2nVoN%M$LT^q#FmtaF?1^27F*IcNX~XRB(|hCFvdcc zc)$=S-)acdk$g4?_>jRqxpI6M3vHZk?0c^3=byamYDNf;uB{3NlKW5IhnOS3DNkMV z?tK8?kJ}pmvp%&&eTVOVjHP`q34hN1@!aK}H(K!vI`~gf|Gv+FNEQD5Yd<~yX7k_l h&G-K)@HZb3BABY{)U1?^%I#E6`MGoTtustd{~yM6srvu` literal 0 HcmV?d00001 diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Square150x150Logo.scale-200.png b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Square150x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..af49fec1a5484db1d52a7f9b5ec90a27c7030186 GIT binary patch literal 2937 zcma)84OCO-8BSud5)jwMLRVKgX(S?$n?Ld|vrsm<$CF7)&zTbyy1FE5bU`Q17MRv`9ue$;R(@8kR;#vJ*IM0>cJIAOte!d7oRgdH zd%ySjdB6L9=gX^A6)VzH7p2l@v~3zJAMw|DFy#^)F@@F*`mqUn=Il>l)8_+ab;nOW{%+iPx z+s{Eu|&pIs)Z7{La9~?xKfyl z#43?gjEL15d4WbOZo#SiP%>DB^+BcnJ=7dHEe;r#G=tuw|ka z%q@}##Uh7;tc%L_64m(kHtw74ty%BJMb)_1)#S0j`)F8_1jF7vScpsnH=0V19bO8y zR`0SjIdCUo&=>JwMQF8KHA<{ODHTiQh}0^@5QRmCA?gOH6_H3K^-_sNB^RrdNuK-R zOO*vOrKCVvDwgUck`kF(E7j{I#iiN;b*ZdCt4m@HPA`EuEqGGf4%!K<;(=I=&Vyrw z%TwcWtxa}8mCZ%Cyf&ActJ6_$ox5z6-D!0-dvnRx6t7y3d+h6QYpKWO;8OdnvERo7 zuEf>ih5`wqY)~o@OeVt-wM?Q!>QzdGRj!bz6fzYrfw$hZfAKzr2-M+D+R>}~oT574c;_3zquHcElqKIsryILt3g8n3jcMb+j?i?-L3FpZJ z2WRVBRdDPc+G5aaYg#5hpE+6nQ|(VSoxT3|biF;BUq#==-27Xi=gihDPYP$7?=9cP zYKE$jeQ|3~_L0VG-(F~2ZPyD0=k{J4Q~h(t__{-mz_w8{JDY9{`1ouzz!Vr5!ECdE z6U~O1k8c}24V7~zzXWTV-Pe4)y}wQJS&q%H5`Fo_f_JvIU489aCX$;P`u#!I-=^4ijC2{&9!O&h>mi?9oYD=GC#%)6{GzN6nQYw+Fal50!#x^asjBBR50i`+mho*ttoqV)ubM2KD9S~k7+FR4>{29?6 z{!l6kDdyTN0YJ9LgkPWeXm|gyi@zM3?0@{&pXT12w|78&W-q!RRF)&iLCEZVH<|fR zN0fr2^t8H(>L?>K#>^+jWROLral(Qy-xoBq1U7A&DV||wClb)Otd9?(gZ|8znMF}D zf<1haWz^s0qgecz;RFGt0C-B4g`jNGHsFU+;{<%t65v^sjk^h$lmWn#B0#_)9ij&d z-~lc`A)YYExi^7sBuPM^Y|wA2g*5?`K?#7tzELQYNxGo$UB$4J8RJp1k(8Jj+~hMT zlN~>M@KTTh^--8y3PK_NZ@AC!{PT=CziBzGd+wTJ^@icH!Bd}%)g8V)%K?|c&WTUk zy}qv1C%(fjRoZ4ozC3{O%@5?)XzH35zHns$pgU*Q?fj4v?fp1Qbm+j;3l;9jam9Da zXVcKjPlQ73x78QPu|Ffm6x?`~e3oD=gl=4kYK?={kD5j~QCXU)`HSdduNNENzA*2$ zOm3PzF!lN5e*06-f1Uot67wY#{o-S1!KZ7E=!~7ynnk9_iJR#kFoNbAOT#^2Gd17F zMmvU6>lndZQGd|ax9kUoXXO+$N?|j@6qpsF&_j7YXvwo_C{JpmLw5&#e6k>atv%es z5)7r*Wvv_JkUpT}M!_o!nVlEk1Zbl=a*2hQ*<|%*K1Glj^FcF`6kTzGQ3lz~2tCc@ z&x|tj;aH&1&9HwcJBcT`;{?a+pnej;M1HO(6Z{#J!cZA04hnFl;NXA+&`=7bjW_^o zfC40u3LMG?NdPtwGl>Tq6u}*QG)}-y;)lu-_>ee3kibW(69n0$0Zy!}9rQz%*v1iO zT9_H>99yIrSPYVy6^);rR}7Yo=J_T@hi+qhTZXnVWyf;JDYm5#eYLTxr*?kiNn!+Y zQ+LUkBafNJ#rH#C(?d5^;gw9o#%daEI{mA*LHPIHPU`#|H$hD zwm>0&+kahQ)E#%~k>&5@&#Vg82H?s%71=)(soi@174pi9--2{w{1$}Sz4zGn3Du&x bht0Iza^2ykEt4(epJ78uh5nDlX8(TxzDYwP literal 0 HcmV?d00001 diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Square44x44Logo.scale-200.png b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Square44x44Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..ce342a2ec8a61291ba76c54604aea7e9d20af11b GIT binary patch literal 1647 zcmaJ?eM}Q)7(e+G1Q(|`V9JhTI2>MkceK4;p;PR&$Pi?ejk3YQ_3o`S&|W_dsOZ8# zWPTt69g`t$ab`0cj-Y0yiBSOqmd)tG7G(}M5aP0_%&9TijB#&)I{zSE^4@#z^FF`l z`8{8`o%wlL(UI|y2!cdsuVamHH~H86F!*-15em4)NqUpCQM5?aoC_eCf@lV4wvF2a zjDQn1JBL69f&@2M3rvzJcfE!eZ8FZUBlFlC5RD)it33{mF9#B82AiyQE%w)`vlwa> zv{<1sm&kSKK$&%2jSFn7$t&P%%6Ue>R=EAnG8N7fqynWG8L3p!4801a;8{+nliO(qd(jNJ_?+9W3#hLIDLoT6~3fx9=`CC-D}-AMrpEO7HK zt3$GicGPc?GmDjy7K2P@La;eu4!$zWCZ`ym{Z$b zu-O6RM&K4JT|BIZB`E-gxqG%FzanI#+2FFmqHqXG7yxWB=w55RGOM)$xMb(>kSNR z2w=1AZi%z=AmG~yea~XaXJR!v7vLn(RUnELfiB1|6D84ICOS}^Zo2AdN}<&*h}G_u z{xZ!(%>tLT3J3<5XhWy-tg+6)0nmUUENLW8TWA{R6bgVd3X;anYFZ^IRis*_P-C-r z;i>%1^eL3UI2-{w8nuFFcs0e~7J{O2k^~Ce%+Ly4U?|=!0LH=t6()xi<^I-rs+9sF z*q{E-CxZbGPeu#a;XJwE;9S1?#R&uns>^0G3p`hEUF*v`M?@h%T%J%RChmD|EVydq zmHWh*_=S%emRC*mhxaVLzT@>Z2SX0u9v*DIJ@WC^kLVdlGV6LpK$KIrlJqc zpJ921)+3JJdTx|<`G&kXpKkjGJv=76R`yYIQ{#c-`%+`#V(7}Q;&@6U8!Td1`d;?N z_9mnI#?AA}4J!r)LN4!E-@H5eXauuB7TOawS>Y|{-P?NNx-lq+z1W-+y(;39P&&LP zL{N80?&=C*qKmdA^moMZRuPcD!B<*mq$ch=0Cnlitw#txRWhb3%TQvPqjkC`F69G4b! ze7z9MZ#+;_#l?H37UqUhDFb^l&s2{oM$3I0o^Q!yx;;V)QmCMo)Tb_ui|mit8MS?U zm##6$sZZ1$@|s%?l@>4Z<*Q}sRBSKMhb4I{e5LdEhsHIHTe8Bod5c>6QtT>$XgUBz z6MK`kO$=jmt@FqggOhJ5j~e@ygRbG;<{Vu)*+nn9aQeo0;$#j;|MS=S$&L?BeV25z xs3B`@=#`5TF{^6(A1rvdY@|-RtQ|iS5{tyX+wH?;n8E)G$kykv-D^wh{{!TZT%7;_ literal 0 HcmV?d00001 diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 0000000000000000000000000000000000000000..f6c02ce97e0a802b85f6021e822c89f8bf57d5cd GIT binary patch literal 1255 zcmaJ>TWs4@7*5+{G#S+&C!qC#> zf>5N3P6jO*Cz>ug*(_DmW=)kea&m$gZ^+nyiF`;j%w@}y8)>p*SH}C`m?DXeieF2U zyQHecc_L%Gh!7GMt+hG06y;+|p4>m~}PjA}rKViGiEnn7G0ZO<>G|7q;2?NwGCM3s?eued6%hd$B+ z*kQJ{#~$S=DFE(%=E+UkmlEI*%3llUf~8Ja9YU1Vui0IbGBkW_gHB%Rd&!!ioX zs40O?i9I{};kle7GMvE7(rk`la=gTI)47=>%?q@^iL-nUo3}h4S}N-KHn8t5mVP8w z&bSErwp+37 zNJJ8?a|{r5Q3R0Z5s-LB1WHOwYC@7pCHWND#cL1cZ?{kJ368_*(UDWUDyb<}0y@o# zfMF016iMWPCb6obAxT$JlB6(2DrlXDTB&!0`!m??4F(qWMhjVZo?JXQmz`1*58Z=& zcDmB|S-E@j?BoFGix0flckqdS4jsPNzhfWyWIM98GxcLs89C(~dw%$_t;JjX-SD}E zfiGV;{8Q%8r}w9x>EEigW81>`kvnU@pK)4+xk9@+bNj9L!AAZ@SZ@q|)&BmY3+HZx zul~BeG4|}-;L%cHViQGQX?^zFfO0&#cHwel=d`lH9sJ-@Sl@n*(8J2>%Ac`IxyY?Q z{=GhWvC#gu-~Ia7*n{=+;qM?Ul_wy1+u7ho;=`>EwP^g~R@{unBds`!#@}tluZQpS zm)M~nYEifJWJGx?_6DcTy>#uh%>!H9=hb^(v`=m3F1{L>db=<5_tm+_&knAQ2EU$s Mu9UqpbNZeC0BbUo^Z)<= literal 0 HcmV?d00001 diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/StoreLogo.png b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..7385b56c0e4d3c6b0efe3324aa1194157d837826 GIT binary patch literal 1451 zcmaJ>eN5D57_Z|bH;{0+1#mbl)eTU3{h)Wf7EZV?;HD@XL@{B`Ui%(2aMxQ~xdXSv z5nzWi(LW)U2=Vc-cY@s7nPt{i0hc6!7xN4NNHI#EQl>YNBy8l4%x9gr_W-j zEZMQmmTIy(>;lblRfh`dIyTgc9W5d!VP$L4(kKrN1c5G~(O_#xG zAJCNTstD^5SeXFB+&$h=ToJP2H>xr$iqPs-#O*;4(!Fjw25-!gEb*)mU}=)J;Iu>w zxK(5XoD0wrPSKQ~rbL^Cw6O_03*l*}i=ydbu7adJ6y;%@tjFeXIXT+ms30pmbOP%Q zX}S;+LBh8Tea~TSkHzvX6$rYb)+n&{kSbIqh|c7hmlxmwSiq5iVhU#iEQ<>a18|O^Sln-8t&+t`*{qBWo5M?wFM(JuimAOb5!K#D}XbslM@#1ZVz_;!9U zpfEpLAOz=0g@bd6Xj_ILi-x^!M}73h^o@}hM$1jflTs|Yuj9AL@A3<-?MV4!^4q`e z)fO@A;{9K^?W?DbnesnPr6kK>$zaKo&;FhFd(GYFCIU^T+OIMb%Tqo+P%oq(IdX7S zf6+HLO?7o0m+p>~Tp5UrXWh!UH!wZ5kv!E`_w)PTpI(#Iw{AS`gH4^b(bm^ZCq^FZ zY9DD7bH}rq9mg88+KgA$Zp!iWncuU2n1AuIa@=sWvUR-s`Qb{R*kk(SPU^`$6BXz8 zn#7yaFOIK%qGxyi`dYtm#&qqox0$h=pNi#u=M8zUG@bpiZ=3sT=1}Trr}39cC)H|v zbL?W)=&s4zrh)7>L(|cc%$1#!zfL?HjpeP%T+x_a+jZ16b^iKOHxFEX$7d|8${H-* zIrOJ5w&i$>*D>AKaIoYg`;{L@jM((Kt?$N$5OnuPqVvq**Nm}(f0wwOF%iX_Pba;V z;m@wxX&NcV3?<1+u?A{y_DIj7#m3Af1rCE)o`D&Y3}0%7E;iX1yMDiS)sh0wKi!36 zL!Wmq?P^Ku&rK~HJd97KkLTRl>ScGFYZNlYytWnhmuu|)L&ND8_PmkayQb{HOY640 bno1(wj@u8DCVuFR|31B*4ek@pZJqxCDDe1x literal 0 HcmV?d00001 diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Wide310x150Logo.scale-200.png b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Assets/Wide310x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..288995b397fdbef1fb7e85afd71445d5de1952c5 GIT binary patch literal 3204 zcmbVPeQXow8NYmBd90>}0NP?GhXW~VaeThm=a0tV#EwJMI!)6M3}|c4_Bl3=Kd>G0 z(GHx1wl<7(tP?FsOQkTilSo*iIvF%uArExJ73~P zSv1xEy!U(Wd4A9D`FQV@W3@F^qJ@PEF$@z`Z!*BbFsS(^?B zyiAzJ+q})bkgiQHWqEb*jJD-coHYr1^iocg)l!Qa{Xqs-l~6J}p-|##ZHYofskQ3$ zI0;xzXyhazBeXhIsg5A=%ufo@f)1yy&ScKS0;HF^!r_2UE^lpZEom(+@duma3awTv zCrCL-%D_SvYWIcdHkmI}#50(fkUi)Qgx!80ju>g1za^}ff>JI8Z@^-iCiaCgg@TgF z+vtE?Q9{VQUX&MW9SYYmGcxA14%N2@7FwBTD4N<(2{nWgV8$e3?-F=L^&FrtWn~(U_Q~~^uYiyeY6-KoTnfh9AWz@ zIKje0)u!_Lw)E}G!#kEfwKVdNt(UAf9*f>tEL_(=xco-T%jTi@7YlC3hs2ik%Le0H ztj}RTeCF(5mwvi3_56>-yB?l;J>-1%!9~=fs|QcNG3J~a@JCu`4SB460s0ZO+##4fFUSGLcj_ja^fL4&BKALfb#$6$O?>P@qx2Agl^x0i&ugt zsy5Pyu=()`7HRMG3IB7F1@`_ z+-!J%#i6e^U$e#+C%Q>_qVRzWRsG^W_n+@OcX@vzI&z;mzHNb!GQ?LWA(wtpqHqTM z1OFw_{Zn?fD)p)`c`kOgv{de=v@suGRqY{N^U7gI1VF3*F=obwaXI6ob5__Yn zVTguS!%(NI09J8x#AO_aW!9W7k*UvB;IWDFC3srwftr{kHj%g)fvnAm;&h_dnl~

MY- zf+K}sCe8qU6Ujs`3ua{U0Of$R_gVQBuUA za0v=mu#vIOqiiAZOr&h*$WyOw&k-xr$;G4Ixa!#TJNr>95(h>l%)PUy4p+^SgR(uR zta%k*?ny-+nAr8spEk1fo{J4i!b^Fia`N{_F6@zidA2ZTTrjl#^5Z-2KfB@Cu}l9s z(*|Z2jc?p~vn2f)3y9i*7zJV1L{$?|&q)4oaT;uXi6>1GkRXVTOzAz(RHEmr=eFIi z`}<>-Q?K0GN8!IYxeP1XKXO+jsJbp~o^);Bc;%b7Flpe7;1`Ny@3r7ZR;?R)aJt8C ziNlEC<@3f_lIV4TwV}&e;D!Ee5_|e#g0LUh=5vmYWYm7&2h*M>QPKvGh9-)wfMMW3 z8J9b%1k7dzPzO0_NGQy92BZ^FR6R~6;^6?lqO;-QUP4BY%cG%3vEhbm#>4vIhPBh3 z-+pZGjh$x%Hp{?=FHsMp0&wNPlj00us{&`1ZOZTqs8%4X&xH=UDr*xyBW(Zp&Em94 zf)ZSfn#yg0N)>!1kWdkqJ^S*z0FF5|fj&qcE#Na|%OY0$uO>!&hP+1ywfD_WXk@4J(?MBftK7>$Nvqh@tDuarN%PrTLQ2Uzysx>UV=V zk^RrDSvdQ?0;=hY67EgII-f4`t=+i*yS=Y~!XlqIy_4x&%+OdfbKOFPXS2X5%4R{N z$SQMX^AK6(fA + + + + Debug + x86 + {3E8198A5-7E41-43F1-880E-E7E2840E5A59} + AppContainerExe + Properties + CodePushDemoApp + CodePushDemoApp + en-US + UAP + 10.0.10586.0 + 10.0.10240.0 + 14 + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + CodePushDemoApp_TemporaryKey.pfx + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x86 + false + prompt + true + + + true + bin\x86\DebugBundle\ + TRACE;DEBUG;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE + ;2008 + true + full + x86 + false + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + bin\x86\ReleaseBundle\ + TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE + true + ;2008 + true + pdbonly + x86 + false + prompt + MinimumRecommendedRules.ruleset + true + true + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + ARM + false + prompt + true + + + true + bin\ARM\DebugBundle\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE + ;2008 + true + full + ARM + false + prompt + MinimumRecommendedRules.ruleset + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + bin\ARM\ReleaseBundle\ + TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE + true + ;2008 + true + pdbonly + ARM + false + prompt + MinimumRecommendedRules.ruleset + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x64 + false + prompt + true + + + true + bin\x64\DebugBundle\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE + ;2008 + true + full + x64 + false + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + bin\x64\ReleaseBundle\ + TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE + true + ;2008 + true + pdbonly + x64 + false + prompt + MinimumRecommendedRules.ruleset + true + true + + + + + + + + App.xaml + + + + + + + Designer + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + + + {446a85d9-55eb-4c7d-8b9d-448306c833d6} + CodePush + + + {c7673ad5-e3aa-468c-a5fd-fa38154e205c} + ReactNative + + + + + PreserveNewest + + + + 14.0 + + + + \ No newline at end of file diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/CodePushDemoApp.nuget.targets b/Examples/CodePushDemoApp/windows/CodePushDemoApp/CodePushDemoApp.nuget.targets new file mode 100644 index 000000000..ff4a29f29 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp/CodePushDemoApp.nuget.targets @@ -0,0 +1,9 @@ + + + + $(UserProfile)\.nuget\packages\ + + + + + \ No newline at end of file diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/CodePushDemoApp_TemporaryKey.pfx b/Examples/CodePushDemoApp/windows/CodePushDemoApp/CodePushDemoApp_TemporaryKey.pfx new file mode 100644 index 0000000000000000000000000000000000000000..08328fc151890556883c49831ec0828a15428fd3 GIT binary patch literal 2454 zcmZuzc|25Y8$M??Mz%5`Tb3-*a%LJ^i0Bm&ib!^uv6g)aQO8!V<&~^SQ4z_QtP@i9 z@3Sw32qRmKQ1piB#dq|3zrMcT@BQOG=en-vxt{y^-RC*?IS`CbL4jxp#+%^qim?W< zt2`hFm^ug>&LQ#?5)-%`f4jK3KvXV_*@R#W8xq5D{Z~d7 z=f!Z^ABMW~qXD2`qXj2RyJ_Ff=3!Er<1s!Ft&TJ%yz&~56gQ^aS&eATB#JEo%S^~J+%3tYB3@3$cW^; zj&1fkoO!U^BkfkLEUDMNd7JmuygX#QxP}Bs|4tcYH`EoaBt*$52dDN;TdQOHJ9S(H ztE(fu6iwp}oac1;m)xu^K{b}hJxO6V1UC;SE@-!vVl7~lac$h2pk7JTv<8Lox ztfhLq6Q1Th9&fXQ2;NJ5hR>%pKkE@UDyLcBGLBc!G!_7v>RQ}pxEiOyX5xcX>9;$N zhIOv;?77w?JG z@2Qnmy_OT=?Vhe%T-qpRCd$$>fuTzA z>sd^RluEicStybHEn~H8Kb7B;WLj5J`ds0eORN7Onrj&=#IjWmoD>g&rjmQ(gBgdO z-qSOw>s}7NIoBeAR}XgRcq_bRu8bihB)6Tu5zX4iPiwZ6bJX;*-|G-Fxgtak(4A=* zF&{inTlCtHrA1QjQhys4_MvsoZRTYM`RS`Qx&x=J2YS%K#vAngX@6k|SC^J8LB|5R zRPuuHDvF`SV)nTZ-3FJ#n7Vm~b$Ywm_dRabz!$efgf3K-_O0`ZXU&&8xVbPm_e(^! zby_bO8}fvX6_dhGa#po89Mpf=eLHinczx?|_3bkSWx7$$jv6BOtS&rn-6{rSx*74; zO>B}3-#+I`FiB&c%*0n65oUv9A$EPr*7W`)EZs;}K}sZNxKi+0%p9o4!#^m!tK0VW zi71KrmGkNQ6k0eMlSnQK`FX=BA)ng2qv9kUW=F7dKOU50X^Y~1AKzEw7u7*vJzk5^ zPBf}^mFw(p+jv?uM)*4agj6Gth8!J{psz zr2p$k@0Y_Fb>W9ndvb}_yC8v|?GnG6h{Iq&001DX|A_?RDG39>2_OP$02K)mpbn6M zgNQ-~oB;?yWPpMoDuUFJ@r%feZA~4yQ~u`afGUDj04K-}hgZUZ7!X$72@=gDOn}pX zJ7Vzzya9hCs6YT9378|-ZRIlHiZDF{Ujcj&%^TrVhl@E*&!4=Bh;De`45JwRk+ zW?iN^&PFUg`P%!EOwZ06Yb7h3Nsel%ARmkM+N;MytJ}Yjbe1h(VJ5(*bZjli({_~| zF2;&=PzrO7?GcdGlew9hwE<7Mep&}qj4DXwDk^T{58yw2tLcHwV|fXSaS;bzzI~HH zzOKDna^uO?gfG=HEKsYiZ#f`4WcaAkf+#^)Z}mkv3Jn6_Lj_0<;zp`1E&zgC7!(9R zg4;}Xn{h*2I8Nk%VX+)&^slu<9urba5V*@Tn&DhsTQZ=-mjo7SnOXBK9JCl@R&+PJ zTRBBK|K?@uac=hd1N}3ZP5QMOH2=z}X#D2jb3gUZhL_~olZC$SZ%WkOBql#PH{V8G zi@H7Zr&N2~c+V00CeiR)<{5)qd;0BESLr95P(C2;aH+S{<4*Az;nsnNbq4<8`8qbA z8hXN*nNzRt-cR?==|->n@N2zmtavdjzpE+YPf{T&R^4t!*Lb;kPpJ3!71?z5nXO`; z8;)HzC;N1JM4v}kd{Qf=;@_-nq}O7CBW3IzvJKS3=@K6m**;Y%=I5LBIV)pGS@C0x zM}lJKus#RAI-*;^1s2d>YfHB;ao4jW?*8W&UIW?-ap15@yl9jNhTz23wd!@OYgr)& nNPCnSM4V?T6k`a3;-OhqjT_LVqQ5eE$7EPLEF49)|B(IzfpaF1 literal 0 HcmV?d00001 diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/MainPage.cs b/Examples/CodePushDemoApp/windows/CodePushDemoApp/MainPage.cs new file mode 100644 index 000000000..030d764a3 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp/MainPage.cs @@ -0,0 +1,62 @@ +using CodePush.ReactNative; +using ReactNative; +using ReactNative.Modules.Core; +using ReactNative.Shell; +using System.Collections.Generic; + +namespace CodePushDemoApp +{ + class MainPage : ReactPage + { + + public override string MainComponentName + { + get + { + return "CodePushDemoApp"; + } + } + + private CodePushReactPackage codePushReactPackage = null; + public override string JavaScriptBundleFile + { + get + { + + codePushReactPackage = new CodePushReactPackage("deployment-key-here", this); + +#if BUNDLE + return codePushReactPackage.GetJavaScriptBundleFile(); +#else + return null; +#endif + } + } + + + public override List Packages + { + get + { + return new List + { + new MainReactPackage(), + codePushReactPackage + }; + } + } + + public override bool UseDeveloperSupport + { + get + { +#if !BUNDLE || DEBUG + return true; +#else + return false; +#endif + } + } + } + +} diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/Package.appxmanifest b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Package.appxmanifest new file mode 100644 index 000000000..1643e92b8 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Package.appxmanifest @@ -0,0 +1,49 @@ + + + + + + + + + + CodePushDemoApp + React Native for UWP + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/Properties/AssemblyInfo.cs b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a70a7f944 --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Properties/AssemblyInfo.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CodePushDemoApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CodePushDemoApp")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/Properties/Default.rd.xml b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Properties/Default.rd.xml new file mode 100644 index 000000000..a43bcd57e --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp/Properties/Default.rd.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Examples/CodePushDemoApp/windows/CodePushDemoApp/project.json b/Examples/CodePushDemoApp/windows/CodePushDemoApp/project.json new file mode 100644 index 000000000..ba450177d --- /dev/null +++ b/Examples/CodePushDemoApp/windows/CodePushDemoApp/project.json @@ -0,0 +1,17 @@ +{ + "dependencies": { + "Facebook.Yoga": "1.0.1-pre", + "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2" + }, + "frameworks": { + "uap10.0": {} + }, + "runtimes": { + "win10-arm": {}, + "win10-arm-aot": {}, + "win10-x86": {}, + "win10-x86-aot": {}, + "win10-x64": {}, + "win10-x64-aot": {} + } +} \ No newline at end of file diff --git a/Examples/CodePushDemoApp/windows/nuget.config b/Examples/CodePushDemoApp/windows/nuget.config new file mode 100644 index 000000000..724f2270c --- /dev/null +++ b/Examples/CodePushDemoApp/windows/nuget.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/package.json b/package.json index f7fb4c1c8..519bd7348 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,14 @@ "code-push-plugin-testing-framework": "file:./code-push-plugin-testing-framework", "del": "latest", "express": "latest", - "gulp-typescript": "2.12.2", "gulp-insert": "latest", "gulp-tslint": "latest", + "gulp-typescript": "2.12.2", "mkdirp": "latest", "q": "^1.4.1", - "run-sequence": "latest" + "run-sequence": "latest", + "tslint": "^4.3.1", + "typescript": "^2.1.5" }, "rnpm": { "android": { diff --git a/windows/CodePush.Net46.Test/ApplicationDataContainerTest.cs b/windows/CodePush.Net46.Test/ApplicationDataContainerTest.cs new file mode 100644 index 000000000..98ae82a59 --- /dev/null +++ b/windows/CodePush.Net46.Test/ApplicationDataContainerTest.cs @@ -0,0 +1,105 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using CodePush.Net46.Adapters.Storage; +using System.Threading.Tasks; + +namespace CodePush.Net46.Test +{ + [TestClass] + public class ApplicationDataContainerTest + { + readonly static string key1 = "key1"; + readonly static string key2 = "key2"; + readonly static string key3 = "key3"; + + readonly static string val1 = "string data1"; + readonly static string val2 = "string data2"; + readonly static string val3 = "string data1"; + + [TestMethod] + public void TestInMemmorySet() + { + var settings = new ApplicationDataContainer(); + + settings.Values[key1] = val1; + settings.Values[key2] = val2; + settings.Values[key3] = val3; + + Assert.AreEqual(settings.Values[key1], val1); + Assert.AreEqual(settings.Values[key2], val2); + Assert.AreEqual(settings.Values[key3], val3); + + settings.DeleteAsync().Wait(); + } + + [TestMethod] + public void TestInMemmoryReset() + { + var settings = new ApplicationDataContainer(); + + settings.Values[key1] = val1; + settings.Values[key1] = val2; + settings.Values[key1] = val3; + + Assert.AreEqual(settings.Values[key1], val3); + + settings.DeleteAsync().Wait(); + } + + [TestMethod] + public void TestInMemmoryRemove() + { + var settings = new ApplicationDataContainer(); + + settings.Values[key1] = val1; + settings.Values[key2] = val2; + settings.Values[key3] = val3; + + settings.Values.Remove(key2); + + Assert.AreEqual(settings.Values[key1], val1); + Assert.IsNull(settings.Values[key2]); + Assert.AreEqual(settings.Values[key3], val3); + + settings.DeleteAsync().Wait(); + } + + [TestMethod] + public void TestPersistentSet() + { + var settings = new ApplicationDataContainer(); + + settings.Values[key1] = val1; + settings.Values[key2] = val2; + settings.Values[key3] = val3; + + settings = new ApplicationDataContainer(); + + Assert.AreEqual(settings.Values[key1], val1); + Assert.AreEqual(settings.Values[key2], val2); + Assert.AreEqual(settings.Values[key3], val3); + + settings.DeleteAsync().Wait(); + } + + [TestMethod] + public void TestPersistentRemove() + { + var settings = new ApplicationDataContainer(); + + settings.Values[key1] = val1; + settings.Values[key2] = val2; + settings.Values[key3] = val3; + + settings.Values.Remove(key2); + + settings = new ApplicationDataContainer(); + + Assert.AreEqual(settings.Values[key1], val1); + Assert.IsNull(settings.Values[key2]); + Assert.AreEqual(settings.Values[key3], val3); + + settings.DeleteAsync().Wait(); + } + } +} diff --git a/windows/CodePush.Net46.Test/CodePush.Net46.Test.csproj b/windows/CodePush.Net46.Test/CodePush.Net46.Test.csproj new file mode 100644 index 000000000..8366f0540 --- /dev/null +++ b/windows/CodePush.Net46.Test/CodePush.Net46.Test.csproj @@ -0,0 +1,125 @@ + + + + Debug + AnyCPU + {BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF} + Library + Properties + CodePush.Net46.Test + CodePush.Net46.Test + v4.6 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + + + + + + + + + + + + + + + + + + + + {4dfe3f9f-5e15-4f17-8fd4-33ff0519348e} + CodePush.Net46 + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/windows/CodePush.Net46.Test/Properties/AssemblyInfo.cs b/windows/CodePush.Net46.Test/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..53a3a9bcb --- /dev/null +++ b/windows/CodePush.Net46.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CodePush.Net46.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CodePush.Net46.Test")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("bbb48f0b-af6f-4a14-afa4-306d3fb0b7cf")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/windows/.gitignore b/windows/CodePush.Net46/.gitignore similarity index 100% rename from windows/.gitignore rename to windows/CodePush.Net46/.gitignore diff --git a/windows/CodePush.Net46/Adapters/Http/HttpProgress.cs b/windows/CodePush.Net46/Adapters/Http/HttpProgress.cs new file mode 100644 index 000000000..c76cea112 --- /dev/null +++ b/windows/CodePush.Net46/Adapters/Http/HttpProgress.cs @@ -0,0 +1,28 @@ +using System; + +namespace CodePush.Net46.Adapters.Http +{ + public enum HttpProgressStage + { + None = 0, + DetectingProxy = 10, + ResolvingName = 20, + ConnectingToServer = 30, + NegotiatingSsl = 40, + SendingHeaders = 50, + SendingContent = 60, + WaitingForResponse = 70, + ReceivingHeaders = 80, + ReceivingContent = 90 + } + + public struct HttpProgress + { + public UInt64 BytesReceived; + public UInt64 BytesSent; + public UInt32 Retries; + public HttpProgressStage Stage; + public UInt64? TotalBytesToReceive; + public UInt64? TotalBytesToSend; + } +} diff --git a/windows/CodePush.Net46/Adapters/Storage/ApplicationDataContainer.cs b/windows/CodePush.Net46/Adapters/Storage/ApplicationDataContainer.cs new file mode 100644 index 000000000..338bdaeed --- /dev/null +++ b/windows/CodePush.Net46/Adapters/Storage/ApplicationDataContainer.cs @@ -0,0 +1,103 @@ +using CodePush.ReactNative; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PCLStorage; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace CodePush.Net46.Adapters.Storage +{ + public enum ApplicationDataCreateDisposition + { + Always = 0, + Existing = 1 + } + + public class DictionaryWithDefault : Dictionary + { + TValue _default; + public TValue DefaultValue + { + get { return _default; } + set { _default = value; } + } + public DictionaryWithDefault() : base() { } + public DictionaryWithDefault(TValue defaultValue) : base() + { + _default = defaultValue; + } + public new TValue this[TKey key] + { + get + { + TValue t; + return base.TryGetValue(key, out t) ? t : _default; + } + set + { + base[key] = value; + DataChanged(this, null); + } + } + + public bool Remove(TKey key) + { + var found = base.Remove(key); + if (found) + DataChanged(this, null); + + return found; + } + + public event EventHandler DataChanged; + + } + + // A naive implementation of Windows.Storage.ApplicationDataContainer + public class ApplicationDataContainer + { + public DictionaryWithDefault Values; + private readonly SemaphoreSlim mutex = new SemaphoreSlim(1, 1); + + const string STORAGE_NAME = "AppStorage.data"; + IFile storageFile = null; + + public ApplicationDataContainer(string name = STORAGE_NAME) + { + storageFile = FileSystem.Current.LocalStorage.CreateFileAsync(name, CreationCollisionOption.OpenIfExists).Result; + var data = CodePushUtils.GetJObjectFromFileAsync(storageFile).Result; + + if (data != null) + { + Values = data.ToObject>(); + } + else + { + Values = new DictionaryWithDefault(); + } + + Values.DataChanged += async (s, e) => await SaveAsync(); + } + + ~ApplicationDataContainer() + { + mutex.Dispose(); + } + + async Task SaveAsync() + { + await mutex.WaitAsync().ConfigureAwait(false); + var jobject = JObject.FromObject(Values); + await storageFile.WriteAllTextAsync(JsonConvert.SerializeObject(jobject)).ConfigureAwait(false); + mutex.Release(); + } + + public async Task DeleteAsync() + { + Values.Clear(); + await storageFile.DeleteAsync(); + } + } +} diff --git a/windows/CodePush.Net46/CodePush.Net46.csproj b/windows/CodePush.Net46/CodePush.Net46.csproj new file mode 100644 index 000000000..3d0a537a6 --- /dev/null +++ b/windows/CodePush.Net46/CodePush.Net46.csproj @@ -0,0 +1,104 @@ + + + + + Debug + AnyCPU + {4DFE3F9F-5E15-4F17-8FD4-33FF0519348E} + Library + Properties + CodePush.Net46 + CodePush.Net46 + v4.6 + 512 + + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + + + $(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + True + + + False + $(SolutionDir)\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.dll + True + + + False + $(SolutionDir)\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.Abstractions.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + {22cbff9c-fe36-43e8-a246-266c7635e662} + ReactNative.Net46 + + + + + + + \ No newline at end of file diff --git a/windows/CodePush.Net46/CodePushUtils.cs b/windows/CodePush.Net46/CodePushUtils.cs new file mode 100644 index 000000000..c49589be5 --- /dev/null +++ b/windows/CodePush.Net46/CodePushUtils.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json.Linq; +using PCLStorage; +using System; +using System.Management; +using System.Threading.Tasks; + +namespace CodePush.ReactNative +{ + internal partial class CodePushUtils + { + internal async static Task GetJObjectFromFileAsync(IFile file) + { + string jsonString = await file.ReadAllTextAsync().ConfigureAwait(false); + if (jsonString.Length == 0) + { + return new JObject(); + } + + try + { + return JObject.Parse(jsonString); + } + catch (Exception) + { + return null; + } + } + + static string GetDeviceIdImpl() + { + ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_BaseBoard"); + ManagementObjectCollection moc = mos.Get(); + string mbId = String.Empty; + foreach (ManagementObject mo in moc) + { + mbId = (string)mo["SerialNumber"]; + break; + } + + ManagementObjectCollection mbsList = null; + ManagementObjectSearcher mbs = new ManagementObjectSearcher("Select * From Win32_processor"); + mbsList = mbs.Get(); + string procId = string.Empty; + foreach (ManagementObject mo in mbsList) + { + procId = mo["ProcessorID"].ToString(); + break; + } + + return procId + "-" + mbId; + } + } +} diff --git a/windows/CodePush.Net46/FileUtils.cs b/windows/CodePush.Net46/FileUtils.cs new file mode 100644 index 000000000..428802dbb --- /dev/null +++ b/windows/CodePush.Net46/FileUtils.cs @@ -0,0 +1,55 @@ +using PCLStorage; +using System; +using System.IO; +using System.Threading.Tasks; + +namespace CodePush.ReactNative +{ + internal class FileUtils + { + internal async static Task MergeFoldersAsync(IFolder source, IFolder target) + { + foreach (IFile sourceFile in await source.GetFilesAsync().ConfigureAwait(false)) + { + await CopyFileAsync(sourceFile.Path, Path.Combine(target.Path, sourceFile.Name)).ConfigureAwait(false); + } + + foreach (IFolder sourceDirectory in await source.GetFoldersAsync().ConfigureAwait(false)) + { + var nextTargetSubDir = await target.CreateFolderAsync(sourceDirectory.Name, CreationCollisionOption.OpenIfExists).ConfigureAwait(false); + await MergeFoldersAsync(sourceDirectory, nextTargetSubDir).ConfigureAwait(false); + } + } + + internal async static Task ClearReactDevBundleCacheAsync() + { + + if (await FileSystem.Current.LocalStorage.CheckExistsAsync(CodePushConstants.ReactDevBundleCacheFileName).ConfigureAwait(false) != ExistenceCheckResult.FileExists) + return; + + var devBundleCacheFile = await FileSystem.Current.LocalStorage.GetFileAsync(CodePushConstants.ReactDevBundleCacheFileName).ConfigureAwait(false); + await devBundleCacheFile.DeleteAsync().ConfigureAwait(false); + } + + internal static Task GetBinaryResourcesModifiedTimeAsync(string fileName) + { + var pathToAssembly = CodePushUtils.GetAppFolder(); + var pathToAssemblyResource = Path.Combine(pathToAssembly, CodePushConstants.AssetsBundlePrefix, fileName); + var lastUpdateTime = File.GetCreationTime(pathToAssemblyResource); + + return Task.FromResult(new DateTimeOffset(lastUpdateTime).ToUnixTimeMilliseconds()); + } + + internal async static Task CopyFileAsync(string sourcePath, string destinationPath) + { + using (var source = File.Open(sourcePath, FileMode.Open, System.IO.FileAccess.Read)) + { + using (var destination = File.Create(destinationPath)) // Replace if exists + { + await source.CopyToAsync(destination); + } + } + } + + } +} diff --git a/windows/CodePush.Net46/Properties/AssemblyInfo.cs b/windows/CodePush.Net46/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..e399db874 --- /dev/null +++ b/windows/CodePush.Net46/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CodePush.Net46")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CodePush.Net46")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4dfe3f9f-5e15-4f17-8fd4-33ff0519348e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/windows/CodePush.Net46/UpdateManager.cs b/windows/CodePush.Net46/UpdateManager.cs new file mode 100644 index 000000000..d48128c61 --- /dev/null +++ b/windows/CodePush.Net46/UpdateManager.cs @@ -0,0 +1,313 @@ +using CodePush.Net46.Adapters.Http; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PCLStorage; +using System; +using System.IO; +using System.IO.Compression; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + + +[assembly: InternalsVisibleTo("CodePush.Net46.UnitTest")] + +namespace CodePush.ReactNative +{ + internal class UpdateManager + { + #region Internal methods + + internal async Task ClearUpdatesAsync() + { + await (await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false)).DeleteAsync().ConfigureAwait(false); + } + + internal async Task DownloadPackageAsync(JObject updatePackage, string expectedBundleFileName, Progress downloadProgress) + { + // Using its hash, get the folder where the new update will be saved + var codePushFolder = await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false); + var newUpdateHash = (string)updatePackage[CodePushConstants.PackageHashKey]; + var newUpdateFolder = await GetPackageFolderAsync(newUpdateHash, false).ConfigureAwait(false); + if (newUpdateFolder != null) + { + // This removes any stale data in newUpdateFolder that could have been left + // uncleared due to a crash or error during the download or install process. + await newUpdateFolder.DeleteAsync().ConfigureAwait(false); + } + + newUpdateFolder = await GetPackageFolderAsync(newUpdateHash, true).ConfigureAwait(false); + var newUpdateMetadataFile = await newUpdateFolder.CreateFileAsync(CodePushConstants.PackageFileName, CreationCollisionOption.ReplaceExisting).ConfigureAwait(false); + var downloadUrlString = (string)updatePackage[CodePushConstants.DownloadUrlKey]; + var downloadFile = await GetDownloadFileAsync().ConfigureAwait(false); + + await UpdateUtils.DownloadBundleAsync(downloadUrlString, downloadFile.Path, downloadProgress); + + try + { + // Unzip the downloaded file and then delete the zip + var unzippedFolder = await GetUnzippedFolderAsync().ConfigureAwait(false); + /** + * TODO: + * 1) ZipFile.ExtractToDirectory is not reliable and throws exception if: + * - folder exists already + * - path is too long (> 250 chars) + * + * 2) Un-zipping is quite long operation. Does it make sense for async? + * await UpdateUtils.UnzipBundleAsync(downloadFile.Path, unzippedFolder.Path); + * + * Possible implementation + * + * internal async static Task UnzipBundleAsync(string zipFileName, string targetDir) + * { + * await Task.Run(() => + * { + * ZipFile.ExtractToDirectory(zipFileName, targetDir) + * return Task.CompletedTask; + * }); + * } + */ + ZipFile.ExtractToDirectory(downloadFile.Path, unzippedFolder.Path); + await downloadFile.DeleteAsync().ConfigureAwait(false); + + // Merge contents with current update based on the manifest + IFile diffManifestFile = null; + try + { + diffManifestFile = await unzippedFolder.GetFileAsync(CodePushConstants.DiffManifestFileName).ConfigureAwait(false); + } + catch (FileNotFoundException) + { + //file may not be present in folder just skip it + } + if (diffManifestFile != null) + { + var currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false); + if (currentPackageFolder == null) + { + throw new InvalidDataException("Received a diff update, but there is no current version to diff against."); + } + + await UpdateUtils.CopyNecessaryFilesFromCurrentPackageAsync(diffManifestFile, currentPackageFolder, newUpdateFolder).ConfigureAwait(false); + await diffManifestFile.DeleteAsync().ConfigureAwait(false); + } + + await FileUtils.MergeFoldersAsync(unzippedFolder, newUpdateFolder).ConfigureAwait(false); + await unzippedFolder.DeleteAsync().ConfigureAwait(false); + + // For zip updates, we need to find the relative path to the jsBundle and save it in the + // metadata so that we can find and run it easily the next time. + var relativeBundlePath = await UpdateUtils.FindJSBundleInUpdateContentsAsync(newUpdateFolder, expectedBundleFileName).ConfigureAwait(false); + if (relativeBundlePath == null) + { + throw new InvalidDataException("Update is invalid - A JS bundle file named \"" + expectedBundleFileName + "\" could not be found within the downloaded contents. Please check that you are releasing your CodePush updates using the exact same JS bundle file name that was shipped with your app's binary."); + } + else + { + if (diffManifestFile != null) + { + // TODO verify hash for diff update + // CodePushUpdateUtils.verifyHashForDiffUpdate(newUpdateFolderPath, newUpdateHash); + } + + updatePackage[CodePushConstants.RelativeBundlePathKey] = relativeBundlePath; + } + } + catch (InvalidDataException) + { + // Downloaded file is not a zip, assume it is a jsbundle + await downloadFile.RenameAsync(expectedBundleFileName).ConfigureAwait(false); + await downloadFile.MoveAsync(newUpdateFolder.Path, NameCollisionOption.ReplaceExisting).ConfigureAwait(false); + } + + // Save metadata to the folder + await newUpdateMetadataFile.WriteAllTextAsync(JsonConvert.SerializeObject(updatePackage)).ConfigureAwait(false); + } + + internal async Task GetCurrentPackageAsync() + { + var packageHash = await GetCurrentPackageHashAsync().ConfigureAwait(false); + return packageHash == null ? null : await GetPackageAsync(packageHash).ConfigureAwait(false); + } + + internal async Task GetCurrentPackageBundleAsync(string bundleFileName) + { + var packageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false); + if (packageFolder == null) + { + return null; + } + + var currentPackage = await GetCurrentPackageAsync().ConfigureAwait(false); + var relativeBundlePath = (string)currentPackage[CodePushConstants.RelativeBundlePathKey]; + + return relativeBundlePath == null + ? await packageFolder.GetFileAsync(bundleFileName).ConfigureAwait(false) + : await packageFolder.GetFileAsync(relativeBundlePath).ConfigureAwait(false); + } + + internal async Task GetCurrentPackageHashAsync() + { + var info = await GetCurrentPackageInfoAsync().ConfigureAwait(false); + var currentPackageShortHash = (string)info[CodePushConstants.CurrentPackageKey]; + if (currentPackageShortHash == null) + { + return null; + } + + var currentPackageMetadata = await GetPackageAsync(currentPackageShortHash).ConfigureAwait(false); + return currentPackageMetadata == null ? null : (string)currentPackageMetadata[CodePushConstants.PackageHashKey]; + } + + internal async Task GetPackageAsync(string packageHash) + { + var packageFolder = await GetPackageFolderAsync(packageHash, false).ConfigureAwait(false); + if (packageFolder == null) + { + return null; + } + + try + { + var packageFile = await packageFolder.GetFileAsync(CodePushConstants.PackageFileName).ConfigureAwait(false); + return await CodePushUtils.GetJObjectFromFileAsync(packageFile).ConfigureAwait(false); + } + catch (IOException) + { + return null; + } + } + + internal async Task GetPackageFolderAsync(string packageHash, bool createIfNotExists) + { + var codePushFolder = await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false); + try + { + packageHash = ShortenPackageHash(packageHash); + return createIfNotExists + ? await codePushFolder.CreateFolderAsync(packageHash, CreationCollisionOption.OpenIfExists).ConfigureAwait(false) + : await codePushFolder.GetFolderAsync(packageHash).ConfigureAwait(false); + } + catch (FileNotFoundException) + { + return null; + } + catch (DirectoryNotFoundException) + { + return null; + } + } + + internal async Task GetPreviousPackageAsync() + { + var packageHash = await GetPreviousPackageHashAsync().ConfigureAwait(false); + return packageHash == null ? null : await GetPackageAsync(packageHash).ConfigureAwait(false); + } + + internal async Task GetPreviousPackageHashAsync() + { + var info = await GetCurrentPackageInfoAsync().ConfigureAwait(false); + var previousPackageShortHash = (string)info[CodePushConstants.PreviousPackageKey]; + if (previousPackageShortHash == null) + { + return null; + } + + var previousPackageMetadata = await GetPackageAsync(previousPackageShortHash).ConfigureAwait(false); + return previousPackageMetadata == null ? null : (string)previousPackageMetadata[CodePushConstants.PackageHashKey]; + } + + internal async Task InstallPackageAsync(JObject updatePackage, bool currentUpdateIsPending) + { + var packageHash = (string)updatePackage[CodePushConstants.PackageHashKey]; + var info = await GetCurrentPackageInfoAsync().ConfigureAwait(false); + if (currentUpdateIsPending) + { + // Don't back up current update to the "previous" position because + // it is an unverified update which should not be rolled back to. + var currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false); + if (currentPackageFolder != null) + { + await currentPackageFolder.DeleteAsync().ConfigureAwait(false); + } + } + else + { + var previousPackageHash = await GetPreviousPackageHashAsync().ConfigureAwait(false); + if (previousPackageHash != null && !previousPackageHash.Equals(packageHash)) + { + var previousPackageFolder = await GetPackageFolderAsync(previousPackageHash, false).ConfigureAwait(false); + if (previousPackageFolder != null) + { + await previousPackageFolder.DeleteAsync().ConfigureAwait(false); + } + } + + info[CodePushConstants.PreviousPackageKey] = info[CodePushConstants.CurrentPackageKey]; + } + + info[CodePushConstants.CurrentPackageKey] = packageHash; + await UpdateCurrentPackageInfoAsync(info).ConfigureAwait(false); + } + + internal async Task RollbackPackageAsync() + { + var info = await GetCurrentPackageInfoAsync().ConfigureAwait(false); + var currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false); + if (currentPackageFolder != null) + { + await currentPackageFolder.DeleteAsync().ConfigureAwait(false); + } + + info[CodePushConstants.CurrentPackageKey] = info[CodePushConstants.PreviousPackageKey]; + info[CodePushConstants.PreviousPackageKey] = null; + await UpdateCurrentPackageInfoAsync(info).ConfigureAwait(false); + } + + #endregion + + #region Private methods + + private async Task GetCurrentPackageFolderAsync() + { + var info = await GetCurrentPackageInfoAsync().ConfigureAwait(false); + var packageHash = (string)info[CodePushConstants.CurrentPackageKey]; + return packageHash == null ? null : await GetPackageFolderAsync(packageHash, false).ConfigureAwait(false); + } + + private async Task GetCurrentPackageInfoAsync() + { + var statusFile = await GetStatusFileAsync().ConfigureAwait(false); + return await CodePushUtils.GetJObjectFromFileAsync(statusFile).ConfigureAwait(false); + } + + private async Task GetDownloadFileAsync() + { + var codePushFolder = await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false); + return await codePushFolder.CreateFileAsync(CodePushConstants.DownloadFileName, CreationCollisionOption.OpenIfExists).ConfigureAwait(false); + } + + private async Task GetStatusFileAsync() + { + var codePushFolder = await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false); + return await codePushFolder.CreateFileAsync(CodePushConstants.StatusFileName, CreationCollisionOption.OpenIfExists).ConfigureAwait(false); + } + + private async Task GetUnzippedFolderAsync() + { + var codePushFolder = await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false); + return await codePushFolder.CreateFolderAsync(CodePushConstants.UnzippedFolderName, CreationCollisionOption.OpenIfExists).ConfigureAwait(false); + } + + private string ShortenPackageHash(string longPackageHash) + { + return longPackageHash.Substring(0, 8); + } + + private async Task UpdateCurrentPackageInfoAsync(JObject packageInfo) + { + var file = await GetStatusFileAsync().ConfigureAwait(false); + await file.WriteAllTextAsync(JsonConvert.SerializeObject(packageInfo)).ConfigureAwait(false); + } + #endregion + } +} diff --git a/windows/CodePush.Net46/UpdateUtils.cs b/windows/CodePush.Net46/UpdateUtils.cs new file mode 100644 index 000000000..c7e5ad0d8 --- /dev/null +++ b/windows/CodePush.Net46/UpdateUtils.cs @@ -0,0 +1,70 @@ +using CodePush.Net46.Adapters.Http; +using Newtonsoft.Json.Linq; +using PCLStorage; +using System; +using System.IO; +using System.Net; +using System.Threading.Tasks; + +namespace CodePush.ReactNative +{ + internal class UpdateUtils + { + internal async static Task CopyNecessaryFilesFromCurrentPackageAsync(IFile diffManifestFile, IFolder currentPackageFolder, IFolder newPackageFolder) + { + await FileUtils.MergeFoldersAsync(currentPackageFolder, newPackageFolder).ConfigureAwait(false); + JObject diffManifest = await CodePushUtils.GetJObjectFromFileAsync(diffManifestFile).ConfigureAwait(false); + var deletedFiles = (JArray)diffManifest["deletedFiles"]; + foreach (string fileNameToDelete in deletedFiles) + { + var fileToDelete = await newPackageFolder.GetFileAsync(fileNameToDelete).ConfigureAwait(false); + await fileToDelete.DeleteAsync().ConfigureAwait(false); + } + } + + internal async static Task FindJSBundleInUpdateContentsAsync(IFolder updateFolder, string expectedFileName) + { + foreach (IFile file in await updateFolder.GetFilesAsync().ConfigureAwait(false)) + { + string fileName = file.Name; + if (fileName.Equals(expectedFileName)) + { + return fileName; + } + } + + foreach (IFolder folder in await updateFolder.GetFoldersAsync().ConfigureAwait(false)) + { + string mainBundlePathInSubFolder = await FindJSBundleInUpdateContentsAsync(folder, expectedFileName).ConfigureAwait(false); + if (mainBundlePathInSubFolder != null) + { + return Path.Combine(folder.Name, mainBundlePathInSubFolder); + } + } + + return null; + } + + internal async static Task DownloadBundleAsync(string url, string fileName, IProgress downloadProgress) + { + var uri = new Uri(url); + var client = new WebClient(); + client.DownloadProgressChanged += (s, e) => + { + downloadProgress.Report(new HttpProgress + { + BytesReceived = (ulong)e.BytesReceived, //conversion long to ulong is safe + TotalBytesToReceive = (ulong)e.TotalBytesToReceive //because size can't be negative + }); + }; + + await client.DownloadFileTaskAsync(uri, fileName); + } + + internal static async Task GetCodePushFolderAsync() + { + var pathToCodePush = Path.Combine(CodePushUtils.GetAppFolder(), CodePushConstants.CodePushFolderPrefix); + return await FileSystem.Current.LocalStorage.CreateFolderAsync(pathToCodePush, CreationCollisionOption.OpenIfExists).ConfigureAwait(false); + } + } +} diff --git a/windows/CodePush.Net46/packages.config b/windows/CodePush.Net46/packages.config new file mode 100644 index 000000000..6ebb2f9df --- /dev/null +++ b/windows/CodePush.Net46/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/windows/CodePush.Shared/CodePush.Shared.projitems b/windows/CodePush.Shared/CodePush.Shared.projitems new file mode 100644 index 000000000..5f85c529c --- /dev/null +++ b/windows/CodePush.Shared/CodePush.Shared.projitems @@ -0,0 +1,21 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 4ad4c826-cc26-4f1d-b60d-b97b22f52e90 + + + CodePush.Shared + + + + + + + + + + + + \ No newline at end of file diff --git a/windows/CodePush.Shared/CodePush.Shared.shproj b/windows/CodePush.Shared/CodePush.Shared.shproj new file mode 100644 index 000000000..fc4e63705 --- /dev/null +++ b/windows/CodePush.Shared/CodePush.Shared.shproj @@ -0,0 +1,13 @@ + + + + 4ad4c826-cc26-4f1d-b60d-b97b22f52e90 + 14.0 + + + + + + + + diff --git a/windows/CodePushConstants.cs b/windows/CodePush.Shared/CodePushConstants.cs similarity index 95% rename from windows/CodePushConstants.cs rename to windows/CodePush.Shared/CodePushConstants.cs index d92a25713..1abc0f6e5 100644 --- a/windows/CodePushConstants.cs +++ b/windows/CodePush.Shared/CodePushConstants.cs @@ -2,7 +2,6 @@ { internal class CodePushConstants { - internal const string AssetsBundlePrefix = "ms-appx:///ReactAssets/"; internal const string BinaryModifiedTimeKey = "binaryModifiedTime"; internal const string CodePushServerUrl = "https://codepush.azurewebsites.net/"; internal const string CodePushFolderPrefix = "CodePush"; @@ -14,7 +13,6 @@ internal class CodePushConstants internal const string DownloadProgressEventName = "CodePushDownloadProgress"; internal const string DownloadUrlKey = "downloadUrl"; internal const string FailedUpdatesKey = "CODE_PUSH_FAILED_UPDATES"; - internal const string FileBundlePrefix = "ms-appdata:///local"; internal const string PackageFileName = "app.json"; internal const string PackageHashKey = "packageHash"; internal const string PendingUpdateHashKey = "hash"; @@ -27,5 +25,11 @@ internal class CodePushConstants internal const string RelativeBundlePathKey = "bundlePath"; internal const string StatusFileName = "codepush.json"; internal const string UnzippedFolderName = "unzipped"; +#if WINDOWS_UWP + internal const string AssetsBundlePrefix = "ms-appx:///ReactAssets/"; + internal const string FileBundlePrefix = "ms-appdata:///local"; +#else + internal const string AssetsBundlePrefix = "ReactAssets/"; +#endif } } diff --git a/windows/CodePushNativeModule.cs b/windows/CodePush.Shared/CodePushNativeModule.cs similarity index 95% rename from windows/CodePushNativeModule.cs rename to windows/CodePush.Shared/CodePushNativeModule.cs index 0cecebdcb..81c9fd16d 100644 --- a/windows/CodePushNativeModule.cs +++ b/windows/CodePush.Shared/CodePushNativeModule.cs @@ -7,7 +7,11 @@ using System.IO; using System.Reflection; using System.Threading.Tasks; +#if WINDOWS_UWP using Windows.Web.Http; +#else +using CodePush.Net46.Adapters.Http; +#endif namespace CodePush.ReactNative { @@ -57,7 +61,7 @@ public async void downloadUpdate(JObject updatePackage, bool notifyProgress, IPr { try { - updatePackage[CodePushConstants.BinaryModifiedTimeKey] = "" + await _codePush.GetBinaryResourcesModifiedTimeAsync().ConfigureAwait(false); + updatePackage[CodePushConstants.BinaryModifiedTimeKey] = "" + await FileUtils.GetBinaryResourcesModifiedTimeAsync(_codePush.AssetsBundleFileName).ConfigureAwait(false); await _codePush.UpdateManager.DownloadPackageAsync( updatePackage, _codePush.AssetsBundleFileName, @@ -194,7 +198,7 @@ public async void installUpdate(JObject updatePackage, InstallMode installMode, await LoadBundleAsync().ConfigureAwait(false); }); }; - + _minimumBackgroundListener = new MinimumBackgroundListener(loadBundleAction, minimumBackgroundDuration); _reactContext.AddLifecycleEventListener(_minimumBackgroundListener); } @@ -240,17 +244,22 @@ public async void restartApp(bool onlyIfUpdateIsPending) await LoadBundleAsync().ConfigureAwait(false); } } - + internal async Task LoadBundleAsync() { // #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 // #2) Update the locally stored JS bundle file path Type reactInstanceManagerType = typeof(ReactInstanceManager); diff --git a/windows/CodePushReactPackage.cs b/windows/CodePush.Shared/CodePushReactPackage.cs similarity index 77% rename from windows/CodePushReactPackage.cs rename to windows/CodePush.Shared/CodePushReactPackage.cs index 921af15cf..ce633ba16 100644 --- a/windows/CodePushReactPackage.cs +++ b/windows/CodePush.Shared/CodePushReactPackage.cs @@ -1,25 +1,18 @@ using Newtonsoft.Json.Linq; -using Newtonsoft.Json; using ReactNative; using ReactNative.Bridge; using ReactNative.Modules.Core; using ReactNative.UIManager; using System; using System.Collections.Generic; -using System.Reflection; using System.Threading.Tasks; -using Windows.ApplicationModel; -using Windows.Storage; -using Windows.Web.Http; + namespace CodePush.ReactNative { public sealed class CodePushReactPackage : IReactPackage { private static CodePushReactPackage CurrentInstance; - private static bool NeedToReportRollback = false; - - private CodePushNativeModule _codePushNativeModule; internal string AppVersion { get; private set; } internal string DeploymentKey { get; private set; } @@ -31,7 +24,7 @@ public sealed class CodePushReactPackage : IReactPackage public CodePushReactPackage(string deploymentKey, ReactPage mainPage) { - AppVersion = Package.Current.Id.Version.Major + "." + Package.Current.Id.Version.Minor + "." + Package.Current.Id.Version.Build; + AppVersion = CodePushUtils.GetAppVersion(); DeploymentKey = deploymentKey; MainPage = mainPage; UpdateManager = new UpdateManager(); @@ -84,8 +77,9 @@ public string GetJavaScriptBundleFile(string assetsBundleFileName) public async Task GetJavaScriptBundleFileAsync(string assetsBundleFileName) { AssetsBundleFileName = assetsBundleFileName; - string binaryJsBundleUrl = CodePushConstants.AssetsBundlePrefix + assetsBundleFileName; - var binaryResourcesModifiedTime = await GetBinaryResourcesModifiedTimeAsync().ConfigureAwait(false); + string binaryJsBundleUrl = CodePushUtils.GetAssetsBundlePrefix() + assetsBundleFileName; + + var binaryResourcesModifiedTime = await FileUtils.GetBinaryResourcesModifiedTimeAsync(AssetsBundleFileName).ConfigureAwait(false); var packageFile = await UpdateManager.GetCurrentPackageBundleAsync(AssetsBundleFileName).ConfigureAwait(false); if (packageFile == null) { @@ -111,7 +105,7 @@ public async Task GetJavaScriptBundleFileAsync(string assetsBundleFileNa { CodePushUtils.LogBundleUrl(packageFile.Path); IsRunningBinaryVersion = false; - return CodePushConstants.FileBundlePrefix + packageFile.Path.Replace(ApplicationData.Current.LocalFolder.Path, "").Replace("\\", "/"); + return CodePushUtils.GetFileBundlePrefix() + packageFile.Path.Replace(CodePushUtils.GetAppFolder(), "").Replace("\\", "/"); } else { @@ -128,17 +122,10 @@ public async Task GetJavaScriptBundleFileAsync(string assetsBundleFileNa } } - #endregion +#endregion - #region Internal methods +#region Internal methods - internal async Task GetBinaryResourcesModifiedTimeAsync() - { - var assetJSBundleFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(CodePushConstants.AssetsBundlePrefix + AssetsBundleFileName)).AsTask().ConfigureAwait(false); - var fileProperties = await assetJSBundleFile.GetBasicPropertiesAsync().AsTask().ConfigureAwait(false); - return fileProperties.DateModified.ToUnixTimeMilliseconds(); - } - internal void InitializeUpdateAfterRestart() { JObject pendingUpdate = SettingsManager.GetPendingUpdate(); @@ -150,7 +137,6 @@ internal void InitializeUpdateAfterRestart() // Pending update was initialized, but notifyApplicationReady was not called. // Therefore, deduce that it is a broken update and rollback. CodePushUtils.Log("Update did not finish loading the last time, rolling back to a previous version."); - NeedToReportRollback = true; RollbackPackageAsync().Wait(); } else @@ -159,7 +145,7 @@ internal void InitializeUpdateAfterRestart() // Clear the React dev bundle cache so that new updates can be loaded. if (MainPage.UseDeveloperSupport) { - ClearReactDevBundleCacheAsync().Wait(); + FileUtils.ClearReactDevBundleCacheAsync().Wait(); } // Mark that we tried to initialize the new update, so that if it crashes, // we will know that we need to rollback when the app next starts. @@ -175,18 +161,9 @@ internal async Task ClearUpdatesAsync() SettingsManager.RemoveFailedUpdates(); } - #endregion +#endregion - #region Private methods - - private async Task ClearReactDevBundleCacheAsync() - { - var devBundleCacheFile = (StorageFile)await ApplicationData.Current.LocalFolder.TryGetItemAsync(CodePushConstants.ReactDevBundleCacheFileName).AsTask().ConfigureAwait(false); - if (devBundleCacheFile != null) - { - await devBundleCacheFile.DeleteAsync().AsTask().ConfigureAwait(false); - } - } +#region Private methods private async Task RollbackPackageAsync() { @@ -196,6 +173,6 @@ private async Task RollbackPackageAsync() SettingsManager.RemovePendingUpdate(); } - #endregion +#endregion } } \ No newline at end of file diff --git a/windows/CodePush.Shared/CodePushUtils.cs b/windows/CodePush.Shared/CodePushUtils.cs new file mode 100644 index 000000000..7b934615d --- /dev/null +++ b/windows/CodePush.Shared/CodePushUtils.cs @@ -0,0 +1,74 @@ +using System; +using System.Diagnostics; +#if WINDOWS_UWP +using Windows.ApplicationModel; +using Windows.Storage; +#else +using System.IO; +#endif + +namespace CodePush.ReactNative +{ + internal partial class CodePushUtils + { + internal static void Log(string message) + { + Debug.WriteLine("[CodePush] " + message, CodePushConstants.ReactNativeLogCategory); + } + + internal static void LogBundleUrl(string path) + { + Log("Loading JS bundle from \"" + path + "\""); + } + + static string _deviceId = String.Empty; + + internal static string GetDeviceId() + { + //It's quite long operation, cache it + if (!String.IsNullOrEmpty(_deviceId)) + return _deviceId; + + _deviceId = GetDeviceIdImpl(); + return _deviceId; + } + + internal static string GetAppVersion() + { +#if WINDOWS_UWP + return Package.Current.Id.Version.Major + "." + Package.Current.Id.Version.Minor + "." + Package.Current.Id.Version.Build; +#else + var version = FileVersionInfo.GetVersionInfo(Environment.GetCommandLineArgs()[0]); + return $"{version.FileMajorPart}.{version.FileMinorPart}.{version.FileBuildPart}"; +#endif + } + + internal static string GetAppFolder() + { +#if WINDOWS_UWP + return ApplicationData.Current.LocalFolder.Path; +#else + return AppDomain.CurrentDomain.BaseDirectory; +#endif + } + + internal static string GetAssetsBundlePrefix() + { +#if WINDOWS_UWP + return CodePushConstants.AssetsBundlePrefix; +#else + return Path.Combine(GetAppFolder(), CodePushConstants.AssetsBundlePrefix); +#endif + } + + internal static string GetFileBundlePrefix() + { +#if WINDOWS_UWP + return CodePushConstants.FileBundlePrefix; +#else + return GetAppFolder(); +#endif + } + + } +} diff --git a/windows/InstallMode.cs b/windows/CodePush.Shared/InstallMode.cs similarity index 100% rename from windows/InstallMode.cs rename to windows/CodePush.Shared/InstallMode.cs diff --git a/windows/MinimumBackgroundListener.cs b/windows/CodePush.Shared/MinimumBackgroundListener.cs similarity index 100% rename from windows/MinimumBackgroundListener.cs rename to windows/CodePush.Shared/MinimumBackgroundListener.cs diff --git a/windows/SettingsManager.cs b/windows/CodePush.Shared/SettingsManager.cs similarity index 86% rename from windows/SettingsManager.cs rename to windows/CodePush.Shared/SettingsManager.cs index b8250f7b6..c68e91405 100644 --- a/windows/SettingsManager.cs +++ b/windows/CodePush.Shared/SettingsManager.cs @@ -1,13 +1,29 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; +#if WINDOWS_UWP using Windows.Storage; +#else +using CodePush.Net46.Adapters.Storage; +using System.IO; +#endif namespace CodePush.ReactNative { internal class SettingsManager { - private static ApplicationDataContainer Settings = ApplicationData.Current.LocalSettings.CreateContainer(CodePushConstants.CodePushPreferences, ApplicationDataCreateDisposition.Always); + private static ApplicationDataContainer Settings = null; + + static SettingsManager () + { + +#if WINDOWS_UWP + Settings = ApplicationData.Current.LocalSettings.CreateContainer(CodePushConstants.CodePushPreferences, ApplicationDataCreateDisposition.Always); +#else + var folder = UpdateUtils.GetCodePushFolderAsync().Result; + Settings = new ApplicationDataContainer(Path.Combine(folder.Path, CodePushConstants.CodePushPreferences)); +#endif + } public static JArray GetFailedUpdates() { diff --git a/windows/UpdateState.cs b/windows/CodePush.Shared/UpdateState.cs similarity index 100% rename from windows/UpdateState.cs rename to windows/CodePush.Shared/UpdateState.cs diff --git a/windows/.npmignore b/windows/CodePush/.gitignore similarity index 100% rename from windows/.npmignore rename to windows/CodePush/.gitignore diff --git a/windows/CodePush.csproj b/windows/CodePush/CodePush.csproj similarity index 82% rename from windows/CodePush.csproj rename to windows/CodePush/CodePush.csproj index c32ed741e..b5e54e6bf 100644 --- a/windows/CodePush.csproj +++ b/windows/CodePush/CodePush.csproj @@ -17,25 +17,6 @@ 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - prompt - 4 - x86 true @@ -107,18 +88,11 @@ - - - - - - - @@ -132,6 +106,7 @@ ReactNative + 14.0 diff --git a/windows/CodePushUtils.cs b/windows/CodePush/CodePushUtils.cs similarity index 72% rename from windows/CodePushUtils.cs rename to windows/CodePush/CodePushUtils.cs index f1478891f..23b929755 100644 --- a/windows/CodePushUtils.cs +++ b/windows/CodePush/CodePushUtils.cs @@ -1,6 +1,5 @@ using Newtonsoft.Json.Linq; using System; -using System.Diagnostics; using System.Threading.Tasks; using Windows.Storage; using Windows.Storage.Streams; @@ -8,7 +7,7 @@ namespace CodePush.ReactNative { - internal class CodePushUtils + internal partial class CodePushUtils { internal async static Task GetJObjectFromFileAsync(StorageFile file) { @@ -28,17 +27,7 @@ internal async static Task GetJObjectFromFileAsync(StorageFile file) } } - internal static void Log(string message) - { - Debug.WriteLine("[CodePush] " + message, CodePushConstants.ReactNativeLogCategory); - } - - internal static void LogBundleUrl(string path) - { - Log("Loading JS bundle from \"" + path + "\""); - } - - internal static string GetDeviceId() + static string GetDeviceIdImpl() { HardwareToken token = HardwareIdentification.GetPackageSpecificToken(null); IBuffer hardwareId = token.Id; diff --git a/windows/FileUtils.cs b/windows/CodePush/FileUtils.cs similarity index 52% rename from windows/FileUtils.cs rename to windows/CodePush/FileUtils.cs index 732fc3e75..639a0229f 100644 --- a/windows/FileUtils.cs +++ b/windows/CodePush/FileUtils.cs @@ -19,5 +19,22 @@ internal async static Task MergeFoldersAsync(StorageFolder source, StorageFolder await MergeFoldersAsync(sourceDirectory, nextTargetSubDir).ConfigureAwait(false); } } + + internal async static Task ClearReactDevBundleCacheAsync() + { + var devBundleCacheFile = (StorageFile)await ApplicationData.Current.LocalFolder.TryGetItemAsync(CodePushConstants.ReactDevBundleCacheFileName).AsTask().ConfigureAwait(false); + if (devBundleCacheFile != null) + { + await devBundleCacheFile.DeleteAsync().AsTask().ConfigureAwait(false); + } + } + + internal async static Task GetBinaryResourcesModifiedTimeAsync(string fileName) + { + var assetJSBundleFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(CodePushConstants.AssetsBundlePrefix + fileName)).AsTask().ConfigureAwait(false); + var fileProperties = await assetJSBundleFile.GetBasicPropertiesAsync().AsTask().ConfigureAwait(false); + return fileProperties.DateModified.ToUnixTimeMilliseconds(); + } + } } diff --git a/windows/Properties/AssemblyInfo.cs b/windows/CodePush/Properties/AssemblyInfo.cs similarity index 100% rename from windows/Properties/AssemblyInfo.cs rename to windows/CodePush/Properties/AssemblyInfo.cs diff --git a/windows/Properties/CodePush.rd.xml b/windows/CodePush/Properties/CodePush.rd.xml similarity index 100% rename from windows/Properties/CodePush.rd.xml rename to windows/CodePush/Properties/CodePush.rd.xml diff --git a/windows/UpdateManager.cs b/windows/CodePush/UpdateManager.cs similarity index 97% rename from windows/UpdateManager.cs rename to windows/CodePush/UpdateManager.cs index ae17a912c..9afb0f0cc 100644 --- a/windows/UpdateManager.cs +++ b/windows/CodePush/UpdateManager.cs @@ -22,13 +22,13 @@ internal async Task ClearUpdatesAsync() internal async Task DownloadPackageAsync(JObject updatePackage, string expectedBundleFileName, Progress downloadProgress) { - // Using its hash, get the folder where the new update will be saved + // Using its hash, get the folder where the new update will be saved StorageFolder codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false); var newUpdateHash = (string)updatePackage[CodePushConstants.PackageHashKey]; StorageFolder newUpdateFolder = await GetPackageFolderAsync(newUpdateHash, false).ConfigureAwait(false); if (newUpdateFolder != null) { - // This removes any stale data in newPackageFolderPath that could have been left + // This removes any stale data in newUpdateFolder that could have been left // uncleared due to a crash or error during the download or install process. await newUpdateFolder.DeleteAsync().AsTask().ConfigureAwait(false); } @@ -98,6 +98,11 @@ internal async Task DownloadPackageAsync(JObject updatePackage, string expectedB await downloadFile.RenameAsync(expectedBundleFileName).AsTask().ConfigureAwait(false); await downloadFile.MoveAsync(newUpdateFolder).AsTask().ConfigureAwait(false); } + /*TODO: ZipFile.ExtractToDirectory is not reliable and throws exceptions if: + - folder exists already + - path is too long + it needs to be handled + */ // Save metadata to the folder await FileIO.WriteTextAsync(newUpdateMetadataFile, JsonConvert.SerializeObject(updatePackage)).AsTask().ConfigureAwait(false); diff --git a/windows/UpdateUtils.cs b/windows/CodePush/UpdateUtils.cs similarity index 100% rename from windows/UpdateUtils.cs rename to windows/CodePush/UpdateUtils.cs diff --git a/windows/project.json b/windows/CodePush/project.json similarity index 100% rename from windows/project.json rename to windows/CodePush/project.json