diff --git a/react-native-webview-bridge/.gitignore b/react-native-webview-bridge/.gitignore
new file mode 100644
index 00000000..fd4f2b06
--- /dev/null
+++ b/react-native-webview-bridge/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+.DS_Store
diff --git a/react-native-webview-bridge/LICENSE b/react-native-webview-bridge/LICENSE
new file mode 100644
index 00000000..8793c67c
--- /dev/null
+++ b/react-native-webview-bridge/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Ali Najafizadeh
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/react-native-webview-bridge/README.md b/react-native-webview-bridge/README.md
new file mode 100644
index 00000000..5daf55c4
--- /dev/null
+++ b/react-native-webview-bridge/README.md
@@ -0,0 +1,181 @@
+# Looking for Maintainer(s)
+I have been really busy and I can't continue maintaing this repo alone. I would like to ask if anyone wants to help I can grant a permission both on github and npm to start merging a lot of request and dealing with issues.
+
+Please send me your github and npm id so I can add you in.
+
+Thanks!
+
+
+## Please take a look at this [issue](https://github.com/alinz/react-native-webview-bridge/issues/109) first
+
+# React Native WebView Javascript Bridge
+I have been testing and reading a lot of way to safely create a bridge between react-native and webview. I'm happy to announced that the wait is over and from **React-Native 0.20 and above**, the bridge is fully functional.
+
+
+
+## Installation
+
+In order to use this extension, you have to do the following steps:
+
+in your react-native project, run `npm install react-native-webview-bridge --save`
+
+### iOS
+
+1. go to xcode's `Project Navigator` tab
+
+
+
+2. right click on `Libraries`
+3. select `Add Files to ...` option
+
+
+
+4. navigate to `node_modules/react-native-webview-bridge/ios` and add `React-Native-Webview-Bridge.xcodeproj` folder
+
+
+
+5. on project `Project Navigator` tab, click on your project's name and select Target's name and from there click on `Build Phases`
+
+
+
+6. expand `Link Binary With Libraries` and click `+` sign to add a new one.
+7. select `libReact-Native-Webviwe-Bridge.a` and click `Add` button.
+
+
+
+8. clean compile to make sure your project can compile and build.
+
+### Android
+
+1. add the following import to `MainApplication.java` (`MainActivity.java` if RN < 0.29) of your application
+
+```java
+import com.github.alinz.reactnativewebviewbridge.WebViewBridgePackage;
+```
+
+2. add the following code to add the package to `MainApplication.java`` (`MainActivity.java` if RN < 0.29)
+
+```java
+protected List getPackages() {
+ return Arrays.asList(
+ new MainReactPackage(),
+ new WebViewBridgePackage() //<- this
+ );
+ }
+```
+
+3. add the following codes to your `android/setting.gradle`
+
+> you might have multiple 3rd party libraries, make sure that you don't create multiple include.
+
+```
+include ':app', ':react-native-webview-bridge'
+project(':react-native-webview-bridge').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview-bridge/android')
+```
+
+4. edit `android/app/build.gradle` and add the following line inside `dependencies`
+
+```
+compile project(':react-native-webview-bridge')
+```
+
+5. run `react-native run-android` to see if everything is compilable.
+
+## Usage
+
+just import the module with one of your choices way:
+
+** CommonJS style **
+
+```js
+var WebViewBridge = require('react-native-webview-bridge');
+```
+
+** ES6/ES2015 style **
+
+```js
+import WebViewBridge from 'react-native-webview-bridge';
+```
+
+`WebViewBridge` is an extension of `WebView`. It injects special script into any pages once it loads. Also it extends the functionality of `WebView` by adding 1 new method and 1 new props.
+
+#### sendToBridge(message)
+the message must be in string. because this is the only way to send data back and forth between native and webview.
+
+
+#### onBridgeMessage
+this is a prop that needs to be a function. it will be called once a message is received from webview. The type of received message is also in string.
+
+#### allowFileAccessFromFileURLs (Android only)
+this is a prop that allows locally loaded pages via file:// to access other file:// resources. Pass-thru to corresponding [setting](https://developer.android.com/reference/android/webkit/WebSettings.html#setAllowFileAccessFromFileURLs(boolean)) in WebView. Default is `false` for Android 4.1 and above.
+
+#### allowUniversalAccessFromFileURLs (Android only)
+this is a prop that allows locally loaded pages via file:// to access resources in any origin. Pass-thru to corresponding [setting](https://developer.android.com/reference/android/webkit/WebSettings.html#setAllowUniversalAccessFromFileURLs(boolean)) in WebView. Default is `false` for Android 4.1 and above.
+
+## Bridge Script
+
+bridge script is a special script which injects into all the webview. It automatically register a global variable called `WebViewBridge`. It has 2 optional methods to implement and one method to send message to native side.
+
+#### send(message)
+
+this method sends a message to native side. the message must be in string type or `onError` method will be called.
+
+#### onMessage
+
+this method needs to be implemented. it will be called once a message arrives from native side. The type of message is in string.
+
+#### onError (iOS only)
+
+this is an error reporting method. It will be called if there is an error happens during sending a message. It receives a error message in string type.
+
+## Notes
+
+> a special bridge script will be injected once the page is going to different URL. So you don't have to manage when it needs to be injected.
+
+> You can still pass your own javascript to be injected into webview. However, Bridge script will be injected first and then your custom script.
+
+
+## Simple Example
+This example can be found in `examples` folder.
+
+```js
+const injectScript = `
+ (function () {
+ if (WebViewBridge) {
+
+ WebViewBridge.onMessage = function (message) {
+ if (message === "hello from react-native") {
+ WebViewBridge.send("got the message inside webview");
+ }
+ };
+
+ WebViewBridge.send("hello from webview");
+ }
+ }());
+`;
+
+var Sample2 = React.createClass({
+ onBridgeMessage(message){
+ const { webviewbridge } = this.refs;
+
+ switch (message) {
+ case "hello from webview":
+ webviewbridge.sendToBridge("hello from react-native");
+ break;
+ case "got the message inside webview":
+ console.log("we have got a message from webview! yeah");
+ break;
+ }
+ },
+
+ render() {
+ return (
+
+ );
+ }
+});
+```
diff --git a/react-native-webview-bridge/android/build.gradle b/react-native-webview-bridge/android/build.gradle
new file mode 100644
index 00000000..dfec22af
--- /dev/null
+++ b/react-native-webview-bridge/android/build.gradle
@@ -0,0 +1,34 @@
+buildscript {
+ repositories {
+ jcenter()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.1.3'
+ }
+}
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.1"
+
+ defaultConfig {
+ minSdkVersion 16
+ targetSdkVersion 23
+ versionCode 1
+ versionName "1.0"
+ }
+ lintOptions {
+ abortOnError false
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile 'com.facebook.react:react-native:0.19.+'
+}
diff --git a/react-native-webview-bridge/android/src/main/AndroidManifest.xml b/react-native-webview-bridge/android/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..84054d58
--- /dev/null
+++ b/react-native-webview-bridge/android/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/react-native-webview-bridge/android/src/main/java/com/github/alinz/reactnativewebviewbridge/JavascriptBridge.java b/react-native-webview-bridge/android/src/main/java/com/github/alinz/reactnativewebviewbridge/JavascriptBridge.java
new file mode 100644
index 00000000..2ad37116
--- /dev/null
+++ b/react-native-webview-bridge/android/src/main/java/com/github/alinz/reactnativewebviewbridge/JavascriptBridge.java
@@ -0,0 +1,29 @@
+package com.github.alinz.reactnativewebviewbridge;
+
+import android.webkit.JavascriptInterface;
+import android.webkit.WebView;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.modules.core.DeviceEventManagerModule;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+class JavascriptBridge {
+ private WebView webView;
+
+ public JavascriptBridge(WebView webView) {
+ this.webView = webView;
+ }
+
+ @JavascriptInterface
+ public void send(String message) {
+ WritableMap event = Arguments.createMap();
+ event.putString("message", message);
+ ReactContext reactContext = (ReactContext) this.webView.getContext();
+ reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
+ this.webView.getId(),
+ "topChange",
+ event);
+ }
+}
\ No newline at end of file
diff --git a/react-native-webview-bridge/android/src/main/java/com/github/alinz/reactnativewebviewbridge/WebViewBridgeManager.java b/react-native-webview-bridge/android/src/main/java/com/github/alinz/reactnativewebviewbridge/WebViewBridgeManager.java
new file mode 100644
index 00000000..c1250163
--- /dev/null
+++ b/react-native-webview-bridge/android/src/main/java/com/github/alinz/reactnativewebviewbridge/WebViewBridgeManager.java
@@ -0,0 +1,78 @@
+package com.github.alinz.reactnativewebviewbridge;
+
+import android.webkit.WebView;
+
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.views.webview.ReactWebViewManager;
+import com.facebook.react.uimanager.annotations.ReactProp;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+public class WebViewBridgeManager extends ReactWebViewManager {
+ private static final String REACT_CLASS = "RCTWebViewBridge";
+
+ public static final int COMMAND_SEND_TO_BRIDGE = 101;
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+
+ @Override
+ public
+ @Nullable
+ Map getCommandsMap() {
+ Map commandsMap = super.getCommandsMap();
+
+ commandsMap.put("sendToBridge", COMMAND_SEND_TO_BRIDGE);
+
+ return commandsMap;
+ }
+
+ @Override
+ protected WebView createViewInstance(ThemedReactContext reactContext) {
+ WebView root = super.createViewInstance(reactContext);
+ root.addJavascriptInterface(new JavascriptBridge(root), "WebViewBridge");
+ return root;
+ }
+
+ @Override
+ public void receiveCommand(WebView root, int commandId, @Nullable ReadableArray args) {
+ super.receiveCommand(root, commandId, args);
+
+ switch (commandId) {
+ case COMMAND_SEND_TO_BRIDGE:
+ sendToBridge(root, args.getString(0));
+ break;
+ default:
+ //do nothing!!!!
+ }
+ }
+
+ private void sendToBridge(WebView root, String message) {
+ String script = "WebViewBridge.onMessage('" + message + "');";
+ WebViewBridgeManager.evaluateJavascript(root, script);
+ }
+
+ static private void evaluateJavascript(WebView root, String javascript) {
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+ root.evaluateJavascript(javascript, null);
+ } else {
+ root.loadUrl("javascript:" + javascript);
+ }
+ }
+
+ @ReactProp(name = "allowFileAccessFromFileURLs")
+ public void setAllowFileAccessFromFileURLs(WebView root, boolean allows) {
+ root.getSettings().setAllowFileAccessFromFileURLs(allows);
+ }
+
+ @ReactProp(name = "allowUniversalAccessFromFileURLs")
+ public void setAllowUniversalAccessFromFileURLs(WebView root, boolean allows) {
+ root.getSettings().setAllowUniversalAccessFromFileURLs(allows);
+ }
+}
\ No newline at end of file
diff --git a/react-native-webview-bridge/android/src/main/java/com/github/alinz/reactnativewebviewbridge/WebViewBridgePackage.java b/react-native-webview-bridge/android/src/main/java/com/github/alinz/reactnativewebviewbridge/WebViewBridgePackage.java
new file mode 100644
index 00000000..1e189c4d
--- /dev/null
+++ b/react-native-webview-bridge/android/src/main/java/com/github/alinz/reactnativewebviewbridge/WebViewBridgePackage.java
@@ -0,0 +1,30 @@
+package com.github.alinz.reactnativewebviewbridge;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class WebViewBridgePackage implements ReactPackage {
+ @Override
+ public List createNativeModules(ReactApplicationContext reactApplicationContext) {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactApplicationContext) {
+ return Arrays.asList(
+ new WebViewBridgeManager()
+ );
+ }
+
+ @Override
+ public List> createJSModules() {
+ return Arrays.asList();
+ }
+}
diff --git a/react-native-webview-bridge/doc/assets/01.png b/react-native-webview-bridge/doc/assets/01.png
new file mode 100644
index 00000000..465b57cb
Binary files /dev/null and b/react-native-webview-bridge/doc/assets/01.png differ
diff --git a/react-native-webview-bridge/doc/assets/02.png b/react-native-webview-bridge/doc/assets/02.png
new file mode 100644
index 00000000..7b599c5c
Binary files /dev/null and b/react-native-webview-bridge/doc/assets/02.png differ
diff --git a/react-native-webview-bridge/doc/assets/03.png b/react-native-webview-bridge/doc/assets/03.png
new file mode 100644
index 00000000..cf9aa8f9
Binary files /dev/null and b/react-native-webview-bridge/doc/assets/03.png differ
diff --git a/react-native-webview-bridge/doc/assets/04.png b/react-native-webview-bridge/doc/assets/04.png
new file mode 100644
index 00000000..9c896565
Binary files /dev/null and b/react-native-webview-bridge/doc/assets/04.png differ
diff --git a/react-native-webview-bridge/doc/assets/05.png b/react-native-webview-bridge/doc/assets/05.png
new file mode 100644
index 00000000..05bf20d3
Binary files /dev/null and b/react-native-webview-bridge/doc/assets/05.png differ
diff --git a/react-native-webview-bridge/examples/SampleRN20/.flowconfig b/react-native-webview-bridge/examples/SampleRN20/.flowconfig
new file mode 100644
index 00000000..c3edaf94
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/.flowconfig
@@ -0,0 +1,65 @@
+[ignore]
+
+# We fork some components by platform.
+.*/*.web.js
+.*/*.android.js
+
+# Some modules have their own node_modules with overlap
+.*/node_modules/node-haste/.*
+
+# Ugh
+.*/node_modules/babel.*
+.*/node_modules/babylon.*
+.*/node_modules/invariant.*
+
+# Ignore react and fbjs where there are overlaps, but don't ignore
+# anything that react-native relies on
+.*/node_modules/fbjs/lib/Map.js
+.*/node_modules/fbjs/lib/Promise.js
+.*/node_modules/fbjs/lib/fetch.js
+.*/node_modules/fbjs/lib/ExecutionEnvironment.js
+.*/node_modules/fbjs/lib/isEmpty.js
+.*/node_modules/fbjs/lib/crc32.js
+.*/node_modules/fbjs/lib/ErrorUtils.js
+
+# Flow has a built-in definition for the 'react' module which we prefer to use
+# over the currently-untyped source
+.*/node_modules/react/react.js
+.*/node_modules/react/lib/React.js
+.*/node_modules/react/lib/ReactDOM.js
+
+# Ignore commoner tests
+.*/node_modules/commoner/test/.*
+
+# See https://github.com/facebook/flow/issues/442
+.*/react-tools/node_modules/commoner/lib/reader.js
+
+# Ignore jest
+.*/node_modules/jest-cli/.*
+
+# Ignore Website
+.*/website/.*
+
+[include]
+
+[libs]
+node_modules/react-native/Libraries/react-native/react-native-interface.js
+
+[options]
+module.system=haste
+
+munge_underscores=true
+
+module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
+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\)$' -> 'RelativeImageStub'
+
+suppress_type=$FlowIssue
+suppress_type=$FlowFixMe
+suppress_type=$FixMe
+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
+
+[version]
+0.21.0
diff --git a/react-native-webview-bridge/examples/SampleRN20/.gitignore b/react-native-webview-bridge/examples/SampleRN20/.gitignore
new file mode 100644
index 00000000..94fc8671
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/.gitignore
@@ -0,0 +1,34 @@
+# 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
+project.xcworkspace
+
+# Android/IJ
+#
+.idea
+.gradle
+local.properties
+
+# node.js
+#
+node_modules/
+npm-debug.log
diff --git a/react-native-webview-bridge/examples/SampleRN20/.watchmanconfig b/react-native-webview-bridge/examples/SampleRN20/.watchmanconfig
new file mode 100644
index 00000000..9e26dfee
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/.watchmanconfig
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/build.gradle b/react-native-webview-bridge/examples/SampleRN20/android/app/build.gradle
new file mode 100644
index 00000000..ca57f4e8
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/app/build.gradle
@@ -0,0 +1,126 @@
+apply plugin: "com.android.application"
+
+import com.android.build.OutputFile
+
+/**
+ * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
+ * and bundleReleaseJsAndAssets).
+ * These basically call `react-native bundle` with the correct arguments during the Android build
+ * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
+ * bundle directly from the development server. Below you can see all the possible configurations
+ * and their defaults. If you decide to add a configuration block, make sure to add it before the
+ * `apply from: "react.gradle"` line.
+ *
+ * project.ext.react = [
+ * // the name of the generated asset file containing your JS bundle
+ * bundleAssetName: "index.android.bundle",
+ *
+ * // the entry file for bundle generation
+ * entryFile: "index.android.js",
+ *
+ * // whether to bundle JS and assets in debug mode
+ * bundleInDebug: false,
+ *
+ * // whether to bundle JS and assets in release mode
+ * bundleInRelease: true,
+ *
+ * // whether to bundle JS and assets in another build variant (if configured).
+ * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
+ * // The configuration property is in the format 'bundleIn${productFlavor}${buildType}'
+ * // bundleInFreeDebug: true,
+ * // bundleInPaidRelease: true,
+ * // bundleInBeta: true,
+ *
+ * // the root of your project, i.e. where "package.json" lives
+ * root: "../../",
+ *
+ * // where to put the JS bundle asset in debug mode
+ * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
+ *
+ * // where to put the JS bundle asset in release mode
+ * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
+ *
+ * // where to put drawable resources / React Native assets, e.g. the ones you use via
+ * // require('./image.png')), in debug mode
+ * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
+ *
+ * // where to put drawable resources / React Native assets, e.g. the ones you use via
+ * // require('./image.png')), in release mode
+ * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
+ *
+ * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
+ * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
+ * // date; if you have any other folders that you want to ignore for performance reasons (gradle
+ * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
+ * // for example, you might want to remove it from here.
+ * inputExcludes: ["android/**", "ios/**"]
+ * ]
+ */
+
+apply from: "react.gradle"
+
+/**
+ * Set this to true to create three separate APKs instead of one:
+ * - A universal APK that works on all devices
+ * - An APK that only works on ARM devices
+ * - An APK that only works on x86 devices
+ * The advantage is the size of the APK is reduced by about 4MB.
+ * Upload all the APKs to the Play Store and people will download
+ * the correct one based on the CPU architecture of their device.
+ */
+def enableSeparateBuildPerCPUArchitecture = false
+
+/**
+ * Run Proguard to shrink the Java bytecode in release builds.
+ */
+def enableProguardInReleaseBuilds = false
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.1"
+
+ defaultConfig {
+ applicationId "com.samplern20"
+ minSdkVersion 16
+ targetSdkVersion 22
+ versionCode 1
+ versionName "1.0"
+ ndk {
+ abiFilters "armeabi-v7a", "x86"
+ }
+ }
+ splits {
+ abi {
+ enable enableSeparateBuildPerCPUArchitecture
+ universalApk false
+ reset()
+ include "armeabi-v7a", "x86"
+ }
+ }
+ buildTypes {
+ release {
+ minifyEnabled enableProguardInReleaseBuilds
+ proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
+ }
+ }
+ // applicationVariants are e.g. debug, release
+ applicationVariants.all { variant ->
+ variant.outputs.each { output ->
+ // For each separate APK per architecture, set a unique version code as described here:
+ // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
+ def versionCodes = ["armeabi-v7a":1, "x86":2]
+ def abi = output.getFilter(OutputFile.ABI)
+ if (abi != null) { // null for the universal-debug, universal-release variants
+ output.versionCodeOverride =
+ versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
+ }
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: "libs", include: ["*.jar"])
+ compile "com.android.support:appcompat-v7:23.0.1"
+ compile "com.facebook.react:react-native:0.20.+"
+ compile project(':react-native-webview-bridge')
+}
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/proguard-rules.pro b/react-native-webview-bridge/examples/SampleRN20/android/app/proguard-rules.pro
new file mode 100644
index 00000000..7d72e469
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/app/proguard-rules.pro
@@ -0,0 +1,67 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Disabling obfuscation is useful if you collect stack traces from production crashes
+# (unless you are using a system that supports de-obfuscate the stack traces).
+-dontobfuscate
+
+# React Native
+
+# Keep our interfaces so they can be used by other ProGuard rules.
+# See http://sourceforge.net/p/proguard/bugs/466/
+-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
+-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
+
+# Do not strip any method/class that is annotated with @DoNotStrip
+-keep @com.facebook.proguard.annotations.DoNotStrip class *
+-keepclassmembers class * {
+ @com.facebook.proguard.annotations.DoNotStrip *;
+}
+
+-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
+ void set*(***);
+ *** get*();
+}
+
+-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
+-keep class * extends com.facebook.react.bridge.NativeModule { *; }
+-keepclassmembers,includedescriptorclasses class * { native ; }
+-keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; }
+-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; }
+-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; }
+
+-dontwarn com.facebook.react.**
+
+# okhttp
+
+-keepattributes Signature
+-keepattributes *Annotation*
+-keep class com.squareup.okhttp.** { *; }
+-keep interface com.squareup.okhttp.** { *; }
+-dontwarn com.squareup.okhttp.**
+
+# okio
+
+-keep class sun.misc.Unsafe { *; }
+-dontwarn java.nio.file.*
+-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
+-dontwarn okio.**
+
+# stetho
+
+-dontwarn com.facebook.stetho.**
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/react.gradle b/react-native-webview-bridge/examples/SampleRN20/android/app/react.gradle
new file mode 100644
index 00000000..4b43bf91
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/app/react.gradle
@@ -0,0 +1,96 @@
+import org.apache.tools.ant.taskdefs.condition.Os
+
+def config = project.hasProperty("react") ? project.react : [];
+
+def bundleAssetName = config.bundleAssetName ?: "index.android.bundle"
+def entryFile = config.entryFile ?: "index.android.js"
+
+// because elvis operator
+def elvisFile(thing) {
+ return thing ? file(thing) : null;
+}
+
+def reactRoot = elvisFile(config.root) ?: file("../../")
+def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
+
+void runBefore(String dependentTaskName, Task task) {
+ Task dependentTask = tasks.findByPath(dependentTaskName);
+ if (dependentTask != null) {
+ dependentTask.dependsOn task
+ }
+}
+
+gradle.projectsEvaluated {
+ // Grab all build types and product flavors
+ def buildTypes = android.buildTypes.collect { type -> type.name }
+ def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
+
+ // When no product flavors defined, use empty
+ if (!productFlavors) productFlavors.add('')
+
+ productFlavors.each { productFlavorName ->
+ buildTypes.each { buildTypeName ->
+ // Create variant and source names
+ def sourceName = "${buildTypeName}"
+ def targetName = "${sourceName.capitalize()}"
+ if (productFlavorName) {
+ sourceName = "${productFlavorName}${targetName}"
+ }
+
+ // React js bundle directories
+ def jsBundleDirConfigName = "jsBundleDir${targetName}"
+ def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?:
+ file("$buildDir/intermediates/assets/${sourceName}")
+
+ def resourcesDirConfigName = "jsBundleDir${targetName}"
+ def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?:
+ file("$buildDir/intermediates/res/merged/${sourceName}")
+ def jsBundleFile = file("$jsBundleDir/$bundleAssetName")
+
+ // Bundle task name for variant
+ def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets"
+
+ def currentBundleTask = tasks.create(
+ name: bundleJsAndAssetsTaskName,
+ type: Exec) {
+ group = "react"
+ description = "bundle JS and assets for ${targetName}."
+
+ // Create dirs if they are not there (e.g. the "clean" task just ran)
+ doFirst {
+ jsBundleDir.mkdirs()
+ resourcesDir.mkdirs()
+ }
+
+ // Set up inputs and outputs so gradle can cache the result
+ inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
+ outputs.dir jsBundleDir
+ outputs.dir resourcesDir
+
+ // Set up the call to the react-native cli
+ workingDir reactRoot
+
+ // Set up dev mode
+ def devEnabled = !targetName.toLowerCase().contains("release")
+ if (Os.isFamily(Os.FAMILY_WINDOWS)) {
+ commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
+ "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
+ } else {
+ commandLine "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
+ "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
+ }
+
+ enabled config."bundleIn${targetName}" ?: targetName.toLowerCase().contains("release")
+ }
+
+ // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process
+ currentBundleTask.dependsOn("merge${targetName}Resources")
+ currentBundleTask.dependsOn("merge${targetName}Assets")
+
+ runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask)
+ runBefore("processX86${targetName}Resources", currentBundleTask)
+ runBefore("processUniversal${targetName}Resources", currentBundleTask)
+ runBefore("process${targetName}Resources", currentBundleTask)
+ }
+ }
+}
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/AndroidManifest.xml b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..0b001a8c
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/java/com/samplern20/MainActivity.java b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/java/com/samplern20/MainActivity.java
new file mode 100644
index 00000000..be7fb75f
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/java/com/samplern20/MainActivity.java
@@ -0,0 +1,43 @@
+package com.samplern20;
+
+import com.facebook.react.ReactActivity;
+import com.facebook.react.ReactPackage;
+import com.facebook.react.shell.MainReactPackage;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.github.alinz.reactnativewebviewbridge.WebViewBridgePackage;
+
+public class MainActivity extends ReactActivity {
+
+ /**
+ * Returns the name of the main component registered from JavaScript.
+ * This is used to schedule rendering of the component.
+ */
+ @Override
+ protected String getMainComponentName() {
+ return "SampleRN20";
+ }
+
+ /**
+ * Returns whether dev mode should be enabled.
+ * This enables e.g. the dev menu.
+ */
+ @Override
+ protected boolean getUseDeveloperSupport() {
+ return BuildConfig.DEBUG;
+ }
+
+ /**
+ * A list of packages used by the app. If the app uses additional views
+ * or modules besides the default ones, add more packages here.
+ */
+ @Override
+ protected List getPackages() {
+ return Arrays.asList(
+ new MainReactPackage(),
+ new WebViewBridgePackage()
+ );
+ }
+}
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..cde69bcc
Binary files /dev/null and b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..c133a0cb
Binary files /dev/null and b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..bfa42f0e
Binary files /dev/null and b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..324e72cd
Binary files /dev/null and b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/values/strings.xml b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..11d8d6a4
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ SampleRN20
+
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/values/styles.xml b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..319eb0ca
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/build.gradle b/react-native-webview-bridge/examples/SampleRN20/android/build.gradle
new file mode 100644
index 00000000..ccdfc4e3
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/build.gradle
@@ -0,0 +1,20 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.3.1'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ mavenLocal()
+ jcenter()
+ }
+}
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/gradle.properties b/react-native-webview-bridge/examples/SampleRN20/android/gradle.properties
new file mode 100644
index 00000000..1fd964e9
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/gradle.properties
@@ -0,0 +1,20 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+android.useDeprecatedNdk=true
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/gradle/wrapper/gradle-wrapper.jar b/react-native-webview-bridge/examples/SampleRN20/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..b5166dad
Binary files /dev/null and b/react-native-webview-bridge/examples/SampleRN20/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/gradle/wrapper/gradle-wrapper.properties b/react-native-webview-bridge/examples/SampleRN20/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..b9fbfaba
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/gradlew b/react-native-webview-bridge/examples/SampleRN20/android/gradlew
new file mode 100755
index 00000000..91a7e269
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/gradlew.bat b/react-native-webview-bridge/examples/SampleRN20/android/gradlew.bat
new file mode 100644
index 00000000..aec99730
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/react-native-webview-bridge/examples/SampleRN20/android/settings.gradle b/react-native-webview-bridge/examples/SampleRN20/android/settings.gradle
new file mode 100644
index 00000000..8238010e
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/android/settings.gradle
@@ -0,0 +1,4 @@
+rootProject.name = 'SampleRN20'
+
+include ':app', ':react-native-webview-bridge'
+project(':react-native-webview-bridge').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview-bridge/android')
diff --git a/react-native-webview-bridge/examples/SampleRN20/app.js b/react-native-webview-bridge/examples/SampleRN20/app.js
new file mode 100644
index 00000000..8e8b6748
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/app.js
@@ -0,0 +1,72 @@
+/**
+ * Sample React Native App
+ * https://github.com/facebook/react-native
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ View,
+ WebView
+} = React;
+
+var WebViewBridge = require('react-native-webview-bridge');
+
+const injectScript = `
+ (function () {
+ if (WebViewBridge) {
+
+ WebViewBridge.onMessage = function (message) {
+ if (message === "hello from react-native") {
+ WebViewBridge.send("got the message inside webview");
+ }
+ };
+
+ WebViewBridge.send("hello from webview");
+ }
+ }());
+`;
+
+var Sample2 = React.createClass({
+ onBridgeMessage: function (message) {
+ const { webviewbridge } = this.refs;
+
+ switch (message) {
+ case "hello from webview":
+ webviewbridge.sendToBridge("hello from react-native");
+ break;
+ case "got the message inside webview":
+ console.log("we have got a message from webview! yeah");
+ break;
+ }
+ },
+ render: function() {
+ return (
+
+
+
+
+ );
+ }
+});
+
+module.exports = Sample2;
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1
+ }
+});
+
diff --git a/react-native-webview-bridge/examples/SampleRN20/index.android.js b/react-native-webview-bridge/examples/SampleRN20/index.android.js
new file mode 100644
index 00000000..6e2f7e17
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/index.android.js
@@ -0,0 +1,12 @@
+/**
+ * Sample React Native App
+ * https://github.com/facebook/react-native
+ */
+'use strict';
+
+var React = require('react-native');
+var { AppRegistry } = React;
+
+var Sample2 = require('./app');
+
+AppRegistry.registerComponent('SampleRN20', () => Sample2);
diff --git a/react-native-webview-bridge/examples/SampleRN20/index.ios.js b/react-native-webview-bridge/examples/SampleRN20/index.ios.js
new file mode 100644
index 00000000..6e2f7e17
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/index.ios.js
@@ -0,0 +1,12 @@
+/**
+ * Sample React Native App
+ * https://github.com/facebook/react-native
+ */
+'use strict';
+
+var React = require('react-native');
+var { AppRegistry } = React;
+
+var Sample2 = require('./app');
+
+AppRegistry.registerComponent('SampleRN20', () => Sample2);
diff --git a/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20.xcodeproj/project.pbxproj b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..c6eb8cb7
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20.xcodeproj/project.pbxproj
@@ -0,0 +1,792 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
+ 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
+ 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
+ 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
+ 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
+ 00E356F31AD99517003FC87E /* SampleRN20Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* SampleRN20Tests.m */; };
+ 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
+ 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
+ 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
+ 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
+ 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
+ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
+ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
+ 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
+ 4134948E1C7E0CE200E31AFB /* libReact-Native-Webview-Bridge.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4134948C1C7E0CDD00E31AFB /* libReact-Native-Webview-Bridge.a */; };
+ 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 134814201AA4EA6300B7C361;
+ remoteInfo = RCTActionSheet;
+ };
+ 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 134814201AA4EA6300B7C361;
+ remoteInfo = RCTGeolocation;
+ };
+ 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 58B5115D1A9E6B3D00147676;
+ remoteInfo = RCTImage;
+ };
+ 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 58B511DB1A9E6C8500147676;
+ remoteInfo = RCTNetwork;
+ };
+ 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
+ remoteInfo = RCTVibration;
+ };
+ 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
+ remoteInfo = SampleRN20;
+ };
+ 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 134814201AA4EA6300B7C361;
+ remoteInfo = RCTSettings;
+ };
+ 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
+ remoteInfo = RCTWebSocket;
+ };
+ 146834031AC3E56700842450 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
+ remoteInfo = React;
+ };
+ 4134948B1C7E0CDD00E31AFB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4134947E1C7E0CDD00E31AFB /* React-Native-Webview-Bridge.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 4114DC4C1C187C3A003CD988;
+ remoteInfo = "React-Native-Webview-Bridge";
+ };
+ 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 134814201AA4EA6300B7C361;
+ remoteInfo = RCTLinking;
+ };
+ 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 58B5119B1A9E6C1200147676;
+ remoteInfo = RCTText;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; };
+ 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; };
+ 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; };
+ 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; };
+ 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; };
+ 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; };
+ 00E356EE1AD99517003FC87E /* SampleRN20Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SampleRN20Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 00E356F21AD99517003FC87E /* SampleRN20Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SampleRN20Tests.m; sourceTree = ""; };
+ 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; };
+ 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; };
+ 13B07F961A680F5B00A75B9A /* SampleRN20.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SampleRN20.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = SampleRN20/AppDelegate.h; sourceTree = ""; };
+ 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = SampleRN20/AppDelegate.m; sourceTree = ""; };
+ 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
+ 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = SampleRN20/Images.xcassets; sourceTree = ""; };
+ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = SampleRN20/Info.plist; sourceTree = ""; };
+ 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = SampleRN20/main.m; sourceTree = ""; };
+ 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; };
+ 4134947E1C7E0CDD00E31AFB /* React-Native-Webview-Bridge.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "React-Native-Webview-Bridge.xcodeproj"; path = "../node_modules/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj"; sourceTree = ""; };
+ 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; };
+ 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 00E356EB1AD99517003FC87E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4134948E1C7E0CE200E31AFB /* libReact-Native-Webview-Bridge.a in Frameworks */,
+ 146834051AC3E58100842450 /* libReact.a in Frameworks */,
+ 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
+ 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
+ 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
+ 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,
+ 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,
+ 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */,
+ 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
+ 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
+ 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 00C302A81ABCB8CE00DB3ED1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 00C302B61ABCB90400DB3ED1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 00C302BC1ABCB91800DB3ED1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 00C302D41ABCB9D200DB3ED1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 00C302E01ABCB9EE00DB3ED1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 00E356EF1AD99517003FC87E /* SampleRN20Tests */ = {
+ isa = PBXGroup;
+ children = (
+ 00E356F21AD99517003FC87E /* SampleRN20Tests.m */,
+ 00E356F01AD99517003FC87E /* Supporting Files */,
+ );
+ path = SampleRN20Tests;
+ sourceTree = "";
+ };
+ 00E356F01AD99517003FC87E /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 00E356F11AD99517003FC87E /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ 139105B71AF99BAD00B5F7CC /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 139FDEE71B06529A00C62182 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 13B07FAE1A68108700A75B9A /* SampleRN20 */ = {
+ isa = PBXGroup;
+ children = (
+ 008F07F21AC5B25A0029DE68 /* main.jsbundle */,
+ 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
+ 13B07FB01A68108700A75B9A /* AppDelegate.m */,
+ 13B07FB51A68108700A75B9A /* Images.xcassets */,
+ 13B07FB61A68108700A75B9A /* Info.plist */,
+ 13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
+ 13B07FB71A68108700A75B9A /* main.m */,
+ );
+ name = SampleRN20;
+ sourceTree = "";
+ };
+ 146834001AC3E56700842450 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 146834041AC3E56700842450 /* libReact.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 4134947F1C7E0CDD00E31AFB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 4134948C1C7E0CDD00E31AFB /* libReact-Native-Webview-Bridge.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 78C398B11ACF4ADC00677621 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 78C398B91ACF4ADC00677621 /* libRCTLinking.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 4134947E1C7E0CDD00E31AFB /* React-Native-Webview-Bridge.xcodeproj */,
+ 146833FF1AC3E56700842450 /* React.xcodeproj */,
+ 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
+ 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
+ 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */,
+ 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */,
+ 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */,
+ 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */,
+ 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
+ 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
+ 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
+ );
+ name = Libraries;
+ sourceTree = "";
+ };
+ 832341B11AAA6A8300B99B32 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 832341B51AAA6A8300B99B32 /* libRCTText.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 83CBB9F61A601CBA00E9B192 = {
+ isa = PBXGroup;
+ children = (
+ 13B07FAE1A68108700A75B9A /* SampleRN20 */,
+ 832341AE1AAA6A7D00B99B32 /* Libraries */,
+ 00E356EF1AD99517003FC87E /* SampleRN20Tests */,
+ 83CBBA001A601CBA00E9B192 /* Products */,
+ );
+ indentWidth = 2;
+ sourceTree = "";
+ tabWidth = 2;
+ };
+ 83CBBA001A601CBA00E9B192 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 13B07F961A680F5B00A75B9A /* SampleRN20.app */,
+ 00E356EE1AD99517003FC87E /* SampleRN20Tests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 00E356ED1AD99517003FC87E /* SampleRN20Tests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "SampleRN20Tests" */;
+ buildPhases = (
+ 00E356EA1AD99517003FC87E /* Sources */,
+ 00E356EB1AD99517003FC87E /* Frameworks */,
+ 00E356EC1AD99517003FC87E /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 00E356F51AD99517003FC87E /* PBXTargetDependency */,
+ );
+ name = SampleRN20Tests;
+ productName = SampleRN20Tests;
+ productReference = 00E356EE1AD99517003FC87E /* SampleRN20Tests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 13B07F861A680F5B00A75B9A /* SampleRN20 */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "SampleRN20" */;
+ buildPhases = (
+ 13B07F871A680F5B00A75B9A /* Sources */,
+ 13B07F8C1A680F5B00A75B9A /* Frameworks */,
+ 13B07F8E1A680F5B00A75B9A /* Resources */,
+ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SampleRN20;
+ productName = "Hello World";
+ productReference = 13B07F961A680F5B00A75B9A /* SampleRN20.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 83CBB9F71A601CBA00E9B192 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = Facebook;
+ TargetAttributes = {
+ 00E356ED1AD99517003FC87E = {
+ CreatedOnToolsVersion = 6.2;
+ TestTargetID = 13B07F861A680F5B00A75B9A;
+ };
+ };
+ };
+ buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "SampleRN20" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 83CBB9F61A601CBA00E9B192;
+ productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
+ projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
+ ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
+ },
+ {
+ ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;
+ ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
+ },
+ {
+ ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */;
+ ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
+ },
+ {
+ ProductGroup = 78C398B11ACF4ADC00677621 /* Products */;
+ ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
+ },
+ {
+ ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */;
+ ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
+ },
+ {
+ ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */;
+ ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
+ },
+ {
+ ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
+ ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
+ },
+ {
+ ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;
+ ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
+ },
+ {
+ ProductGroup = 139FDEE71B06529A00C62182 /* Products */;
+ ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
+ },
+ {
+ ProductGroup = 4134947F1C7E0CDD00E31AFB /* Products */;
+ ProjectRef = 4134947E1C7E0CDD00E31AFB /* React-Native-Webview-Bridge.xcodeproj */;
+ },
+ {
+ ProductGroup = 146834001AC3E56700842450 /* Products */;
+ ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
+ },
+ );
+ projectRoot = "";
+ targets = (
+ 13B07F861A680F5B00A75B9A /* SampleRN20 */,
+ 00E356ED1AD99517003FC87E /* SampleRN20Tests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+ 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTActionSheet.a;
+ remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTGeolocation.a;
+ remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTImage.a;
+ remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTNetwork.a;
+ remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTVibration.a;
+ remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTSettings.a;
+ remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTWebSocket.a;
+ remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 146834041AC3E56700842450 /* libReact.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libReact.a;
+ remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 4134948C1C7E0CDD00E31AFB /* libReact-Native-Webview-Bridge.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = "libReact-Native-Webview-Bridge.a";
+ remoteRef = 4134948B1C7E0CDD00E31AFB /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTLinking.a;
+ remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTText.a;
+ remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 00E356EC1AD99517003FC87E /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 13B07F8E1A680F5B00A75B9A /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
+ 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Bundle React Native code and images";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 00E356EA1AD99517003FC87E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 00E356F31AD99517003FC87E /* SampleRN20Tests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 13B07F871A680F5B00A75B9A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
+ 13B07FC11A68108700A75B9A /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 13B07F861A680F5B00A75B9A /* SampleRN20 */;
+ targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 13B07FB21A68108700A75B9A /* Base */,
+ );
+ name = LaunchScreen.xib;
+ path = SampleRN20;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 00E356F61AD99517003FC87E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SampleRN20Tests/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SampleRN20.app/SampleRN20";
+ };
+ name = Debug;
+ };
+ 00E356F71AD99517003FC87E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ COPY_PHASE_STRIP = NO;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SampleRN20Tests/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.2;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SampleRN20.app/SampleRN20";
+ };
+ name = Release;
+ };
+ 13B07F941A680F5B00A75B9A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ DEAD_CODE_STRIPPING = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+ "$(SRCROOT)/../node_modules/react-native/React/**",
+ );
+ INFOPLIST_FILE = SampleRN20/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = SampleRN20;
+ };
+ name = Debug;
+ };
+ 13B07F951A680F5B00A75B9A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+ "$(SRCROOT)/../node_modules/react-native/React/**",
+ );
+ INFOPLIST_FILE = SampleRN20/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = SampleRN20;
+ };
+ name = Release;
+ };
+ 83CBBA201A601CBA00E9B192 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+ "$(SRCROOT)/../node_modules/react-native/React/**",
+ );
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 83CBBA211A601CBA00E9B192 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+ "$(SRCROOT)/../node_modules/react-native/React/**",
+ );
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "SampleRN20Tests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 00E356F61AD99517003FC87E /* Debug */,
+ 00E356F71AD99517003FC87E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "SampleRN20" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 13B07F941A680F5B00A75B9A /* Debug */,
+ 13B07F951A680F5B00A75B9A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "SampleRN20" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 83CBBA201A601CBA00E9B192 /* Debug */,
+ 83CBBA211A601CBA00E9B192 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
+}
diff --git a/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20.xcodeproj/xcshareddata/xcschemes/SampleRN20.xcscheme b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20.xcodeproj/xcshareddata/xcschemes/SampleRN20.xcscheme
new file mode 100644
index 00000000..988357e2
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20.xcodeproj/xcshareddata/xcschemes/SampleRN20.xcscheme
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/AppDelegate.h b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/AppDelegate.h
new file mode 100644
index 00000000..a9654d5e
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/AppDelegate.h
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#import
+
+@interface AppDelegate : UIResponder
+
+@property (nonatomic, strong) UIWindow *window;
+
+@end
diff --git a/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/AppDelegate.m b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/AppDelegate.m
new file mode 100644
index 00000000..7c9c1443
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/AppDelegate.m
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#import "AppDelegate.h"
+
+#import "RCTRootView.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ NSURL *jsCodeLocation;
+
+ /**
+ * Loading JavaScript code - uncomment the one you want.
+ *
+ * OPTION 1
+ * Load from development server. Start the server from the repository root:
+ *
+ * $ npm start
+ *
+ * To run on device, change `localhost` to the IP address of your computer
+ * (you can get this by typing `ifconfig` into the terminal and selecting the
+ * `inet` value under `en0:`) and make sure your computer and iOS device are
+ * on the same Wi-Fi network.
+ */
+
+ jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
+
+ /**
+ * OPTION 2
+ * Load from pre-bundled file on disk. The static bundle is automatically
+ * generated by "Bundle React Native code and images" build step.
+ */
+
+// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
+
+ RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
+ moduleName:@"SampleRN20"
+ initialProperties:nil
+ launchOptions:launchOptions];
+
+ self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+ UIViewController *rootViewController = [UIViewController new];
+ rootViewController.view = rootView;
+ self.window.rootViewController = rootViewController;
+ [self.window makeKeyAndVisible];
+ return YES;
+}
+
+@end
diff --git a/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/Base.lproj/LaunchScreen.xib b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/Base.lproj/LaunchScreen.xib
new file mode 100644
index 00000000..44c5186c
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/Base.lproj/LaunchScreen.xib
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/Images.xcassets/AppIcon.appiconset/Contents.json b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 00000000..118c98f7
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,38 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/Info.plist b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/Info.plist
new file mode 100644
index 00000000..91963b26
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/Info.plist
@@ -0,0 +1,48 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+ NSLocationWhenInUseUsageDescription
+
+ NSAppTransportSecurity
+
+
+ NSAllowsArbitraryLoads
+
+
+
+
diff --git a/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/main.m b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/main.m
new file mode 100644
index 00000000..3d767fcb
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20/main.m
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#import
+
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20Tests/Info.plist b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20Tests/Info.plist
new file mode 100644
index 00000000..886825cc
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20Tests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20Tests/SampleRN20Tests.m b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20Tests/SampleRN20Tests.m
new file mode 100644
index 00000000..266d246c
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/ios/SampleRN20Tests/SampleRN20Tests.m
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#import
+#import
+
+#import "RCTLog.h"
+#import "RCTRootView.h"
+
+#define TIMEOUT_SECONDS 240
+#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
+
+@interface SampleRN20Tests : XCTestCase
+
+@end
+
+@implementation SampleRN20Tests
+
+- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
+{
+ if (test(view)) {
+ return YES;
+ }
+ for (UIView *subview in [view subviews]) {
+ if ([self findSubviewInView:subview matching:test]) {
+ return YES;
+ }
+ }
+ return NO;
+}
+
+- (void)testRendersWelcomeScreen
+{
+ UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
+ NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
+ BOOL foundElement = NO;
+
+ __block NSString *redboxError = nil;
+ RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
+ if (level >= RCTLogLevelError) {
+ redboxError = message;
+ }
+ });
+
+ while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
+ [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
+ [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
+
+ foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
+ if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
+ return YES;
+ }
+ return NO;
+ }];
+ }
+
+ RCTSetLogFunction(RCTDefaultLogFunction);
+
+ XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
+ XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
+}
+
+
+@end
diff --git a/react-native-webview-bridge/examples/SampleRN20/package.json b/react-native-webview-bridge/examples/SampleRN20/package.json
new file mode 100644
index 00000000..b031a531
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "SampleRN20",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "start": "node node_modules/react-native/local-cli/cli.js start"
+ },
+ "dependencies": {
+ "react-native": "0.20.0",
+ "react-native-webview-bridge": "../.."
+ }
+}
diff --git a/react-native-webview-bridge/examples/SampleRN20/test.html b/react-native-webview-bridge/examples/SampleRN20/test.html
new file mode 100644
index 00000000..6dc25e24
--- /dev/null
+++ b/react-native-webview-bridge/examples/SampleRN20/test.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Hello test html
+
+
\ No newline at end of file
diff --git a/react-native-webview-bridge/ios/RCTWebViewBridge.h b/react-native-webview-bridge/ios/RCTWebViewBridge.h
new file mode 100644
index 00000000..c7d34222
--- /dev/null
+++ b/react-native-webview-bridge/ios/RCTWebViewBridge.h
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * Copyright (c) 2015-present, Ali Najafizadeh (github.com/alinz)
+ * All rights reserved
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#import
+
+@class RCTWebViewBridge;
+
+/**
+ * Special scheme used to pass messages to the injectedJavaScript
+ * code without triggering a page load. Usage:
+ *
+ * window.location.href = RCTJSNavigationScheme + '://hello'
+ */
+extern NSString *const RCTJSNavigationScheme;
+
+@protocol RCTWebViewBridgeDelegate
+
+- (BOOL)webView:(RCTWebViewBridge *)webView
+shouldStartLoadForRequest:(NSMutableDictionary *)request
+ withCallback:(RCTDirectEventBlock)callback;
+
+@end
+
+@interface RCTWebViewBridge : RCTView
+
+@property (nonatomic, weak) id delegate;
+
+@property (nonatomic, copy) NSDictionary *source;
+@property (nonatomic, assign) UIEdgeInsets contentInset;
+@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
+@property (nonatomic, assign) BOOL hideKeyboardAccessoryView;
+@property (nonatomic, copy) NSString *injectedJavaScript;
+
+- (void)goForward;
+- (void)goBack;
+- (void)reload;
+- (void)sendToBridge:(NSString *)message;
+
+@end
diff --git a/react-native-webview-bridge/ios/RCTWebViewBridge.m b/react-native-webview-bridge/ios/RCTWebViewBridge.m
new file mode 100644
index 00000000..49984931
--- /dev/null
+++ b/react-native-webview-bridge/ios/RCTWebViewBridge.m
@@ -0,0 +1,403 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * Copyright (c) 2015-present, Ali Najafizadeh (github.com/alinz)
+ * All rights reserved
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#import "RCTWebViewBridge.h"
+
+#import
+
+#import
+#import
+#import
+#import
+#import
+#import
+#import "UIView+React.h"
+#import
+
+//This is a very elegent way of defining multiline string in objective-c.
+//source: http://stackoverflow.com/a/23387659/828487
+#define NSStringMultiline(...) [[NSString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
+
+//we don'e need this one since it has been defined in RCTWebView.m
+//NSString *const RCTJSNavigationScheme = @"react-js-navigation";
+NSString *const RCTWebViewBridgeSchema = @"wvb";
+
+// runtime trick to remove UIWebview keyboard default toolbar
+// see: http://stackoverflow.com/questions/19033292/ios-7-uiwebview-keyboard-issue/19042279#19042279
+@interface _SwizzleHelper : NSObject @end
+@implementation _SwizzleHelper
+-(id)inputAccessoryView
+{
+ return nil;
+}
+@end
+
+@interface RCTWebViewBridge ()
+
+@property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
+@property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
+@property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
+@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
+@property (nonatomic, copy) RCTDirectEventBlock onBridgeMessage;
+
+@end
+
+@implementation RCTWebViewBridge
+{
+ UIWebView *_webView;
+ NSString *_injectedJavaScript;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ if ((self = [super initWithFrame:frame])) {
+ super.backgroundColor = [UIColor clearColor];
+ _automaticallyAdjustContentInsets = YES;
+ _contentInset = UIEdgeInsetsZero;
+ _webView = [[UIWebView alloc] initWithFrame:self.bounds];
+ _webView.delegate = self;
+ [self addSubview:_webView];
+ }
+ return self;
+}
+
+RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
+
+- (void)goForward
+{
+ [_webView goForward];
+}
+
+- (void)goBack
+{
+ [_webView goBack];
+}
+
+- (void)reload
+{
+ [_webView reload];
+}
+
+- (void)sendToBridge:(NSString *)message
+{
+ //we are warpping the send message in a function to make sure that if
+ //WebView is not injected, we don't crash the app.
+ NSString *format = NSStringMultiline(
+ (function(){
+ if (WebViewBridge && WebViewBridge.__push__) {
+ WebViewBridge.__push__('%@');
+ }
+ }());
+ );
+
+ NSString *command = [NSString stringWithFormat: format, message];
+ [_webView stringByEvaluatingJavaScriptFromString:command];
+}
+
+- (NSURL *)URL
+{
+ return _webView.request.URL;
+}
+
+- (void)setSource:(NSDictionary *)source
+{
+ if (![_source isEqualToDictionary:source]) {
+ _source = [source copy];
+
+ // Check for a static html source first
+ NSString *html = [RCTConvert NSString:source[@"html"]];
+ if (html) {
+ NSURL *baseURL = [RCTConvert NSURL:source[@"baseUrl"]];
+ [_webView loadHTMLString:html baseURL:baseURL];
+ return;
+ }
+
+ NSURLRequest *request = [RCTConvert NSURLRequest:source];
+ // Because of the way React works, as pages redirect, we actually end up
+ // passing the redirect urls back here, so we ignore them if trying to load
+ // the same url. We'll expose a call to 'reload' to allow a user to load
+ // the existing page.
+ if ([request.URL isEqual:_webView.request.URL]) {
+ return;
+ }
+ if (!request.URL) {
+ // Clear the webview
+ [_webView loadHTMLString:@"" baseURL:nil];
+ return;
+ }
+ [_webView loadRequest:request];
+ }
+}
+
+- (void)layoutSubviews
+{
+ [super layoutSubviews];
+ _webView.frame = self.bounds;
+}
+
+- (void)setContentInset:(UIEdgeInsets)contentInset
+{
+ _contentInset = contentInset;
+ [RCTView autoAdjustInsetsForView:self
+ withScrollView:_webView.scrollView
+ updateOffset:NO];
+}
+
+- (void)setBackgroundColor:(UIColor *)backgroundColor
+{
+ CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
+ self.opaque = _webView.opaque = (alpha == 1.0);
+ _webView.backgroundColor = backgroundColor;
+}
+
+- (UIColor *)backgroundColor
+{
+ return _webView.backgroundColor;
+}
+
+- (NSMutableDictionary *)baseEvent
+{
+ NSMutableDictionary *event = [[NSMutableDictionary alloc] initWithDictionary:@{
+ @"url": _webView.request.URL.absoluteString ?: @"",
+ @"loading" : @(_webView.loading),
+ @"title": [_webView stringByEvaluatingJavaScriptFromString:@"document.title"],
+ @"canGoBack": @(_webView.canGoBack),
+ @"canGoForward" : @(_webView.canGoForward),
+ }];
+
+ return event;
+}
+
+- (void)refreshContentInset
+{
+ [RCTView autoAdjustInsetsForView:self
+ withScrollView:_webView.scrollView
+ updateOffset:YES];
+}
+
+-(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView
+{
+ if (!hideKeyboardAccessoryView) {
+ return;
+ }
+
+ UIView* subview;
+ for (UIView* view in _webView.scrollView.subviews) {
+ if([[view.class description] hasPrefix:@"UIWeb"])
+ subview = view;
+ }
+
+ if(subview == nil) return;
+
+ NSString* name = [NSString stringWithFormat:@"%@_SwizzleHelper", subview.class.superclass];
+ Class newClass = NSClassFromString(name);
+
+ if(newClass == nil)
+ {
+ newClass = objc_allocateClassPair(subview.class, [name cStringUsingEncoding:NSASCIIStringEncoding], 0);
+ if(!newClass) return;
+
+ Method method = class_getInstanceMethod([_SwizzleHelper class], @selector(inputAccessoryView));
+ class_addMethod(newClass, @selector(inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method));
+
+ objc_registerClassPair(newClass);
+ }
+
+ object_setClass(subview, newClass);
+}
+
+#pragma mark - UIWebViewDelegate methods
+
+- (BOOL)webView:(__unused UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
+ navigationType:(UIWebViewNavigationType)navigationType
+{
+ BOOL isJSNavigation = [request.URL.scheme isEqualToString:RCTJSNavigationScheme];
+
+ if (!isJSNavigation && [request.URL.scheme isEqualToString:RCTWebViewBridgeSchema]) {
+ NSString* message = [webView stringByEvaluatingJavaScriptFromString:@"WebViewBridge.__fetch__()"];
+
+ NSMutableDictionary *onBridgeMessageEvent = [[NSMutableDictionary alloc] initWithDictionary:@{
+ @"messages": [self stringArrayJsonToArray: message]
+ }];
+
+ _onBridgeMessage(onBridgeMessageEvent);
+
+ isJSNavigation = YES;
+ }
+
+ // skip this for the JS Navigation handler
+ if (!isJSNavigation && _onShouldStartLoadWithRequest) {
+ NSMutableDictionary *event = [self baseEvent];
+ [event addEntriesFromDictionary: @{
+ @"url": (request.URL).absoluteString,
+ @"navigationType": @(navigationType)
+ }];
+ if (![self.delegate webView:self
+ shouldStartLoadForRequest:event
+ withCallback:_onShouldStartLoadWithRequest]) {
+ return NO;
+ }
+ }
+
+ if (_onLoadingStart) {
+ // We have this check to filter out iframe requests and whatnot
+ BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
+ if (isTopFrame) {
+ NSMutableDictionary *event = [self baseEvent];
+ [event addEntriesFromDictionary: @{
+ @"url": (request.URL).absoluteString,
+ @"navigationType": @(navigationType)
+ }];
+ _onLoadingStart(event);
+ }
+ }
+
+ // JS Navigation handler
+ return !isJSNavigation;
+}
+
+- (void)webView:(__unused UIWebView *)webView didFailLoadWithError:(NSError *)error
+{
+ if (_onLoadingError) {
+ if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) {
+ // NSURLErrorCancelled is reported when a page has a redirect OR if you load
+ // a new URL in the WebView before the previous one came back. We can just
+ // ignore these since they aren't real errors.
+ // http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os
+ return;
+ }
+
+ NSMutableDictionary *event = [self baseEvent];
+ [event addEntriesFromDictionary:@{
+ @"domain": error.domain,
+ @"code": @(error.code),
+ @"description": error.localizedDescription,
+ }];
+ _onLoadingError(event);
+ }
+}
+
+- (void)webViewDidFinishLoad:(UIWebView *)webView
+{
+ //injecting WebViewBridge Script
+ NSString *webViewBridgeScriptContent = [self webViewBridgeScript];
+ [webView stringByEvaluatingJavaScriptFromString:webViewBridgeScriptContent];
+ //////////////////////////////////////////////////////////////////////////////
+
+ if (_injectedJavaScript != nil) {
+ NSString *jsEvaluationValue = [webView stringByEvaluatingJavaScriptFromString:_injectedJavaScript];
+
+ NSMutableDictionary *event = [self baseEvent];
+ event[@"jsEvaluationValue"] = jsEvaluationValue;
+
+ _onLoadingFinish(event);
+ }
+ // we only need the final 'finishLoad' call so only fire the event when we're actually done loading.
+ else if (_onLoadingFinish && !webView.loading && ![webView.request.URL.absoluteString isEqualToString:@"about:blank"]) {
+ _onLoadingFinish([self baseEvent]);
+ }
+}
+
+- (NSArray*)stringArrayJsonToArray:(NSString *)message
+{
+ return [NSJSONSerialization JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding]
+ options:NSJSONReadingAllowFragments
+ error:nil];
+}
+
+//since there is no easy way to load the static lib resource in ios,
+//we are loading the script from this method.
+- (NSString *)webViewBridgeScript {
+ // NSBundle *bundle = [NSBundle mainBundle];
+ // NSString *webViewBridgeScriptFile = [bundle pathForResource:@"webviewbridge"
+ // ofType:@"js"];
+ // NSString *webViewBridgeScriptContent = [NSString stringWithContentsOfFile:webViewBridgeScriptFile
+ // encoding:NSUTF8StringEncoding
+ // error:nil];
+
+ return NSStringMultiline(
+ (function (window) {
+ 'use strict';
+
+ //Make sure that if WebViewBridge already in scope we don't override it.
+ if (window.WebViewBridge) {
+ return;
+ }
+
+ var RNWBSchema = 'wvb';
+ var sendQueue = [];
+ var receiveQueue = [];
+ var doc = window.document;
+ var customEvent = doc.createEvent('Event');
+
+ function callFunc(func, message) {
+ if ('function' === typeof func) {
+ func(message);
+ }
+ }
+
+ function signalNative() {
+ window.location = RNWBSchema + '://message' + new Date().getTime();
+ }
+
+ //I made the private function ugly signiture so user doesn't called them accidently.
+ //if you do, then I have nothing to say. :(
+ var WebViewBridge = {
+ //this function will be called by native side to push a new message
+ //to webview.
+ __push__: function (message) {
+ receiveQueue.push(message);
+ //reason I need this setTmeout is to return this function as fast as
+ //possible to release the native side thread.
+ setTimeout(function () {
+ var message = receiveQueue.pop();
+ callFunc(WebViewBridge.onMessage, message);
+ }, 15); //this magic number is just a random small value. I don't like 0.
+ },
+ __fetch__: function () {
+ //since our sendQueue array only contains string, and our connection to native
+ //can only accept string, we need to convert array of strings into single string.
+ var messages = JSON.stringify(sendQueue);
+
+ //we make sure that sendQueue is resets
+ sendQueue = [];
+
+ //return the messages back to native side.
+ return messages;
+ },
+ //make sure message is string. because only string can be sent to native,
+ //if you don't pass it as string, onError function will be called.
+ send: function (message) {
+ if ('string' !== typeof message) {
+ callFunc(WebViewBridge.onError, "message is type '" + typeof message + "', and it needs to be string");
+ return;
+ }
+
+ //we queue the messages to make sure that native can collects all of them in one shot.
+ sendQueue.push(message);
+ //signal the objective-c that there is a message in the queue
+ signalNative();
+ },
+ onMessage: null,
+ onError: null
+ };
+
+ window.WebViewBridge = WebViewBridge;
+
+ //dispatch event
+ customEvent.initEvent('WebViewBridge', true, true);
+ doc.dispatchEvent(customEvent);
+ }(window));
+ );
+}
+
+@end
diff --git a/react-native-webview-bridge/ios/RCTWebViewBridgeManager.h b/react-native-webview-bridge/ios/RCTWebViewBridgeManager.h
new file mode 100644
index 00000000..00578f3f
--- /dev/null
+++ b/react-native-webview-bridge/ios/RCTWebViewBridgeManager.h
@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * Copyright (c) 2015-present, Ali Najafizadeh (github.com/alinz)
+ * All rights reserved
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#import
+
+@interface RCTWebViewBridgeManager : RCTViewManager
+
+@end
diff --git a/react-native-webview-bridge/ios/RCTWebViewBridgeManager.m b/react-native-webview-bridge/ios/RCTWebViewBridgeManager.m
new file mode 100644
index 00000000..b7ae548e
--- /dev/null
+++ b/react-native-webview-bridge/ios/RCTWebViewBridgeManager.m
@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * Copyright (c) 2015-present, Ali Najafizadeh (github.com/alinz)
+ * All rights reserved
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#import "RCTWebViewBridgeManager.h"
+
+#import
+#import
+#import "RCTWebViewBridge.h"
+#import "UIView+React.h"
+
+@interface RCTWebViewBridgeManager ()
+
+@end
+
+@implementation RCTWebViewBridgeManager
+{
+ NSConditionLock *_shouldStartLoadLock;
+ BOOL _shouldStartLoad;
+}
+
+RCT_EXPORT_MODULE()
+
+- (UIView *)view
+{
+ RCTWebViewBridge *webView = [RCTWebViewBridge new];
+ webView.delegate = self;
+ return webView;
+}
+
+RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
+RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL)
+RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL)
+RCT_REMAP_VIEW_PROPERTY(scalesPageToFit, _webView.scalesPageToFit, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
+RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
+RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(hideKeyboardAccessoryView, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
+RCT_REMAP_VIEW_PROPERTY(allowsInlineMediaPlayback, _webView.allowsInlineMediaPlayback, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(onBridgeMessage, RCTDirectEventBlock)
+
+- (NSDictionary *)constantsToExport
+{
+ return @{
+ @"JSNavigationScheme": RCTJSNavigationScheme,
+ @"NavigationType": @{
+ @"LinkClicked": @(UIWebViewNavigationTypeLinkClicked),
+ @"FormSubmitted": @(UIWebViewNavigationTypeFormSubmitted),
+ @"BackForward": @(UIWebViewNavigationTypeBackForward),
+ @"Reload": @(UIWebViewNavigationTypeReload),
+ @"FormResubmitted": @(UIWebViewNavigationTypeFormResubmitted),
+ @"Other": @(UIWebViewNavigationTypeOther)
+ },
+ };
+}
+
+RCT_EXPORT_METHOD(goBack:(nonnull NSNumber *)reactTag)
+{
+ [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
+ RCTWebViewBridge *view = viewRegistry[reactTag];
+ if (![view isKindOfClass:[RCTWebViewBridge class]]) {
+ RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
+ } else {
+ [view goBack];
+ }
+ }];
+}
+
+RCT_EXPORT_METHOD(goForward:(nonnull NSNumber *)reactTag)
+{
+ [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
+ id view = viewRegistry[reactTag];
+ if (![view isKindOfClass:[RCTWebViewBridge class]]) {
+ RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
+ } else {
+ [view goForward];
+ }
+ }];
+}
+
+RCT_EXPORT_METHOD(reload:(nonnull NSNumber *)reactTag)
+{
+ [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
+ RCTWebViewBridge *view = viewRegistry[reactTag];
+ if (![view isKindOfClass:[RCTWebViewBridge class]]) {
+ RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
+ } else {
+ [view reload];
+ }
+ }];
+}
+
+RCT_EXPORT_METHOD(sendToBridge:(nonnull NSNumber *)reactTag
+ value:(NSString*)message)
+{
+ [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
+ RCTWebViewBridge *view = viewRegistry[reactTag];
+ if (![view isKindOfClass:[RCTWebViewBridge class]]) {
+ RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
+ } else {
+ [view sendToBridge: message];
+ }
+ }];
+}
+
+#pragma mark - Exported synchronous methods
+
+- (BOOL)webView:(__unused RCTWebViewBridge *)webView
+shouldStartLoadForRequest:(NSMutableDictionary *)request
+ withCallback:(RCTDirectEventBlock)callback
+{
+ _shouldStartLoadLock = [[NSConditionLock alloc] initWithCondition:arc4random()];
+ _shouldStartLoad = YES;
+ request[@"lockIdentifier"] = @(_shouldStartLoadLock.condition);
+ callback(request);
+
+ // Block the main thread for a maximum of 250ms until the JS thread returns
+ if ([_shouldStartLoadLock lockWhenCondition:0 beforeDate:[NSDate dateWithTimeIntervalSinceNow:.25]]) {
+ BOOL returnValue = _shouldStartLoad;
+ [_shouldStartLoadLock unlock];
+ _shouldStartLoadLock = nil;
+ return returnValue;
+ } else {
+ RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to YES");
+ return YES;
+ }
+}
+
+RCT_EXPORT_METHOD(startLoadWithResult:(BOOL)result lockIdentifier:(NSInteger)lockIdentifier)
+{
+ if ([_shouldStartLoadLock tryLockWhenCondition:lockIdentifier]) {
+ _shouldStartLoad = result;
+ [_shouldStartLoadLock unlockWithCondition:0];
+ } else {
+ RCTLogWarn(@"startLoadWithResult invoked with invalid lockIdentifier: "
+ "got %zd, expected %zd", lockIdentifier, _shouldStartLoadLock.condition);
+ }
+}
+
+@end
diff --git a/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/project.pbxproj b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..8f5454de
--- /dev/null
+++ b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/project.pbxproj
@@ -0,0 +1,281 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 4114DC5C1C187CCB003CD988 /* RCTWebViewBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 4114DC591C187CCB003CD988 /* RCTWebViewBridge.m */; };
+ 4114DC5D1C187CCB003CD988 /* RCTWebViewBridgeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4114DC5B1C187CCB003CD988 /* RCTWebViewBridgeManager.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 4114DC4A1C187C3A003CD988 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "include/$(PRODUCT_NAME)";
+ dstSubfolderSpec = 16;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 4114DC4C1C187C3A003CD988 /* libReact-Native-Webview-Bridge.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libReact-Native-Webview-Bridge.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4114DC581C187CCB003CD988 /* RCTWebViewBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewBridge.h; sourceTree = SOURCE_ROOT; };
+ 4114DC591C187CCB003CD988 /* RCTWebViewBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebViewBridge.m; sourceTree = SOURCE_ROOT; };
+ 4114DC5A1C187CCB003CD988 /* RCTWebViewBridgeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewBridgeManager.h; sourceTree = SOURCE_ROOT; };
+ 4114DC5B1C187CCB003CD988 /* RCTWebViewBridgeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebViewBridgeManager.m; sourceTree = SOURCE_ROOT; };
+ 4114DC5F1C187CE4003CD988 /* webviewbridge.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = webviewbridge.js; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 4114DC491C187C3A003CD988 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 4114DC431C187C3A003CD988 = {
+ isa = PBXGroup;
+ children = (
+ 4114DC4E1C187C3A003CD988 /* React-Native-Webview-Bridge */,
+ 4114DC5E1C187CE4003CD988 /* scripts */,
+ 4114DC4D1C187C3A003CD988 /* Products */,
+ );
+ sourceTree = "";
+ };
+ 4114DC4D1C187C3A003CD988 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 4114DC4C1C187C3A003CD988 /* libReact-Native-Webview-Bridge.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 4114DC4E1C187C3A003CD988 /* React-Native-Webview-Bridge */ = {
+ isa = PBXGroup;
+ children = (
+ 4114DC581C187CCB003CD988 /* RCTWebViewBridge.h */,
+ 4114DC591C187CCB003CD988 /* RCTWebViewBridge.m */,
+ 4114DC5A1C187CCB003CD988 /* RCTWebViewBridgeManager.h */,
+ 4114DC5B1C187CCB003CD988 /* RCTWebViewBridgeManager.m */,
+ );
+ path = "React-Native-Webview-Bridge";
+ sourceTree = "";
+ };
+ 4114DC5E1C187CE4003CD988 /* scripts */ = {
+ isa = PBXGroup;
+ children = (
+ 4114DC5F1C187CE4003CD988 /* webviewbridge.js */,
+ );
+ name = scripts;
+ path = ../scripts;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 4114DC4B1C187C3A003CD988 /* React-Native-Webview-Bridge */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4114DC551C187C3A003CD988 /* Build configuration list for PBXNativeTarget "React-Native-Webview-Bridge" */;
+ buildPhases = (
+ 4114DC481C187C3A003CD988 /* Sources */,
+ 4114DC491C187C3A003CD988 /* Frameworks */,
+ 4114DC4A1C187C3A003CD988 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "React-Native-Webview-Bridge";
+ productName = "React-Native-Webview-Bridge";
+ productReference = 4114DC4C1C187C3A003CD988 /* libReact-Native-Webview-Bridge.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 4114DC441C187C3A003CD988 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0710;
+ ORGANIZATIONNAME = alinz;
+ TargetAttributes = {
+ 4114DC4B1C187C3A003CD988 = {
+ CreatedOnToolsVersion = 7.1.1;
+ };
+ };
+ };
+ buildConfigurationList = 4114DC471C187C3A003CD988 /* Build configuration list for PBXProject "React-Native-Webview-Bridge" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 4114DC431C187C3A003CD988;
+ productRefGroup = 4114DC4D1C187C3A003CD988 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 4114DC4B1C187C3A003CD988 /* React-Native-Webview-Bridge */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 4114DC481C187C3A003CD988 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4114DC5D1C187CCB003CD988 /* RCTWebViewBridgeManager.m in Sources */,
+ 4114DC5C1C187CCB003CD988 /* RCTWebViewBridge.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 4114DC531C187C3A003CD988 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 4114DC541C187C3A003CD988 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 4114DC561C187C3A003CD988 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(inhereted)",
+ "$(SRCROOT)/../../../node_module/React/**",
+ "$(SRCROOT)/../../../node_modules/react-native/React/**",
+ );
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ };
+ name = Debug;
+ };
+ 4114DC571C187C3A003CD988 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(inhereted)",
+ "$(SRCROOT)/../../../node_module/React/**",
+ "$(SRCROOT)/../../../node_modules/react-native/React/**",
+ );
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 4114DC471C187C3A003CD988 /* Build configuration list for PBXProject "React-Native-Webview-Bridge" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4114DC531C187C3A003CD988 /* Debug */,
+ 4114DC541C187C3A003CD988 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4114DC551C187C3A003CD988 /* Build configuration list for PBXNativeTarget "React-Native-Webview-Bridge" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4114DC561C187C3A003CD988 /* Debug */,
+ 4114DC571C187C3A003CD988 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 4114DC441C187C3A003CD988 /* Project object */;
+}
diff --git a/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 00000000..74cbe5b1
--- /dev/null
+++ b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/project.xcworkspace/xcuserdata/ali.xcuserdatad/UserInterfaceState.xcuserstate b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/project.xcworkspace/xcuserdata/ali.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 00000000..5e877a8b
Binary files /dev/null and b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/project.xcworkspace/xcuserdata/ali.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/ali.xcuserdatad/xcschemes/react-native-webview-bridge.xcscheme b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/ali.xcuserdatad/xcschemes/react-native-webview-bridge.xcscheme
new file mode 100644
index 00000000..e211548a
--- /dev/null
+++ b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/ali.xcuserdatad/xcschemes/react-native-webview-bridge.xcscheme
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/ali.xcuserdatad/xcschemes/xcschememanagement.plist b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/ali.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 00000000..2f988c46
--- /dev/null
+++ b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/ali.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,22 @@
+
+
+
+
+ SchemeUserState
+
+ React-Native-Webview-Bridge.xcscheme
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ 4114DC4B1C187C3A003CD988
+
+ primary
+
+
+
+
+
diff --git a/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/taxi.xcuserdatad/xcschemes/xcschememanagement.plist b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/taxi.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 00000000..35d2065c
--- /dev/null
+++ b/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/taxi.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,14 @@
+
+
+
+
+ SchemeUserState
+
+ React-Native-Webview-Bridge.xcscheme
+
+ orderHint
+ 6
+
+
+
+
diff --git a/react-native-webview-bridge/package-lock.json b/react-native-webview-bridge/package-lock.json
new file mode 100644
index 00000000..738cbf4b
--- /dev/null
+++ b/react-native-webview-bridge/package-lock.json
@@ -0,0 +1,129 @@
+{
+ "name": "react-native-webview-bridge",
+ "version": "0.33.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "create-react-class": {
+ "version": "15.6.2",
+ "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.2.tgz",
+ "integrity": "sha1-zx7RXxKq1/FO9fLf4F5sQvke8Co=",
+ "requires": {
+ "fbjs": "0.8.16",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1"
+ }
+ },
+ "encoding": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+ "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+ "requires": {
+ "iconv-lite": "0.4.19"
+ }
+ },
+ "fbjs": {
+ "version": "0.8.16",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz",
+ "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=",
+ "requires": {
+ "core-js": "1.2.7",
+ "isomorphic-fetch": "2.2.1",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1",
+ "promise": "7.3.1",
+ "setimmediate": "1.0.5",
+ "ua-parser-js": "0.7.17"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+ "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+ },
+ "isomorphic-fetch": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+ "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
+ "requires": {
+ "node-fetch": "1.7.3",
+ "whatwg-fetch": "2.0.3"
+ }
+ },
+ "js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
+ },
+ "loose-envify": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
+ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
+ "requires": {
+ "js-tokens": "3.0.2"
+ }
+ },
+ "node-fetch": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
+ "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+ "requires": {
+ "encoding": "0.1.12",
+ "is-stream": "1.1.0"
+ }
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "requires": {
+ "asap": "2.0.6"
+ }
+ },
+ "prop-types": {
+ "version": "15.6.0",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz",
+ "integrity": "sha1-zq8IMCL8RrSjX2nhPvda7Q1jmFY=",
+ "requires": {
+ "fbjs": "0.8.16",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1"
+ }
+ },
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
+ },
+ "ua-parser-js": {
+ "version": "0.7.17",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz",
+ "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g=="
+ },
+ "whatwg-fetch": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz",
+ "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ="
+ }
+ }
+}
diff --git a/react-native-webview-bridge/package.json b/react-native-webview-bridge/package.json
new file mode 100644
index 00000000..d95e1726
--- /dev/null
+++ b/react-native-webview-bridge/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-native-webview-bridge",
+ "version": "0.33.0",
+ "description": "React Native WebView Javascript Bridge",
+ "main": "webview-bridge",
+ "directories": {
+ "example": "example",
+ "lib": "lib"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git@github.com:alinz/react-native-webview-bridge.git"
+ },
+ "keywords": [
+ "react-native",
+ "react-component",
+ "ios",
+ "webview-bridge"
+ ],
+ "author": "Ali Najafizadeh",
+ "contributors": [
+ "Hunter Medney"
+ ],
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/alinz/react-native-webview-bridge/issues"
+ },
+ "homepage": "https://github.com/alinz/react-native-webview-bridge",
+ "dependencies": {
+ "create-react-class": "^15.6.2",
+ "invariant": "2.2.0",
+ "keymirror": "0.1.1",
+ "prop-types": "^15.6.0"
+ }
+}
diff --git a/react-native-webview-bridge/scripts/webviewbridge.js b/react-native-webview-bridge/scripts/webviewbridge.js
new file mode 100644
index 00000000..32b43e0f
--- /dev/null
+++ b/react-native-webview-bridge/scripts/webviewbridge.js
@@ -0,0 +1,72 @@
+(function (window) {
+ 'use strict';
+
+ //Make sure that if WebViewBridge already in scope we don't override it.
+ if (window.WebViewBridge) {
+ return;
+ }
+
+ var RNWBSchema = 'wvb';
+ var sendQueue = [];
+ var receiveQueue = [];
+ var doc = window.document;
+ var customEvent = doc.createEvent('Event');
+
+ function callFunc(func, message) {
+ if ('function' === typeof func) {
+ func(message);
+ }
+ }
+
+ function signalNative() {
+ window.location = RNWBSchema + '://message' + new Date().getTime();
+ }
+
+ //I made the private function ugly signiture so user doesn't called them accidently.
+ //if you do, then I have nothing to say. :(
+ var WebViewBridge = {
+ //this function will be called by native side to push a new message
+ //to webview.
+ __push__: function (message) {
+ receiveQueue.push(message);
+ //reason I need this setTmeout is to return this function as fast as
+ //possible to release the native side thread.
+ setTimeout(function () {
+ var message = receiveQueue.pop();
+ callFunc(WebViewBridge.onMessage, message);
+ }, 15); //this magic number is just a random small value. I don't like 0.
+ },
+ __fetch__: function () {
+ //since our sendQueue array only contains string, and our connection to native
+ //can only accept string, we need to convert array of strings into single string.
+ var messages = JSON.stringify(sendQueue);
+
+ //we make sure that sendQueue is resets
+ sendQueue = [];
+
+ //return the messages back to native side.
+ return messages;
+ },
+ //make sure message is string. because only string can be sent to native,
+ //if you don't pass it as string, onError function will be called.
+ send: function (message) {
+ if ('string' !== typeof message) {
+ callFunc(WebViewBridge.onError, "message is type '" + typeof message + "', and it needs to be string");
+ return;
+ }
+
+ //we queue the messages to make sure that native can collects all of them in one shot.
+ sendQueue.push(message);
+ //signal the objective-c that there is a message in the queue
+ signalNative();
+ },
+ onMessage: null,
+ onError: null
+ };
+
+ window.WebViewBridge = WebViewBridge;
+
+ //dispatch event
+ customEvent.initEvent('WebViewBridge', true, true);
+ doc.dispatchEvent(customEvent);
+}(window));
diff --git a/react-native-webview-bridge/webview-bridge/index.android.js b/react-native-webview-bridge/webview-bridge/index.android.js
new file mode 100644
index 00000000..bdfe8180
--- /dev/null
+++ b/react-native-webview-bridge/webview-bridge/index.android.js
@@ -0,0 +1,233 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * Copyright (c) 2016-present, Ali Najafizadeh
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule WebViewBridge
+ */
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var invariant = require('invariant');
+var keyMirror = require('keymirror');
+var resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource');
+
+var {
+ ReactNativeViewAttributes,
+ UIManager,
+ EdgeInsetsPropType,
+ StyleSheet,
+ Text,
+ View,
+ WebView,
+ requireNativeComponent,
+ DeviceEventEmitter,
+ NativeModules: {
+ WebViewBridgeManager
+ }
+} = ReactNative;
+var { PropTypes } = React;
+
+var RCT_WEBVIEWBRIDGE_REF = 'webviewbridge';
+
+var WebViewBridgeState = keyMirror({
+ IDLE: null,
+ LOADING: null,
+ ERROR: null,
+});
+
+var RCTWebViewBridge = requireNativeComponent('RCTWebViewBridge', WebViewBridge);
+
+/**
+ * Renders a native WebView.
+ */
+var WebViewBridge = React.createClass({
+
+ propTypes: {
+ ...RCTWebViewBridge.propTypes,
+
+ /**
+ * Will be called once the message is being sent from webview
+ */
+ onBridgeMessage: PropTypes.func,
+ },
+
+ getInitialState: function() {
+ return {
+ viewState: WebViewBridgeState.IDLE,
+ lastErrorEvent: null,
+ startInLoadingState: true,
+ };
+ },
+
+
+ componentWillMount: function() {
+ DeviceEventEmitter.addListener("webViewBridgeMessage", (body) => {
+ const { onBridgeMessage } = this.props;
+ const message = body.message;
+ if (onBridgeMessage) {
+ onBridgeMessage(message);
+ }
+ });
+
+ if (this.props.startInLoadingState) {
+ this.setState({viewState: WebViewBridgeState.LOADING});
+ }
+ },
+
+ render: function() {
+ var otherView = null;
+
+ if (this.state.viewState === WebViewBridgeState.LOADING) {
+ otherView = this.props.renderLoading && this.props.renderLoading();
+ } else if (this.state.viewState === WebViewBridgeState.ERROR) {
+ var errorEvent = this.state.lastErrorEvent;
+ otherView = this.props.renderError && this.props.renderError(
+ errorEvent.domain,
+ errorEvent.code,
+ errorEvent.description);
+ } else if (this.state.viewState !== WebViewBridgeState.IDLE) {
+ console.error('RCTWebViewBridge invalid state encountered: ' + this.state.loading);
+ }
+
+ var webViewStyles = [styles.container, this.props.style];
+ if (this.state.viewState === WebViewBridgeState.LOADING ||
+ this.state.viewState === WebViewBridgeState.ERROR) {
+ // if we're in either LOADING or ERROR states, don't show the webView
+ webViewStyles.push(styles.hidden);
+ }
+
+ var {javaScriptEnabled, domStorageEnabled} = this.props;
+ if (this.props.javaScriptEnabledAndroid) {
+ console.warn('javaScriptEnabledAndroid is deprecated. Use javaScriptEnabled instead');
+ javaScriptEnabled = this.props.javaScriptEnabledAndroid;
+ }
+ if (this.props.domStorageEnabledAndroid) {
+ console.warn('domStorageEnabledAndroid is deprecated. Use domStorageEnabled instead');
+ domStorageEnabled = this.props.domStorageEnabledAndroid;
+ }
+
+ let {source, ...props} = {...this.props};
+
+ var webView =
+ ;
+
+ return (
+
+ {webView}
+ {otherView}
+
+ );
+ },
+
+ onMessage(event) {
+ if (this.props.onBridgeMessage != null && event.nativeEvent != null) {
+ this.props.onBridgeMessage(event.nativeEvent.message)
+ }
+ },
+
+ goForward: function() {
+ UIManager.dispatchViewManagerCommand(
+ this.getWebViewBridgeHandle(),
+ UIManager.RCTWebViewBridge.Commands.goForward,
+ null
+ );
+ },
+
+ goBack: function() {
+ UIManager.dispatchViewManagerCommand(
+ this.getWebViewBridgeHandle(),
+ UIManager.RCTWebViewBridge.Commands.goBack,
+ null
+ );
+ },
+
+ reload: function() {
+ UIManager.dispatchViewManagerCommand(
+ this.getWebViewBridgeHandle(),
+ UIManager.RCTWebViewBridge.Commands.reload,
+ null
+ );
+ },
+
+ sendToBridge: function (message: string) {
+ UIManager.dispatchViewManagerCommand(
+ this.getWebViewBridgeHandle(),
+ UIManager.RCTWebViewBridge.Commands.sendToBridge,
+ [message]
+ );
+ },
+
+ /**
+ * We return an event with a bunch of fields including:
+ * url, title, loading, canGoBack, canGoForward
+ */
+ updateNavigationState: function(event) {
+ if (this.props.onNavigationStateChange) {
+ this.props.onNavigationStateChange(event.nativeEvent);
+ }
+ },
+
+ getWebViewBridgeHandle: function() {
+ return ReactNative.findNodeHandle(this.refs[RCT_WEBVIEWBRIDGE_REF]);
+ },
+
+ onLoadingStart: function(event) {
+ var onLoadStart = this.props.onLoadStart;
+ onLoadStart && onLoadStart(event);
+ this.updateNavigationState(event);
+ },
+
+ onLoadingError: function(event) {
+ event.persist(); // persist this event because we need to store it
+ var {onError, onLoadEnd} = this.props;
+ onError && onError(event);
+ onLoadEnd && onLoadEnd(event);
+
+ this.setState({
+ lastErrorEvent: event.nativeEvent,
+ viewState: WebViewBridgeState.ERROR
+ });
+ },
+
+ onLoadingFinish: function(event) {
+ var {onLoad, onLoadEnd} = this.props;
+ onLoad && onLoad(event);
+ onLoadEnd && onLoadEnd(event);
+ this.setState({
+ viewState: WebViewBridgeState.IDLE,
+ });
+ this.updateNavigationState(event);
+ },
+});
+
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ hidden: {
+ height: 0,
+ flex: 0, // disable 'flex:1' when hiding a View
+ },
+});
+
+module.exports = WebViewBridge;
\ No newline at end of file
diff --git a/react-native-webview-bridge/webview-bridge/index.ios.js b/react-native-webview-bridge/webview-bridge/index.ios.js
new file mode 100644
index 00000000..f7b09e5e
--- /dev/null
+++ b/react-native-webview-bridge/webview-bridge/index.ios.js
@@ -0,0 +1,324 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * Copyright (c) 2016-present, Ali Najafizadeh
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule WebViewBridge
+ * @flow
+ */
+'use strict';
+
+var React = require('react');
+var ReactNative = require('react-native');
+var invariant = require('invariant');
+var keyMirror = require('keymirror');
+var resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource');
+var PropTypes = require('prop-types');
+
+var {
+ ActivityIndicator,
+ EdgeInsetsPropType,
+ StyleSheet,
+ Text,
+ View,
+ WebView,
+ requireNativeComponent,
+ UIManager,
+ NativeModules: {
+ WebViewBridgeManager
+ }
+} = ReactNative;
+
+
+var BGWASH = 'rgba(255,255,255,0.8)';
+var RCT_WEBVIEWBRIDGE_REF = 'webviewbridge';
+
+var RCTWebViewBridgeManager = WebViewBridgeManager;
+
+var WebViewBridgeState = keyMirror({
+ IDLE: null,
+ LOADING: null,
+ ERROR: null,
+});
+
+var NavigationType = {
+ click: RCTWebViewBridgeManager.NavigationType.LinkClicked,
+ formsubmit: RCTWebViewBridgeManager.NavigationType.FormSubmitted,
+ backforward: RCTWebViewBridgeManager.NavigationType.BackForward,
+ reload: RCTWebViewBridgeManager.NavigationType.Reload,
+ formresubmit: RCTWebViewBridgeManager.NavigationType.FormResubmitted,
+ other: RCTWebViewBridgeManager.NavigationType.Other,
+};
+
+var JSNavigationScheme = RCTWebViewBridgeManager.JSNavigationScheme;
+
+type ErrorEvent = {
+ domain: any;
+ code: any;
+ description: any;
+}
+
+type Event = Object;
+
+var defaultRenderLoading = () => (
+
+
+
+);
+var defaultRenderError = (errorDomain, errorCode, errorDesc) => (
+
+
+ Error loading page
+
+
+ {'Domain: ' + errorDomain}
+
+
+ {'Error Code: ' + errorCode}
+
+
+ {'Description: ' + errorDesc}
+
+
+);
+
+/**
+ * Renders a native WebView.
+ */
+var createReactClass = require('create-react-class');
+var WebViewBridge = createReactClass({
+ statics: {
+ JSNavigationScheme: JSNavigationScheme,
+ NavigationType: NavigationType,
+ },
+
+ propTypes: {
+ ...WebView.propTypes,
+
+ /**
+ * Will be called once the message is being sent from webview
+ */
+ onBridgeMessage: PropTypes.func,
+
+ hideKeyboardAccessoryView: PropTypes.bool,
+
+ keyboardDisplayRequiresUserAction: PropTypes.bool,
+ },
+
+ getInitialState: function() {
+ return {
+ viewState: WebViewBridgeState.IDLE,
+ lastErrorEvent: (null: ?ErrorEvent),
+ startInLoadingState: true,
+ };
+ },
+
+ componentWillMount: function() {
+ if (this.props.startInLoadingState) {
+ this.setState({viewState: WebViewBridgeState.LOADING});
+ }
+ },
+
+ render: function() {
+ var otherView = null;
+
+ if (this.state.viewState === WebViewBridgeState.LOADING) {
+ otherView = (this.props.renderLoading || defaultRenderLoading)();
+ } else if (this.state.viewState === WebViewBridgeState.ERROR) {
+ var errorEvent = this.state.lastErrorEvent;
+ invariant(
+ errorEvent != null,
+ 'lastErrorEvent expected to be non-null'
+ );
+ otherView = (this.props.renderError || defaultRenderError)(
+ errorEvent.domain,
+ errorEvent.code,
+ errorEvent.description
+ );
+ } else if (this.state.viewState !== WebViewBridgeState.IDLE) {
+ console.error(
+ 'RCTWebViewBridge invalid state encountered: ' + this.state.loading
+ );
+ }
+
+ var webViewStyles = [styles.container, styles.webView, this.props.style];
+ if (this.state.viewState === WebViewBridgeState.LOADING ||
+ this.state.viewState === WebViewBridgeState.ERROR) {
+ // if we're in either LOADING or ERROR states, don't show the webView
+ webViewStyles.push(styles.hidden);
+ }
+
+ var onShouldStartLoadWithRequest = this.props.onShouldStartLoadWithRequest && ((event: Event) => {
+ var shouldStart = this.props.onShouldStartLoadWithRequest &&
+ this.props.onShouldStartLoadWithRequest(event.nativeEvent);
+ RCTWebViewBridgeManager.startLoadWithResult(!!shouldStart, event.nativeEvent.lockIdentifier);
+ });
+
+ var {javaScriptEnabled, domStorageEnabled} = this.props;
+ if (this.props.javaScriptEnabledAndroid) {
+ console.warn('javaScriptEnabledAndroid is deprecated. Use javaScriptEnabled instead');
+ javaScriptEnabled = this.props.javaScriptEnabledAndroid;
+ }
+ if (this.props.domStorageEnabledAndroid) {
+ console.warn('domStorageEnabledAndroid is deprecated. Use domStorageEnabled instead');
+ domStorageEnabled = this.props.domStorageEnabledAndroid;
+ }
+
+ var onBridgeMessage = (event: Event) => {
+ const onBridgeMessageCallback = this.props.onBridgeMessage;
+ if (onBridgeMessageCallback) {
+ const messages = event.nativeEvent.messages;
+ messages.forEach((message) => {
+ onBridgeMessageCallback(message);
+ });
+ }
+ };
+
+ let {source, ...props} = {...this.props};
+ delete props.onBridgeMessage;
+ delete props.onShouldStartLoadWithRequest;
+
+ var webView =
+ ;
+
+ return (
+
+ {webView}
+ {otherView}
+
+ );
+ },
+
+ goForward: function() {
+ UIManager.dispatchViewManagerCommand(
+ this.getWebViewBridgeHandle(),
+ UIManager.RCTWebViewBridge.Commands.goForward,
+ null
+ );
+ },
+
+ goBack: function() {
+ UIManager.dispatchViewManagerCommand(
+ this.getWebViewBridgeHandle(),
+ UIManager.RCTWebViewBridge.Commands.goBack,
+ null
+ );
+ },
+
+ reload: function() {
+ UIManager.dispatchViewManagerCommand(
+ this.getWebViewBridgeHandle(),
+ UIManager.RCTWebViewBridge.Commands.reload,
+ null
+ );
+ },
+
+ sendToBridge: function (message: string) {
+ WebViewBridgeManager.sendToBridge(this.getWebViewBridgeHandle(), message);
+ },
+
+ /**
+ * We return an event with a bunch of fields including:
+ * url, title, loading, canGoBack, canGoForward
+ */
+ updateNavigationState: function(event: Event) {
+ if (this.props.onNavigationStateChange) {
+ this.props.onNavigationStateChange(event.nativeEvent);
+ }
+ },
+
+ getWebViewBridgeHandle: function(): any {
+ return ReactNative.findNodeHandle(this.refs[RCT_WEBVIEWBRIDGE_REF]);
+ },
+
+ onLoadingStart: function(event: Event) {
+ var onLoadStart = this.props.onLoadStart;
+ onLoadStart && onLoadStart(event);
+ this.updateNavigationState(event);
+ },
+
+ onLoadingError: function(event: Event) {
+ event.persist(); // persist this event because we need to store it
+ var {onError, onLoadEnd} = this.props;
+ onError && onError(event);
+ onLoadEnd && onLoadEnd(event);
+ console.warn('Encountered an error loading page', event.nativeEvent);
+
+ this.setState({
+ lastErrorEvent: event.nativeEvent,
+ viewState: WebViewBridgeState.ERROR
+ });
+ },
+
+ onLoadingFinish: function(event: Event) {
+ var {onLoad, onLoadEnd} = this.props;
+ onLoad && onLoad(event);
+ onLoadEnd && onLoadEnd(event);
+ this.setState({
+ viewState: WebViewBridgeState.IDLE,
+ });
+ this.updateNavigationState(event);
+ },
+});
+
+var RCTWebViewBridge = requireNativeComponent('RCTWebViewBridge', WebViewBridge, {
+ nativeOnly: {
+ onLoadingStart: true,
+ onLoadingError: true,
+ onLoadingFinish: true,
+ },
+});
+
+var styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ errorContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: BGWASH,
+ },
+ errorText: {
+ fontSize: 14,
+ textAlign: 'center',
+ marginBottom: 2,
+ },
+ errorTextTitle: {
+ fontSize: 15,
+ fontWeight: '500',
+ marginBottom: 10,
+ },
+ hidden: {
+ height: 0,
+ flex: 0, // disable 'flex:1' when hiding a View
+ },
+ loadingView: {
+ backgroundColor: BGWASH,
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ webView: {
+ backgroundColor: '#ffffff',
+ }
+});
+
+module.exports = WebViewBridge;