diff --git a/.github/workflows/react-native-code-push-ci.yml b/.github/workflows/react-native-code-push-ci.yml index 58cf88f61..27e2c2029 100644 --- a/.github/workflows/react-native-code-push-ci.yml +++ b/.github/workflows/react-native-code-push-ci.yml @@ -38,7 +38,7 @@ jobs: - name: Setup Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7.4' + ruby-version: '2.7.6' bundler-cache: true - name: Package Installation run: npm install @@ -58,7 +58,7 @@ jobs: - name: Setup Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7.4' + ruby-version: '2.7.6' bundler-cache: true - name: Install dependencies run: npm install diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 88b57143b..cc30651c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,10 +37,10 @@ Follow these steps to test your modifications to the plugin manually: First, make sure you have installed the dependencies for the plugin by following the steps above. -Then, make sure you have installed `react-native-cli`. +Then, make sure you have installed `react-native`. ``` -npm install -g react-native-cli +npm install -g react-native ``` To run Android tests, make sure you have `sdk\tools`, `sdk\emulator` and `sdk\platform-tools` in your PATH. @@ -131,4 +131,4 @@ To run the core unit tests on Android and pull the plugin from NPM: NPM=true CORE=true npm run test:android ``` -...and so on! \ No newline at end of file +...and so on! diff --git a/README.md b/README.md index 8e8b25026..2e2ede692 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,8 @@ We try our best to maintain backwards compatibility of our plugin with previous | v0.59 | v5.6+ *(RN refactored js bundle loader code)* | | v0.60-v0.61 | v6.0+ *(RN migrated to Autolinking)* | | v0.62-v0.64 | v6.2+ *(RN removed LiveReload)* | -| v0.65-v0.69 | v7.2+ *(RN updated iPhone-target-version)* | +| v0.65-v0.70 | v7.0+ *(RN updated iPhone-target-version)* | +| v0.71 | v7.2+ *(RN moved to react-native-gradle-plugin)* | *NOTE: `react-native-code-push` versions lower than **[v5.7.0](https://github.com/microsoft/react-native-code-push/releases/tag/v5.7.0)** will stop working in the near future. You can find more information in our [documentation](https://github.com/microsoft/code-push/blob/master/migration-notice.md).* diff --git a/android/codepush.gradle b/android/codepush.gradle index 78134d358..a0f9d2748 100644 --- a/android/codepush.gradle +++ b/android/codepush.gradle @@ -2,8 +2,8 @@ import java.nio.file.Paths; -def config = project.hasProperty("react") ? project.react : []; -def bundleAssetName = config.bundleAssetName ?: "index.android.bundle" +def config = project.extensions.findByName("react") ?: [] +def bundleAssetName = config.bundleAssetName.get() ?: "index.android.bundle" // because elvis operator def elvisFile(thing) { @@ -23,11 +23,18 @@ android.buildTypes.each { buildType -> buildType.resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis()) } -gradle.projectsEvaluated { +gradle.projectsEvaluated { + def debuggableVariants = config.debuggableVariants.get() ?: ['debug'] + android.applicationVariants.all { variant -> + // No code push for debuggable variants + if (debuggableVariants.contains(variant.name)) { + return; + } + def nodeModulesPath; if (config.root) { - nodeModulesPath = Paths.get(config.root, "/node_modules"); + nodeModulesPath = Paths.get(config.root.asFile.get().absolutePath, "/node_modules"); } else if (project.hasProperty('nodeModulesPath')) { nodeModulesPath = project.nodeModulesPath } else { @@ -42,16 +49,16 @@ gradle.projectsEvaluated { def jsBundleFile; // Additional node commandline arguments - def nodeExecutableAndArgs = config.nodeExecutableAndArgs ?: ["node"] - def extraPackagerArgs = config.extraPackagerArgs ?: [] + def nodeExecutableAndArgs = config.nodeExecutableAndArgs.get() ?: ["node"] + def extraPackagerArgs = config.extraPackagerArgs.get() ?: [] // Make this task run right after the bundle task def generateBundledResourcesHash; - if (variant.hasProperty("bundleJsAndAssets")) { - def reactBundleTask = variant.bundleJsAndAssets - jsBundleDir = reactBundleTask.generatedAssetsFolders[0].absolutePath - resourcesDir = reactBundleTask.generatedResFolders[0].absolutePath + def reactBundleTask = tasks.findByName("createBundle${targetName}JsAndAssets") + if (reactBundleTask) { + jsBundleDir = reactBundleTask.property('jsBundleDir').asFile.get() + resourcesDir = reactBundleTask.property('resourcesDir').asFile.get() jsBundleFile = file("$jsBundleDir/$bundleAssetName") generateBundledResourcesHash = tasks.create( @@ -59,23 +66,21 @@ gradle.projectsEvaluated { type: Exec) { commandLine (*nodeExecutableAndArgs, "${nodeModulesPath}/react-native-code-push/scripts/generateBundledResourcesHash.js", resourcesDir, jsBundleFile, jsBundleDir) - enabled config."bundleIn${targetName}" || - config."bundleIn${variant.buildType.name.capitalize()}" ?: - targetName.toLowerCase().contains("release") + enabled !debuggableVariants.contains(variant.name) ?: targetName.toLowerCase().contains("release") } - + runBefore("merge${targetName}Resources", generateBundledResourcesHash) - runBefore("merge${targetName}Assets", generateBundledResourcesHash) + runBefore("merge${targetName}Assets", generateBundledResourcesHash) } else { def jsBundleDirConfigName = "jsBundleDir${targetName}" - jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?: + jsBundleDir = elvisFile(config."$jsBundleDirConfigName").get() ?: file("$buildDir/intermediates/assets/${targetPath}") def resourcesDirConfigName = "resourcesDir${targetName}" - resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?: + resourcesDir = elvisFile(config."${resourcesDirConfigName}").get() ?: file("$buildDir/intermediates/res/merged/${targetPath}") - // In case version of 'Android Plugin for Gradle'' is lower than 1.3.0 + // In case version of 'Android Plugin for Gradle'' is lower than 1.3.0 // '$buildDir' has slightly different structure - 'merged' folder // does not exists so '${targetPath}' folder contains directly in 'res' folder. if (!resourcesDir.exists() && file("$buildDir/intermediates/res/${targetPath}").exists()) { @@ -107,7 +112,8 @@ gradle.projectsEvaluated { generateBundledResourcesHash.dependsOn("recordFilesBeforeBundleCommand${targetName}") } - generateBundledResourcesHash.dependsOn("bundle${targetName}JsAndAssets") + generateBundledResourcesHash.dependsOn("createBundle${targetName}JsAndAssets") + runBefore("processArmeabi-v7a${targetName}Resources", generateBundledResourcesHash) runBefore("processX86${targetName}Resources", generateBundledResourcesHash) runBefore("processUniversal${targetName}Resources", generateBundledResourcesHash) diff --git a/code-push-plugin-testing-framework/script/testConfig.js b/code-push-plugin-testing-framework/script/testConfig.js index 40b7118f8..ba3651b76 100644 --- a/code-push-plugin-testing-framework/script/testConfig.js +++ b/code-push-plugin-testing-framework/script/testConfig.js @@ -2,7 +2,7 @@ // IMPORTS // var os = require("os"); var path = require("path"); -var TestUtil_1 = require("./TestUtil"); +var TestUtil_1 = require("./testUtil"); ////////////////////////////////////////////////////////////////////////////////////////// // Configuration variables. // What plugin to use, what project directories to use, etc. diff --git a/docs/setup-android.md b/docs/setup-android.md index 605dbeb1a..6201de2f1 100644 --- a/docs/setup-android.md +++ b/docs/setup-android.md @@ -27,11 +27,10 @@ In order to integrate CodePush into your Android project, please perform the fol project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app') ``` -2. In your `android/app/build.gradle` file, add the `codepush.gradle` file as an additional build task definition underneath `react.gradle`: +2. In your `android/app/build.gradle` file, add the `codepush.gradle` file as an additional build task definition to the end of the file: ```gradle ... - apply from: "../../node_modules/react-native/react.gradle" apply from: "../../node_modules/react-native-code-push/android/codepush.gradle" ... ``` diff --git a/package-lock.json b/package-lock.json index 0bf10f0f6..822bd9d3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-native-code-push", - "version": "7.1.0", + "version": "7.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "react-native-code-push", - "version": "7.1.0", + "version": "7.2.0", "license": "MIT", "dependencies": { "code-push": "^4.1.0", diff --git a/package.json b/package.json index f78d6db8d..f5112e995 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-code-push", - "version": "7.1.0", + "version": "7.2.0", "description": "React Native plugin for the CodePush service", "main": "CodePush.js", "typings": "typings/react-native-code-push.d.ts", diff --git a/test/template/index.android.js b/test/template/index.android.js deleted file mode 100644 index c0f5ee06a..000000000 --- a/test/template/index.android.js +++ /dev/null @@ -1 +0,0 @@ -import "./index.js"; \ No newline at end of file diff --git a/test/template/index.ios.js b/test/template/index.ios.js deleted file mode 100644 index c0f5ee06a..000000000 --- a/test/template/index.ios.js +++ /dev/null @@ -1 +0,0 @@ -import "./index.js"; \ No newline at end of file diff --git a/test/template/ios/TestCodePush/AppDelegate.m b/test/template/ios/TestCodePush/AppDelegate.m deleted file mode 100644 index 71e71ccfc..000000000 --- a/test/template/ios/TestCodePush/AppDelegate.m +++ /dev/null @@ -1,34 +0,0 @@ -#import "AppDelegate.h" - -#import - -#import -#import -#import - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - - RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; - RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge - moduleName:@"CODE_PUSH_TEST_APP_NAME" - initialProperties:nil]; - - rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; - - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [UIViewController new]; - rootViewController.view = rootView; - self.window.rootViewController = rootViewController; - [self.window makeKeyAndVisible]; - return YES; -} - - - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge - { - return [CodePush bundleURL]; - } - -@end diff --git a/test/template/ios/TestCodePush/AppDelegate.mm b/test/template/ios/TestCodePush/AppDelegate.mm new file mode 100644 index 000000000..dce0b50fe --- /dev/null +++ b/test/template/ios/TestCodePush/AppDelegate.mm @@ -0,0 +1,41 @@ +#import "AppDelegate.h" + +#import + +#import +#import +#import + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge + moduleName:@"CODE_PUSH_TEST_APP_NAME" + initialProperties:nil]; + + self.moduleName = @"TestCodePush"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = @{}; + + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ + return [CodePush bundleURL]; +} + +/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. +/// +/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html +/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). +/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. +- (BOOL)concurrentRootEnabled +{ + return true; +} + +@end diff --git a/test/test.ts b/test/test.ts index 2b3255509..1fed184ba 100644 --- a/test/test.ts +++ b/test/test.ts @@ -83,9 +83,10 @@ class RNAndroid extends Platform.Android implements RNPlatform { //// Set up gradle to build CodePush with the app // Add CodePush to android/app/build.gradle const buildGradle = path.join(innerprojectDirectory, "android", "app", "build.gradle"); + TestUtil.replaceString(buildGradle, - "apply from: \"../../node_modules/react-native/react.gradle\"", - "apply from: \"../../node_modules/react-native/react.gradle\"\napply from: \"" + gradleContent + "\""); + "apply from: file\\(\"../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle\"\\); applyNativeModulesAppBuildGradle\\(project\\)", + "apply from: file(\"../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle\"); applyNativeModulesAppBuildGradle(project)\napply from: \"" + gradleContent + "\""); // Add CodePush to android/settings.gradle const settingsGradle = path.join(innerprojectDirectory, "android", "settings.gradle"); @@ -122,13 +123,10 @@ class RNAndroid extends Platform.Android implements RNPlatform { * Build function of the test application, the command depends on the OS */ buildFunction(androidDirectory: string): Q.Promise { - if (process.platform === "darwin") { - return TestUtil.getProcessOutput(`./gradlew assembleRelease --daemon`, { noLogStdOut: true, cwd: androidDirectory }) - .then(() => { return null; }); - } else { - return TestUtil.getProcessOutput(`gradlew assembleRelease --daemon`, { noLogStdOut: true, cwd: androidDirectory }) + const gradlewCommand = process.platform === "darwin" || process.platform === "linux" ? "./gradlew" : "gradlew"; + return TestUtil.getProcessOutput(`${gradlewCommand} clean`, { noLogStdOut: true, cwd: androidDirectory }) + .then(() => TestUtil.getProcessOutput(`${gradlewCommand} assembleRelease --daemon`, { noLogStdOut: true, cwd: androidDirectory })) .then(() => { return null; }); - } } /** @@ -178,7 +176,7 @@ class RNIOS extends Platform.IOS implements RNPlatform { installPlatform(projectDirectory: string): Q.Promise { const iOSProject: string = path.join(projectDirectory, TestConfig.TestAppName, "ios"); const infoPlistPath: string = path.join(iOSProject, TestConfig.TestAppName, "Info.plist"); - const appDelegatePath: string = path.join(iOSProject, TestConfig.TestAppName, "AppDelegate.m"); + const appDelegatePath: string = path.join(iOSProject, TestConfig.TestAppName, "AppDelegate.mm"); // Install the Podfile @@ -195,9 +193,9 @@ class RNIOS extends Platform.IOS implements RNPlatform { // Add the correct bundle identifier .then(TestUtil.replaceString.bind(undefined, path.join(iOSProject, TestConfig.TestAppName + ".xcodeproj", "project.pbxproj"), "PRODUCT_BUNDLE_IDENTIFIER = [^;]*", "PRODUCT_BUNDLE_IDENTIFIER = \"" + TestConfig.TestNamespace + "\"")) - // Copy the AppDelegate.m to the project + // Copy the AppDelegate.mm to the project .then(TestUtil.copyFile.bind(undefined, - path.join(TestConfig.templatePath, "ios", TestConfig.TestAppName, "AppDelegate.m"), + path.join(TestConfig.templatePath, "ios", TestConfig.TestAppName, "AppDelegate.mm"), appDelegatePath, true)) .then(TestUtil.replaceString.bind(undefined, appDelegatePath, TestUtil.CODE_PUSH_TEST_APP_NAME_PLACEHOLDER, TestConfig.TestAppName)); } @@ -307,7 +305,7 @@ class RNProjectManager extends ProjectManager { } mkdirp.sync(projectDirectory); - return TestUtil.getProcessOutput("npx react-native init " + appName + " --version 0.67.1", { cwd: projectDirectory, timeout: 30 * 60 * 1000 }) + return TestUtil.getProcessOutput("npx react-native init " + appName + " --version 0.71.3", { cwd: projectDirectory, timeout: 30 * 60 * 1000 }) .then((e) => { console.log(`"npx react-native init ${appName}" success. cwd=${projectDirectory}`); return e; }) .then(this.copyTemplate.bind(this, templatePath, projectDirectory)) .then(TestUtil.getProcessOutput.bind(undefined, TestConfig.thisPluginInstallString, { cwd: path.join(projectDirectory, TestConfig.TestAppName) })) @@ -377,7 +375,7 @@ class RNProjectManager extends ProjectManager { deferred.resolve(undefined); }); return deferred.promise - .then(TestUtil.getProcessOutput.bind(undefined, "npx react-native bundle --platform " + targetPlatform.getName() + " --entry-file index." + targetPlatform.getName() + ".js --bundle-output " + bundlePath + " --assets-dest " + bundleFolder + " --dev false", + .then(TestUtil.getProcessOutput.bind(undefined, "npx react-native bundle --entry-file index.js --platform " + targetPlatform.getName() + " --bundle-output " + bundlePath + " --assets-dest " + bundleFolder + " --dev false", { cwd: path.join(projectDirectory, TestConfig.TestAppName) })) .then(TestUtil.archiveFolder.bind(undefined, bundleFolder, "", path.join(projectDirectory, TestConfig.TestAppName, "update.zip"), isDiff)); }