├── .flowconfig ├── .gitattributes ├── .gitignore ├── README.md ├── android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── org │ └── mauritsd │ └── reactnativedynamicbundle │ ├── RNDynamicBundleModule.java │ └── RNDynamicBundlePackage.java ├── example ├── .buckconfig ├── .eslintrc.js ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .prettierrc.js ├── .watchmanconfig ├── App.js ├── __tests__ │ └── App-test.js ├── android │ ├── app │ │ ├── BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.js ├── ios │ ├── Podfile │ ├── Podfile.lock │ ├── example-tvOS │ │ └── Info.plist │ ├── example-tvOSTests │ │ └── Info.plist │ ├── example.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── example-tvOS.xcscheme │ │ │ └── example.xcscheme │ ├── example.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── example │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── main.m │ └── exampleTests │ │ ├── Info.plist │ │ └── exampleTests.m ├── metro.config.js └── package.json ├── index.js ├── ios ├── RNDynamicBundle.h ├── RNDynamicBundle.m ├── RNDynamicBundle.podspec ├── RNDynamicBundle.xcodeproj │ └── project.pbxproj └── RNDynamicBundle.xcworkspace │ └── contents.xcworkspacedata ├── package.json └── yarn.lock /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | .*/example/.* 5 | 6 | ; Ignore "BUCK" generated dirs 7 | /\.buckd/ 8 | 9 | ; Ignore unexpected extra "@providesModule" 10 | .*/node_modules/.*/node_modules/fbjs/.* 11 | 12 | ; Ignore duplicate module providers 13 | ; For RN Apps installed via npm, "Libraries" folder is inside 14 | ; "node_modules/react-native" but in the source repo it is in the root 15 | .*/Libraries/react-native/React.js 16 | 17 | ; Ignore polyfills 18 | .*/Libraries/polyfills/.* 19 | 20 | ; Ignore metro 21 | .*/node_modules/metro/.* 22 | 23 | [include] 24 | 25 | [libs] 26 | node_modules/react-native/Libraries/react-native/react-native-interface.js 27 | node_modules/react-native/flow/ 28 | node_modules/react-native/flow-github/ 29 | 30 | [options] 31 | emoji=true 32 | 33 | module.system=haste 34 | 35 | munge_underscores=true 36 | 37 | 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\)$' -> 'RelativeImageStub' 38 | 39 | module.file_ext=.js 40 | module.file_ext=.jsx 41 | module.file_ext=.json 42 | module.file_ext=.native.js 43 | 44 | suppress_type=$FlowIssue 45 | suppress_type=$FlowFixMe 46 | suppress_type=$FlowFixMeProps 47 | suppress_type=$FlowFixMeState 48 | 49 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 50 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 51 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 52 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 53 | 54 | [version] 55 | ^0.68.0 56 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # OSX 3 | # 4 | .DS_Store 5 | 6 | # node.js 7 | # 8 | node_modules/ 9 | npm-debug.log 10 | yarn-error.log 11 | example/yarn.lock 12 | 13 | # Xcode 14 | # 15 | build/ 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | xcuserdata 25 | *.xccheckout 26 | *.moved-aside 27 | DerivedData 28 | *.hmap 29 | *.ipa 30 | *.xcuserstate 31 | project.xcworkspace 32 | 33 | 34 | # Android/IntelliJ 35 | # 36 | build/ 37 | .idea 38 | .gradle 39 | local.properties 40 | *.iml 41 | 42 | # BUCK 43 | buck-out/ 44 | \.buckd/ 45 | *.keystore 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # react-native-dynamic-bundle 3 | 4 | ## What is this? 5 | 6 | react-native-dynamic-bundle is a library, similar to react-native-auto-updater 7 | and CodePush, that allows you to change the React Native bundle loaded by 8 | an application without updating the application itself (i.e. through the App 9 | Store or Google Play). You could use this functionality to, for example: 10 | * Get app updates to users quicker. 11 | * Make A/B-testing or gradual rollouts as easy as on the web. 12 | 13 | react-native-dynamic-bundle differs from react-native-auto-updater and 14 | alternatives in that it does not attempt to be a complete solution, only 15 | providing the bare necessities for switching bundles and reloading the app. This 16 | requires you to implement the logic to download and keep track of the bundles 17 | yourself, but does give you complete freedom in how you implement your updater 18 | or A/B testing logic. 19 | 20 | ## To do's 21 | * Explanations of how to set it up on the native side. In the meanwhile have 22 | a look at AppDelegate.m for iOS and MainActivity.java / MainApplication.java 23 | for Android. 24 | 25 | 26 | ## Getting started 27 | 28 | `$ npm install react-native-dynamic-bundle --save` 29 | 30 | or 31 | 32 | `$ yarn add react-native-dynamic-bundle` 33 | 34 | 35 | ### Mostly automatic installation 36 | 37 | `$ react-native link react-native-dynamic-bundle` 38 | 39 | ### Manual installation 40 | 41 | 42 | #### iOS 43 | 44 | 1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]` 45 | 2. Go to `node_modules` ➜ `react-native-dynamic-bundle` and add `RNDynamicBundle.xcodeproj` 46 | 3. In XCode, in the project navigator, select your project. Add `libRNDynamicBundle.a` to your project's `Build Phases` ➜ `Link Binary With Libraries` 47 | 4. Run your project (`Cmd+R`)< 48 | 49 | #### Android 50 | 51 | 1. Open up `android/app/src/main/java/[...]/MainActivity.java` 52 | - Add `import org.mauritsd.reactnativedynamicbundle.RNDynamicBundlePackage;` to the imports at the top of the file 53 | - Add `new RNDynamicBundlePackage()` to the list returned by the `getPackages()` method 54 | 2. Append the following lines to `android/settings.gradle`: 55 | ``` 56 | include ':react-native-dynamic-bundle' 57 | project(':react-native-dynamic-bundle').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-dynamic-bundle/android') 58 | ``` 59 | 3. Insert the following lines inside the dependencies block in `android/app/build.gradle`: 60 | ``` 61 | compile project(':react-native-dynamic-bundle') 62 | ``` 63 | 64 | 65 | ## Usage 66 | ```javascript 67 | import { 68 | setActiveBundle, 69 | registerBundle, 70 | unregisterBundle, 71 | reloadBundle 72 | } from 'react-native-dynamic-bundle'; 73 | 74 | /* Register a bundle in the documents directory of the app. This could be 75 | * pre-packaged in your app, downloaded over http, etc. Paths are relative 76 | * to your documents directory. 77 | */ 78 | registerBundle('a_b_test', 'bundles/a_b_test.bundle'); 79 | 80 | /* Set the active bundle to a_b_test. This means that on the next load 81 | * this bundle will be loaded instead of the default. 82 | */ 83 | setActiveBundle('a_b_test'); 84 | 85 | /* Unregister a bundle once you're done with it. Note that you will have to 86 | * remove the file yourself. 87 | */ 88 | unregisterBundle('a_b_test'); 89 | 90 | /* In some circumstances (e.g. the user consents to an update) we want to 91 | * force a bundle reload instead of waiting until the next app restart. 92 | * Note that this will have to result in the destruction of the current 93 | * RCTBridge and its recreation with the new bundle URL. It is therefore 94 | * recommended to sync data and let actions complete before calling this. 95 | */ 96 | reloadBundle(); 97 | ``` 98 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | } 10 | } 11 | 12 | apply plugin: 'com.android.library' 13 | 14 | android { 15 | compileSdkVersion 23 16 | buildToolsVersion "23.0.1" 17 | 18 | defaultConfig { 19 | minSdkVersion 16 20 | targetSdkVersion 22 21 | versionCode 1 22 | versionName "1.0" 23 | } 24 | lintOptions { 25 | abortOnError false 26 | } 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | } 32 | 33 | dependencies { 34 | compile 'com.facebook.react:react-native:+' 35 | } 36 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/java/org/mauritsd/reactnativedynamicbundle/RNDynamicBundleModule.java: -------------------------------------------------------------------------------- 1 | 2 | package org.mauritsd.reactnativedynamicbundle; 3 | 4 | import android.content.Context; 5 | import android.content.SharedPreferences; 6 | import android.net.Uri; 7 | import android.util.Log; 8 | 9 | import com.facebook.react.bridge.Arguments; 10 | import com.facebook.react.bridge.Promise; 11 | import com.facebook.react.bridge.ReactApplicationContext; 12 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 13 | import com.facebook.react.bridge.ReactMethod; 14 | import com.facebook.react.bridge.Callback; 15 | import com.facebook.react.bridge.WritableMap; 16 | import com.facebook.react.module.annotations.ReactModule; 17 | 18 | import java.io.File; 19 | 20 | @ReactModule(name = "RNDynamicBundle") 21 | public class RNDynamicBundleModule extends ReactContextBaseJavaModule { 22 | public interface OnReloadRequestedListener { 23 | void onReloadRequested(); 24 | } 25 | 26 | private final ReactApplicationContext reactContext; 27 | private final SharedPreferences bundlePrefs; 28 | private final SharedPreferences extraPrefs; 29 | private OnReloadRequestedListener listener; 30 | 31 | /* Sadly need this to avoid a circular dependency in the ReactNativeHost 32 | * TODO: Refactor to avoid code duplication. 33 | */ 34 | public static String launchResolveBundlePath(Context ctx) { 35 | SharedPreferences bundlePrefs = ctx.getSharedPreferences("_bundles", Context.MODE_PRIVATE); 36 | SharedPreferences extraPrefs = ctx.getSharedPreferences("_extra", Context.MODE_PRIVATE); 37 | 38 | String activeBundle = extraPrefs.getString("activeBundle", null); 39 | if (activeBundle == null) { 40 | return null; 41 | } 42 | return bundlePrefs.getString(activeBundle, null); 43 | } 44 | 45 | public RNDynamicBundleModule(ReactApplicationContext reactContext) { 46 | super(reactContext); 47 | this.reactContext = reactContext; 48 | this.bundlePrefs = reactContext.getSharedPreferences("_bundles", Context.MODE_PRIVATE); 49 | this.extraPrefs = reactContext.getSharedPreferences("_extra", Context.MODE_PRIVATE); 50 | } 51 | 52 | @Override 53 | public String getName() { 54 | return "RNDynamicBundle"; 55 | } 56 | 57 | @ReactMethod 58 | public void setActiveBundle(String bundleId) { 59 | SharedPreferences.Editor editor = this.extraPrefs.edit(); 60 | editor.putString("activeBundle", bundleId); 61 | editor.commit(); 62 | } 63 | 64 | @ReactMethod 65 | public void registerBundle(String bundleId, String relativePath) { 66 | File absolutePath = new File(reactContext.getFilesDir(), relativePath); 67 | 68 | SharedPreferences.Editor editor = this.bundlePrefs.edit(); 69 | editor.putString(bundleId, absolutePath.getAbsolutePath()); 70 | editor.commit(); 71 | } 72 | 73 | @ReactMethod 74 | public void unregisterBundle(String bundleId) { 75 | SharedPreferences.Editor editor = this.bundlePrefs.edit(); 76 | editor.remove(bundleId); 77 | editor.commit(); 78 | } 79 | 80 | @ReactMethod 81 | public void reloadBundle() { 82 | if (listener != null) { 83 | listener.onReloadRequested(); 84 | } 85 | } 86 | 87 | @ReactMethod 88 | public void getBundles(Promise promise) { 89 | WritableMap bundles = Arguments.createMap(); 90 | for (String bundleId: bundlePrefs.getAll().keySet()) { 91 | String path = bundlePrefs.getString(bundleId, null); 92 | Uri url = Uri.fromFile(new File(path)); 93 | 94 | bundles.putString(bundleId, url.toString()); 95 | } 96 | 97 | promise.resolve(bundles); 98 | } 99 | 100 | @ReactMethod 101 | public void getActiveBundle(Promise promise) { 102 | promise.resolve(extraPrefs.getString("activeBundle", null)); 103 | } 104 | 105 | public String resolveBundlePath() { 106 | String activeBundle = extraPrefs.getString("activeBundle", null); 107 | if (activeBundle == null) { 108 | return null; 109 | } 110 | return bundlePrefs.getString(activeBundle, null); 111 | } 112 | 113 | public OnReloadRequestedListener getListener() { 114 | return listener; 115 | } 116 | 117 | public void setListener(OnReloadRequestedListener listener) { 118 | this.listener = listener; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /android/src/main/java/org/mauritsd/reactnativedynamicbundle/RNDynamicBundlePackage.java: -------------------------------------------------------------------------------- 1 | 2 | package org.mauritsd.reactnativedynamicbundle; 3 | 4 | import java.util.Arrays; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.bridge.NativeModule; 10 | import com.facebook.react.bridge.ReactApplicationContext; 11 | import com.facebook.react.uimanager.ViewManager; 12 | import com.facebook.react.bridge.JavaScriptModule; 13 | public class RNDynamicBundlePackage implements ReactPackage { 14 | @Override 15 | public List createNativeModules(ReactApplicationContext reactContext) { 16 | return Arrays.asList(new RNDynamicBundleModule(reactContext)); 17 | } 18 | 19 | // Deprecated from RN 0.47 20 | public List> createJSModules() { 21 | return Collections.emptyList(); 22 | } 23 | 24 | @Override 25 | public List createViewManagers(ReactApplicationContext reactContext) { 26 | return Collections.emptyList(); 27 | } 28 | } -------------------------------------------------------------------------------- /example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /example/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | }; 5 | -------------------------------------------------------------------------------- /example/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | node_modules/react-native/Libraries/react-native/React.js 15 | 16 | ; Ignore polyfills 17 | node_modules/react-native/Libraries/polyfills/.* 18 | 19 | ; These should not be required directly 20 | ; require from fbjs/lib instead: require('fbjs/lib/warning') 21 | node_modules/warning/.* 22 | 23 | ; Flow doesn't support platforms 24 | .*/Libraries/Utilities/HMRLoadingView.js 25 | 26 | [untyped] 27 | .*/node_modules/@react-native-community/cli/.*/.* 28 | 29 | [include] 30 | 31 | [libs] 32 | node_modules/react-native/Libraries/react-native/react-native-interface.js 33 | node_modules/react-native/flow/ 34 | 35 | [options] 36 | emoji=true 37 | 38 | esproposal.optional_chaining=enable 39 | esproposal.nullish_coalescing=enable 40 | 41 | module.file_ext=.js 42 | module.file_ext=.json 43 | module.file_ext=.ios.js 44 | 45 | module.system=haste 46 | module.system.haste.use_name_reducers=true 47 | # get basename 48 | module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' 49 | # strip .js or .js.flow suffix 50 | module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' 51 | # strip .ios suffix 52 | module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' 53 | module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' 54 | module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' 55 | module.system.haste.paths.blacklist=.*/__tests__/.* 56 | module.system.haste.paths.blacklist=.*/__mocks__/.* 57 | module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.* 58 | module.system.haste.paths.whitelist=/node_modules/react-native/RNTester/.* 59 | module.system.haste.paths.whitelist=/node_modules/react-native/IntegrationTests/.* 60 | module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/react-native/react-native-implementation.js 61 | module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.* 62 | 63 | munge_underscores=true 64 | 65 | 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\)$' -> 'RelativeImageStub' 66 | 67 | suppress_type=$FlowIssue 68 | suppress_type=$FlowFixMe 69 | suppress_type=$FlowFixMeProps 70 | suppress_type=$FlowFixMeState 71 | 72 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) 73 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ 74 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 75 | 76 | [lints] 77 | sketchy-null-number=warn 78 | sketchy-null-mixed=warn 79 | sketchy-number=warn 80 | untyped-type-import=warn 81 | nonstrict-import=warn 82 | deprecated-type=warn 83 | unsafe-getters-setters=warn 84 | inexact-spread=warn 85 | unnecessary-invariant=warn 86 | signature-verification-failure=warn 87 | deprecated-utility=error 88 | 89 | [strict] 90 | deprecated-type 91 | nonstrict-import 92 | sketchy-null 93 | unclear-type 94 | unsafe-getters-setters 95 | untyped-import 96 | untyped-type-import 97 | 98 | [version] 99 | ^0.98.0 100 | -------------------------------------------------------------------------------- /example/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | 58 | # CocoaPods 59 | /ios/Pods/ 60 | -------------------------------------------------------------------------------- /example/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | }; 7 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/App.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample RNDynamicBundle app 3 | * https://github.com/mauritsd/react-native-dynamic-bundle 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | StyleSheet, 10 | View, 11 | Button, 12 | TextInput 13 | } from 'react-native'; 14 | import { 15 | setActiveBundle, 16 | registerBundle, 17 | reloadBundle, 18 | getActiveBundle, 19 | getBundles, 20 | } from 'react-native-dynamic-bundle'; 21 | import RNFS from 'react-native-fs'; 22 | 23 | type Props = {}; 24 | export default class App extends Component { 25 | constructor(props) { 26 | super(props); 27 | 28 | this.state = { 29 | url: "" 30 | } 31 | } 32 | 33 | render() { 34 | return ( 35 | 36 | { this.setState({ url });}} 39 | value={this.state.url} 40 | autocorrect={false} 41 | placeholder="URL" 42 | autoCapitalize="none" 43 | /> 44 |