React Native Windows >=0.63.11 Initial Implementation PR (#1994)

* Add React Native Windows 0.63.5+ support

* modify windows/.npmignore

* Update setup-windows.md

* Revert package.json changes

* Add newline at the end of added files

* Update demo app package.json to show minimum version

* Update setup-windows.md

* Update setup-windows.md

Co-authored-by: Aleksey <amoroz@uw.edu>
This commit is contained in:
alexmoroz15 2020-12-16 11:22:57 -08:00 коммит произвёл GitHub
Родитель b15a019f2c
Коммит 75785cbabc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
119 изменённых файлов: 22733 добавлений и 73 удалений

Просмотреть файл

@ -0,0 +1,6 @@
[android]
target = Google Inc.:Google APIs:23
[maven_repositories]
central = https://repo1.maven.org/maven2

Просмотреть файл

@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: '@react-native-community',
};

Просмотреть файл

@ -0,0 +1,73 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*
; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
node_modules/warning/.*
; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
[include]
[libs]
node_modules/react-native/interface.js
node_modules/react-native/flow/
[options]
emoji=true
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js
munge_underscores=true
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error
[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import
[version]
^0.122.0

1
Examples/CodePushDemoAppCpp/.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
*.pbxproj -text

63
Examples/CodePushDemoAppCpp/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,63 @@
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
# Visual Studio Code
#
.vscode/
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots
# Bundle artifact
*.jsbundle
# CocoaPods
/ios/Pods/

Просмотреть файл

@ -0,0 +1,6 @@
module.exports = {
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
};

Просмотреть файл

@ -0,0 +1 @@
{}

Просмотреть файл

@ -0,0 +1,177 @@
import React, { Component } from 'react';
import {
AppRegistry,
Dimensions,
Image,
SafeAreaView,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import CodePush from "react-native-code-push";
class App extends Component<{}> {
constructor() {
super();
this.state = { restartAllowed: true };
}
codePushStatusDidChange(syncStatus) {
switch(syncStatus) {
case CodePush.SyncStatus.CHECKING_FOR_UPDATE:
this.setState({ syncMessage: "Checking for update." });
break;
case CodePush.SyncStatus.DOWNLOADING_PACKAGE:
this.setState({ syncMessage: "Downloading package." });
break;
case CodePush.SyncStatus.AWAITING_USER_ACTION:
this.setState({ syncMessage: "Awaiting user action." });
break;
case CodePush.SyncStatus.INSTALLING_UPDATE:
this.setState({ syncMessage: "Installing update." });
break;
case CodePush.SyncStatus.UP_TO_DATE:
this.setState({ syncMessage: "App up to date.", progress: false });
break;
case CodePush.SyncStatus.UPDATE_IGNORED:
this.setState({ syncMessage: "Update cancelled by user.", progress: false });
break;
case CodePush.SyncStatus.UPDATE_INSTALLED:
this.setState({ syncMessage: "Update installed and will be applied on restart.", progress: false });
break;
case CodePush.SyncStatus.UNKNOWN_ERROR:
this.setState({ syncMessage: "An unknown error occurred.", progress: false });
break;
}
}
codePushDownloadDidProgress(progress) {
this.setState({ progress });
}
toggleAllowRestart() {
this.state.restartAllowed
? CodePush.disallowRestart()
: CodePush.allowRestart();
this.setState({ restartAllowed: !this.state.restartAllowed });
}
getUpdateMetadata() {
CodePush.getUpdateMetadata(CodePush.UpdateState.RUNNING)
.then((metadata: LocalPackage) => {
this.setState({ syncMessage: metadata ? JSON.stringify(metadata) : "Running binary version", progress: false });
}, (error: any) => {
this.setState({ syncMessage: "Error: " + error, progress: false });
});
}
/** Update is downloaded silently, and applied on restart (recommended) */
sync() {
CodePush.sync(
{},
this.codePushStatusDidChange.bind(this),
this.codePushDownloadDidProgress.bind(this)
);
}
/** Update pops a confirmation dialog, and then immediately reboots the app */
syncImmediate() {
CodePush.sync(
{ installMode: CodePush.InstallMode.IMMEDIATE, updateDialog: true },
this.codePushStatusDidChange.bind(this),
this.codePushDownloadDidProgress.bind(this)
);
}
restartApp() {
CodePush.restartApp();
}
render() {
let progressView;
if (this.state.progress) {
progressView = (
<Text style={styles.messages}>{this.state.progress.receivedBytes} of {this.state.progress.totalBytes} bytes received</Text>
);
}
return (
<SafeAreaView>
<ScrollView>
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to CodePush!
</Text>
<Text style={styles.welcome}>
Demo bundle
</Text>
<TouchableOpacity onPress={this.restartApp.bind(this)}>
<Text style={styles.syncButton}>Press to restart</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.sync.bind(this)}>
<Text style={styles.syncButton}>Press for background sync</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.syncImmediate.bind(this)}>
<Text style={styles.syncButton}>Press for dialog-driven sync</Text>
</TouchableOpacity>
{progressView}
<TouchableOpacity onPress={this.toggleAllowRestart.bind(this)}>
<Text style={styles.restartToggleButton}>Restart { this.state.restartAllowed ? "allowed" : "forbidden"}</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.getUpdateMetadata.bind(this)}>
<Text style={styles.syncButton}>Press for Update Metadata</Text>
</TouchableOpacity>
<Text style={styles.messages}>{this.state.syncMessage || ""}</Text>
</View>
</ScrollView>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
backgroundColor: "#F5FCFF",
paddingTop: 50
},
image: {
margin: 30,
width: Dimensions.get("window").width - 100,
height: 365 * (Dimensions.get("window").width - 100) / 651,
},
messages: {
marginTop: 30,
textAlign: "center",
},
restartToggleButton: {
color: "blue",
fontSize: 17
},
syncButton: {
color: "green",
fontSize: 17
},
welcome: {
fontSize: 20,
textAlign: "center",
margin: 20
},
});
/**
* Configured with a MANUAL check frequency for easy testing. For production apps, it is recommended to configure a
* different check frequency, such as ON_APP_START, for a 'hands-off' approach where CodePush.sync() does not
* need to be explicitly called. All options of CodePush.sync() are also available in this decorator.
*/
let codePushOptions = { checkFrequency: CodePush.CheckFrequency.MANUAL };
App = CodePush(codePushOptions)(App);
export default App;

Просмотреть файл

@ -0,0 +1,4 @@
{
"name": "CodePushDemoAppCpp",
"displayName": "CodePushDemoAppCpp"
}

Просмотреть файл

@ -0,0 +1,3 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};

Двоичные данные
Examples/CodePushDemoAppCpp/images/laptop_phone_howitworks.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 29 KiB

Просмотреть файл

@ -0,0 +1,9 @@
/**
* @format
*/
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);

Просмотреть файл

@ -0,0 +1,29 @@
/**
* Metro configuration for React Native
* https://github.com/facebook/react-native
*
* @format
*/
const path = require('path');
const blacklist = require('metro-config/src/defaults/blacklist');
module.exports = {
resolver: {
blacklistRE: blacklist([
// This stops "react-native run-windows" from causing the metro server to crash if its already running
new RegExp(
`${path.resolve(__dirname, 'windows').replace(/[/\\]/g, '/')}.*`,
),
// This prevents "react-native run-windows" from hitting: EBUSY: resource busy or locked, open msbuild.ProjectImports.zip
/.*\.ProjectImports\.zip/,
]),
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};

Просмотреть файл

@ -0,0 +1,31 @@
{
"name": "CodePushDemoAppCpp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start",
"test": "jest",
"lint": "eslint .",
"windows": "react-native run-windows"
},
"dependencies": {
"react": "^16.13.1",
"react-native": "^0.63.3",
"react-native-code-push": "^6.4.0",
"react-native-windows": "^0.63.6"
},
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/runtime": "^7.8.4",
"@react-native-community/eslint-config": "^1.1.0",
"appcenter-cli": "^2.7.2",
"babel-jest": "^25.1.0",
"eslint": "^6.5.1",
"jest": "^25.1.0",
"metro-react-native-babel-preset": "^0.59.0",
"react-test-renderer": "16.13.1"
},
"jest": {
"preset": "react-native"
}
}

