diff --git a/Examples/CodePushDemoApp/.flowconfig b/Examples/CodePushDemoApp/.flowconfig index b69d071bc..f565799e7 100644 --- a/Examples/CodePushDemoApp/.flowconfig +++ b/Examples/CodePushDemoApp/.flowconfig @@ -1,7 +1,7 @@ [ignore] # We fork some components by platform. -.*/*.android.js +.*/*[.]android.js # Ignore templates with `@flow` in header .*/local-cli/generator.* @@ -48,11 +48,11 @@ suppress_type=$FlowIssue suppress_type=$FlowFixMe suppress_type=$FixMe -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(30\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(30\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-2]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-2]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy unsafe.enable_getters_and_setters=true [version] -^0.30.0 +^0.32.0 diff --git a/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj b/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj index 4c53a5e42..701e561a0 100644 --- a/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj +++ b/Examples/CodePushDemoApp/iOS/CodePushDemoApp.xcodeproj/project.pbxproj @@ -616,7 +616,7 @@ "$(inherited)", ); INFOPLIST_FILE = CodePushDemoAppTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CodePushDemoApp.app/CodePushDemoApp"; @@ -629,7 +629,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; INFOPLIST_FILE = CodePushDemoAppTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CodePushDemoApp.app/CodePushDemoApp"; @@ -640,6 +640,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; HEADER_SEARCH_PATHS = ( "$(inherited)", @@ -655,6 +656,7 @@ "-lc++", ); PRODUCT_NAME = CodePushDemoApp; + VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; @@ -662,6 +664,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 1; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, @@ -676,6 +679,7 @@ "-lc++", ); PRODUCT_NAME = CodePushDemoApp; + VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; @@ -718,7 +722,7 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", ); - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -758,7 +762,7 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", ); - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; diff --git a/Examples/CodePushDemoApp/package.json b/Examples/CodePushDemoApp/package.json index 7cd118319..432604c51 100644 --- a/Examples/CodePushDemoApp/package.json +++ b/Examples/CodePushDemoApp/package.json @@ -8,7 +8,7 @@ "dependencies": { "babel-preset-react-native-stage-0": "1.0.1", "react": "15.3.1", - "react-native": "0.33.0", + "react-native": "0.34.1", "react-native-code-push": "file:../../" } } diff --git a/README.md b/README.md index f591bec78..90f82d2ec 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,10 @@ We try our best to maintain backwards compatability of our plugin with previous | v0.14 | v1.3.0 *(introduced Android support)* | | v0.15-v0.18 | v1.4.0-v1.6.0 *(introduced iOS asset support)* | | v0.19-v0.28 | v1.7.0+ *(introduced Android asset support)* | -| v0.29-v0.31 | v1.13.0+ *(RN refactored native hosting code)* | -| v0.32-v0.33 | v1.14.6+ *(RN refactored native hosting code)* | -| v0.34+ | TBD :) We work hard to respond to new RN releases, but they do occasionally break us. We will update this chart with each RN release, so that users can check to see what our "official" support is. +| v0.29-v0.30 | v1.13.0+ *(RN refactored native hosting code)* | +| v0.31-v0.33 | v1.14.6+ *(RN refactored native hosting code)* | +| v0.34 | v1.15.0+ *(RN refactored native hosting code)* | +| v0.35+ | TBD :) We work hard to respond to new RN releases, but they do occasionally break us. We will update this chart with each RN release, so that users can check to see what our "official" support is. ## Supported Components @@ -83,7 +84,7 @@ Once you've followed the general-purpose ["getting started"](http://codepush.too npm install --save react-native-code-push@latest ``` -As with all other React Native plugins, the integration experience is different for iOS and Android, so perform the following setup steps depending on which platform(s) you are targeting. Note, if you are targeting both platforms it is recommended to create separate CodePush applications for each platform. +As with all other React Native plugins, the integration experience is different for iOS and Android, so perform the following setup steps depending on which platform(s) you are targeting. Note, if you are targeting both platforms it is recommended to create separate CodePush applications for each platform. If you want to see how other projects have integrated with CodePush, you can check out the excellent [example apps](#example-apps--starters) provided by the community. Additionally, if you'd like to quickly familiarize yourself with CodePush + React Native, you can check out the awesome getting started videos produced by [Bilal Budhani](https://www.youtube.com/watch?v=uN0FRWk-YW8&feature=youtu.be) and/or [Deepak Sisodiya ](https://www.youtube.com/watch?v=f6I9y7V-Ibk). diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java index 71dacf9b4..97a753af2 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java @@ -96,6 +96,49 @@ public void run() { }); } + // Use reflection to find and set the appropriate fields on ReactInstanceManager. See #556 for a proposal for a less brittle way + // to approach this. + private void setJSBundle(ReactInstanceManager instanceManager, String latestJSBundleFile) throws NoSuchFieldException, IllegalAccessException { + try { + Field bundleLoaderField = instanceManager.getClass().getDeclaredField("mBundleLoader"); + Class jsBundleLoaderClass = Class.forName("com.facebook.react.cxxbridge.JSBundleLoader"); + Method createFileLoaderMethod = null; + + Method[] methods = jsBundleLoaderClass.getDeclaredMethods(); + for (Method method : methods) { + if (method.getName() == "createFileLoader") { + createFileLoaderMethod = method; + break; + } + } + + if (createFileLoaderMethod == null) { + throw new NoSuchMethodException("Could not find a recognized 'createFileLoader' method"); + } + + int numParameters = createFileLoaderMethod.getGenericParameterTypes().length; + Object latestJSBundleLoader; + + if (numParameters == 1) { + // RN >= v0.34 + latestJSBundleLoader = createFileLoaderMethod.invoke(jsBundleLoaderClass, latestJSBundleFile); + } else if (numParameters == 2) { + // RN >= v0.31 && RN < v0.34 + latestJSBundleLoader = createFileLoaderMethod.invoke(jsBundleLoaderClass, getReactApplicationContext(), latestJSBundleFile); + } else { + throw new NoSuchMethodException("Could not find a recognized 'createFileLoader' method"); + } + + bundleLoaderField.setAccessible(true); + bundleLoaderField.set(instanceManager, latestJSBundleLoader); + } catch (Exception e) { + // RN < v0.31 + Field jsBundleField = instanceManager.getClass().getDeclaredField("mJSBundleFile"); + jsBundleField.setAccessible(true); + jsBundleField.set(instanceManager, latestJSBundleFile); + } + } + private void loadBundle() { mCodePush.clearDebugCacheIfNeeded(); try { @@ -109,20 +152,7 @@ private void loadBundle() { String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName()); // #2) Update the locally stored JS bundle file path - try { - // RN >= v0.30 - Field bundleLoaderField = instanceManager.getClass().getDeclaredField("mBundleLoader"); - Class jsBundleLoaderClass = Class.forName("com.facebook.react.cxxbridge.JSBundleLoader"); - Method createFileLoaderMethod = jsBundleLoaderClass.getDeclaredMethod("createFileLoader", Context.class, String.class); - Object latestJSBundleLoader = createFileLoaderMethod.invoke(jsBundleLoaderClass, getReactApplicationContext(), latestJSBundleFile); - bundleLoaderField.setAccessible(true); - bundleLoaderField.set(instanceManager, latestJSBundleLoader); - } catch (Exception e) { - // RN <= v0.30 - Field jsBundleField = instanceManager.getClass().getDeclaredField("mJSBundleFile"); - jsBundleField.setAccessible(true); - jsBundleField.set(instanceManager, latestJSBundleFile); - } + setJSBundle(instanceManager, latestJSBundleFile); // #3) Get the context creation method and fire it on the UI thread (which RN enforces) final Method recreateMethod = instanceManager.getClass().getMethod("recreateReactContextInBackground"); @@ -147,6 +177,7 @@ public void run() { } } + // Use reflection to find the ReactInstanceManager. See #556 for a proposal for a less brittle way to approach this. private ReactInstanceManager resolveInstanceManager() throws NoSuchFieldException, IllegalAccessException { ReactInstanceManager instanceManager = CodePush.getReactInstanceManager(); if (instanceManager != null) { diff --git a/package.json b/package.json index 141c42b48..325bec70f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-code-push", - "version": "1.14.7-beta", + "version": "1.15.0-beta", "description": "React Native plugin for the CodePush service", "main": "CodePush.js", "typings": "typings/react-native-code-push.d.ts",