92
Examples/CodePushDemoAppCpp/windows/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,92 @@
*AppPackages*
*BundleArtifacts*
#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
#Files generated by the VS build
**/Generated Files/**

Просмотреть файл

@ -0,0 +1,205 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29215.179
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CodePushDemoAppCpp", "CodePushDemoAppCpp\CodePushDemoAppCpp.vcxproj", "{609F44F6-01CF-4270-85A3-09F9CA10B434}"
ProjectSection(ProjectDependencies) = postProject
{F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\node_modules\react-native-windows\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}"
ProjectSection(ProjectDependencies) = postProject
{A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\node_modules\react-native-windows\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\node_modules\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Shared", "..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems", "{0CC28589-39E4-4288-B162-97B959F8B843}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Universal", "..\node_modules\react-native-windows\JSI\Universal\JSI.Universal.vcxproj", "{A62D504A-16B8-41D2-9F19-E2E86019E5E4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\node_modules\react-native-windows\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReactNative", "ReactNative", "{5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Shared", "..\node_modules\react-native-windows\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "..\node_modules\react-native-windows\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Include", "..\node_modules\react-native-windows\include\Include.vcxitems", "{EF074BA1-2D54-4D49-A28E-5E040B47CD2E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CodePush", "..\..\..\windows\CodePush\CodePush.vcxproj", "{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{0cc28589-39e4-4288-b162-97b959f8b843}*SharedItemsImports = 9
..\node_modules\react-native-windows\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9
..\node_modules\react-native-windows\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9
..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{a62d504a-16b8-41d2-9f19-e2e86019e5e4}*SharedItemsImports = 4
..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9
..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9
..\node_modules\react-native-windows\include\Include.vcxitems*{ef074ba1-2d54-4d49-a28e-5e040b47cd2e}*SharedItemsImports = 9
..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
..\node_modules\react-native-windows\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
..\node_modules\react-native-windows\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM.ActiveCfg = Debug|ARM
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM.Build.0 = Debug|ARM
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM.Deploy.0 = Debug|ARM
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM64.ActiveCfg = Debug|ARM64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM64.Build.0 = Debug|ARM64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM64.Deploy.0 = Debug|ARM64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x64.ActiveCfg = Debug|x64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x64.Build.0 = Debug|x64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x64.Deploy.0 = Debug|x64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x86.ActiveCfg = Debug|Win32
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x86.Build.0 = Debug|Win32
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x86.Deploy.0 = Debug|Win32
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM.ActiveCfg = Release|ARM
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM.Build.0 = Release|ARM
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM.Deploy.0 = Release|ARM
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM64.ActiveCfg = Release|ARM64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM64.Build.0 = Release|ARM64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM64.Deploy.0 = Release|ARM64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x64.ActiveCfg = Release|x64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x64.Build.0 = Release|x64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x64.Deploy.0 = Release|x64
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x86.ActiveCfg = Release|Win32
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x86.Build.0 = Release|Win32
{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x86.Deploy.0 = Release|Win32
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.ActiveCfg = Debug|ARM
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.Build.0 = Debug|ARM
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.ActiveCfg = Release|ARM
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.Build.0 = Release|ARM
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32
{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.ActiveCfg = Debug|ARM
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.Build.0 = Debug|ARM
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.Build.0 = Debug|x64
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.ActiveCfg = Debug|Win32
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.Build.0 = Debug|Win32
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.ActiveCfg = Release|ARM
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.Build.0 = Release|ARM
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.ActiveCfg = Release|ARM64
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.Build.0 = Release|ARM64
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.ActiveCfg = Release|x64
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.Build.0 = Release|x64
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.ActiveCfg = Release|Win32
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.Build.0 = Release|Win32
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.ActiveCfg = Debug|ARM
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.Build.0 = Debug|ARM
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.Build.0 = Debug|ARM64
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.ActiveCfg = Debug|x64
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.Build.0 = Debug|x64
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.ActiveCfg = Debug|Win32
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.Build.0 = Debug|Win32
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.ActiveCfg = Release|ARM
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.Build.0 = Release|ARM
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.ActiveCfg = Release|ARM64
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.Build.0 = Release|ARM64
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.ActiveCfg = Release|x64
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.ActiveCfg = Debug|ARM
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.Build.0 = Debug|ARM
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.ActiveCfg = Debug|ARM64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.Build.0 = Debug|ARM64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.ActiveCfg = Debug|x64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.Build.0 = Debug|x64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.ActiveCfg = Debug|Win32
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.Build.0 = Debug|Win32
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.ActiveCfg = Release|ARM
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.Build.0 = Release|ARM
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.ActiveCfg = Release|ARM64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.Build.0 = Release|ARM64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.ActiveCfg = Release|x64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.Build.0 = Release|x64
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.ActiveCfg = Release|Win32
{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.Build.0 = Release|Win32
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.ActiveCfg = Debug|ARM
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.Build.0 = Debug|ARM
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.Build.0 = Debug|ARM64
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.ActiveCfg = Debug|x64
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.Build.0 = Debug|x64
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.ActiveCfg = Debug|Win32
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.Build.0 = Debug|Win32
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.ActiveCfg = Release|ARM
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.Build.0 = Release|ARM
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.ActiveCfg = Release|ARM64
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.Build.0 = Release|ARM64
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.ActiveCfg = Release|x64
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|ARM.ActiveCfg = Debug|ARM
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|ARM.Build.0 = Debug|ARM
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|ARM64.ActiveCfg = Debug|ARM64
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|ARM64.Build.0 = Debug|ARM64
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|x64.ActiveCfg = Debug|x64
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|x64.Build.0 = Debug|x64
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|x86.ActiveCfg = Debug|Win32
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|x86.Build.0 = Debug|Win32
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|ARM.ActiveCfg = Release|ARM
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|ARM.Build.0 = Release|ARM
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|ARM64.ActiveCfg = Release|ARM64
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|ARM64.Build.0 = Release|ARM64
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|x64.ActiveCfg = Release|x64
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|x64.Build.0 = Release|x64
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|x86.ActiveCfg = Release|Win32
{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{0CC28589-39E4-4288-B162-97B959F8B843} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{A62D504A-16B8-41D2-9F19-E2E86019E5E4} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
{EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1 @@
/Bundle

Просмотреть файл

@ -0,0 +1,162 @@
#include "pch.h"
#include "App.h"
#include "AutolinkedNativeModules.g.h"
#include "ReactPackageProvider.h"
#include "winrt/Microsoft.CodePush.ReactNative.h"
#include "winrt/Windows.Storage.h"
#include "winrt/Windows.Foundation.h"
#include "winrt/Windows.Data.Json.h"
#include <string_view>
using namespace winrt::CodePushDemoAppCpp;
using namespace winrt::CodePushDemoAppCpp::implementation;
using namespace winrt;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::Storage;
using namespace Windows::Data::Json;
using namespace Microsoft::ReactNative;
using namespace std;
/// <summary>
/// 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().
/// </summary>
App::App() noexcept
{
#if BUNDLE
m_host.InstanceSettings().JavaScriptBundleFile(L"index.windows");
m_host.InstanceSettings().UseWebDebugger(false);
m_host.InstanceSettings().UseFastRefresh(false);
#else
m_host.InstanceSettings().JavaScriptMainModuleName(L"index");
m_host.InstanceSettings().UseWebDebugger(true);
m_host.InstanceSettings().UseFastRefresh(true);
#endif
#if _DEBUG
m_host.InstanceSettings().UseDeveloperSupport(true);
#else
m_host.InstanceSettings().UseDeveloperSupport(false);
#endif
RegisterAutolinkedNativeModulePackages(m_host.InstanceSettings().PackageProviders()); // Includes any autolinked modules
m_host.InstanceSettings().PackageProviders().Append(make<ReactPackageProvider>()); // Includes all modules in this project
InitializeComponent();
Suspending({ this, &App::OnSuspending });
#if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
UnhandledException([this](IInspectable const&, UnhandledExceptionEventArgs const& e)
{
if (IsDebuggerPresent())
{
auto errorMessage = e.Message();
__debugbreak();
}
});
#endif
}
/// <summary>
/// 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.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
void App::OnLaunched(activation::LaunchActivatedEventArgs const& e)
{
winrt::Microsoft::CodePush::ReactNative::CodePushConfig::SetHost(Host());
auto configMap{ winrt::single_threaded_map<hstring, hstring>() };
configMap.Insert(L"appVersion", L"1.0.0");
configMap.Insert(L"deploymentKey", L"<app deployment key>");
winrt::Microsoft::CodePush::ReactNative::CodePushConfig::Init(configMap);
Frame rootFrame{ nullptr };
auto content = Window::Current().Content();
if (content)
{
rootFrame = content.try_as<Frame>();
}
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
// Create a Frame to act as the navigation context and associate it with
// a SuspensionManager key
rootFrame = Frame();
rootFrame.NavigationFailed({ this, &App::OnNavigationFailed });
if (e.PreviousExecutionState() == ApplicationExecutionState::Terminated)
{
// Restore the saved session state only when appropriate, scheduling the
// final launch steps after the restore is complete
}
if (e.PrelaunchActivated() == false)
{
if (rootFrame.Content() == nullptr)
{
// 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.Navigate(xaml_typename<CodePushDemoAppCpp::MainPage>(), box_value(e.Arguments()));
}
// Place the frame in the current Window
Window::Current().Content(rootFrame);
// Ensure the current window is active
Window::Current().Activate();
}
}
else
{
if (e.PrelaunchActivated() == false)
{
if (rootFrame.Content() == nullptr)
{
// 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.Navigate(xaml_typename<CodePushDemoAppCpp::MainPage>(), box_value(e.Arguments()));
}
// Ensure the current window is active
Window::Current().Activate();
}
}
}
/// <summary>
/// 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.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
void App::OnSuspending([[maybe_unused]] IInspectable const& sender, [[maybe_unused]] SuspendingEventArgs const& e)
{
// Save application state and stop any background activity
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
void App::OnNavigationFailed(IInspectable const&, NavigationFailedEventArgs const& e)
{
throw hresult_error(E_FAIL, hstring(L"Failed to load Page ") + e.SourcePageType().Name);
}

Просмотреть файл

@ -0,0 +1,22 @@
#pragma once
#include "App.xaml.g.h"
#include "winrt/Microsoft.ReactNative.h"
namespace activation = winrt::Windows::ApplicationModel::Activation;
namespace winrt::CodePushDemoAppCpp::implementation
{
struct App : AppT<App>
{
App() noexcept;
void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs const&);
void OnSuspending(IInspectable const&, Windows::ApplicationModel::SuspendingEventArgs const&);
void OnNavigationFailed(IInspectable const&, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs const&);
winrt::Microsoft::ReactNative::ReactNativeHost& Host() noexcept { return m_host; }
private:
winrt::Microsoft::ReactNative::ReactNativeHost m_host;
};
} // namespace winrt::CodePushDemoAppCpp::implementation

Просмотреть файл

@ -0,0 +1,3 @@
namespace CodePushDemoAppCpp
{
}

Просмотреть файл

@ -0,0 +1,6 @@
<Application
x:Class="CodePushDemoAppCpp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CodePushDemoAppCpp">
</Application>

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 7.5 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.1 KiB

Просмотреть файл

@ -0,0 +1,18 @@
// AutolinkedNativeModules.g.cpp contents generated by "react-native autolink-windows"
// clang-format off
#include "pch.h"
#include "AutolinkedNativeModules.g.h"
// Includes from react-native-code-push-windows
#include "winrt/Microsoft.CodePush.ReactNative.h"
namespace winrt::Microsoft::ReactNative
{
void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::ReactNative::IReactPackageProvider> const& packageProviders)
{
// IReactPackageProviders from react-native-code-push-windows
packageProviders.Append(winrt::Microsoft::CodePush::ReactNative::ReactPackageProvider());
}
}

Просмотреть файл

@ -0,0 +1,10 @@
// AutolinkedNativeModules.g.h contents generated by "react-native autolink-windows"
#pragma once
namespace winrt::Microsoft::ReactNative
{
void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::ReactNative::IReactPackageProvider> const& packageProviders);
}

Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- AutolinkedNativeModules.g.targets contents generated by "react-native autolink-windows" -->
<ItemGroup>
<!-- Projects from react-native-code-push-windows -->
<!-- We use direct dependecy instead to develop the CodePush component -->
<!-- <ProjectReference Include="$(ProjectDir)..\..\node_modules\react-native-code-push-windows\windows\CodePush\CodePush.vcxproj">
<Project>{a6b6216e-fa3f-45e2-9c8e-40023cce9132}</Project>
</ProjectReference> -->
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,203 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="16.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup Label="Globals">
<CppWinRTOptimized>true</CppWinRTOptimized>
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
<MinimalCoreWin>true</MinimalCoreWin>
<ProjectGuid>{609f44f6-01cf-4270-85a3-09f9ca10b434}</ProjectGuid>
<ProjectName>CodePushDemoAppCpp</ProjectName>
<RootNamespace>CodePushDemoAppCpp</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>16.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.18362.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.16299.0</WindowsTargetPlatformMinVersion>
<PackageCertificateKeyFile>CodePushDemoAppCpp_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>5FBADC5BFA887CF7B571A1685542D69E23F6A0F2</PackageCertificateThumbprint>
<PackageCertificatePassword>password</PackageCertificatePassword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="ReactNativeWindowsProps">
<ReactNativeWindowsDir Condition="'$(ReactNativeWindowsDir)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\</ReactNativeWindowsDir>
<!-- This demo app uses bundle even in Debug mode -->
<UseBundle>true</UseBundle>
<!-- We use this project for developing the CodePush module. We disable autolinking to use it from the source location -->
<RunAutolinkCheck>false</RunAutolinkCheck>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="PropertySheet.props" />
</ImportGroup>
<ImportGroup Label="ReactNativeWindowsPropertySheets">
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\external\Microsoft.ReactNative.Uwp.CppApp.props" Condition="Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppApp.props')" />
<Import Project="..\packages\$(WinUIPackageProps)" Condition="'$(WinUIPackageProps)'!='' And Exists('..\packages\$(WinUIPackageProps)')" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="MainPage.h">
<DependentUpon>MainPage.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="ReactPackageProvider.h" />
<ClInclude Include="AutolinkedNativeModules.g.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="App.h">
<DependentUpon>App.xaml</DependentUpon>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<SubType>Designer</SubType>
</ApplicationDefinition>
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Image Include="Assets\LockScreenLogo.scale-200.png" />
<Image Include="Assets\SplashScreen.scale-200.png" />
<Image Include="Assets\Square150x150Logo.scale-200.png" />
<Image Include="Assets\Square44x44Logo.scale-200.png" />
<Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Image Include="Assets\StoreLogo.png" />
<Image Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="MainPage.cpp">
<DependentUpon>MainPage.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="ReactPackageProvider.cpp" />
<ClCompile Include="AutolinkedNativeModules.g.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="App.cpp">
<DependentUpon>App.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
</ItemGroup>
<ItemGroup>
<Midl Include="App.idl">
<DependentUpon>App.xaml</DependentUpon>
</Midl>
<Midl Include="MainPage.idl">
<DependentUpon>MainPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="PropertySheet.props" />
</ItemGroup>
<ItemGroup>
<Page Include="MainPage.xaml">
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\windows\CodePush\CodePush.vcxproj">
<Project>{a6b6216e-fa3f-45e2-9c8e-40023cce9132}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ReactNativeWindowsTargets">
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppApp.targets" Condition="Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppApp.targets')" />
</ImportGroup>
<Target Name="EnsureReactNativeWindowsTargets" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references targets in your node_modules\react-native-windows folder. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppApp.props')" Text="$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppApp.props'))" />
<Error Condition="!Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppApp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppApp.targets'))" />
</Target>
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\packages\$(WinUIPackageName).$(WinUIPackageVersion)\build\native\$(WinUIPackageName).targets" Condition="Exists('..\packages\$(WinUIPackageName).$(WinUIPackageVersion)\build\native\$(WinUIPackageName).targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\packages\$(WinUIPackageName).$(WinUIPackageVersion)\build\native\$(WinUIPackageName).targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\$(WinUIPackageName).$(WinUIPackageVersion)\build\native\$(WinUIPackageName).targets'))" />
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ApplicationDefinition Include="App.xaml" />
</ItemGroup>
<ItemGroup>
<Midl Include="App.idl" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="App.cpp" />
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="ReactPackageProvider.cpp" />
<ClCompile Include="AutolinkedNativeModules.g.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="App.h" />
<ClInclude Include="ReactPackageProvider.h" />
<ClInclude Include="AutolinkedNativeModules.g.h" />
</ItemGroup>
<ItemGroup>
<Image Include="Assets\Wide310x150Logo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\StoreLogo.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square150x150Logo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SplashScreen.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\LockScreenLogo.scale-200.png">
<Filter>Assets</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest" />
</ItemGroup>
<ItemGroup>
<Filter Include="Assets">
<UniqueIdentifier>{e48dc53e-40b1-40cb-970a-f89935452892}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Page Include="MainPage.xaml" />
</ItemGroup>
</Project>

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,22 @@
#include "pch.h"
#include "MainPage.h"
#if __has_include("MainPage.g.cpp")
#include "MainPage.g.cpp"
#endif
#include "App.h"
using namespace winrt;
using namespace Windows::UI::Xaml;
namespace winrt::CodePushDemoAppCpp::implementation
{
MainPage::MainPage()
{
InitializeComponent();
auto app = Application::Current().as<App>();
ReactRootView().ReactNativeHost(app->Host());
}
}

Просмотреть файл

@ -0,0 +1,19 @@
#pragma once
#include "MainPage.g.h"
#include <winrt/Microsoft.ReactNative.h>
namespace winrt::CodePushDemoAppCpp::implementation
{
struct MainPage : MainPageT<MainPage>
{
MainPage();
};
}
namespace winrt::CodePushDemoAppCpp::factory_implementation
{
struct MainPage : MainPageT<MainPage, implementation::MainPage>
{
};
}

Просмотреть файл

@ -0,0 +1,8 @@
namespace CodePushDemoAppCpp
{
[default_interface]
runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
{
MainPage();
}
}

Просмотреть файл

@ -0,0 +1,16 @@
<Page
x:Class="CodePushDemoAppCpp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CodePushDemoAppCpp"
xmlns:react="using:Microsoft.ReactNative"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<react:ReactRootView
x:Name="ReactRootView"
ComponentName="CodePushDemoAppCpp"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
MinHeight="400"/>
</Page>

Просмотреть файл

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
IgnorableNamespaces="uap mp">
<Identity
Name="bd8be20e-1e17-4299-8d0e-5862cc4428a8"
Publisher="CN=Aleksey"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="bd8be20e-1e17-4299-8d0e-5862cc4428a8" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>CodePushDemoAppCpp</DisplayName>
<PublisherDisplayName>Aleksey</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application
Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="CodePushDemoAppCpp.App">
<uap:VisualElements
DisplayName="CodePushDemoAppCpp"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png"
Description="CodePushDemoAppCpp"
BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"/>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
</Capabilities>
</Package>

Просмотреть файл

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<!--
To customize common C++/WinRT project properties:
* right-click the project node
* expand the Common Properties item
* select the C++/WinRT property page
For more advanced scenarios, and complete documentation, please see:
https://github.com/Microsoft/xlang/tree/master/src/package/cppwinrt/nuget
-->
<PropertyGroup />
<ItemDefinitionGroup />
</Project>

Просмотреть файл

@ -0,0 +1,16 @@
#include "pch.h"
#include "ReactPackageProvider.h"
#include "NativeModules.h"
using namespace winrt::Microsoft::ReactNative;
namespace winrt::CodePushDemoAppCpp::implementation
{
void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept
{
AddAttributedModules(packageBuilder);
}
} // namespace winrt::CodePushDemoAppCpp::implementation

Просмотреть файл

@ -0,0 +1,12 @@
#pragma once
#include "winrt/Microsoft.ReactNative.h"
namespace winrt::CodePushDemoAppCpp::implementation
{
struct ReactPackageProvider : winrt::implements<ReactPackageProvider, winrt::Microsoft::ReactNative::IReactPackageProvider>
{
public: // IReactPackageProvider
void CreatePackage(winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder) noexcept;
};
} // namespace winrt::CodePushDemoAppCpp::implementation

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.200615.7" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.3.191129002" targetFramework="native" />
</packages>

Просмотреть файл

@ -0,0 +1 @@
#include "pch.h"

Просмотреть файл

@ -0,0 +1,26 @@
#pragma once
#define NOMINMAX
#include <hstring.h>
#include <restrictederrorinfo.h>
#include <unknwn.h>
#include <windows.h>
#include <winrt/Windows.ApplicationModel.Activation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
#include <winrt/Windows.UI.Xaml.Controls.h>
#include <winrt/Windows.UI.Xaml.Data.h>
#include <winrt/Windows.UI.Xaml.Interop.h>
#include <winrt/Windows.UI.Xaml.Markup.h>
#include <winrt/Windows.UI.Xaml.Navigation.h>
#include <winrt/Windows.UI.Xaml.h>
#include <winrt/Microsoft.ReactNative.h>
#include <winrt/Microsoft.UI.Xaml.Automation.Peers.h>
#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h>
#include <winrt/Microsoft.UI.Xaml.Controls.h>
#include <winrt/Microsoft.UI.Xaml.Media.h>
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -2,9 +2,42 @@
Once you've acquired the CodePush plugin, you need to integrate it into the Visual Studio project of your React Native app and configure it correctly. To do this, take the following steps:
### Plugin Installation (Windows)
### Plugin Installation and Configuration for React Native Windows 0.63.6 version and above
1. Open the Visual Studio solution located at `windows\<AppName>\<AppName>.sln` within your app
#### Plugin Installation (Windows-npx)
Once the plugin has been downloaded, run `npx react-native autolink-windows` in your application's root directory to automatically add the CodePush c++ project to your application's windows solution file.
#### Plugin Configuration (Windows)
1. Replace the following files located at `windows/<app name>` with those in the CodePushDemoAppCpp example app in this repo found at `Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp`:
1. app.h
2. app.cpp
3. app.xaml
2. In the above files, replace any occurance of `CodePushDemoAppCpp` with the name of your application
3. Enter your application's app version and deployment key to the `configMap` object at the top of your app's `OnLaunched` method in `App.cpp`:
```c++
...
void App::OnLaunched(activation::LaunchActivatedEventArgs const& e)
{
winrt::Microsoft::CodePush::ReactNative::CodePushConfig::SetHost(Host());
auto configMap{ winrt::single_threaded_map<hstring, hstring>() };
configMap.Insert(L"appVersion", L"1.0.0");
configMap.Insert(L"deploymentKey", L"<app deployment key>");
winrt::Microsoft::CodePush::ReactNative::CodePushConfig::Init(configMap);
...
}
...
```
### Plugin Installation and Configuration for React Native Windows lower than 0.60
#### Plugin Installation (Windows)
1. Open the Visual Studio solution located at `windows-legacy\<AppName>\<AppName>.sln` within your app
2. Right-click the solution node in the `Solution Explorer` window and select the `Add -> Existing Project...` menu item
@ -20,7 +53,7 @@ Once you've acquired the CodePush plugin, you need to integrate it into the Visu
![Add Reference Dialog](https://cloud.githubusercontent.com/assets/116461/14467147/cb805b6e-008e-11e6-964f-f856c59b65af.PNG)
### Plugin Configuration (Windows)
#### Plugin Configuration (Windows)
After installing the plugin, you need to configure your app to consult CodePush for the location of your JS bundle, since it will "take control" of managing the current and all future versions. To do this, update the `MainReactNativeHost.cs` file to use CodePush via the following changes:

78
windows-legacy/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,78 @@
*AppPackages*
*BundleArtifacts*
*ReactAssets*
#OS junk files
[Tt]humbs.db
*.DS_Store
#Visual Studio files
*.[Oo]bj
*.user
*.aps
*.pch
*.vspscc
*.vssscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.[Cc]ache
*.ilk
*.log
*.lib
*.sbr
*.sdf
*.opensdf
*.opendb
*.unsuccessfulbuild
ipch/
[Oo]bj/
[Bb]in
[Dd]ebug*/
[Rr]elease*/
Ankh.NoLoad
#MonoDevelop
*.pidb
*.userprefs
#Tooling
_ReSharper*/
*.resharper
[Tt]est[Rr]esult*
*.sass-cache
#Project files
[Bb]uild/
#Subversion files
.svn
# Office Temp Files
~$*
# vim Temp Files
*~
#NuGet
packages/
*.nupkg
#ncrunch
*ncrunch*
*crunch*.local.xml
# visual studio database projects
*.dbmdl
#Test files
*.testsettings
#Other files
*.DotSettings
.vs/
*project.lock.json

Просмотреть файл

@ -0,0 +1,8 @@
# Make sure we don't publish build artifacts to NPM
ARM/
Debug/
x64/
x86/
bin/
obj/
.vs/

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

424
windows/.gitignore поставляемый
Просмотреть файл

@ -1,78 +1,362 @@
*AppPackages*
*BundleArtifacts*
*ReactAssets*
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
#OS junk files
[Tt]humbs.db
*.DS_Store
#Visual Studio files
*.[Oo]bj
*.user
*.aps
*.pch
*.vspscc
*.vssscc
*_i.c
*_p.c
*.ncb
# User-specific files
*.rsuser
*.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
*.user
*.userosscache
*.sln.docstates
#MonoDevelop
*.pidb
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
#Tooling
_ReSharper*/
*.resharper
[Tt]est[Rr]esult*
*.sass-cache
# Mono auto generated files
mono_crash.*
#Project files
[Bb]uild/
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
#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
# Visual Studio 2015/2017 cache/options directory
.vs/
*project.lock.json
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd

Просмотреть файл

@ -6,3 +6,6 @@ x86/
bin/
obj/
.vs/
# Don't publish settings used for developement
Directory.Build.props

Просмотреть файл

@ -0,0 +1,11 @@
# Make sure we don't publish build artifacts to NPM
.vs/
ARM/
ARM64/
x64/
x86/
Debug/
Release/
bin/
obj/
Generated Files/

Просмотреть файл

@ -0,0 +1,3 @@
EXPORTS
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE

Просмотреть файл

@ -0,0 +1,199 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup Label="Globals">
<CppWinRTOptimized>true</CppWinRTOptimized>
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
<CppWinRTGenerateWindowsMetadata>true</CppWinRTGenerateWindowsMetadata>
<MinimalCoreWin>true</MinimalCoreWin>
<ProjectGuid>{a6b6216e-fa3f-45e2-9c8e-40023cce9132}</ProjectGuid>
<ProjectName>CodePush</ProjectName>
<RootNamespace>Microsoft.CodePush.ReactNative</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.18362.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="ReactNativeWindowsProps">
<ReactNativeWindowsDir Condition="'$(ReactNativeWindowsDir)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\</ReactNativeWindowsDir>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="PropertySheet.props" />
</ImportGroup>
<ImportGroup Label="ReactNativeWindowsPropertySheets">
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.props" Condition="Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.props')" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<!--Temporarily disable cppwinrt heap enforcement to work around xaml compiler generated std::shared_ptr use -->
<AdditionalOptions Condition="'$(CppWinRTHeapEnforcement)'==''">/DWINRT_NO_MAKE_DETECTION %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>
</DisableSpecificWarnings>
<PreprocessorDefinitions>_WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateWindowsMetadata>true</GenerateWindowsMetadata>
<ModuleDefinitionFile>CodePush.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="CodePushConfig.h" />
<ClInclude Include="CodePushDownloadHandler.h" />
<ClInclude Include="CodePushNativeModule.h" />
<ClInclude Include="CodePushPackage.h" />
<ClInclude Include="CodePushTelemetryManager.h" />
<ClInclude Include="CodePushUpdateUtils.h" />
<ClInclude Include="CodePushUtils.h" />
<ClInclude Include="FileUtils.h" />
<ClInclude Include="miniz\miniz.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="ReactPackageProvider.h">
<DependentUpon>ReactPackageProvider.idl</DependentUpon>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CodePushConfig.cpp" />
<ClCompile Include="CodePushDownloadHandler.cpp" />
<ClCompile Include="CodePushNativeModule.cpp" />
<ClCompile Include="CodePushPackage.cpp" />
<ClCompile Include="CodePushTelemetryManager.cpp" />
<ClCompile Include="CodePushUpdateUtils.cpp" />
<ClCompile Include="CodePushUtils.cpp" />
<ClCompile Include="FileUtils.cpp" />
<ClCompile Include="miniz\miniz.c">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="ReactPackageProvider.cpp">
<DependentUpon>ReactPackageProvider.idl</DependentUpon>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Midl Include="CodePushConfig.idl" />
<Midl Include="ReactPackageProvider.idl" />
</ItemGroup>
<ItemGroup>
<None Include="CodePush.def" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="PropertySheet.props" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ReactNativeWindowsTargets">
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.targets" Condition="Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.targets')" />
</ImportGroup>
<Target Name="EnsureReactNativeWindowsTargets" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references targets in your node_modules\react-native-windows folder that are missing. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.props')" Text="$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.props'))" />
<Error Condition="!Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Uwp.CppLib.targets'))" />
</Target>
<ImportGroup Label="ExtensionTargets">
<Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200615.7\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
<ItemGroup>
<ProjectReference Update="$(ReactNativeWindowsDir)\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj">
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
</ProjectReference>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Resources">
<UniqueIdentifier>accd3aa8-1ba0-4223-9bbe-0c431709210b</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="CodePush">
<UniqueIdentifier>{c2eae772-39a8-4b12-aad7-60e9ca2072ef}</UniqueIdentifier>
</Filter>
<Filter Include="miniz">
<UniqueIdentifier>{53513ea0-fe7c-4f69-8d3e-c1a9efbb7333}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="miniz\miniz.c">
<Filter>miniz</Filter>
</ClCompile>
<ClCompile Include="CodePushConfig.cpp">
<Filter>CodePush</Filter>
</ClCompile>
<ClCompile Include="CodePushDownloadHandler.cpp">
<Filter>CodePush</Filter>
</ClCompile>
<ClCompile Include="CodePushNativeModule.cpp">
<Filter>CodePush</Filter>
</ClCompile>
<ClCompile Include="CodePushPackage.cpp">
<Filter>CodePush</Filter>
</ClCompile>
<ClCompile Include="CodePushTelemetryManager.cpp">
<Filter>CodePush</Filter>
</ClCompile>
<ClCompile Include="CodePushUpdateUtils.cpp">
<Filter>CodePush</Filter>
</ClCompile>
<ClCompile Include="CodePushUtils.cpp">
<Filter>CodePush</Filter>
</ClCompile>
<ClCompile Include="FileUtils.cpp">
<Filter>CodePush</Filter>
</ClCompile>
<ClCompile Include="ReactPackageProvider.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="miniz\miniz.h">
<Filter>miniz</Filter>
</ClInclude>
<ClInclude Include="CodePushConfig.h">
<Filter>CodePush</Filter>
</ClInclude>
<ClInclude Include="CodePushDownloadHandler.h">
<Filter>CodePush</Filter>
</ClInclude>
<ClInclude Include="CodePushNativeModule.h">
<Filter>CodePush</Filter>
</ClInclude>
<ClInclude Include="CodePushPackage.h">
<Filter>CodePush</Filter>
</ClInclude>
<ClInclude Include="CodePushTelemetryManager.h">
<Filter>CodePush</Filter>
</ClInclude>
<ClInclude Include="CodePushUpdateUtils.h">
<Filter>CodePush</Filter>
</ClInclude>
<ClInclude Include="CodePushUtils.h">
<Filter>CodePush</Filter>
</ClInclude>
<ClInclude Include="FileUtils.h">
<Filter>CodePush</Filter>
</ClInclude>
<ClInclude Include="ReactPackageProvider.h" />
</ItemGroup>
<ItemGroup>
<None Include="CodePush.def" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
</ItemGroup>
<ItemGroup>
<Midl Include="ReactPackageProvider.idl" />
<Midl Include="CodePushConfig.idl">
<Filter>CodePush</Filter>
</Midl>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,104 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "CodePushConfig.h"
#include "CodePushConfig.g.cpp"
#include "CodePushNativeModule.h"
#include "winrt/Windows.Foundation.Collections.h"
#include "winrt/Windows.Storage.h"
namespace winrt::Microsoft::CodePush::ReactNative::implementation
{
using namespace Windows::Storage;
using namespace Windows::Data::Json;
using namespace Windows::Foundation::Collections;
CodePushConfig CodePushConfig::s_currentConfig{};
/*static*/ CodePushConfig& CodePushConfig::Current() noexcept
{
return s_currentConfig;
}
JsonObject CodePushConfig::GetConfiguration()
{
JsonObject configObject;
for (const auto& pair : m_configuration)
{
configObject.Insert(pair.Key(), JsonValue::CreateStringValue(pair.Value()));
}
return configObject;
}
/*static*/ void CodePushConfig::Init(IMap<hstring, hstring> const& configMap) noexcept
{
std::optional<hstring> appVersion;
std::optional<hstring> buildVersion;
std::optional<hstring> deploymentKey;
std::optional<hstring> publicKey;
std::optional<hstring> serverUrl;
if (configMap != nullptr)
{
appVersion = configMap.TryLookup(AppVersionConfigKey);
buildVersion = configMap.TryLookup(BuildVersionConfigKey);
deploymentKey = configMap.TryLookup(DeploymentKeyConfigKey);
publicKey = configMap.TryLookup(PublicKeyKey);
serverUrl = configMap.TryLookup(ServerURLConfigKey);
}
s_currentConfig.m_configuration = winrt::single_threaded_map<hstring, hstring>();
auto addToConfiguration = [=](std::wstring_view key, std::optional<hstring> optValue) {
if (optValue.has_value())
{
s_currentConfig.m_configuration.Insert(key, optValue.value());
}
};
auto localSettings{ ::Microsoft::CodePush::ReactNative::CodePushNativeModule::GetLocalSettings() };
hstring clientUniqueId;
auto clientUniqueIdData{ localSettings.Values().TryLookup(ClientUniqueIDConfigKey) };
if (clientUniqueIdData == nullptr)
{
auto newGuid{ GuidHelper::CreateNewGuid() };
clientUniqueId = to_hstring(newGuid);
localSettings.Values().Insert(ClientUniqueIDConfigKey, box_value(clientUniqueId));
}
else
{
clientUniqueId = unbox_value<hstring>(clientUniqueIdData);
}
addToConfiguration(AppVersionConfigKey, appVersion);
addToConfiguration(BuildVersionConfigKey, buildVersion);
addToConfiguration(DeploymentKeyConfigKey, deploymentKey);
addToConfiguration(PublicKeyKey, publicKey);
addToConfiguration(ServerURLConfigKey, serverUrl);
s_currentConfig.m_configuration.Insert(ClientUniqueIDConfigKey, clientUniqueId);
if (!serverUrl.has_value())
{
s_currentConfig.m_configuration.Insert(ServerURLConfigKey, L"https://codepush.appcenter.ms/");
}
::Microsoft::CodePush::ReactNative::CodePushNativeModule::LoadBundle();
}
hstring CodePushConfig::QueryConfig(std::wstring_view key)
{
auto value{ m_configuration.TryLookup(key) };
if (value.has_value())
{
return value.value();
}
return L"";
}
/*static*/ void CodePushConfig::SetHost(Microsoft::ReactNative::ReactNativeHost const& host) noexcept
{
::Microsoft::CodePush::ReactNative::CodePushNativeModule::SetHost(host);
}
}

Просмотреть файл

@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "CodePushConfig.g.h"
#include "NativeModules.h"
#include <string_view>
#include "winrt/Microsoft.ReactNative.h"
#include "winrt/Windows.Data.Json.h"
#include "winrt/Windows.Foundation.Collections.h"
namespace winrt::Microsoft::CodePush::ReactNative::implementation
{
struct CodePushConfig : CodePushConfigT<CodePushConfig>
{
CodePushConfig() = default;
static void Init(Windows::Foundation::Collections::IMap<hstring, hstring> const& configMap) noexcept;
static void SetHost(Microsoft::ReactNative::ReactNativeHost const& host) noexcept;
static CodePushConfig& Current() noexcept;
hstring GetAppVersion() { return QueryConfig(AppVersionConfigKey); }
void SetAppVersion(std::wstring_view appVersion) { m_configuration.Insert(AppVersionConfigKey, appVersion); }
hstring GetBuildVersion() { return QueryConfig(BuildVersionConfigKey); }
Windows::Data::Json::JsonObject GetConfiguration();
hstring GetDeploymentKey() { return QueryConfig(DeploymentKeyConfigKey); }
void SetDeploymentKey(std::wstring_view deploymentKey) { m_configuration.Insert(DeploymentKeyConfigKey, deploymentKey); }
hstring GetServerUrl() { return QueryConfig(ServerURLConfigKey); }
void SetServerUrl(std::wstring_view serverUrl) { m_configuration.Insert(ServerURLConfigKey, serverUrl); }
hstring GetPublicKey() { return QueryConfig(PublicKeyKey); }
void SetPublicKey(std::wstring_view publicKey) { m_configuration.Insert(PublicKeyKey, publicKey); }
private:
static constexpr std::wstring_view AppVersionConfigKey{ L"appVersion" };
static constexpr std::wstring_view BuildVersionConfigKey{ L"buildVersion" };
static constexpr std::wstring_view ClientUniqueIDConfigKey{ L"clientUniqueId" };
static constexpr std::wstring_view DeploymentKeyConfigKey{ L"deploymentKey" };
static constexpr std::wstring_view ServerURLConfigKey{ L"serverUrl" };
static constexpr std::wstring_view PublicKeyKey{ L"publicKey" };
Windows::Foundation::Collections::IMap<hstring, hstring> m_configuration;
static CodePushConfig s_currentConfig;
hstring QueryConfig(std::wstring_view key);
};
}
namespace winrt::Microsoft::CodePush::ReactNative::factory_implementation
{
struct CodePushConfig : CodePushConfigT<CodePushConfig, implementation::CodePushConfig>
{
};
}
namespace Microsoft::CodePush::ReactNative
{
using winrt::Microsoft::CodePush::ReactNative::implementation::CodePushConfig;
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
namespace Microsoft.CodePush.ReactNative
{
[webhosthidden]
[default_interface]
runtimeclass CodePushConfig {
static void Init(IMap<String, String> configMap);
static void SetHost(Microsoft.ReactNative.ReactNativeHost host);
};
} // namespace CppModule

Просмотреть файл

@ -0,0 +1,73 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "winrt/Windows.Data.Json.h"
#include "winrt/Windows.Foundation.h"
#include "winrt/Windows.Storage.h"
#include "winrt/Windows.Storage.Streams.h"
#include "winrt/Windows.Web.Http.h"
#include "winrt/Windows.Web.Http.Headers.h"
#include "CodePushDownloadHandler.h"
namespace Microsoft::CodePush::ReactNative
{
using namespace winrt;
using namespace Windows::Data::Json;
using namespace Windows::Foundation;
using namespace Windows::Storage;
using namespace Windows::Storage::Streams;
using namespace Windows::Web::Http;
CodePushDownloadHandler::CodePushDownloadHandler(
StorageFile downloadFile,
std::function<void(int64_t, int64_t)> progressCallback) :
receivedContentLength(0),
expectedContentLength(0),
progressCallback(progressCallback),
downloadFile(downloadFile) {}
IAsyncOperation<bool> CodePushDownloadHandler::Download(std::wstring_view url)
{
HttpClient client;
auto headers{ client.DefaultRequestHeaders() };
headers.Append(L"Accept-Encoding", L"identity");
HttpRequestMessage reqm{ HttpMethod::Get(), Uri(url) };
auto resm{ co_await client.SendRequestAsync(reqm, HttpCompletionOption::ResponseHeadersRead) };
expectedContentLength = resm.Content().Headers().ContentLength().GetInt64();
auto inputStream{ co_await resm.Content().ReadAsInputStreamAsync() };
auto outputStream{ co_await downloadFile.OpenAsync(FileAccessMode::ReadWrite) };
uint8_t header[4] = {};
for (;;)
{
auto outputBuffer{ co_await inputStream.ReadAsync(Buffer{ BufferSize }, BufferSize, InputStreamOptions::None) };
if (outputBuffer.Length() == 0)
{
break;
}
co_await outputStream.WriteAsync(outputBuffer);
if (receivedContentLength < ARRAYSIZE(header))
{
for (uint32_t i{ static_cast<uint32_t>(receivedContentLength) }; i < min(ARRAYSIZE(header), outputBuffer.Length()); i++)
{
header[i] = outputBuffer.data()[i];
}
}
receivedContentLength += outputBuffer.Length();
progressCallback(/*expectedContentLength*/ expectedContentLength, /*receivedContentLength*/ receivedContentLength);
}
bool isZip{ header[0] == 'P' && header[1] == 'K' && header[2] == 3 && header[3] == 4 };
co_return isZip;
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "winrt/Windows.Storage.h"
#include "winrt/Windows.Foundation.h"
#include "winrt/Windows.Data.Json.h"
#include <string_view>
#include <functional>
namespace Microsoft::CodePush::ReactNative
{
struct CodePushDownloadHandler
{
winrt::Windows::Storage::StorageFile downloadFile;
int64_t expectedContentLength;
int64_t receivedContentLength;
std::function<void(int64_t, int64_t)> progressCallback;
std::wstring_view downloadUrl;
CodePushDownloadHandler(
winrt::Windows::Storage::StorageFile downloadFile,
std::function<void(int64_t, int64_t)> progressCallback);
// Returns true if the downloaded file is a zip file
winrt::Windows::Foundation::IAsyncOperation<bool> Download(std::wstring_view url);
private:
static constexpr uint32_t BufferSize{ 256 * 1024 };
};
}

Просмотреть файл

@ -0,0 +1,955 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "CodePushNativeModule.h"
#include "CodePushUtils.h"
#include "CodePushUpdateUtils.h"
#include "CodePushPackage.h"
#include "CodePushTelemetryManager.h"
#include "CodePushConfig.h"
#include "CodePushUtils.h"
#include <string_view>
#include "miniz/miniz.h"
#include "winrt/Windows.ApplicationModel.h"
#include "winrt/Windows.Data.Json.h"
#include "winrt/Windows.Storage.FileProperties.h"
#include "ReactPackageProvider.h"
namespace Microsoft::CodePush::ReactNative
{
using namespace winrt;
using namespace winrt::Microsoft::ReactNative;
using namespace Windows::Data::Json;
using namespace Windows::Storage;
using namespace Windows::Foundation;
ReactNativeHost CodePushNativeModule::s_host{};
CodePushNativeModule::CodePushInstallMode CodePushNativeModule::s_installMode{};
bool CodePushNativeModule::isRunningBinaryVersion{ false };
bool CodePushNativeModule::needToReportRollback{ false };
/*static*/ bool CodePushNativeModule::s_initialized{ false };
/*static*/ hstring CodePushNativeModule::s_javaScriptBundleFileName{ L"index.windows" };
/*static*/ IAsyncOperation<StorageFile> CodePushNativeModule::GetBinaryBundleAsync()
{
auto appXFolder{ Windows::ApplicationModel::Package::Current().InstalledLocation() };
auto bundleFolder{ (co_await appXFolder.TryGetItemAsync(L"Bundle")).try_as<StorageFolder>() };
if (bundleFolder == nullptr)
{
co_return nullptr;
}
auto bundleFile{ (co_await bundleFolder.TryGetItemAsync(s_javaScriptBundleFileName + BundleExtension)).try_as<StorageFile>() };
co_return bundleFile;
}
/*static*/ IAsyncOperation<StorageFile> CodePushNativeModule::GetBundleFileAsync()
{
auto bundleFileName{ s_host.InstanceSettings().JavaScriptBundleFile() };
if (!bundleFileName.empty())
{
s_javaScriptBundleFileName = bundleFileName;
}
auto packageBundle{ co_await CodePushPackage::GetCurrentPackageBundleAsync() };
auto binaryBundle{ co_await GetBinaryBundleAsync() };
if (packageBundle == nullptr)
{
CodePushUtils::LogBundleUrl(binaryBundle);
isRunningBinaryVersion = true;
co_return binaryBundle;
}
auto binaryAppVersion{ CodePushConfig::Current().GetAppVersion() };
auto currentPackageMetadata{ co_await CodePushPackage::GetCurrentPackageAsync() };
if (currentPackageMetadata == nullptr)
{
CodePushUtils::LogBundleUrl(binaryBundle);
isRunningBinaryVersion = true;
co_return binaryBundle;
}
auto packageDate{ currentPackageMetadata.GetNamedString(BinaryBundleDateKey, L"") };
auto packageAppVersion{ currentPackageMetadata.GetNamedString(AppVersionKey, L"") };
if ((co_await CodePushUpdateUtils::ModifiedDateStringOfFileAsync(binaryBundle)) == packageDate && binaryAppVersion == packageAppVersion)
{
// Return package file because it is newer than the JS bundle in the AppX folder
CodePushUtils::LogBundleUrl(packageBundle);
isRunningBinaryVersion = false;
co_return packageBundle;
}
else
{
auto isRelease{ false };
#ifndef _DEBUG
isRelease = true;
#endif
if (isRelease || binaryAppVersion != packageAppVersion)
{
co_await ClearUpdatesStaticAsync();
}
CodePushUtils::LogBundleUrl(binaryBundle);
isRunningBinaryVersion = true;
co_return binaryBundle;
}
}
/*static*/ IAsyncOperation<StorageFolder> CodePushNativeModule::GetBundleAssetsFolderAsync()
{
auto appXFolder{ Windows::ApplicationModel::Package::Current().InstalledLocation() };
auto bundleFolder{ (co_await appXFolder.TryGetItemAsync(L"Bundle")).try_as<StorageFolder>() };
if (bundleFolder != nullptr)
{
auto bundleAssetsFolder{ (co_await bundleFolder.TryGetItemAsync(CodePushUpdateUtils::AssetsFolderName)).try_as<StorageFolder>() };
co_return bundleAssetsFolder;
}
co_return nullptr;
}
// Rather than store files in the library files, CodePush for ReactNativeWindows will use AppData folders.
/*static*/ StorageFolder CodePushNativeModule::GetLocalStorageFolder()
{
return ApplicationData::Current().LocalFolder();
}
/*static*/ ApplicationDataContainer CodePushNativeModule::GetLocalSettings()
{
return ApplicationData::Current().LocalSettings();
}
void CodePushNativeModule::OverrideAppVersion(std::wstring_view appVersion)
{
CodePushConfig::Current().SetAppVersion(appVersion);
}
void CodePushNativeModule::SetDeploymentKey(std::wstring_view deploymentKey)
{
CodePushConfig::Current().SetDeploymentKey(deploymentKey);
}
/*
* This method checks to see whether a specific package hash
* has previously failed installation.
*/
bool CodePushNativeModule::IsFailedHash(std::wstring_view packageHash)
{
auto localSettings{ GetLocalSettings() };
auto failedUpdatesData{ localSettings.Values().TryLookup(FailedUpdatesKey) };
if (failedUpdatesData == nullptr)
{
return false;
}
auto failedUpdatesString{ unbox_value<hstring>(failedUpdatesData) };
JsonArray failedUpdates;
auto success{ JsonArray::TryParse(failedUpdatesString, failedUpdates) };
if (!success || packageHash.empty())
{
return false;
}
else
{
for (const auto& failedPackage : failedUpdates)
{
// We don't have to worry about backwards compatability, but just to be safe...
if (failedPackage.ValueType() == JsonValueType::Object)
{
auto failedPackageHash{ failedPackage.GetObject().GetNamedString(PackageHashKey) };
if (packageHash == failedPackageHash)
{
return true;
}
}
}
return false;
}
}
/*
* This method is used to get information about the latest rollback.
* This information will be used to decide whether the application
* should ignore the update or not.
*/
JsonObject CodePushNativeModule::GetRollbackInfo() { return nullptr; }
/*
* This method is used to get the count of rollback for the package
* using the latest rollback information.
*/
int CodePushNativeModule::GetRollbackCountForPackage(std::wstring_view packageHash, const JsonObject& latestRollbackInfo)
{
auto oldPackageHash{ latestRollbackInfo.GetNamedString(LatestRollbackPackageHashKey, L"null") };
if (packageHash == oldPackageHash)
{
auto oldCount{ latestRollbackInfo.GetNamedNumber(LatestRollbackCountKey, 0) };
return static_cast<int>(oldCount);
}
return 0;
}
/*
* This method checks to see whether a specific package hash
* represents a downloaded and installed update, that hasn't
* been applied yet via an app restart.
*/
/*static*/ bool CodePushNativeModule::IsPendingUpdate(std::wstring_view packageHash)
{
auto localSettings{ GetLocalSettings() };
auto pendingUpdateData{ localSettings.Values().TryLookup(PendingUpdateKey) };
if (pendingUpdateData != nullptr)
{
auto pendingUpdateString{ unbox_value<hstring>(pendingUpdateData) };
JsonObject pendingUpdate;
auto success{ JsonObject::TryParse(pendingUpdateString, pendingUpdate) };
// If there is a pending update whose "state" isn't loading, then we consider it "pending".
// Additionally, if a specific hash was provided, we ensure it matches that of the pending update.
auto updateIsPending{ success &&
pendingUpdate != nullptr &&
pendingUpdate.GetNamedBoolean(PendingUpdateIsLoadingKey, false) == false &&
(packageHash.empty() || pendingUpdate.GetNamedString(PendingUpdateHashKey, L"null") == packageHash) };
return updateIsPending;
}
return false;
}
/*
* This method is used to clear updates that are installed
* under a different app version and hence don't apply anymore,
* during a debug run configuration and when React Native Windows is
* running the JS bundle from the dev server.
*/
IAsyncAction CodePushNativeModule::ClearDebugUpdates()
{
#ifndef BUNDLE
auto binaryAppVersion{ CodePushConfig::Current().GetAppVersion() };
auto currentPackageMetadata{ co_await CodePushPackage::GetCurrentPackageAsync() };
if (currentPackageMetadata != nullptr)
{
auto packageAppVersion{ currentPackageMetadata.GetNamedString(AppVersionKey, L"") };
if (binaryAppVersion.empty() || binaryAppVersion != packageAppVersion)
{
co_await ClearUpdatesStaticAsync();
}
}
#endif
co_return;
}
/*static*/ IAsyncAction CodePushNativeModule::ClearUpdatesStaticAsync()
{
co_await CodePushPackage::ClearUpdatesAsync();
RemovePendingUpdate();
RemoveFailedUpdates();
}
void CodePushNativeModule::DispatchDownloadProgressEvent()
{
// Notify the script-side about the progress
m_context.CallJSFunction(
L"RCTDeviceEventEmitter",
L"emit",
L"CodePushDownloadProgress",
JSValueObject{
{"totalBytes", m_latestExpectedContentLength },
{"receivedBytes", m_latestReceivedContentLength } });
}
/*static*/ IAsyncAction CodePushNativeModule::LoadBundle()
{
if (!s_host.InstanceSettings().UseWebDebugger())
{
auto bundleFile{ co_await GetBundleFileAsync() };
if (bundleFile != nullptr)
{
std::wstring_view bundlePath{ bundleFile.Path() };
hstring bundleRootPath{ bundlePath.substr(0, bundlePath.rfind('\\')) };
s_host.InstanceSettings().BundleRootPath(bundleRootPath);
}
}
s_host.ReloadInstance();
// The instance will call Initialize() upon reloading this module
}
/*
* This method is used when an update has failed installation
* and the app needs to be rolled back to the previous bundle.
* This method is automatically called when the rollback timer
* expires without the app indicating whether the update succeeded,
* and therefore, it shouldn't be called directly.
*/
IAsyncAction CodePushNativeModule::RollbackPackage()
{
auto failedPackage{ co_await CodePushPackage::GetCurrentPackageAsync() };
if (failedPackage == nullptr)
{
CodePushUtils::Log(L"Attempted to perform a rollback when there is no current update.");
}
else
{
SaveFailedUpdate(failedPackage);
}
// Rollback to the previous version and de-register the new update
co_await CodePushPackage::RollbackPackage();
RemovePendingUpdate();
co_await LoadBundle();
}
/*
* This method is used to clear away failed updates in the event that
* a new app store binary is installed.
*/
/*static*/ void CodePushNativeModule::RemoveFailedUpdates()
{
auto localSettings{ GetLocalSettings() };
localSettings.Values().TryRemove(FailedUpdatesKey);
}
/*
* This method is used to register the fact that a pending
* update succeeded and therefore can be removed.
*/
/*static*/ void CodePushNativeModule::RemovePendingUpdate()
{
// remove pending update from LocalSettings
auto localSettings{ GetLocalSettings() };
localSettings.Values().TryRemove(PendingUpdateKey);
}
IAsyncAction CodePushNativeModule::RestartAppInternal(bool onlyIfUpdateIsPending)
{
if (m_restartInProgress)
{
CodePushUtils::Log(L"Restart request queued until the current restart is completed.");
m_restartQueue.push_back(onlyIfUpdateIsPending);
}
else if (!m_allowed)
{
CodePushUtils::Log(L"Restart request queued until restarts are re-allowed.");
m_restartQueue.push_back(onlyIfUpdateIsPending);
co_return;
}
m_restartInProgress = true;
if (!onlyIfUpdateIsPending || IsPendingUpdate(L""))
{
co_await LoadBundle();
CodePushUtils::Log(L"Restarting app.");
co_return;
}
m_restartInProgress = false;
if (m_restartQueue.size() > 0)
{
auto buf{ m_restartQueue[0] };
m_restartQueue.erase(m_restartQueue.begin());
co_await RestartAppInternal(buf);
}
}
/*
* When an update failed to apply, this method can be called
* to store its hash so that it can be ignored on future
* attempts to check the server for an update.
*/
void CodePushNativeModule::SaveFailedUpdate(JsonObject& failedPackage)
{
if (IsFailedHash(failedPackage.GetNamedString(PackageHashKey)))
{
return;
}
auto localSettings{ GetLocalSettings() };
auto failedUpdates{ localSettings.Values().TryLookup(FailedUpdatesKey).try_as<JsonArray>() };
if (failedUpdates == nullptr)
{
failedUpdates = JsonArray{};
}
failedUpdates.Append(failedPackage);
localSettings.Values().Insert(FailedUpdatesKey, box_value(failedUpdates.Stringify()));
}
/*
* When an update is installed whose mode isn't Immediate, this method
* can be called to store the pending update's metadata (e.g. packageHash)
* so that it can be used when the actual update application occurs at a later point.
*/
void CodePushNativeModule::SavePendingUpdate(std::wstring_view packageHash, bool isLoading)
{
// Since we're not restarting, we need to store the fact that the update
// was installed, but hasn't yet become "active".
auto localSettings{ GetLocalSettings() };
JsonObject pendingUpdate{};
pendingUpdate.Insert(PendingUpdateHashKey, JsonValue::CreateStringValue(packageHash));
pendingUpdate.Insert(PendingUpdateIsLoadingKey, JsonValue::CreateBooleanValue(isLoading));
localSettings.Values().Insert(PendingUpdateKey, box_value(pendingUpdate.Stringify()));
}
/*static*/ void CodePushNativeModule::SetHost(const ReactNativeHost& host)
{
s_host = host;
}
void CodePushNativeModule::Initialize(ReactContext const& reactContext) noexcept
{
m_context = reactContext;
InitializeUpdateAfterRestart();
}
void CodePushNativeModule::GetConstants(winrt::Microsoft::ReactNative::ReactConstantProvider& constants) noexcept
{
constants.Add(L"codePushInstallModeImmediate", CodePushInstallMode::Immediate);
constants.Add(L"codePushInstallModeOnNextRestart", CodePushInstallMode::OnNextRestart);
constants.Add(L"codePushInstallModeOnNextResume", CodePushInstallMode::OnNextResume);
constants.Add(L"codePushInstallModeOnNextSuspend", CodePushInstallMode::OnNextSuspend);
constants.Add(L"codePushUpdateStateRunning", CodePushUpdateState::Running);
constants.Add(L"codePushUpdateStatePending", CodePushUpdateState::Pending);
constants.Add(L"codePushUpdateStateLatest", CodePushUpdateState::Latest);
}
/*
* This is native-side of the RemotePackage.download method
*/
fire_and_forget CodePushNativeModule::DownloadUpdateAsync(JsonObject updatePackage, bool notifyProgress, ReactPromise<IJsonValue> promise) noexcept
{
auto binaryBundle{ co_await GetBinaryBundleAsync() };
if (binaryBundle != nullptr)
{
auto modifiedDate{ co_await CodePushUpdateUtils::ModifiedDateStringOfFileAsync(binaryBundle) };
updatePackage.Insert(BinaryBundleDateKey, JsonValue::CreateStringValue(modifiedDate));
}
auto publicKey{ CodePushConfig::Current().GetPublicKey() };
try
{
co_await CodePushPackage::DownloadPackageAsync(
updatePackage,
s_javaScriptBundleFileName + BundleExtension,
/* publicKey */ publicKey,
/* progressCallback */ [=](int64_t expectedContentLength, int64_t receivedContentLength) {
// React-Native-Windows doesn't have a frame observer to my knowledge.
if (notifyProgress)
{
m_latestExpectedContentLength = expectedContentLength;
m_latestReceivedContentLength = receivedContentLength;
DispatchDownloadProgressEvent();
}
});
}
catch (const hresult_error& ex)
{
SaveFailedUpdate(updatePackage);
m_didUpdateProgress = false;
promise.Reject(ex.message().c_str());
}
auto newPackage{ co_await CodePushPackage::GetPackageAsync(updatePackage.GetNamedString(PackageHashKey)) };
if (newPackage == nullptr)
{
promise.Reject(L"An error has occurred retreiving the downloaded package.");
}
else
{
promise.Resolve(newPackage);
}
co_return;
}
/*
* This is the native side of the CodePush.getConfiguration method. It isn't
* currently exposed via the "react-native-code-push" module, and is used
* internally only by the CodePush.checkForUpdate method in order to get the
* app version, as well as the deployment key that was configured in App.cpp.
*/
fire_and_forget CodePushNativeModule::GetConfiguration(ReactPromise<IJsonValue> promise) noexcept
{
auto configuration{ CodePushConfig::Current().GetConfiguration() };
if (isRunningBinaryVersion)
{
hstring binaryHash;
try
{
auto errorMessage{ L"Error: Package hashing is currently unimplemented. Binary hash was not obtained." };
auto error{ hresult_error(E_NOTIMPL, errorMessage) };
CodePushUtils::Log(error);
throw error;
}
catch(...)
{
CodePushUtils::Log(L"Error obtaining hash for binary contents.");
promise.Resolve(configuration);
co_return;
}
if (binaryHash.empty())
{
// The hash was not generated either due to a previous unknown error or the fact that
// the React Native assets were not bundled in the binary (e.g. during release)
// builds.
promise.Resolve(configuration);
co_return;
}
configuration.Insert(PackageHashKey, JsonValue::CreateStringValue(binaryHash));
promise.Resolve(configuration);
co_return;
}
promise.Resolve(configuration);
}
/*
* This method is the native side of the CodePush.getUpdateMetadata method.
*/
fire_and_forget CodePushNativeModule::GetUpdateMetadataAsync(CodePushUpdateState updateState, ReactPromise<IJsonValue> promise) noexcept
{
auto package{ co_await CodePushPackage::GetCurrentPackageAsync() };
if (package == nullptr)
{
// The app hasn't downloaded any CodePush updates yet,
// so we simply return nil regardless if the user
// wanted to retrieve the pending or running update.
promise.Resolve(JsonValue::CreateNullValue());
co_return;
}
// We have a CodePush update, so let's see if it's currently in a pending state.
bool currentUpdateIsPending{ IsPendingUpdate(package.GetNamedString(PackageHashKey)) };
if (updateState == CodePushUpdateState::Pending && !currentUpdateIsPending) {
// The caller wanted a pending update
// but there isn't currently one.
promise.Resolve(JsonValue::CreateNullValue());
}
else if (updateState == CodePushUpdateState::Running && currentUpdateIsPending) {
// The caller wants the running update, but the current
// one is pending, so we need to grab the previous.
promise.Resolve(co_await CodePushPackage::GetPreviousPackageAsync());
}
else {
// The current package satisfies the request:
// 1) Caller wanted a pending, and there is a pending update
// 2) Caller wanted the running update, and there isn't a pending
// 3) Caller wants the latest update, regardless if it's pending or not
if (isRunningBinaryVersion) {
// This only matters in Debug builds. Since we do not clear "outdated" updates,
// we need to indicate to the JS side that somehow we have a current update on
// disk that is not actually running.
package.Insert(L"_isDebugOnly", JsonValue::CreateBooleanValue(true));
}
// Enable differentiating pending vs. non-pending updates
package.Insert(PackageIsPendingKey, JsonValue::CreateBooleanValue(currentUpdateIsPending));
promise.Resolve(package);
}
co_return;
}
/*
* This method is the native side of the LocalPackage.install method.
*/
fire_and_forget CodePushNativeModule::InstallUpdateAsync(JsonObject updatePackage, CodePushInstallMode installMode, int minimumBackgroundDuration, ReactPromise<void> promise) noexcept
{
try
{
co_await CodePushPackage::InstallPackageAsync(updatePackage, IsPendingUpdate(L""));
}
catch (const hresult_error& ex)
{
promise.Reject(ex.message().c_str());
co_return;
}
SavePendingUpdate(updatePackage.GetNamedString(PackageHashKey), false);
s_installMode = installMode;
if (s_installMode == CodePushInstallMode::OnNextResume || s_installMode == CodePushInstallMode::OnNextSuspend) {
// Essentially, for RNW, InstallMode is currently always Immediate
auto errorMessage{ L"Error: ON_NEXT_RESUME and ON_NEXT_SUSPEND install modes are not currently supported." };
hresult_error error{ E_NOTIMPL, errorMessage };
CodePushUtils::Log(error);
throw error;
}
// Signal to JS that the update has been applied.
promise.Resolve();
co_return;
}
/*
* This method isn't publicly exposed via the "react-native-code-push"
* module, and is only used internally to populate the RemotePackage.failedInstall property.
*/
void CodePushNativeModule::IsFailedUpdate(std::wstring packageHash, ReactPromise<bool> promise) noexcept
{
auto isFailedHash{ IsFailedHash(packageHash) };
promise.Resolve(isFailedHash);
}
/*
* This method is used to save information about the latest rollback.
* This information will be used to decide whether the application
* should ignore the update or not.
*/
void CodePushNativeModule::SetLatestRollbackInfo(std::wstring packageHash) noexcept
{
if (packageHash.empty())
{
return;
}
auto localSettings{ GetLocalSettings() };
JsonObject latestRollbackInfo;
auto res{ localSettings.Values().TryLookup(LatestRollbackInfoKey) };
if (res != nullptr)
{
auto infoString{ unbox_value<hstring>(res) };
JsonObject::TryParse(infoString, latestRollbackInfo);
}
auto initialRollbackCount{ GetRollbackCountForPackage(packageHash, latestRollbackInfo) };
auto count{ initialRollbackCount + 1 };
auto currentTimeMillis{ clock::to_time_t(clock::now()) * 1000 };
latestRollbackInfo.Insert(LatestRollbackCountKey, JsonValue::CreateNumberValue(count));
latestRollbackInfo.Insert(LatestRollbackTimeKey, JsonValue::CreateNumberValue(static_cast<double>(currentTimeMillis)));
latestRollbackInfo.Insert(LatestRollbackPackageHashKey, JsonValue::CreateStringValue(packageHash));
localSettings.Values().Insert(LatestRollbackInfoKey, box_value(latestRollbackInfo.Stringify()));
}
/*
* This method is used when the app is started to either
* initialize a pending update or rollback a faulty update
* to the previous version.
*/
IAsyncAction CodePushNativeModule::InitializeUpdateAfterRestart()
{
if (s_host.InstanceSettings().UseWebDebugger())
{
co_await ClearDebugUpdates();
}
auto localSettings{ GetLocalSettings() };
auto pendingUpdateData{ localSettings.Values().TryLookup(PendingUpdateKey) };
if (pendingUpdateData != nullptr)
{
auto pendingUpdateString{ unbox_value<hstring>(pendingUpdateData) };
JsonObject pendingUpdate;
auto success{ JsonObject::TryParse(pendingUpdateString, pendingUpdate) };
if (success)
{
m_isFirstRunAfterUpdate = true;
auto updateIsLoading{ pendingUpdate.GetNamedBoolean(PendingUpdateIsLoadingKey, false) };
if (updateIsLoading)
{
// Pending update was initialized, but notifyApplicationReady was not called.
// Therefore, deduce that it is a broken update and rollback.
CodePushUtils::Log(L"Update did not finish loading the last time, rolling back to a previous version.");
needToReportRollback = true;
co_await RollbackPackage();
}
else
{
// 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.
SavePendingUpdate(pendingUpdate.GetNamedString(PendingUpdateHashKey, L""), true);
}
}
}
}
/*
* This method is used to get information about the latest rollback.
* This information will be used to decide whether the application
* should ignore the update or not.
*/
void CodePushNativeModule::GetLatestRollbackInfo(ReactPromise<IJsonValue> promise) noexcept
{
auto localSettings{ GetLocalSettings() };
auto res{ localSettings.Values().TryLookup(LatestRollbackInfoKey) };
auto infoString{ unbox_value<hstring>(res) };
JsonObject latestRollbackInfo;
auto success{ JsonObject::TryParse(infoString, latestRollbackInfo) };
if (success)
{
promise.Resolve(latestRollbackInfo);
}
else
{
promise.Resolve(JsonValue::CreateNullValue());
}
}
/*
* This method isn't publicly exposed via the "react-native-code-push"
* module, and is only used internally to populate the LocalPackage.isFirstRun property.
*/
fire_and_forget CodePushNativeModule::IsFirstRun(std::wstring packageHash, ReactPromise<bool> promise) noexcept
{
auto isFirstRun = m_isFirstRunAfterUpdate
&& !packageHash.empty()
&& packageHash == co_await CodePushPackage::GetCurrentPackageHashAsync();
promise.Resolve(isFirstRun);
}
/*
* This method is the native side of the CodePush.notifyApplicationReady() method.
*/
void CodePushNativeModule::NotifyApplicationReady(ReactPromise<IJsonValue> promise) noexcept
{
RemovePendingUpdate();
promise.Resolve(JsonValue::CreateNullValue());
}
void CodePushNativeModule::Allow(ReactPromise<JSValue> promise) noexcept
{
CodePushUtils::Log(L"Re-allowing restarts.");
m_allowed = true;
if (m_restartQueue.size() > 0)
{
CodePushUtils::Log(L"Executing pending restart.");
auto buf{ m_restartQueue[0] };
m_restartQueue.erase(m_restartQueue.begin());
RestartAppInternal(buf);
}
promise.Resolve(JSValue::Null);
}
void CodePushNativeModule::ClearPendingRestart() noexcept
{
m_restartQueue.clear();
}
void CodePushNativeModule::Disallow(ReactPromise<JSValue> promise) noexcept
{
CodePushUtils::Log(L"Disallowing restarts.");
m_allowed = false;
promise.Resolve(JSValue::Null);
}
/*
* This method is the native side of the CodePush.restartApp() method.
*/
fire_and_forget CodePushNativeModule::RestartApp(bool onlyIfUpdateIsPending, ReactPromise<JSValue> promise) noexcept
{
co_await RestartAppInternal(onlyIfUpdateIsPending);
promise.Resolve(JSValue::Null);
}
/*
* This method clears CodePush's downloaded updates.
* It is needed to switch to a different deployment if the current deployment is more recent.
* Note: we dont recommend to use this method in scenarios other than that (CodePush will call this method
* automatically when needed in other cases) as it could lead to unpredictable behavior.
*/
fire_and_forget CodePushNativeModule::ClearUpdates() noexcept
{
co_await ClearUpdatesStaticAsync();
}
/*
* This method is the native side of the CodePush.downloadAndReplaceCurrentBundle()
* method, which replaces the current bundle with the one downloaded from
* removeBundleUrl. It is only to be used during tests and no-ops if the test
* configuration flag is not set.
*/
fire_and_forget CodePushNativeModule::DownloadAndReplaceCurrentBundle(std::wstring remoteBundleUrl) noexcept
{
auto errorMessage{ L"Error: DownloadAndReplaceCurrentBundle is not currently implmented" };
hresult_error error{ E_NOTIMPL, errorMessage };
CodePushUtils::Log(error);
throw error;
}
/*
* This method is checks if a new status update exists (new version was installed,
* or an update failed) and return its details (version label, status).
*/
fire_and_forget CodePushNativeModule::GetNewStatusReportAsync(ReactPromise<IJsonValue> promise) noexcept
{
if (needToReportRollback)
{
needToReportRollback = false;
auto localSettings{ GetLocalSettings() };
auto failedUpdatesData{ localSettings.Values().TryLookup(FailedUpdatesKey) };
if (failedUpdatesData != nullptr)
{
auto failedUpdatesString{ unbox_value<hstring>(failedUpdatesData) };
JsonArray failedUpdates;
auto success{ JsonArray::TryParse(failedUpdatesString, failedUpdates) };
if (success)
{
auto lastFailedPackage{ failedUpdates.GetObjectAt(failedUpdates.Size() - 1) };
if (lastFailedPackage != nullptr)
{
promise.Resolve(CodePushTelemetryManager::GetRollbackReport(lastFailedPackage));
co_return;
}
}
}
}
else if (m_isFirstRunAfterUpdate)
{
auto currentPackage = co_await CodePushPackage::GetCurrentPackageAsync();
if (currentPackage != nullptr)
{
promise.Resolve(CodePushTelemetryManager::GetUpdateReport(currentPackage));
co_return;
}
}
else if (isRunningBinaryVersion)
{
auto appVersionString{ CodePushConfig::Current().GetAppVersion() };
promise.Resolve(CodePushTelemetryManager::GetBinaryUpdateReport(appVersionString));
co_return;
}
else
{
auto retryStatusReport{ CodePushTelemetryManager::GetRetryStatusReport() };
if (retryStatusReport != nullptr)
{
promise.Resolve(retryStatusReport);
co_return;
}
}
promise.Resolve(JsonValue::CreateNullValue());
co_return;
}
void CodePushNativeModule::RecordStatusReported(JsonObject statusReport) noexcept
{
CodePushTelemetryManager::RecordStatusReported(statusReport);
}
void CodePushNativeModule::SaveStatusReportForRetry(JsonObject statusReport) noexcept
{
CodePushTelemetryManager::SaveStatusReportForRetry(statusReport);
}
} // namespace CodePush
// Helper functions for reading and sending JsonValues to and from JavaScript
namespace winrt::Microsoft::ReactNative
{
using namespace winrt::Windows::Data::Json;
void WriteValue(IJSValueWriter const& writer, IJsonValue const& value) noexcept
{
if (value == nullptr)
{
writer.WriteNull();
}
else
{
switch (value.ValueType())
{
case JsonValueType::Object:
writer.WriteObjectBegin();
for (const auto& pair : value.GetObject())
{
writer.WritePropertyName(pair.Key());
WriteValue(writer, pair.Value());
}
writer.WriteObjectEnd();
break;
case JsonValueType::Array:
writer.WriteArrayBegin();
for (const auto& elem : value.GetArray())
{
WriteValue(writer, elem);
}
writer.WriteArrayEnd();
break;
case JsonValueType::Boolean:
writer.WriteBoolean(value.GetBoolean());
break;
case JsonValueType::Number:
writer.WriteDouble(value.GetNumber());
break;
case JsonValueType::String:
writer.WriteString(value.GetString());
break;
case JsonValueType::Null:
writer.WriteNull();
break;
}
}
}
void ReadValue(IJSValueReader const& reader, /*out*/ JsonObject& value) noexcept
{
if (reader.ValueType() == JSValueType::Object)
{
hstring propertyName;
while (reader.GetNextObjectProperty(propertyName))
{
value.Insert(propertyName, ReadValue<IJsonValue>(reader));
}
}
}
void ReadValue(IJSValueReader const& reader, /*out*/ IJsonValue& value) noexcept
{
if (reader.ValueType() == JSValueType::Object)
{
JsonObject valueObject;
hstring propertyName;
while (reader.GetNextObjectProperty(propertyName))
{
valueObject.Insert(propertyName, ReadValue<IJsonValue>(reader));
}
value = valueObject;
}
else if (reader.ValueType() == JSValueType::Array)
{
JsonArray valueArray;
while (reader.GetNextArrayItem())
{
valueArray.Append(ReadValue<IJsonValue>(reader));
}
value = valueArray;
}
else
{
switch (reader.ValueType())
{
case JSValueType::Boolean:
value = JsonValue::CreateBooleanValue(reader.GetBoolean());
break;
case JSValueType::Double:
value = JsonValue::CreateNumberValue(reader.GetDouble());
break;
case JSValueType::Int64:
value = JsonValue::CreateNumberValue(static_cast<double>(reader.GetInt64()));
break;
case JSValueType::String:
value = JsonValue::CreateStringValue(reader.GetString());
break;
case JSValueType::Null:
value = JsonValue::CreateNullValue();
break;
}
}
}
}

Просмотреть файл

@ -0,0 +1,247 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include "NativeModules.h"
#include "winrt/Windows.Data.Json.h"
#include "winrt/Windows.Storage.h"
#include "CodePushConfig.h"
// Helper functions for reading and sending JsonValues to and from JavaScript
namespace winrt::Microsoft::ReactNative
{
void ReadValue(IJSValueReader const& reader, /*out*/ Windows::Data::Json::JsonObject& value) noexcept;
void ReadValue(IJSValueReader const& reader, /*out*/ Windows::Data::Json::IJsonValue& value) noexcept;
}
namespace Microsoft::CodePush::ReactNative
{
REACT_MODULE(CodePushNativeModule, L"CodePush");
struct CodePushNativeModule
{
enum class CodePushInstallMode
{
Immediate = 0,
OnNextRestart = 1,
OnNextResume = 2,
OnNextSuspend = 3
};
enum class CodePushUpdateState
{
Running = 0,
Pending = 1,
Latest = 2
};
static winrt::Windows::Foundation::IAsyncAction LoadBundle();
static void SetHost(const winrt::Microsoft::ReactNative::ReactNativeHost& host);
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> GetBinaryBundleAsync();
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> GetBundleFileAsync();
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFolder> GetBundleAssetsFolderAsync();
static winrt::Windows::Storage::StorageFolder GetLocalStorageFolder();
static winrt::Windows::Storage::ApplicationDataContainer GetLocalSettings();
void OverrideAppVersion(std::wstring_view appVersion);
void SetDeploymentKey(std::wstring_view deploymentKey);
bool IsFailedHash(std::wstring_view packageHash);
winrt::Windows::Data::Json::JsonObject GetRollbackInfo();
int GetRollbackCountForPackage(
std::wstring_view packageHash,
const winrt::Windows::Data::Json::JsonObject& latestRollbackInfo);
static bool IsPendingUpdate(std::wstring_view packageHash);
winrt::Windows::Foundation::IAsyncAction ClearDebugUpdates();
REACT_INIT(Initialize);
void Initialize(winrt::Microsoft::ReactNative::ReactContext const& reactContext) noexcept;
REACT_CONSTANT_PROVIDER(GetConstants);
void GetConstants(winrt::Microsoft::ReactNative::ReactConstantProvider& constants) noexcept;
/*
* This is native-side of the JavaScript RemotePackage.download method
*/
REACT_METHOD(DownloadUpdateAsync, L"downloadUpdate");
winrt::fire_and_forget DownloadUpdateAsync(
winrt::Windows::Data::Json::JsonObject updatePackage,
bool notifyProgress,
winrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;
/*
* This is the native side of the CodePush.getConfiguration method. It isn't
* currently exposed via the "react-native-code-push" module, and is used
* internally only by the CodePush.checkForUpdate method in order to get the
* app version, as well as the deployment key that was configured in the Info.plist file.
*/
REACT_METHOD(GetConfiguration, L"getConfiguration");
winrt::fire_and_forget GetConfiguration(winrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;
/*
* This method is the native side of the CodePush.getUpdateMetadata method.
*/
REACT_METHOD(GetUpdateMetadataAsync, L"getUpdateMetadata");
winrt::fire_and_forget GetUpdateMetadataAsync(
CodePushUpdateState updateState,
winrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;
/*
* This method is the native side of the LocalPackage.install method.
*/
REACT_METHOD(InstallUpdateAsync, L"installUpdate");
winrt::fire_and_forget InstallUpdateAsync(
winrt::Windows::Data::Json::JsonObject updatePackage,
CodePushInstallMode installMode,
int minimumBackgroundDuration,
winrt::Microsoft::ReactNative::ReactPromise<void> promise) noexcept;
/*
* This method isn't publicly exposed via the "react-native-code-push"
* module, and is only used internally to populate the RemotePackage.failedInstall property.
*/
REACT_METHOD(IsFailedUpdate, L"isFailedUpdate");
void IsFailedUpdate(
std::wstring packageHash,
winrt::Microsoft::ReactNative::ReactPromise<bool> promise) noexcept;
REACT_METHOD(SetLatestRollbackInfo, L"setLatestRollbackInfo");
void SetLatestRollbackInfo(std::wstring packageHash) noexcept;
REACT_METHOD(GetLatestRollbackInfo, L"getLatestRollbackInfo");
void GetLatestRollbackInfo(winrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;
/*
* This method isn't publicly exposed via the "react-native-code-push"
* module, and is only used internally to populate the LocalPackage.isFirstRun property.
*/
REACT_METHOD(IsFirstRun, L"isFirstRun");
winrt::fire_and_forget IsFirstRun(
std::wstring packageHash,
winrt::Microsoft::ReactNative::ReactPromise<bool> promise) noexcept;
/*
* This method is the native side of the CodePush.notifyApplicationReady() method.
*/
REACT_METHOD(NotifyApplicationReady, L"notifyApplicationReady");
void NotifyApplicationReady(winrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;
REACT_METHOD(Allow, L"allow");
void Allow(winrt::Microsoft::ReactNative::ReactPromise<winrt::Microsoft::ReactNative::JSValue> promise) noexcept;
REACT_METHOD(ClearPendingRestart, L"clearPendingRestart");
void ClearPendingRestart() noexcept;
REACT_METHOD(Disallow, L"disallow");
void Disallow(winrt::Microsoft::ReactNative::ReactPromise<winrt::Microsoft::ReactNative::JSValue> promise) noexcept;
/*
* This method is the native side of the CodePush.restartApp() method.
*/
REACT_METHOD(RestartApp, L"restartApp");
winrt::fire_and_forget RestartApp(
bool onlyIfUpdateIsPending,
winrt::Microsoft::ReactNative::ReactPromise<winrt::Microsoft::ReactNative::JSValue> promise) noexcept;
/*
* This method clears CodePush's downloaded updates.
* It is needed to switch to a different deployment if the current deployment is more recent.
* Note: we dont recommend to use this method in scenarios other than that (CodePush will call this method
* automatically when needed in other cases) as it could lead to unpredictable behavior.
*/
REACT_METHOD(ClearUpdates, L"clearUpdates");
winrt::fire_and_forget ClearUpdates() noexcept;
/*
* This method is the native side of the CodePush.downloadAndReplaceCurrentBundle()
* method, which replaces the current bundle with the one downloaded from
* removeBundleUrl. It is only to be used during tests and no-ops if the test
* configuration flag is not set.
*/
REACT_METHOD(DownloadAndReplaceCurrentBundle, L"downloadAndReplaceCurrentBundle");
winrt::fire_and_forget DownloadAndReplaceCurrentBundle(std::wstring remoteBundleUrl) noexcept;
/*
* This method is checks if a new status update exists (new version was installed,
* or an update failed) and return its details (version label, status).
*/
REACT_METHOD(GetNewStatusReportAsync, L"getNewStatusReport");
winrt::fire_and_forget GetNewStatusReportAsync(winrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;
REACT_METHOD(RecordStatusReported, L"recordStatusReported");
void RecordStatusReported(winrt::Windows::Data::Json::JsonObject statusReport) noexcept;
REACT_METHOD(SaveStatusReportForRetry, L"saveStatusReportForRetry");
void SaveStatusReportForRetry(winrt::Windows::Data::Json::JsonObject statusReport) noexcept;
private:
bool m_isFirstRunAfterUpdate{ false };
static CodePushInstallMode s_installMode;
// Used to coordinate the dispatching of download progress events to JS.
uint64_t m_latestExpectedContentLength{ 0 };
uint64_t m_latestReceivedContentLength{ 0 };
bool m_didUpdateProgress{ false };
bool m_allowed{ true };
bool m_restartInProgress{ false };
std::vector<uint8_t> m_restartQueue;
static constexpr std::wstring_view BundleExtension{ L".bundle" };
static winrt::hstring s_javaScriptBundleFileName;
// These constants represent emitted events
static constexpr std::wstring_view DownloadProgressEvent{ L"CodePushDownloadProgress" };
// These constants represent valid deployment statuses
static constexpr std::wstring_view DeploymentFailed{ L"DeploymentFailed" };
static constexpr std::wstring_view DeploymentSucceeded{ L"DeploymentSucceeded" };
// These keys represent the names we use to store data in LocalSettings
static constexpr std::wstring_view FailedUpdatesKey{ L"CODE_PUSH_FAILED_UPDATES" };
static constexpr std::wstring_view PendingUpdateKey{ L"CODE_PUSH_PENDING_UPDATE" };
// These keys are already "namespaced" by the PendingUpdateKey, so
// their values don't need to be obfuscated to prevent collision with app data
static constexpr std::wstring_view PendingUpdateHashKey{ L"hash" };
static constexpr std::wstring_view PendingUpdateIsLoadingKey{ L"isLoading" };
// These keys are used to inspect/augment the metadata
// that is associated with an update's package.
static constexpr std::wstring_view AppVersionKey{ L"appVersion" };
static constexpr std::wstring_view BinaryBundleDateKey{ L"binaryDate" }; // The date of the BUILD -> the modified date of the executable
static constexpr std::wstring_view PackageHashKey{ L"packageHash" };
static constexpr std::wstring_view PackageIsPendingKey{ L"isPending" };
static bool isRunningBinaryVersion;
static bool needToReportRollback;
static winrt::Microsoft::ReactNative::ReactNativeHost s_host;
winrt::Microsoft::ReactNative::ReactContext m_context;
// These keys represent the names we use to store information about the latest rollback
static constexpr std::wstring_view LatestRollbackInfoKey{ L"LATEST_ROLLBACK_INFO" };
static constexpr std::wstring_view LatestRollbackPackageHashKey{ L"packageHash" };
static constexpr std::wstring_view LatestRollbackTimeKey{ L"time" };
static constexpr std::wstring_view LatestRollbackCountKey{ L"count" };
// Bool that keeps track of whether the app has been initialized at least once.
static bool s_initialized;
static winrt::Windows::Foundation::IAsyncAction ClearUpdatesStaticAsync();
void DispatchDownloadProgressEvent();
winrt::Windows::Foundation::IAsyncAction InitializeUpdateAfterRestart();
winrt::Windows::Foundation::IAsyncAction RollbackPackage();
static void RemoveFailedUpdates();
static void RemovePendingUpdate();
winrt::Windows::Foundation::IAsyncAction RestartAppInternal(bool onlyIfUpdateIsPending);
void SaveFailedUpdate(winrt::Windows::Data::Json::JsonObject& failedPackage);
void SavePendingUpdate(std::wstring_view packageHash, bool isLoading);
};
}

Просмотреть файл

@ -0,0 +1,461 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "CodePushDownloadHandler.h"
#include "CodePushNativeModule.h"
#include "CodePushPackage.h"
#include "CodePushUtils.h"
#include "CodePushUpdateUtils.h"
#include "FileUtils.h"
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Foundation.h>
#include <functional>
namespace Microsoft::CodePush::ReactNative
{
using namespace winrt;
using namespace Windows::Data::Json;
using namespace Windows::Foundation;
using namespace Windows::Storage;
using namespace Windows::Storage::Streams;
/*static*/ IAsyncAction CodePushPackage::ClearUpdatesAsync()
{
auto codePushFolder{ co_await GetCodePushFolderAsync() };
codePushFolder.DeleteAsync();
}
/*static*/ IAsyncAction CodePushPackage::DownloadPackageAsync(
JsonObject& updatePackage,
std::wstring_view expectedBundleFileName,
std::wstring_view publicKey,
std::function<void(int64_t, int64_t)> progressCallback)
{
auto newUpdateHash{ updatePackage.GetNamedString(L"packageHash") };
auto codePushFolder{ co_await GetCodePushFolderAsync() };
auto downloadFile{ co_await codePushFolder.CreateFileAsync(DownloadFileName, CreationCollisionOption::ReplaceExisting) };
CodePushDownloadHandler downloadHandler{
downloadFile,
progressCallback };
auto isZip{ co_await downloadHandler.Download(updatePackage.GetNamedString(L"downloadUrl")) };
StorageFolder newUpdateFolder{ co_await codePushFolder.CreateFolderAsync(newUpdateHash, CreationCollisionOption::ReplaceExisting) };
StorageFile newUpdateMetadataFile{ nullptr };
auto mutableUpdatePackage{ updatePackage };
if (isZip)
{
auto unzippedFolder{ co_await codePushFolder.CreateFolderAsync(UnzippedFolderName, CreationCollisionOption::ReplaceExisting) };
co_await FileUtils::UnzipAsync(downloadFile, unzippedFolder);
downloadFile.DeleteAsync();
auto isDiffUpdate{ false };
auto diffManifestFile{ (co_await unzippedFolder.TryGetItemAsync(DiffManifestFileName)).try_as<StorageFile>() };
if (diffManifestFile != nullptr)
{
isDiffUpdate = true;
}
if (isDiffUpdate)
{
// Copy the current package to the new package.
auto currentPackageFolder{ co_await GetCurrentPackageFolderAsync() };
if (currentPackageFolder == nullptr)
{
// Currently running the binary version, copy files from the bundled resources
auto newUpdateCodePushFolder{ co_await newUpdateFolder.CreateFolderAsync(CodePushUpdateUtils::ManifestFolderPrefix) };
auto binaryAssetsFolder{ co_await CodePushNativeModule::GetBundleAssetsFolderAsync() };
auto newUpdateAssetsFolder{ co_await newUpdateCodePushFolder.CreateFolderAsync(CodePushUpdateUtils::AssetsFolderName) };
CodePushUpdateUtils::CopyEntriesInFolderAsync(binaryAssetsFolder, newUpdateAssetsFolder);
auto binaryBundleFile{ co_await CodePushNativeModule::GetBinaryBundleAsync() };
co_await binaryBundleFile.CopyAsync(newUpdateCodePushFolder);
}
else
{
// Copy the contents of the current package to the new package. (how are conflicts resolved?)
co_await CodePushUpdateUtils::CopyEntriesInFolderAsync(currentPackageFolder, newUpdateFolder);
}
auto manifestContent{ co_await FileIO::ReadTextAsync(diffManifestFile, UnicodeEncoding::Utf8) };
auto manifestJson{ JsonObject::Parse(manifestContent) };
auto deletedFiles{ manifestJson.TryLookup(L"deletedFiles") };
auto deletedFilesArray{ deletedFiles.try_as<JsonArray>() };
if (deletedFilesArray != nullptr)
{
for (const auto& deletedFileName : deletedFilesArray)
{
auto fileToDelete{ (co_await newUpdateFolder.TryGetItemAsync(deletedFileName.GetString())).try_as<StorageFile>() };
if (fileToDelete != nullptr)
{
co_await fileToDelete.DeleteAsync();
}
}
}
co_await diffManifestFile.DeleteAsync();
}
co_await CodePushUpdateUtils::CopyEntriesInFolderAsync(unzippedFolder, newUpdateFolder);
co_await unzippedFolder.DeleteAsync();
auto relativeBundlePath{ co_await FileUtils::FindFilePathAsync(newUpdateFolder, expectedBundleFileName) };
if (!relativeBundlePath.empty())
{
mutableUpdatePackage.Insert(RelativeBundlePathKey, JsonValue::CreateStringValue(relativeBundlePath));
}
else
{
auto errorMessage{ L"Error: Unable to find JS bundle in downloaded package." };
hresult_error error{ E_INVALIDARG, errorMessage };
CodePushUtils::Log(error);
throw error;
}
auto newUpdateMetadata{ co_await newUpdateFolder.TryGetItemAsync(UpdateMetadataFileName) };
if (newUpdateMetadata != nullptr)
{
co_await newUpdateMetadata.DeleteAsync();
}
CodePushUtils::Log((isDiffUpdate) ? L"Applying diff update." : L"Applying full update.");
auto isSignatureVerificationEnabled{ !publicKey.empty() };
auto signatureFile{ co_await CodePushUpdateUtils::GetSignatureFileAsync(newUpdateFolder) };
auto isSignatureAppearedInBundle{ signatureFile != nullptr };
if (isSignatureVerificationEnabled)
{
if (isSignatureAppearedInBundle)
{
auto errorMessage{ L"Error: Signature Verification is not currently supported." };
hresult_error error{ E_NOTIMPL, errorMessage };
CodePushUtils::Log(error);
throw error;
}
else
{
auto errorMessage{ L"Error! Public key was provided but there is no JWT signature within app bundle to verify " \
L"Possible reasons, why that might happen: \n" \
L"1. You've been released CodePush bundle update using a version of the CodePush CLI that does not support code signing.\n" \
L"2. You've been released CodePush bundle update without providing --privateKeyPath option." };
hresult_error error{ E_FAIL, errorMessage };
CodePushUtils::Log(error);
throw error;
}
}
else
{
bool needToVerifyHash;
if (isSignatureAppearedInBundle)
{
CodePushUtils::Log(L"Warning! JWT signature exists in codepush update but code integrity check couldn't be performed" \
L" because there is no public key configured. " \
L"Please ensure that a public key is properly configured within your application.");
needToVerifyHash = true;
}
else
{
needToVerifyHash = isDiffUpdate;
}
if (needToVerifyHash)
{
try
{
auto errorMessage{ L"Error: package content verification is not currently supported." };
hresult_error error{ E_NOTIMPL, errorMessage };
CodePushUtils::Log(error);
throw error;
}
catch (...) {}
}
}
}
else
{
co_await downloadFile.MoveAsync(newUpdateFolder, UpdateBundleFileName, NameCollisionOption::ReplaceExisting);
}
newUpdateMetadataFile = co_await newUpdateFolder.CreateFileAsync(UpdateMetadataFileName, CreationCollisionOption::ReplaceExisting);
auto packageJsonString{ mutableUpdatePackage.Stringify() };
co_await FileIO::WriteTextAsync(newUpdateMetadataFile, packageJsonString);
co_return;
}
/*static*/ IAsyncOperation<StorageFolder> CodePushPackage::GetCodePushFolderAsync()
{
auto localStorage{ CodePushNativeModule::GetLocalStorageFolder() };
auto codePushFolder{ co_await localStorage.CreateFolderAsync(L"CodePush", CreationCollisionOption::OpenIfExists) };
co_return codePushFolder;
}
/*static*/ IAsyncOperation<JsonObject> CodePushPackage::GetCurrentPackageAsync()
{
auto packageHash{ co_await GetCurrentPackageHashAsync() };
if (packageHash.empty())
{
co_return nullptr;
}
co_return co_await GetPackageAsync(packageHash);
}
/*static*/ IAsyncOperation<StorageFile> CodePushPackage::GetCurrentPackageBundleAsync()
{
auto packageFolder{ co_await GetCurrentPackageFolderAsync() };
if (packageFolder == nullptr)
{
co_return nullptr;
}
auto currentPackage{ co_await GetCurrentPackageAsync() };
if (currentPackage == nullptr)
{
co_return nullptr;
}
auto relativeBundlePath{ currentPackage.GetNamedString(RelativeBundlePathKey, L"") };
if (!relativeBundlePath.empty())
{
auto currentBundle{ (co_await packageFolder.TryGetItemAsync(relativeBundlePath)).try_as<StorageFile>() };
co_return currentBundle;
}
co_return nullptr;
}
/*static*/ IAsyncOperation<StorageFolder> CodePushPackage::GetCurrentPackageFolderAsync()
{
auto info{ co_await GetCurrentPackageInfoAsync() };
if (info == nullptr)
{
return nullptr;
}
auto packageHash{ info.GetNamedString(L"currentPackage", L"") };
if (packageHash.empty())
{
return nullptr;
}
auto codePushFolder{ co_await GetCodePushFolderAsync() };
auto packageFolder{ (co_await codePushFolder.TryGetItemAsync(packageHash)).try_as<StorageFolder>() };
co_return packageFolder;
}
/*static*/ IAsyncOperation<hstring> CodePushPackage::GetCurrentPackageHashAsync()
{
auto info{ co_await GetCurrentPackageInfoAsync() };
if (info == nullptr)
{
co_return L"";
}
auto currentPackage{ info.TryLookup(L"currentPackage") };
if (currentPackage == nullptr)
{
co_return L"";
}
co_return currentPackage.GetString();
}
/*static*/ IAsyncOperation<JsonObject> CodePushPackage::GetCurrentPackageInfoAsync()
{
try
{
auto statusFile{ co_await GetStatusFileAsync() };
if (statusFile == nullptr)
{
co_return JsonObject{};
}
auto content{ co_await FileIO::ReadTextAsync(statusFile) };
JsonObject json;
auto success{ JsonObject::TryParse(content, json) };
if (!success)
{
co_return nullptr;
}
co_return json;
}
catch (...)
{
// Either the file does not exist or does not contain valid JSON
co_return nullptr;
}
co_return nullptr;
}
/*static*/ IAsyncOperation<JsonObject> CodePushPackage::GetPreviousPackageAsync()
{
auto packageHash{ co_await GetPreviousPackageHashAsync() };
if (packageHash.empty())
{
co_return nullptr;
}
co_return co_await GetPackageAsync(packageHash);
}
/*static*/ IAsyncOperation<hstring> CodePushPackage::GetPreviousPackageHashAsync()
{
auto info{ co_await GetCurrentPackageInfoAsync() };
if (info == nullptr)
{
co_return L"";
}
auto previousHash{ info.TryLookup(L"previousPackage") };
if (previousHash == nullptr)
{
co_return L"";
}
co_return previousHash.GetString();
}
/*static*/ IAsyncOperation<JsonObject> CodePushPackage::GetPackageAsync(std::wstring_view packageHash)
{
auto updateDirectory{ co_await GetPackageFolderAsync(packageHash) };
if (updateDirectory != nullptr)
{
auto updateMetadataFile{ (co_await updateDirectory.TryGetItemAsync(UpdateMetadataFileName)).try_as<StorageFile>() };
if (updateMetadataFile != nullptr)
{
auto updateMetadataString{ co_await FileIO::ReadTextAsync(updateMetadataFile) };
JsonObject updateMetadata;
auto success{ JsonObject::TryParse(updateMetadataString, updateMetadata) };
if (success)
{
co_return updateMetadata;
}
}
}
co_return nullptr;
}
/*static*/ IAsyncOperation<StorageFolder> CodePushPackage::GetPackageFolderAsync(std::wstring_view packageHash)
{
auto codePushFolder{ co_await GetCodePushFolderAsync() };
co_return (co_await codePushFolder.TryGetItemAsync(packageHash)).try_as<StorageFolder>();
}
/*static*/ IAsyncOperation<bool> CodePushPackage::InstallPackageAsync(JsonObject updatePackage, bool removePendingUpdate)
{
auto packageHash{ updatePackage.GetNamedString(L"packageHash") };
auto info{ co_await GetCurrentPackageInfoAsync() };
if (info == nullptr)
{
co_return false;
}
if (info.HasKey(L"currentPackage") && packageHash == info.GetNamedString(L"currentPackage"))
{
// The current package is already the one being installed, so we should no-op.
co_return true;
}
if (removePendingUpdate)
{
auto currentPackageFolder{ co_await GetCurrentPackageFolderAsync() };
if (currentPackageFolder != nullptr)
{
try
{
co_await currentPackageFolder.DeleteAsync();
}
catch (...)
{
CodePushUtils::Log(L"Error deleting pending package.");
}
}
}
else
{
auto previousPackageHash{ co_await GetPreviousPackageHashAsync() };
if (!previousPackageHash.empty() && previousPackageHash != packageHash)
{
auto previousPackageFolder{ co_await GetPackageFolderAsync(previousPackageHash) };
try
{
co_await previousPackageFolder.DeleteAsync();
}
catch (...)
{
CodePushUtils::Log(L"Error deleting old package.");
}
}
IJsonValue currentPackage;
if (info.HasKey(L"currentPackage"))
{
currentPackage = info.Lookup(L"currentPackage");
}
else
{
currentPackage = JsonValue::CreateStringValue(L"");
}
info.Insert(L"previousPackage", currentPackage);
}
info.Insert(L"currentPackage", JsonValue::CreateStringValue(packageHash));
co_return co_await UpdateCurrentPackageInfoAsync(info);
}
/*static*/ IAsyncAction CodePushPackage::RollbackPackage()
{
auto info{ co_await GetCurrentPackageInfoAsync() };
if (info == nullptr)
{
CodePushUtils::Log(L"Error getting current package info.");
co_return;
}
auto currentPackageFolder{ co_await GetCurrentPackageFolderAsync() };
if (currentPackageFolder == nullptr)
{
CodePushUtils::Log(L"Error getting package folder path.");
}
try
{
co_await currentPackageFolder.DeleteAsync();
}
catch (...)
{
CodePushUtils::Log(L"Error deleting current package contents.");
}
info.Insert(L"currentPackage", info.TryLookup(L"previousPackage"));
info.Remove(L"previousPackage");
co_await UpdateCurrentPackageInfoAsync(info);
}
/*static*/ IAsyncOperation<StorageFile> CodePushPackage::GetStatusFileAsync()
{
auto codePushFolder{ co_await GetCodePushFolderAsync() };
co_return (co_await codePushFolder.TryGetItemAsync(CodePushPackage::StatusFile)).try_as<StorageFile>();
}
/*static*/ IAsyncOperation<bool> CodePushPackage::UpdateCurrentPackageInfoAsync(JsonObject packageInfo)
{
auto packageInfoString{ packageInfo.Stringify() };
auto infoFile{ co_await GetStatusFileAsync() };
if (infoFile == nullptr)
{
auto codePushFolder{ co_await GetCodePushFolderAsync() };
infoFile = co_await codePushFolder.CreateFileAsync(CodePushPackage::StatusFile);
}
co_await FileIO::WriteTextAsync(infoFile, packageInfoString);
co_return true;
}
}

Просмотреть файл

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include <winrt/Windows.Data.Json.h>
#include <functional>
namespace Microsoft::CodePush::ReactNative
{
struct CodePushPackage
{
static constexpr std::wstring_view DiffManifestFileName{ L"hotcodepush.json" };
static constexpr std::wstring_view DownloadFileName{ L"download.zip" };
static constexpr std::wstring_view RelativeBundlePathKey{ L"bundlePath" };
static constexpr std::wstring_view StatusFile{ L"codepush.json" };
static constexpr std::wstring_view UpdateBundleFileName{ L"app.jsbundle" };
static constexpr std::wstring_view UpdateMetadataFileName{ L"app.json" };
static constexpr std::wstring_view UnzippedFolderName{ L"unzipped" };
static winrt::Windows::Foundation::IAsyncAction ClearUpdatesAsync();
static winrt::Windows::Foundation::IAsyncAction DownloadPackageAsync(
winrt::Windows::Data::Json::JsonObject& updatePackage,
std::wstring_view expectedBundleFileName,
std::wstring_view publicKey,
std::function<void(int64_t, int64_t)> progressCallback);
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Data::Json::JsonObject> GetCurrentPackageAsync();
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Data::Json::JsonObject> GetPreviousPackageAsync();
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFolder> GetCurrentPackageFolderAsync();
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> GetCurrentPackageBundleAsync();
static winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> GetCurrentPackageHashAsync();
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Data::Json::JsonObject> GetPackageAsync(std::wstring_view packageHash);
static winrt::Windows::Foundation::IAsyncOperation<bool> InstallPackageAsync(winrt::Windows::Data::Json::JsonObject updatePackage, bool removePendingUpdate);
static winrt::Windows::Foundation::IAsyncAction RollbackPackage();
private:
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFolder> GetCodePushFolderAsync();
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Data::Json::JsonObject> GetCurrentPackageInfoAsync();
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFolder> GetPackageFolderAsync(std::wstring_view packageHash);
static winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> GetPreviousPackageHashAsync();
static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> GetStatusFileAsync();
static winrt::Windows::Foundation::IAsyncOperation<bool> UpdateCurrentPackageInfoAsync(winrt::Windows::Data::Json::JsonObject packageInfo);
};
}

Просмотреть файл

@ -0,0 +1,213 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "CodePushTelemetryManager.h"
#include "CodePushNativeModule.h"
#include "winrt/Windows.Storage.h"
#include "winrt/Windows.Data.Json.h"
#include <string_view>
namespace Microsoft::CodePush::ReactNative
{
using namespace winrt;
using namespace Windows::Data::Json;
using namespace Windows::Storage;
static const std::wstring_view AppVersionKey{ L"appVersion" };
static const std::wstring_view DeploymentFailed{ L"DeploymentFailed" };
static const std::wstring_view DeploymentKeyKey{ L"deploymentKey" };
static const std::wstring_view DeploymentSucceeded{ L"DeploymentSucceeded" };
static const std::wstring_view LabelKey{ L"label" };
static const std::wstring_view LastDeploymentReportKey{ L"CODE_PUSH_LAST_DEPLOYMENT_REPORT" };
static const std::wstring_view PackageKey{ L"package" };
static const std::wstring_view PreviousDeploymentKeyKey{ L"previousDeploymentKey" };
static const std::wstring_view PreviousLabelOrAppVersionKey{ L"previousLabelOrAppVersion" };
static const std::wstring_view RetryDeploymentReportKey{ L"CODE_PUSH_RETRY_DEPLOYMENT_REPORT" };
static const std::wstring_view StatusKey{ L"status" };
/*static*/ JsonObject CodePushTelemetryManager::GetBinaryUpdateReport(std::wstring_view appVersion)
{
auto previousStatusReportIdentifier{ GetPreviousStatusReportIdentifier() };
if (previousStatusReportIdentifier.empty())
{
ClearRetryStatusReport();
JsonObject out;
out.Insert(AppVersionKey, JsonValue::CreateStringValue(appVersion));
return out;
}
else if (previousStatusReportIdentifier != appVersion)
{
if (IsStatusReportIdentifierCodePushLabel(previousStatusReportIdentifier))
{
auto previousDeploymentKey{ GetDeploymentKeyFromStatusReportIdentifier(previousStatusReportIdentifier) };
auto previousLabel{ GetVersionLabelFromStatusReportIdentifier(previousStatusReportIdentifier) };
ClearRetryStatusReport();
JsonObject out;
out.Insert(AppVersionKey, JsonValue::CreateStringValue(appVersion));
out.Insert(PreviousDeploymentKeyKey, JsonValue::CreateStringValue(previousDeploymentKey));
out.Insert(PreviousLabelOrAppVersionKey, JsonValue::CreateStringValue(previousLabel));
return out;
}
else
{
ClearRetryStatusReport();
// Previous status report was with a binary app version.
JsonObject out;
out.Insert(AppVersionKey, JsonValue::CreateStringValue(appVersion));
out.Insert(PreviousLabelOrAppVersionKey, JsonValue::CreateStringValue(previousStatusReportIdentifier));
return out;
}
}
return nullptr;
}
/*static*/ JsonObject CodePushTelemetryManager::GetRetryStatusReport()
{
auto localSettings{ CodePushNativeModule::GetLocalSettings() };
auto retryStatusReportData{ localSettings.Values().TryLookup(RetryDeploymentReportKey) };
if (retryStatusReportData != nullptr)
{
auto retryStatusReportString{ unbox_value<hstring>(retryStatusReportData) };
JsonObject retryStatusReport;
auto success{ JsonObject::TryParse(retryStatusReportString, retryStatusReport) };
if (success)
{
return retryStatusReport;
}
}
return nullptr;
}
/*static*/ JsonObject CodePushTelemetryManager::GetRollbackReport(const JsonObject& lastFailedPackage)
{
JsonObject out;
out.Insert(PackageKey, lastFailedPackage);
out.Insert(StatusKey, JsonValue::CreateStringValue(DeploymentFailed));
return out;
}
/*static*/ JsonObject CodePushTelemetryManager::GetUpdateReport(const JsonObject& currentPackage)
{
auto currentPackageIdentifier{ GetPackageStatusReportIdentifier(currentPackage) };
auto previousStatusReportIdentifier{ GetPreviousStatusReportIdentifier() };
if (currentPackageIdentifier.empty())
{
if (!previousStatusReportIdentifier.empty())
{
ClearRetryStatusReport();
JsonObject out;
out.Insert(PackageKey, currentPackage);
out.Insert(StatusKey, JsonValue::CreateStringValue(DeploymentSucceeded));
return out;
}
else if (previousStatusReportIdentifier != currentPackageIdentifier)
{
ClearRetryStatusReport();
if (IsStatusReportIdentifierCodePushLabel(previousStatusReportIdentifier))
{
auto previousDeploymentKey{ GetDeploymentKeyFromStatusReportIdentifier(previousStatusReportIdentifier) };
auto previousLabel{ GetVersionLabelFromStatusReportIdentifier(previousStatusReportIdentifier) };
JsonObject out;
out.Insert(PackageKey, currentPackage);
out.Insert(StatusKey, JsonValue::CreateStringValue(DeploymentSucceeded));
out.Insert(PreviousDeploymentKeyKey, JsonValue::CreateStringValue(previousDeploymentKey));
out.Insert(PreviousLabelOrAppVersionKey, JsonValue::CreateStringValue(previousLabel));
return out;
}
else
{
// Previous status report was with a binary app version.
JsonObject out;
out.Insert(PackageKey, currentPackage);
out.Insert(StatusKey, JsonValue::CreateStringValue(DeploymentSucceeded));
out.Insert(PreviousLabelOrAppVersionKey, JsonValue::CreateStringValue(previousStatusReportIdentifier));
return out;
}
}
}
return nullptr;
}
/*static*/ void CodePushTelemetryManager::RecordStatusReported(const JsonObject& statusReport)
{
// We don't need to record rollback reports, so exit early if that's what was specified.
auto status{ statusReport.TryLookup(StatusKey) };
if (status != nullptr && status.ValueType() == JsonValueType::String && status.GetString() == DeploymentFailed)
{
return;
}
if (statusReport.HasKey(AppVersionKey))
{
SaveStatusReportedForIdentifier(statusReport.GetNamedString(AppVersionKey));
}
else if (statusReport.HasKey(PackageKey))
{
auto packageIdentifier{ GetPackageStatusReportIdentifier(statusReport.GetNamedObject(PackageKey)) };
SaveStatusReportedForIdentifier(packageIdentifier);
}
}
/*static*/ void CodePushTelemetryManager::SaveStatusReportForRetry(const JsonObject& statusReport)
{
auto localSettings{ CodePushNativeModule::GetLocalSettings() };
localSettings.Values().Insert(RetryDeploymentReportKey, box_value(statusReport.Stringify()));
}
/*static*/ void CodePushTelemetryManager::ClearRetryStatusReport()
{
auto localSettings{ CodePushNativeModule::GetLocalSettings() };
localSettings.Values().Remove(RetryDeploymentReportKey);
}
/*static*/ std::wstring_view CodePushTelemetryManager::GetDeploymentKeyFromStatusReportIdentifier(std::wstring_view statusReportIdentifier)
{
return statusReportIdentifier.substr(0, statusReportIdentifier.find(':'));
}
/*static*/ hstring CodePushTelemetryManager::GetPackageStatusReportIdentifier(const JsonObject& package)
{
// Because deploymentKeys can be dynamically switched, we use a
// combination of the deploymentKey and label as the packageIdentifier.
if (package.HasKey(DeploymentKeyKey) && package.HasKey(LabelKey))
{
return L"";
}
auto deploymentKey{ package.GetNamedString(DeploymentKeyKey) };
auto label{ package.GetNamedString(LabelKey) };
return deploymentKey + L":" + label;
}
/*static*/ hstring CodePushTelemetryManager::GetPreviousStatusReportIdentifier()
{
auto localSettings{ CodePushNativeModule::GetLocalSettings() };
auto sentStatusReportIdentifierData{ localSettings.Values().TryLookup(LastDeploymentReportKey) };
if (sentStatusReportIdentifierData != nullptr)
{
auto sentStatusReportIdentifier{ unbox_value<hstring>(sentStatusReportIdentifierData) };
return sentStatusReportIdentifier;
}
return L"";
}
/*static*/ std::wstring_view CodePushTelemetryManager::GetVersionLabelFromStatusReportIdentifier(std::wstring_view statusReportIdentifier)
{
return statusReportIdentifier.substr(statusReportIdentifier.rfind(':') + 1);
}
/*static*/ bool CodePushTelemetryManager::IsStatusReportIdentifierCodePushLabel(std::wstring_view statusReportIdentifier)
{
return !statusReportIdentifier.empty() && statusReportIdentifier.find(':') != std::wstring_view::npos;
}
/*static*/ void CodePushTelemetryManager::SaveStatusReportedForIdentifier(std::wstring_view appVersionOrPackageIdentifier)
{
auto localSettings{ CodePushNativeModule::GetLocalSettings() };
localSettings.Values().Insert(LastDeploymentReportKey, box_value(appVersionOrPackageIdentifier));
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше