├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── android
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── github
│ └── alinz
│ └── reactnativewebviewbridge
│ ├── JavascriptBridge.java
│ ├── WebViewBridgeManager.java
│ └── WebViewBridgePackage.java
├── doc
└── assets
│ ├── 01.png
│ ├── 02.png
│ ├── 03.png
│ ├── 04.png
│ └── 05.png
├── example
├── .babelrc
├── .buckconfig
├── .flowconfig
├── .gitattributes
├── .gitignore
├── .watchmanconfig
├── android
│ ├── app
│ │ ├── BUCK
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ ├── react.gradle
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── samplern20
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── MainApplication.java
│ │ │ └── res
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── keystores
│ │ ├── BUCK
│ │ └── debug.keystore.properties
│ └── settings.gradle
├── app.js
├── app.json
├── index.android.js
├── index.ios.js
├── ios
│ ├── SampleRN20.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ ├── SampleRN20-tvOS.xcscheme
│ │ │ └── SampleRN20.xcscheme
│ ├── SampleRN20
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.xib
│ │ ├── Images.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ └── main.m
│ └── SampleRN20Tests
│ │ ├── Info.plist
│ │ └── SampleRN20Tests.m
├── package.json
├── test.html
└── yarn.lock
├── ios
├── RCTWebViewBridge.h
├── RCTWebViewBridge.m
├── RCTWebViewBridgeManager.h
├── RCTWebViewBridgeManager.m
└── React-Native-Webview-Bridge.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── ali.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ └── ali.xcuserdatad
│ └── xcschemes
│ ├── react-native-webview-bridge.xcscheme
│ └── xcschememanagement.plist
├── package.json
├── scripts
└── webviewbridge.js
└── webview-bridge
├── index.android.js
└── index.ios.js
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | ############
3 | # Node
4 | ############
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 |
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 |
15 | # Directory for instrumented libs generated by jscoverage/JSCover
16 | lib-cov
17 |
18 | # Coverage directory used by tools like istanbul
19 | coverage
20 |
21 | # nyc test coverage
22 | .nyc_output
23 |
24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
25 | .grunt
26 |
27 | # node-waf configuration
28 | .lock-wscript
29 |
30 | # Compiled binary addons (http://nodejs.org/api/addons.html)
31 | build/Release
32 |
33 | # Dependency directories
34 | node_modules
35 | jspm_packages
36 |
37 | # Optional npm cache directory
38 | .npm
39 |
40 | # Optional REPL history
41 | .node_repl_history
42 |
43 | ################
44 | # JetBrains
45 | ################
46 | .idea
47 |
48 | ## File-based project format:
49 | *.iws
50 |
51 | ## Plugin-specific files:
52 |
53 | # IntelliJ
54 | /out/
55 |
56 | # mpeltonen/sbt-idea plugin
57 | .idea_modules/
58 |
59 | # JIRA plugin
60 | atlassian-ide-plugin.xml
61 |
62 | # Crashlytics plugin (for Android Studio and IntelliJ)
63 | com_crashlytics_export_strings.xml
64 | crashlytics.properties
65 | crashlytics-build.properties
66 | fabric.properties
67 |
68 |
69 | ############
70 | # iOS
71 | ############
72 | # Xcode
73 | #
74 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
75 |
76 | ## Build generated
77 | ios/build/
78 | ios/DerivedData/
79 |
80 | ## Various settings
81 | *.pbxuser
82 | !default.pbxuser
83 | *.mode1v3
84 | !default.mode1v3
85 | *.mode2v3
86 | !default.mode2v3
87 | *.perspectivev3
88 | !default.perspectivev3
89 | ios/xcuserdata/
90 |
91 | ## Other
92 | *.moved-aside
93 | *.xcuserstate
94 |
95 | ## Obj-C/Swift specific
96 | *.hmap
97 | *.ipa
98 | *.dSYM.zip
99 | *.dSYM
100 |
101 | # CocoaPods
102 | #
103 | # We recommend against adding the Pods directory to your .gitignore. However
104 | # you should judge for yourself, the pros and cons are mentioned at:
105 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
106 | #
107 | ios/Pods/
108 |
109 | # Carthage
110 | #
111 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
112 | # Carthage/Checkouts
113 |
114 | Carthage/Build
115 |
116 | # fastlane
117 | #
118 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
119 | # screenshots whenever they are needed.
120 | # For more information about the recommended setup visit:
121 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
122 |
123 | fastlane/report.xml
124 | fastlane/screenshots
125 |
126 |
127 | ############
128 | # Android
129 | ############
130 | # Built application files
131 | *.apk
132 | *.ap_
133 |
134 | # Files for the Dalvik VM
135 | *.dex
136 |
137 | # Java class files
138 | *.class
139 |
140 | # Generated files
141 | android/bin/
142 | android/gen/
143 | android/out/
144 |
145 | # Gradle files
146 | android/.gradle/
147 | android/build/
148 |
149 | # Local configuration file (sdk path, etc)
150 | local.properties
151 |
152 | # Proguard folder generated by Eclipse
153 | android/proguard/
154 |
155 | # Log Files
156 | *.log
157 |
158 | # Android Studio Navigation editor temp files
159 | android/.navigation/
160 |
161 | # Android Studio captures folder
162 | android/captures/
163 |
164 | # Intellij
165 | *.iml
166 |
167 | # Keystore files
168 | *.jks
169 |
170 | ##################
171 | # React-Native
172 | ##################
173 | # OSX
174 | #
175 | .DS_Store
176 |
177 | # Xcode
178 | #
179 | build/
180 | *.pbxuser
181 | !default.pbxuser
182 | *.mode1v3
183 | !default.mode1v3
184 | *.mode2v3
185 | !default.mode2v3
186 | *.perspectivev3
187 | !default.perspectivev3
188 | xcuserdata
189 | *.xccheckout
190 | *.moved-aside
191 | DerivedData
192 | *.hmap
193 | *.ipa
194 | *.xcuserstate
195 | project.xcworkspace
196 |
197 | # Android/IJ
198 | #
199 | .idea
200 | .gradle
201 | local.properties
202 |
203 | # node.js
204 | #
205 | node_modules/
206 | npm-debug.log
207 |
208 | # BUCK
209 | buck-out/
210 | \.buckd/
211 | android/app/libs
212 | android/keystores/debug.keystore
213 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | test/
3 | examples/
4 | doc/
5 |
6 | .npmignore
7 |
8 | #################
9 | # from .gitignore:
10 | ################
11 |
12 |
13 | ############
14 | # Node
15 | ############
16 | # Logs
17 | logs
18 | *.log
19 | npm-debug.log*
20 |
21 | # Runtime data
22 | pids
23 | *.pid
24 | *.seed
25 |
26 | # Directory for instrumented libs generated by jscoverage/JSCover
27 | lib-cov
28 |
29 | # Coverage directory used by tools like istanbul
30 | coverage
31 |
32 | # nyc test coverage
33 | .nyc_output
34 |
35 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
36 | .grunt
37 |
38 | # node-waf configuration
39 | .lock-wscript
40 |
41 | # Compiled binary addons (http://nodejs.org/api/addons.html)
42 | build/Release
43 |
44 | # Dependency directories
45 | node_modules
46 | jspm_packages
47 |
48 | # Optional npm cache directory
49 | .npm
50 |
51 | # Optional REPL history
52 | .node_repl_history
53 |
54 | ################
55 | # JetBrains
56 | ################
57 | .idea
58 |
59 | ## File-based project format:
60 | *.iws
61 |
62 | ## Plugin-specific files:
63 |
64 | # IntelliJ
65 | /out/
66 |
67 | # mpeltonen/sbt-idea plugin
68 | .idea_modules/
69 |
70 | # JIRA plugin
71 | atlassian-ide-plugin.xml
72 |
73 | # Crashlytics plugin (for Android Studio and IntelliJ)
74 | com_crashlytics_export_strings.xml
75 | crashlytics.properties
76 | crashlytics-build.properties
77 | fabric.properties
78 |
79 |
80 | ############
81 | # iOS
82 | ############
83 | # Xcode
84 | #
85 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
86 |
87 | ## Build generated
88 | ios/build/
89 | ios/DerivedData/
90 |
91 | ## Various settings
92 | *.pbxuser
93 | !default.pbxuser
94 | *.mode1v3
95 | !default.mode1v3
96 | *.mode2v3
97 | !default.mode2v3
98 | *.perspectivev3
99 | !default.perspectivev3
100 | ios/xcuserdata/
101 |
102 | ## Other
103 | *.moved-aside
104 | *.xcuserstate
105 |
106 | ## Obj-C/Swift specific
107 | *.hmap
108 | *.ipa
109 | *.dSYM.zip
110 | *.dSYM
111 |
112 | # CocoaPods
113 | #
114 | # We recommend against adding the Pods directory to your .gitignore. However
115 | # you should judge for yourself, the pros and cons are mentioned at:
116 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
117 | #
118 | ios/Pods/
119 |
120 | # Carthage
121 | #
122 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
123 | # Carthage/Checkouts
124 |
125 | Carthage/Build
126 |
127 | # fastlane
128 | #
129 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
130 | # screenshots whenever they are needed.
131 | # For more information about the recommended setup visit:
132 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
133 |
134 | fastlane/report.xml
135 | fastlane/screenshots
136 |
137 |
138 | ############
139 | # Android
140 | ############
141 | # Built application files
142 | *.apk
143 | *.ap_
144 |
145 | # Files for the Dalvik VM
146 | *.dex
147 |
148 | # Java class files
149 | *.class
150 |
151 | # Generated files
152 | android/bin/
153 | android/gen/
154 | android/out/
155 |
156 | # Gradle files
157 | .gradle/
158 | android/.gradle/
159 | android/build/
160 | android/*/build/
161 |
162 | # Local configuration file (sdk path, etc)
163 | local.properties
164 |
165 | # Proguard folder generated by Eclipse
166 | android/proguard/
167 |
168 | # Log Files
169 | *.log
170 |
171 | # Android Studio Navigation editor temp files
172 | android/.navigation/
173 |
174 | # Android Studio captures folder
175 | android/captures/
176 |
177 | # Intellij
178 | *.iml
179 |
180 | # Keystore files
181 | *.jks
182 |
183 | ##################
184 | # React-Native
185 | ##################
186 | # OSX
187 | #
188 | .DS_Store
189 |
190 | # Xcode
191 | #
192 | build/
193 | *.pbxuser
194 | !default.pbxuser
195 | *.mode1v3
196 | !default.mode1v3
197 | *.mode2v3
198 | !default.mode2v3
199 | *.perspectivev3
200 | !default.perspectivev3
201 | xcuserdata
202 | *.xccheckout
203 | *.moved-aside
204 | DerivedData
205 | *.hmap
206 | *.ipa
207 | *.xcuserstate
208 | project.xcworkspace
209 |
210 | # Android/IJ
211 | #
212 | .idea
213 | android/.idea
214 | android/.gradle
215 | android/local.properties
216 |
217 | # node.js
218 | #
219 | node_modules/
220 | npm-debug.log
221 |
222 | # BUCK
223 | buck-out/
224 | \.buckd/
225 | android/app/libs
226 | android/keystores/debug.keystore
227 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Ali Najafizadeh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Please take a look at this [issue](https://github.com/alinz/react-native-webview-bridge/issues/109) first
2 |
3 | # React Native WebView Javascript Bridge
4 | 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.
5 |
6 |
7 |
8 | ## Installation
9 |
10 | In order to use this extension, you have to do the following steps:
11 |
12 | in your react-native project, run `npm install react-native-webview-bridge --save`
13 |
14 | ### iOS
15 |
16 | 1. go to xcode's `Project Navigator` tab
17 |
18 |
19 |
20 | 2. right click on `Libraries`
21 | 3. select `Add Files to ...` option
22 |
23 |
24 |
25 | 4. navigate to `node_modules/react-native-webview-bridge/ios` and add `React-Native-Webview-Bridge.xcodeproj` folder
26 |
27 |
28 |
29 | 5. on project `Project Navigator` tab, click on your project's name and select Target's name and from there click on `Build Phases`
30 |
31 |
32 |
33 | 6. expand `Link Binary With Libraries` and click `+` sign to add a new one.
34 | 7. select `libReact-Native-Webviwe-Bridge.a` and click `Add` button.
35 |
36 |
37 |
38 | 8. clean compile to make sure your project can compile and build.
39 |
40 | ### Android
41 |
42 | 1. add the following import to `MainApplication.java` (`MainActivity.java` if RN < 0.29) of your application
43 |
44 | ```java
45 | import com.github.alinz.reactnativewebviewbridge.WebViewBridgePackage;
46 | ```
47 |
48 | 2. add the following code to add the package to `MainApplication.java`` (`MainActivity.java` if RN < 0.29)
49 |
50 | ```java
51 | protected List getPackages() {
52 | return Arrays.asList(
53 | new MainReactPackage(),
54 | new WebViewBridgePackage() //<- this
55 | );
56 | }
57 | ```
58 |
59 | 3. add the following codes to your `android/setting.gradle`
60 |
61 | > you might have multiple 3rd party libraries, make sure that you don't create multiple include.
62 |
63 | ```
64 | include ':app', ':react-native-webview-bridge'
65 | project(':react-native-webview-bridge').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview-bridge/android')
66 | ```
67 |
68 | 4. edit `android/app/build.gradle` and add the following line inside `dependencies`
69 |
70 | ```
71 | compile project(':react-native-webview-bridge')
72 | ```
73 |
74 | 5. run `react-native run-android` to see if everything is compilable.
75 |
76 | ## Usage
77 |
78 | just import the module with one of your choices way:
79 |
80 | ** CommonJS style **
81 |
82 | ```js
83 | var WebViewBridge = require('react-native-webview-bridge');
84 | ```
85 |
86 | ** ES6/ES2015 style **
87 |
88 | ```js
89 | import WebViewBridge from 'react-native-webview-bridge';
90 | ```
91 |
92 | `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.
93 |
94 | #### sendToBridge(message)
95 | the message must be in string. because this is the only way to send data back and forth between native and webview.
96 |
97 |
98 | #### onBridgeMessage
99 | 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.
100 |
101 | #### allowFileAccessFromFileURLs (Android only)
102 | 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.
103 |
104 | #### allowUniversalAccessFromFileURLs (Android only)
105 | 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.
106 |
107 | ## Bridge Script
108 |
109 | 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.
110 |
111 | #### send(message)
112 |
113 | this method sends a message to native side. the message must be in string type or `onError` method will be called.
114 |
115 | #### onMessage
116 |
117 | this method needs to be implemented. it will be called once a message arrives from native side. The type of message is in string.
118 |
119 | #### onError (iOS only)
120 |
121 | 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.
122 |
123 | ## Notes
124 |
125 | > 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.
126 |
127 | > You can still pass your own javascript to be injected into webview. However, Bridge script will be injected first and then your custom script.
128 |
129 |
130 | ## Simple Example
131 | This example can be found in `examples` folder.
132 |
133 | ```js
134 | const injectScript = `
135 | (function () {
136 | if (WebViewBridge) {
137 |
138 | WebViewBridge.onMessage = function (message) {
139 | if (message === "hello from react-native") {
140 | WebViewBridge.send("got the message inside webview");
141 | }
142 | };
143 |
144 | WebViewBridge.send("hello from webview");
145 | }
146 | }());
147 | `;
148 |
149 | var Sample2 = React.createClass({
150 | onBridgeMessage(message){
151 | const { webviewbridge } = this.refs;
152 |
153 | switch (message) {
154 | case "hello from webview":
155 | webviewbridge.sendToBridge("hello from react-native");
156 | break;
157 | case "got the message inside webview":
158 | console.log("we have got a message from webview! yeah");
159 | break;
160 | }
161 | },
162 |
163 | render() {
164 | return (
165 |
170 | );
171 | }
172 | });
173 | ```
174 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | jcenter()
4 | }
5 |
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:1.1.3'
8 | }
9 | }
10 |
11 | apply plugin: 'com.android.library'
12 |
13 | android {
14 | compileSdkVersion 23
15 | buildToolsVersion "23.0.1"
16 |
17 | defaultConfig {
18 | minSdkVersion 16
19 | targetSdkVersion 23
20 | versionCode 1
21 | versionName "1.0"
22 | }
23 | lintOptions {
24 | abortOnError false
25 | }
26 | }
27 |
28 | repositories {
29 | mavenCentral()
30 | }
31 |
32 | dependencies {
33 | compile 'com.facebook.react:react-native:0.19.+'
34 | }
35 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/src/main/java/com/github/alinz/reactnativewebviewbridge/JavascriptBridge.java:
--------------------------------------------------------------------------------
1 | package com.github.alinz.reactnativewebviewbridge;
2 |
3 | import android.webkit.JavascriptInterface;
4 | import android.webkit.WebView;
5 |
6 | import com.facebook.react.bridge.Arguments;
7 | import com.facebook.react.bridge.ReactContext;
8 | import com.facebook.react.bridge.WritableMap;
9 | import com.facebook.react.modules.core.DeviceEventManagerModule;
10 | import com.facebook.react.uimanager.events.RCTEventEmitter;
11 |
12 | class JavascriptBridge {
13 | private WebView webView;
14 |
15 | public JavascriptBridge(WebView webView) {
16 | this.webView = webView;
17 | }
18 |
19 | @JavascriptInterface
20 | public void send(String message) {
21 | WritableMap event = Arguments.createMap();
22 | event.putString("message", message);
23 | ReactContext reactContext = (ReactContext) this.webView.getContext();
24 | reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
25 | this.webView.getId(),
26 | "topChange",
27 | event);
28 | }
29 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/github/alinz/reactnativewebviewbridge/WebViewBridgeManager.java:
--------------------------------------------------------------------------------
1 | package com.github.alinz.reactnativewebviewbridge;
2 |
3 | import android.webkit.WebView;
4 |
5 | import com.facebook.react.bridge.ReadableArray;
6 | import com.facebook.react.uimanager.ThemedReactContext;
7 | import com.facebook.react.views.webview.ReactWebViewManager;
8 | import com.facebook.react.uimanager.annotations.ReactProp;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Map;
12 |
13 | import javax.annotation.Nullable;
14 |
15 | public class WebViewBridgeManager extends ReactWebViewManager {
16 | private static final String REACT_CLASS = "RCTWebViewBridge";
17 |
18 | public static final int COMMAND_SEND_TO_BRIDGE = 101;
19 |
20 | @Override
21 | public String getName() {
22 | return REACT_CLASS;
23 | }
24 |
25 | @Override
26 | public
27 | @Nullable
28 | Map getCommandsMap() {
29 | Map commandsMap = super.getCommandsMap();
30 |
31 | commandsMap.put("sendToBridge", COMMAND_SEND_TO_BRIDGE);
32 |
33 | return commandsMap;
34 | }
35 |
36 | @Override
37 | protected WebView createViewInstance(ThemedReactContext reactContext) {
38 | WebView root = super.createViewInstance(reactContext);
39 | root.addJavascriptInterface(new JavascriptBridge(root), "WebViewBridge");
40 | return root;
41 | }
42 |
43 | @Override
44 | public void receiveCommand(WebView root, int commandId, @Nullable ReadableArray args) {
45 | super.receiveCommand(root, commandId, args);
46 |
47 | switch (commandId) {
48 | case COMMAND_SEND_TO_BRIDGE:
49 | sendToBridge(root, args.getString(0));
50 | break;
51 | default:
52 | //do nothing!!!!
53 | }
54 | }
55 |
56 | private void sendToBridge(WebView root, String message) {
57 | String script = "WebViewBridge.onMessage('" + message + "');";
58 | WebViewBridgeManager.evaluateJavascript(root, script);
59 | }
60 |
61 | static private void evaluateJavascript(WebView root, String javascript) {
62 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
63 | root.evaluateJavascript(javascript, null);
64 | } else {
65 | root.loadUrl("javascript:" + javascript);
66 | }
67 | }
68 |
69 | @ReactProp(name = "allowFileAccessFromFileURLs")
70 | public void setAllowFileAccessFromFileURLs(WebView root, boolean allows) {
71 | root.getSettings().setAllowFileAccessFromFileURLs(allows);
72 | }
73 |
74 | @ReactProp(name = "allowUniversalAccessFromFileURLs")
75 | public void setAllowUniversalAccessFromFileURLs(WebView root, boolean allows) {
76 | root.getSettings().setAllowUniversalAccessFromFileURLs(allows);
77 | }
78 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/github/alinz/reactnativewebviewbridge/WebViewBridgePackage.java:
--------------------------------------------------------------------------------
1 | package com.github.alinz.reactnativewebviewbridge;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.JavaScriptModule;
5 | import com.facebook.react.bridge.NativeModule;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.react.uimanager.ViewManager;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Arrays;
11 | import java.util.List;
12 |
13 | public class WebViewBridgePackage implements ReactPackage {
14 | @Override
15 | public List createNativeModules(ReactApplicationContext reactApplicationContext) {
16 | return new ArrayList<>();
17 | }
18 |
19 | @Override
20 | public List createViewManagers(ReactApplicationContext reactApplicationContext) {
21 | return Arrays.asList(
22 | new WebViewBridgeManager()
23 | );
24 | }
25 |
26 | @Override
27 | public List> createJSModules() {
28 | return Arrays.asList();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/doc/assets/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/doc/assets/01.png
--------------------------------------------------------------------------------
/doc/assets/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/doc/assets/02.png
--------------------------------------------------------------------------------
/doc/assets/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/doc/assets/03.png
--------------------------------------------------------------------------------
/doc/assets/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/doc/assets/04.png
--------------------------------------------------------------------------------
/doc/assets/05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/doc/assets/05.png
--------------------------------------------------------------------------------
/example/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-native"]
3 | }
--------------------------------------------------------------------------------
/example/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/example/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 |
3 | # We fork some components by platform.
4 | .*/*.web.js
5 | .*/*.android.js
6 |
7 | # Some modules have their own node_modules with overlap
8 | .*/node_modules/node-haste/.*
9 |
10 | # Ugh
11 | .*/node_modules/babel.*
12 | .*/node_modules/babylon.*
13 | .*/node_modules/invariant.*
14 |
15 | # Ignore react and fbjs where there are overlaps, but don't ignore
16 | # anything that react-native relies on
17 | .*/node_modules/fbjs/lib/Map.js
18 | .*/node_modules/fbjs/lib/Promise.js
19 | .*/node_modules/fbjs/lib/fetch.js
20 | .*/node_modules/fbjs/lib/ExecutionEnvironment.js
21 | .*/node_modules/fbjs/lib/isEmpty.js
22 | .*/node_modules/fbjs/lib/crc32.js
23 | .*/node_modules/fbjs/lib/ErrorUtils.js
24 |
25 | # Flow has a built-in definition for the 'react' module which we prefer to use
26 | # over the currently-untyped source
27 | .*/node_modules/react/react.js
28 | .*/node_modules/react/lib/React.js
29 | .*/node_modules/react/lib/ReactDOM.js
30 |
31 | # Ignore commoner tests
32 | .*/node_modules/commoner/test/.*
33 |
34 | # See https://github.com/facebook/flow/issues/442
35 | .*/react-tools/node_modules/commoner/lib/reader.js
36 |
37 | # Ignore jest
38 | .*/node_modules/jest-cli/.*
39 |
40 | # Ignore Website
41 | .*/website/.*
42 |
43 | [include]
44 |
45 | [libs]
46 | node_modules/react-native/Libraries/react-native/react-native-interface.js
47 |
48 | [options]
49 | module.system=haste
50 |
51 | munge_underscores=true
52 |
53 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
54 | 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'
55 |
56 | suppress_type=$FlowIssue
57 | suppress_type=$FlowFixMe
58 | suppress_type=$FixMe
59 |
60 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
61 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
62 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
63 |
64 | [version]
65 | 0.21.0
66 |
--------------------------------------------------------------------------------
/example/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IJ
26 | #
27 | .idea
28 | .gradle
29 | local.properties
30 |
31 | # node.js
32 | #
33 | node_modules/
34 | npm-debug.log
35 |
--------------------------------------------------------------------------------
/example/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/example/android/app/BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | lib_deps = []
12 |
13 | for jarfile in glob(['libs/*.jar']):
14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')]
15 | lib_deps.append(':' + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
21 | for aarfile in glob(['libs/*.aar']):
22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
23 | lib_deps.append(':' + name)
24 | android_prebuilt_aar(
25 | name = name,
26 | aar = aarfile,
27 | )
28 |
29 | android_library(
30 | name = "all-libs",
31 | exported_deps = lib_deps,
32 | )
33 |
34 | android_library(
35 | name = "app-code",
36 | srcs = glob([
37 | "src/main/java/**/*.java",
38 | ]),
39 | deps = [
40 | ":all-libs",
41 | ":build_config",
42 | ":res",
43 | ],
44 | )
45 |
46 | android_build_config(
47 | name = "build_config",
48 | package = "com.samplern20",
49 | )
50 |
51 | android_resource(
52 | name = "res",
53 | package = "com.samplern20",
54 | res = "src/main/res",
55 | )
56 |
57 | android_binary(
58 | name = "app",
59 | keystore = "//android/keystores:debug",
60 | manifest = "src/main/AndroidManifest.xml",
61 | package_type = "debug",
62 | deps = [
63 | ":app-code",
64 | ],
65 | )
66 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 |
3 | import com.android.build.OutputFile
4 |
5 | /**
6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7 | * and bundleReleaseJsAndAssets).
8 | * These basically call `react-native bundle` with the correct arguments during the Android build
9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10 | * bundle directly from the development server. Below you can see all the possible configurations
11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
12 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
13 | *
14 | * project.ext.react = [
15 | * // the name of the generated asset file containing your JS bundle
16 | * bundleAssetName: "index.android.bundle",
17 | *
18 | * // the entry file for bundle generation
19 | * entryFile: "index.android.js",
20 | *
21 | * // whether to bundle JS and assets in debug mode
22 | * bundleInDebug: false,
23 | *
24 | * // whether to bundle JS and assets in release mode
25 | * bundleInRelease: true,
26 | *
27 | * // whether to bundle JS and assets in another build variant (if configured).
28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
29 | * // The configuration property can be in the following formats
30 | * // 'bundleIn${productFlavor}${buildType}'
31 | * // 'bundleIn${buildType}'
32 | * // bundleInFreeDebug: true,
33 | * // bundleInPaidRelease: true,
34 | * // bundleInBeta: true,
35 | *
36 | * // the root of your project, i.e. where "package.json" lives
37 | * root: "../../",
38 | *
39 | * // where to put the JS bundle asset in debug mode
40 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
41 | *
42 | * // where to put the JS bundle asset in release mode
43 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
44 | *
45 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
46 | * // require('./image.png')), in debug mode
47 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
48 | *
49 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
50 | * // require('./image.png')), in release mode
51 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
52 | *
53 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
54 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
55 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
56 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
57 | * // for example, you might want to remove it from here.
58 | * inputExcludes: ["android/**", "ios/**"],
59 | *
60 | * // override which node gets called and with what additional arguments
61 | * nodeExecutableAndArgs: ["node"]
62 | *
63 | * // supply additional arguments to the packager
64 | * extraPackagerArgs: []
65 | * ]
66 | */
67 |
68 | apply from: "../../node_modules/react-native/react.gradle"
69 |
70 | /**
71 | * Set this to true to create two separate APKs instead of one:
72 | * - An APK that only works on ARM devices
73 | * - An APK that only works on x86 devices
74 | * The advantage is the size of the APK is reduced by about 4MB.
75 | * Upload all the APKs to the Play Store and people will download
76 | * the correct one based on the CPU architecture of their device.
77 | */
78 | def enableSeparateBuildPerCPUArchitecture = false
79 |
80 | /**
81 | * Run Proguard to shrink the Java bytecode in release builds.
82 | */
83 | def enableProguardInReleaseBuilds = false
84 |
85 | android {
86 | compileSdkVersion 23
87 | buildToolsVersion "23.0.1"
88 |
89 | defaultConfig {
90 | applicationId "com.samplern20"
91 | minSdkVersion 16
92 | targetSdkVersion 22
93 | versionCode 1
94 | versionName "1.0"
95 | ndk {
96 | abiFilters "armeabi-v7a", "x86"
97 | }
98 | }
99 | splits {
100 | abi {
101 | reset()
102 | enable enableSeparateBuildPerCPUArchitecture
103 | universalApk false // If true, also generate a universal APK
104 | include "armeabi-v7a", "x86"
105 | }
106 | }
107 | buildTypes {
108 | release {
109 | minifyEnabled enableProguardInReleaseBuilds
110 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
111 | }
112 | }
113 | // applicationVariants are e.g. debug, release
114 | applicationVariants.all { variant ->
115 | variant.outputs.each { output ->
116 | // For each separate APK per architecture, set a unique version code as described here:
117 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
118 | def versionCodes = ["armeabi-v7a":1, "x86":2]
119 | def abi = output.getFilter(OutputFile.ABI)
120 | if (abi != null) { // null for the universal-debug, universal-release variants
121 | output.versionCodeOverride =
122 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
123 | }
124 | }
125 | }
126 | }
127 |
128 | dependencies {
129 | compile fileTree(dir: "libs", include: ["*.jar"])
130 | compile "com.android.support:appcompat-v7:23.0.1"
131 | compile "com.facebook.react:react-native:+" // From node_modules
132 | }
133 |
134 | // Run this once to be able to run the application with BUCK
135 | // puts all compile dependencies into folder libs for BUCK to use
136 | task copyDownloadableDepsToLibs(type: Copy) {
137 | from configurations.compile
138 | into 'libs'
139 | }
140 |
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Disabling obfuscation is useful if you collect stack traces from production crashes
20 | # (unless you are using a system that supports de-obfuscate the stack traces).
21 | -dontobfuscate
22 |
23 | # React Native
24 |
25 | # Keep our interfaces so they can be used by other ProGuard rules.
26 | # See http://sourceforge.net/p/proguard/bugs/466/
27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
30 |
31 | # Do not strip any method/class that is annotated with @DoNotStrip
32 | -keep @com.facebook.proguard.annotations.DoNotStrip class *
33 | -keep @com.facebook.common.internal.DoNotStrip class *
34 | -keepclassmembers class * {
35 | @com.facebook.proguard.annotations.DoNotStrip *;
36 | @com.facebook.common.internal.DoNotStrip *;
37 | }
38 |
39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
40 | void set*(***);
41 | *** get*();
42 | }
43 |
44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; }
46 | -keepclassmembers,includedescriptorclasses class * { native ; }
47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; }
48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; }
49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; }
50 |
51 | -dontwarn com.facebook.react.**
52 |
53 | # okhttp
54 |
55 | -keepattributes Signature
56 | -keepattributes *Annotation*
57 | -keep class okhttp3.** { *; }
58 | -keep interface okhttp3.** { *; }
59 | -dontwarn okhttp3.**
60 |
61 | # okio
62 |
63 | -keep class sun.misc.Unsafe { *; }
64 | -dontwarn java.nio.file.*
65 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
66 | -dontwarn okio.**
67 |
--------------------------------------------------------------------------------
/example/android/app/react.gradle:
--------------------------------------------------------------------------------
1 | import org.apache.tools.ant.taskdefs.condition.Os
2 |
3 | def config = project.hasProperty("react") ? project.react : [];
4 |
5 | def bundleAssetName = config.bundleAssetName ?: "index.android.bundle"
6 | def entryFile = config.entryFile ?: "index.android.js"
7 |
8 | // because elvis operator
9 | def elvisFile(thing) {
10 | return thing ? file(thing) : null;
11 | }
12 |
13 | def reactRoot = elvisFile(config.root) ?: file("../../")
14 | def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
15 |
16 | void runBefore(String dependentTaskName, Task task) {
17 | Task dependentTask = tasks.findByPath(dependentTaskName);
18 | if (dependentTask != null) {
19 | dependentTask.dependsOn task
20 | }
21 | }
22 |
23 | gradle.projectsEvaluated {
24 | // Grab all build types and product flavors
25 | def buildTypes = android.buildTypes.collect { type -> type.name }
26 | def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
27 |
28 | // When no product flavors defined, use empty
29 | if (!productFlavors) productFlavors.add('')
30 |
31 | productFlavors.each { productFlavorName ->
32 | buildTypes.each { buildTypeName ->
33 | // Create variant and source names
34 | def sourceName = "${buildTypeName}"
35 | def targetName = "${sourceName.capitalize()}"
36 | if (productFlavorName) {
37 | sourceName = "${productFlavorName}${targetName}"
38 | }
39 |
40 | // React js bundle directories
41 | def jsBundleDirConfigName = "jsBundleDir${targetName}"
42 | def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?:
43 | file("$buildDir/intermediates/assets/${sourceName}")
44 |
45 | def resourcesDirConfigName = "jsBundleDir${targetName}"
46 | def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?:
47 | file("$buildDir/intermediates/res/merged/${sourceName}")
48 | def jsBundleFile = file("$jsBundleDir/$bundleAssetName")
49 |
50 | // Bundle task name for variant
51 | def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets"
52 |
53 | def currentBundleTask = tasks.create(
54 | name: bundleJsAndAssetsTaskName,
55 | type: Exec) {
56 | group = "react"
57 | description = "bundle JS and assets for ${targetName}."
58 |
59 | // Create dirs if they are not there (e.g. the "clean" task just ran)
60 | doFirst {
61 | jsBundleDir.mkdirs()
62 | resourcesDir.mkdirs()
63 | }
64 |
65 | // Set up inputs and outputs so gradle can cache the result
66 | inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
67 | outputs.dir jsBundleDir
68 | outputs.dir resourcesDir
69 |
70 | // Set up the call to the react-native cli
71 | workingDir reactRoot
72 |
73 | // Set up dev mode
74 | def devEnabled = !targetName.toLowerCase().contains("release")
75 | if (Os.isFamily(Os.FAMILY_WINDOWS)) {
76 | commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
77 | "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
78 | } else {
79 | commandLine "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
80 | "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
81 | }
82 |
83 | enabled config."bundleIn${targetName}" ?: targetName.toLowerCase().contains("release")
84 | }
85 |
86 | // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process
87 | currentBundleTask.dependsOn("merge${targetName}Resources")
88 | currentBundleTask.dependsOn("merge${targetName}Assets")
89 |
90 | runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask)
91 | runBefore("processX86${targetName}Resources", currentBundleTask)
92 | runBefore("processUniversal${targetName}Resources", currentBundleTask)
93 | runBefore("process${targetName}Resources", currentBundleTask)
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
19 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/samplern20/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.samplern20;
2 |
3 | import com.facebook.react.ReactActivity;
4 |
5 | public class MainActivity extends ReactActivity {
6 |
7 | /**
8 | * Returns the name of the main component registered from JavaScript.
9 | * This is used to schedule rendering of the component.
10 | */
11 | @Override
12 | protected String getMainComponentName() {
13 | return "SampleRN20";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/samplern20/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.samplern20;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.react.ReactApplication;
6 | import com.facebook.react.ReactNativeHost;
7 | import com.facebook.react.ReactPackage;
8 | import com.facebook.react.shell.MainReactPackage;
9 | import com.facebook.soloader.SoLoader;
10 |
11 | import java.util.Arrays;
12 | import java.util.List;
13 |
14 | public class MainApplication extends Application implements ReactApplication {
15 |
16 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
17 | @Override
18 | public boolean getUseDeveloperSupport() {
19 | return BuildConfig.DEBUG;
20 | }
21 |
22 | @Override
23 | protected List getPackages() {
24 | return Arrays.asList(
25 | new MainReactPackage()
26 | );
27 | }
28 | };
29 |
30 | @Override
31 | public ReactNativeHost getReactNativeHost() {
32 | return mReactNativeHost;
33 | }
34 |
35 | @Override
36 | public void onCreate() {
37 | super.onCreate();
38 | SoLoader.init(this, /* native exopackage */ false);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SampleRN20
3 |
4 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | mavenLocal()
18 | jcenter()
19 | maven {
20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
21 | url "$rootDir/../node_modules/react-native/android"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | android.useDeprecatedNdk=true
21 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
6 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/android/keystores/BUCK:
--------------------------------------------------------------------------------
1 | keystore(
2 | name = "debug",
3 | properties = "debug.keystore.properties",
4 | store = "debug.keystore",
5 | visibility = [
6 | "PUBLIC",
7 | ],
8 | )
9 |
--------------------------------------------------------------------------------
/example/android/keystores/debug.keystore.properties:
--------------------------------------------------------------------------------
1 | key.store=debug.keystore
2 | key.alias=androiddebugkey
3 | key.store.password=android
4 | key.alias.password=android
5 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'SampleRN20'
2 |
3 | include ':app'
4 |
--------------------------------------------------------------------------------
/example/app.js:
--------------------------------------------------------------------------------
1 |
2 | import React, {Component} from 'react';
3 | import {StyleSheet, View} from 'react-native';
4 | import WebViewBridge from 'react-native-webview-bridge';
5 |
6 | const injectScript = `
7 | (function () {
8 | if (WebViewBridge) {
9 |
10 | WebViewBridge.onMessage = function (message) {
11 | if (message === "hello from react-native") {
12 | WebViewBridge.send("got the message inside webview");
13 | }
14 | };
15 |
16 | WebViewBridge.send("hello from webview");
17 | }
18 | }());
19 | `;
20 |
21 | export default class Sample2 extends Component {
22 | constructor(props) {
23 | super(props);
24 | this.onBridgeMessage = this.onBridgeMessage.bind(this);
25 | }
26 |
27 | onBridgeMessage(message) {
28 | switch (message) {
29 | case "hello from webview":
30 | this.webviewbridge.sendToBridge("hello from react-native");
31 | break;
32 | case "got the message inside webview":
33 | console.log("we have got a message from webview! yeah");
34 | break;
35 | }
36 | }
37 |
38 | render() {
39 | return (
40 |
41 | this.webviewbridge = r}
43 | onBridgeMessage={this.onBridgeMessage}
44 | javaScriptEnabled={true}
45 | injectedJavaScript={injectScript}
46 | source={{uri: "https://google.com"}}
47 | />
48 |
55 |
56 | );
57 | }
58 | };
59 |
60 | const styles = StyleSheet.create({
61 | container: {
62 | flex: 1
63 | }
64 | });
65 |
66 |
--------------------------------------------------------------------------------
/example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SampleRN20",
3 | "displayName": "SampleRN20"
4 | }
--------------------------------------------------------------------------------
/example/index.android.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample React Native App
3 | * https://github.com/facebook/react-native
4 | */
5 | 'use strict';
6 |
7 | var React = require('react-native');
8 | var { AppRegistry } = React;
9 |
10 | var Sample2 = require('./app');
11 |
12 | AppRegistry.registerComponent('SampleRN20', () => Sample2);
13 |
--------------------------------------------------------------------------------
/example/index.ios.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { AppRegistry } from 'react-native';
3 |
4 | import Sample2 from './app';
5 |
6 | AppRegistry.registerComponent('SampleRN20', () => Sample2);
7 |
--------------------------------------------------------------------------------
/example/ios/SampleRN20.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
11 | 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
12 | 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
13 | 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
14 | 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
15 | 00E356F31AD99517003FC87E /* SampleRN20Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* SampleRN20Tests.m */; };
16 | 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
17 | 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
18 | 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
19 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
20 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
21 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
22 | 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
23 | 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
24 | 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
25 | 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
26 | 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
27 | D8263ECC1EAE0122005156F4 /* libReact-Native-Webview-Bridge.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D8263EC31EAE0114005156F4 /* libReact-Native-Webview-Bridge.a */; };
28 | /* End PBXBuildFile section */
29 |
30 | /* Begin PBXContainerItemProxy section */
31 | 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = {
32 | isa = PBXContainerItemProxy;
33 | containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
34 | proxyType = 2;
35 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
36 | remoteInfo = RCTActionSheet;
37 | };
38 | 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = {
39 | isa = PBXContainerItemProxy;
40 | containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
41 | proxyType = 2;
42 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
43 | remoteInfo = RCTGeolocation;
44 | };
45 | 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = {
46 | isa = PBXContainerItemProxy;
47 | containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
48 | proxyType = 2;
49 | remoteGlobalIDString = 58B5115D1A9E6B3D00147676;
50 | remoteInfo = RCTImage;
51 | };
52 | 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = {
53 | isa = PBXContainerItemProxy;
54 | containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
55 | proxyType = 2;
56 | remoteGlobalIDString = 58B511DB1A9E6C8500147676;
57 | remoteInfo = RCTNetwork;
58 | };
59 | 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = {
60 | isa = PBXContainerItemProxy;
61 | containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
62 | proxyType = 2;
63 | remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
64 | remoteInfo = RCTVibration;
65 | };
66 | 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
67 | isa = PBXContainerItemProxy;
68 | containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
69 | proxyType = 1;
70 | remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
71 | remoteInfo = SampleRN20;
72 | };
73 | 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = {
74 | isa = PBXContainerItemProxy;
75 | containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
76 | proxyType = 2;
77 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
78 | remoteInfo = RCTSettings;
79 | };
80 | 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = {
81 | isa = PBXContainerItemProxy;
82 | containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
83 | proxyType = 2;
84 | remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
85 | remoteInfo = RCTWebSocket;
86 | };
87 | 146834031AC3E56700842450 /* PBXContainerItemProxy */ = {
88 | isa = PBXContainerItemProxy;
89 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
90 | proxyType = 2;
91 | remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
92 | remoteInfo = React;
93 | };
94 | 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = {
95 | isa = PBXContainerItemProxy;
96 | containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
97 | proxyType = 2;
98 | remoteGlobalIDString = 2D2A283A1D9B042B00D4039D;
99 | remoteInfo = "RCTImage-tvOS";
100 | };
101 | 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */ = {
102 | isa = PBXContainerItemProxy;
103 | containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
104 | proxyType = 2;
105 | remoteGlobalIDString = 2D2A28471D9B043800D4039D;
106 | remoteInfo = "RCTLinking-tvOS";
107 | };
108 | 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
109 | isa = PBXContainerItemProxy;
110 | containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
111 | proxyType = 2;
112 | remoteGlobalIDString = 2D2A28541D9B044C00D4039D;
113 | remoteInfo = "RCTNetwork-tvOS";
114 | };
115 | 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
116 | isa = PBXContainerItemProxy;
117 | containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
118 | proxyType = 2;
119 | remoteGlobalIDString = 2D2A28611D9B046600D4039D;
120 | remoteInfo = "RCTSettings-tvOS";
121 | };
122 | 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */ = {
123 | isa = PBXContainerItemProxy;
124 | containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
125 | proxyType = 2;
126 | remoteGlobalIDString = 2D2A287B1D9B048500D4039D;
127 | remoteInfo = "RCTText-tvOS";
128 | };
129 | 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */ = {
130 | isa = PBXContainerItemProxy;
131 | containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
132 | proxyType = 2;
133 | remoteGlobalIDString = 2D2A28881D9B049200D4039D;
134 | remoteInfo = "RCTWebSocket-tvOS";
135 | };
136 | 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */ = {
137 | isa = PBXContainerItemProxy;
138 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
139 | proxyType = 2;
140 | remoteGlobalIDString = 2D2A28131D9B038B00D4039D;
141 | remoteInfo = "React-tvOS";
142 | };
143 | 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = {
144 | isa = PBXContainerItemProxy;
145 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
146 | proxyType = 2;
147 | remoteGlobalIDString = 3D3C059A1DE3340900C268FA;
148 | remoteInfo = yoga;
149 | };
150 | 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = {
151 | isa = PBXContainerItemProxy;
152 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
153 | proxyType = 2;
154 | remoteGlobalIDString = 3D3C06751DE3340C00C268FA;
155 | remoteInfo = "yoga-tvOS";
156 | };
157 | 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = {
158 | isa = PBXContainerItemProxy;
159 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
160 | proxyType = 2;
161 | remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4;
162 | remoteInfo = cxxreact;
163 | };
164 | 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
165 | isa = PBXContainerItemProxy;
166 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
167 | proxyType = 2;
168 | remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4;
169 | remoteInfo = "cxxreact-tvOS";
170 | };
171 | 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
172 | isa = PBXContainerItemProxy;
173 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
174 | proxyType = 2;
175 | remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4;
176 | remoteInfo = jschelpers;
177 | };
178 | 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
179 | isa = PBXContainerItemProxy;
180 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
181 | proxyType = 2;
182 | remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4;
183 | remoteInfo = "jschelpers-tvOS";
184 | };
185 | 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
186 | isa = PBXContainerItemProxy;
187 | containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
188 | proxyType = 2;
189 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
190 | remoteInfo = RCTAnimation;
191 | };
192 | 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
193 | isa = PBXContainerItemProxy;
194 | containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
195 | proxyType = 2;
196 | remoteGlobalIDString = 2D2A28201D9B03D100D4039D;
197 | remoteInfo = "RCTAnimation-tvOS";
198 | };
199 | 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
200 | isa = PBXContainerItemProxy;
201 | containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
202 | proxyType = 2;
203 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
204 | remoteInfo = RCTLinking;
205 | };
206 | 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
207 | isa = PBXContainerItemProxy;
208 | containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
209 | proxyType = 2;
210 | remoteGlobalIDString = 58B5119B1A9E6C1200147676;
211 | remoteInfo = RCTText;
212 | };
213 | D8263EC21EAE0114005156F4 /* PBXContainerItemProxy */ = {
214 | isa = PBXContainerItemProxy;
215 | containerPortal = D8263EAD1EAE0114005156F4 /* React-Native-Webview-Bridge.xcodeproj */;
216 | proxyType = 2;
217 | remoteGlobalIDString = 4114DC4C1C187C3A003CD988;
218 | remoteInfo = "React-Native-Webview-Bridge";
219 | };
220 | /* End PBXContainerItemProxy section */
221 |
222 | /* Begin PBXFileReference section */
223 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; };
224 | 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; };
225 | 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; };
226 | 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; };
227 | 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; };
228 | 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; };
229 | 00E356EE1AD99517003FC87E /* SampleRN20Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SampleRN20Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
230 | 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
231 | 00E356F21AD99517003FC87E /* SampleRN20Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SampleRN20Tests.m; sourceTree = ""; };
232 | 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; };
233 | 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; };
234 | 13B07F961A680F5B00A75B9A /* SampleRN20.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SampleRN20.app; sourceTree = BUILT_PRODUCTS_DIR; };
235 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = SampleRN20/AppDelegate.h; sourceTree = ""; };
236 | 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = SampleRN20/AppDelegate.m; sourceTree = ""; };
237 | 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
238 | 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = SampleRN20/Images.xcassets; sourceTree = ""; };
239 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = SampleRN20/Info.plist; sourceTree = ""; };
240 | 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = SampleRN20/main.m; sourceTree = ""; };
241 | 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; };
242 | 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; };
243 | 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; };
244 | 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; };
245 | D8263EAD1EAE0114005156F4 /* 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 = ""; };
246 | /* End PBXFileReference section */
247 |
248 | /* Begin PBXFrameworksBuildPhase section */
249 | 00E356EB1AD99517003FC87E /* Frameworks */ = {
250 | isa = PBXFrameworksBuildPhase;
251 | buildActionMask = 2147483647;
252 | files = (
253 | 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */,
254 | );
255 | runOnlyForDeploymentPostprocessing = 0;
256 | };
257 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
258 | isa = PBXFrameworksBuildPhase;
259 | buildActionMask = 2147483647;
260 | files = (
261 | D8263ECC1EAE0122005156F4 /* libReact-Native-Webview-Bridge.a in Frameworks */,
262 | 146834051AC3E58100842450 /* libReact.a in Frameworks */,
263 | 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */,
264 | 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
265 | 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
266 | 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
267 | 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,
268 | 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,
269 | 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */,
270 | 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
271 | 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
272 | 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
273 | );
274 | runOnlyForDeploymentPostprocessing = 0;
275 | };
276 | /* End PBXFrameworksBuildPhase section */
277 |
278 | /* Begin PBXGroup section */
279 | 00C302A81ABCB8CE00DB3ED1 /* Products */ = {
280 | isa = PBXGroup;
281 | children = (
282 | 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */,
283 | );
284 | name = Products;
285 | sourceTree = "";
286 | };
287 | 00C302B61ABCB90400DB3ED1 /* Products */ = {
288 | isa = PBXGroup;
289 | children = (
290 | 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */,
291 | );
292 | name = Products;
293 | sourceTree = "";
294 | };
295 | 00C302BC1ABCB91800DB3ED1 /* Products */ = {
296 | isa = PBXGroup;
297 | children = (
298 | 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */,
299 | 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */,
300 | );
301 | name = Products;
302 | sourceTree = "";
303 | };
304 | 00C302D41ABCB9D200DB3ED1 /* Products */ = {
305 | isa = PBXGroup;
306 | children = (
307 | 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */,
308 | 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */,
309 | );
310 | name = Products;
311 | sourceTree = "";
312 | };
313 | 00C302E01ABCB9EE00DB3ED1 /* Products */ = {
314 | isa = PBXGroup;
315 | children = (
316 | 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */,
317 | );
318 | name = Products;
319 | sourceTree = "";
320 | };
321 | 00E356EF1AD99517003FC87E /* SampleRN20Tests */ = {
322 | isa = PBXGroup;
323 | children = (
324 | 00E356F21AD99517003FC87E /* SampleRN20Tests.m */,
325 | 00E356F01AD99517003FC87E /* Supporting Files */,
326 | );
327 | path = SampleRN20Tests;
328 | sourceTree = "";
329 | };
330 | 00E356F01AD99517003FC87E /* Supporting Files */ = {
331 | isa = PBXGroup;
332 | children = (
333 | 00E356F11AD99517003FC87E /* Info.plist */,
334 | );
335 | name = "Supporting Files";
336 | sourceTree = "";
337 | };
338 | 139105B71AF99BAD00B5F7CC /* Products */ = {
339 | isa = PBXGroup;
340 | children = (
341 | 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */,
342 | 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */,
343 | );
344 | name = Products;
345 | sourceTree = "";
346 | };
347 | 139FDEE71B06529A00C62182 /* Products */ = {
348 | isa = PBXGroup;
349 | children = (
350 | 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
351 | 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */,
352 | );
353 | name = Products;
354 | sourceTree = "";
355 | };
356 | 13B07FAE1A68108700A75B9A /* SampleRN20 */ = {
357 | isa = PBXGroup;
358 | children = (
359 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */,
360 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
361 | 13B07FB01A68108700A75B9A /* AppDelegate.m */,
362 | 13B07FB51A68108700A75B9A /* Images.xcassets */,
363 | 13B07FB61A68108700A75B9A /* Info.plist */,
364 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
365 | 13B07FB71A68108700A75B9A /* main.m */,
366 | );
367 | name = SampleRN20;
368 | sourceTree = "";
369 | };
370 | 146834001AC3E56700842450 /* Products */ = {
371 | isa = PBXGroup;
372 | children = (
373 | 146834041AC3E56700842450 /* libReact.a */,
374 | 3DAD3EA31DF850E9000B6D8A /* libReact.a */,
375 | 3DAD3EA51DF850E9000B6D8A /* libyoga.a */,
376 | 3DAD3EA71DF850E9000B6D8A /* libyoga.a */,
377 | 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */,
378 | 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */,
379 | 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */,
380 | 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */,
381 | );
382 | name = Products;
383 | sourceTree = "";
384 | };
385 | 5E91572E1DD0AC6500FF2AA8 /* Products */ = {
386 | isa = PBXGroup;
387 | children = (
388 | 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */,
389 | 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */,
390 | );
391 | name = Products;
392 | sourceTree = "";
393 | };
394 | 78C398B11ACF4ADC00677621 /* Products */ = {
395 | isa = PBXGroup;
396 | children = (
397 | 78C398B91ACF4ADC00677621 /* libRCTLinking.a */,
398 | 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */,
399 | );
400 | name = Products;
401 | sourceTree = "";
402 | };
403 | 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
404 | isa = PBXGroup;
405 | children = (
406 | D8263EAD1EAE0114005156F4 /* React-Native-Webview-Bridge.xcodeproj */,
407 | 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */,
408 | 146833FF1AC3E56700842450 /* React.xcodeproj */,
409 | 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
410 | 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
411 | 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */,
412 | 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */,
413 | 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */,
414 | 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */,
415 | 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
416 | 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
417 | 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
418 | );
419 | name = Libraries;
420 | sourceTree = "";
421 | };
422 | 832341B11AAA6A8300B99B32 /* Products */ = {
423 | isa = PBXGroup;
424 | children = (
425 | 832341B51AAA6A8300B99B32 /* libRCTText.a */,
426 | 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */,
427 | );
428 | name = Products;
429 | sourceTree = "";
430 | };
431 | 83CBB9F61A601CBA00E9B192 = {
432 | isa = PBXGroup;
433 | children = (
434 | 13B07FAE1A68108700A75B9A /* SampleRN20 */,
435 | 832341AE1AAA6A7D00B99B32 /* Libraries */,
436 | 00E356EF1AD99517003FC87E /* SampleRN20Tests */,
437 | 83CBBA001A601CBA00E9B192 /* Products */,
438 | );
439 | indentWidth = 2;
440 | sourceTree = "";
441 | tabWidth = 2;
442 | };
443 | 83CBBA001A601CBA00E9B192 /* Products */ = {
444 | isa = PBXGroup;
445 | children = (
446 | 13B07F961A680F5B00A75B9A /* SampleRN20.app */,
447 | 00E356EE1AD99517003FC87E /* SampleRN20Tests.xctest */,
448 | );
449 | name = Products;
450 | sourceTree = "";
451 | };
452 | D8263EAE1EAE0114005156F4 /* Products */ = {
453 | isa = PBXGroup;
454 | children = (
455 | D8263EC31EAE0114005156F4 /* libReact-Native-Webview-Bridge.a */,
456 | );
457 | name = Products;
458 | sourceTree = "";
459 | };
460 | /* End PBXGroup section */
461 |
462 | /* Begin PBXNativeTarget section */
463 | 00E356ED1AD99517003FC87E /* SampleRN20Tests */ = {
464 | isa = PBXNativeTarget;
465 | buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "SampleRN20Tests" */;
466 | buildPhases = (
467 | 00E356EA1AD99517003FC87E /* Sources */,
468 | 00E356EB1AD99517003FC87E /* Frameworks */,
469 | 00E356EC1AD99517003FC87E /* Resources */,
470 | );
471 | buildRules = (
472 | );
473 | dependencies = (
474 | 00E356F51AD99517003FC87E /* PBXTargetDependency */,
475 | );
476 | name = SampleRN20Tests;
477 | productName = SampleRN20Tests;
478 | productReference = 00E356EE1AD99517003FC87E /* SampleRN20Tests.xctest */;
479 | productType = "com.apple.product-type.bundle.unit-test";
480 | };
481 | 13B07F861A680F5B00A75B9A /* SampleRN20 */ = {
482 | isa = PBXNativeTarget;
483 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "SampleRN20" */;
484 | buildPhases = (
485 | 13B07F871A680F5B00A75B9A /* Sources */,
486 | 13B07F8C1A680F5B00A75B9A /* Frameworks */,
487 | 13B07F8E1A680F5B00A75B9A /* Resources */,
488 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
489 | );
490 | buildRules = (
491 | );
492 | dependencies = (
493 | );
494 | name = SampleRN20;
495 | productName = "Hello World";
496 | productReference = 13B07F961A680F5B00A75B9A /* SampleRN20.app */;
497 | productType = "com.apple.product-type.application";
498 | };
499 | /* End PBXNativeTarget section */
500 |
501 | /* Begin PBXProject section */
502 | 83CBB9F71A601CBA00E9B192 /* Project object */ = {
503 | isa = PBXProject;
504 | attributes = {
505 | LastUpgradeCheck = 0610;
506 | ORGANIZATIONNAME = Facebook;
507 | TargetAttributes = {
508 | 00E356ED1AD99517003FC87E = {
509 | CreatedOnToolsVersion = 6.2;
510 | TestTargetID = 13B07F861A680F5B00A75B9A;
511 | };
512 | };
513 | };
514 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "SampleRN20" */;
515 | compatibilityVersion = "Xcode 3.2";
516 | developmentRegion = English;
517 | hasScannedForEncodings = 0;
518 | knownRegions = (
519 | en,
520 | Base,
521 | );
522 | mainGroup = 83CBB9F61A601CBA00E9B192;
523 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
524 | projectDirPath = "";
525 | projectReferences = (
526 | {
527 | ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
528 | ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
529 | },
530 | {
531 | ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */;
532 | ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
533 | },
534 | {
535 | ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;
536 | ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
537 | },
538 | {
539 | ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */;
540 | ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
541 | },
542 | {
543 | ProductGroup = 78C398B11ACF4ADC00677621 /* Products */;
544 | ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
545 | },
546 | {
547 | ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */;
548 | ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
549 | },
550 | {
551 | ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */;
552 | ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
553 | },
554 | {
555 | ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
556 | ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
557 | },
558 | {
559 | ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;
560 | ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
561 | },
562 | {
563 | ProductGroup = 139FDEE71B06529A00C62182 /* Products */;
564 | ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
565 | },
566 | {
567 | ProductGroup = D8263EAE1EAE0114005156F4 /* Products */;
568 | ProjectRef = D8263EAD1EAE0114005156F4 /* React-Native-Webview-Bridge.xcodeproj */;
569 | },
570 | {
571 | ProductGroup = 146834001AC3E56700842450 /* Products */;
572 | ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
573 | },
574 | );
575 | projectRoot = "";
576 | targets = (
577 | 13B07F861A680F5B00A75B9A /* SampleRN20 */,
578 | 00E356ED1AD99517003FC87E /* SampleRN20Tests */,
579 | );
580 | };
581 | /* End PBXProject section */
582 |
583 | /* Begin PBXReferenceProxy section */
584 | 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = {
585 | isa = PBXReferenceProxy;
586 | fileType = archive.ar;
587 | path = libRCTActionSheet.a;
588 | remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */;
589 | sourceTree = BUILT_PRODUCTS_DIR;
590 | };
591 | 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = {
592 | isa = PBXReferenceProxy;
593 | fileType = archive.ar;
594 | path = libRCTGeolocation.a;
595 | remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */;
596 | sourceTree = BUILT_PRODUCTS_DIR;
597 | };
598 | 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = {
599 | isa = PBXReferenceProxy;
600 | fileType = archive.ar;
601 | path = libRCTImage.a;
602 | remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */;
603 | sourceTree = BUILT_PRODUCTS_DIR;
604 | };
605 | 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = {
606 | isa = PBXReferenceProxy;
607 | fileType = archive.ar;
608 | path = libRCTNetwork.a;
609 | remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */;
610 | sourceTree = BUILT_PRODUCTS_DIR;
611 | };
612 | 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = {
613 | isa = PBXReferenceProxy;
614 | fileType = archive.ar;
615 | path = libRCTVibration.a;
616 | remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */;
617 | sourceTree = BUILT_PRODUCTS_DIR;
618 | };
619 | 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = {
620 | isa = PBXReferenceProxy;
621 | fileType = archive.ar;
622 | path = libRCTSettings.a;
623 | remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */;
624 | sourceTree = BUILT_PRODUCTS_DIR;
625 | };
626 | 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = {
627 | isa = PBXReferenceProxy;
628 | fileType = archive.ar;
629 | path = libRCTWebSocket.a;
630 | remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */;
631 | sourceTree = BUILT_PRODUCTS_DIR;
632 | };
633 | 146834041AC3E56700842450 /* libReact.a */ = {
634 | isa = PBXReferenceProxy;
635 | fileType = archive.ar;
636 | path = libReact.a;
637 | remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
638 | sourceTree = BUILT_PRODUCTS_DIR;
639 | };
640 | 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = {
641 | isa = PBXReferenceProxy;
642 | fileType = archive.ar;
643 | path = "libRCTImage-tvOS.a";
644 | remoteRef = 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */;
645 | sourceTree = BUILT_PRODUCTS_DIR;
646 | };
647 | 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */ = {
648 | isa = PBXReferenceProxy;
649 | fileType = archive.ar;
650 | path = "libRCTLinking-tvOS.a";
651 | remoteRef = 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */;
652 | sourceTree = BUILT_PRODUCTS_DIR;
653 | };
654 | 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */ = {
655 | isa = PBXReferenceProxy;
656 | fileType = archive.ar;
657 | path = "libRCTNetwork-tvOS.a";
658 | remoteRef = 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */;
659 | sourceTree = BUILT_PRODUCTS_DIR;
660 | };
661 | 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */ = {
662 | isa = PBXReferenceProxy;
663 | fileType = archive.ar;
664 | path = "libRCTSettings-tvOS.a";
665 | remoteRef = 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */;
666 | sourceTree = BUILT_PRODUCTS_DIR;
667 | };
668 | 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */ = {
669 | isa = PBXReferenceProxy;
670 | fileType = archive.ar;
671 | path = "libRCTText-tvOS.a";
672 | remoteRef = 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */;
673 | sourceTree = BUILT_PRODUCTS_DIR;
674 | };
675 | 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */ = {
676 | isa = PBXReferenceProxy;
677 | fileType = archive.ar;
678 | path = "libRCTWebSocket-tvOS.a";
679 | remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */;
680 | sourceTree = BUILT_PRODUCTS_DIR;
681 | };
682 | 3DAD3EA31DF850E9000B6D8A /* libReact.a */ = {
683 | isa = PBXReferenceProxy;
684 | fileType = archive.ar;
685 | path = libReact.a;
686 | remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */;
687 | sourceTree = BUILT_PRODUCTS_DIR;
688 | };
689 | 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = {
690 | isa = PBXReferenceProxy;
691 | fileType = archive.ar;
692 | path = libyoga.a;
693 | remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */;
694 | sourceTree = BUILT_PRODUCTS_DIR;
695 | };
696 | 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = {
697 | isa = PBXReferenceProxy;
698 | fileType = archive.ar;
699 | path = libyoga.a;
700 | remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */;
701 | sourceTree = BUILT_PRODUCTS_DIR;
702 | };
703 | 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = {
704 | isa = PBXReferenceProxy;
705 | fileType = archive.ar;
706 | path = libcxxreact.a;
707 | remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */;
708 | sourceTree = BUILT_PRODUCTS_DIR;
709 | };
710 | 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = {
711 | isa = PBXReferenceProxy;
712 | fileType = archive.ar;
713 | path = libcxxreact.a;
714 | remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */;
715 | sourceTree = BUILT_PRODUCTS_DIR;
716 | };
717 | 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = {
718 | isa = PBXReferenceProxy;
719 | fileType = archive.ar;
720 | path = libjschelpers.a;
721 | remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */;
722 | sourceTree = BUILT_PRODUCTS_DIR;
723 | };
724 | 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = {
725 | isa = PBXReferenceProxy;
726 | fileType = archive.ar;
727 | path = libjschelpers.a;
728 | remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */;
729 | sourceTree = BUILT_PRODUCTS_DIR;
730 | };
731 | 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
732 | isa = PBXReferenceProxy;
733 | fileType = archive.ar;
734 | path = libRCTAnimation.a;
735 | remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
736 | sourceTree = BUILT_PRODUCTS_DIR;
737 | };
738 | 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */ = {
739 | isa = PBXReferenceProxy;
740 | fileType = archive.ar;
741 | path = "libRCTAnimation-tvOS.a";
742 | remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
743 | sourceTree = BUILT_PRODUCTS_DIR;
744 | };
745 | 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
746 | isa = PBXReferenceProxy;
747 | fileType = archive.ar;
748 | path = libRCTLinking.a;
749 | remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */;
750 | sourceTree = BUILT_PRODUCTS_DIR;
751 | };
752 | 832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
753 | isa = PBXReferenceProxy;
754 | fileType = archive.ar;
755 | path = libRCTText.a;
756 | remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
757 | sourceTree = BUILT_PRODUCTS_DIR;
758 | };
759 | D8263EC31EAE0114005156F4 /* libReact-Native-Webview-Bridge.a */ = {
760 | isa = PBXReferenceProxy;
761 | fileType = archive.ar;
762 | path = "libReact-Native-Webview-Bridge.a";
763 | remoteRef = D8263EC21EAE0114005156F4 /* PBXContainerItemProxy */;
764 | sourceTree = BUILT_PRODUCTS_DIR;
765 | };
766 | /* End PBXReferenceProxy section */
767 |
768 | /* Begin PBXResourcesBuildPhase section */
769 | 00E356EC1AD99517003FC87E /* Resources */ = {
770 | isa = PBXResourcesBuildPhase;
771 | buildActionMask = 2147483647;
772 | files = (
773 | );
774 | runOnlyForDeploymentPostprocessing = 0;
775 | };
776 | 13B07F8E1A680F5B00A75B9A /* Resources */ = {
777 | isa = PBXResourcesBuildPhase;
778 | buildActionMask = 2147483647;
779 | files = (
780 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
781 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
782 | );
783 | runOnlyForDeploymentPostprocessing = 0;
784 | };
785 | /* End PBXResourcesBuildPhase section */
786 |
787 | /* Begin PBXShellScriptBuildPhase section */
788 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
789 | isa = PBXShellScriptBuildPhase;
790 | buildActionMask = 2147483647;
791 | files = (
792 | );
793 | inputPaths = (
794 | );
795 | name = "Bundle React Native code and images";
796 | outputPaths = (
797 | );
798 | runOnlyForDeploymentPostprocessing = 0;
799 | shellPath = /bin/sh;
800 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
801 | };
802 | /* End PBXShellScriptBuildPhase section */
803 |
804 | /* Begin PBXSourcesBuildPhase section */
805 | 00E356EA1AD99517003FC87E /* Sources */ = {
806 | isa = PBXSourcesBuildPhase;
807 | buildActionMask = 2147483647;
808 | files = (
809 | 00E356F31AD99517003FC87E /* SampleRN20Tests.m in Sources */,
810 | );
811 | runOnlyForDeploymentPostprocessing = 0;
812 | };
813 | 13B07F871A680F5B00A75B9A /* Sources */ = {
814 | isa = PBXSourcesBuildPhase;
815 | buildActionMask = 2147483647;
816 | files = (
817 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
818 | 13B07FC11A68108700A75B9A /* main.m in Sources */,
819 | );
820 | runOnlyForDeploymentPostprocessing = 0;
821 | };
822 | /* End PBXSourcesBuildPhase section */
823 |
824 | /* Begin PBXTargetDependency section */
825 | 00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
826 | isa = PBXTargetDependency;
827 | target = 13B07F861A680F5B00A75B9A /* SampleRN20 */;
828 | targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
829 | };
830 | /* End PBXTargetDependency section */
831 |
832 | /* Begin PBXVariantGroup section */
833 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
834 | isa = PBXVariantGroup;
835 | children = (
836 | 13B07FB21A68108700A75B9A /* Base */,
837 | );
838 | name = LaunchScreen.xib;
839 | path = SampleRN20;
840 | sourceTree = "";
841 | };
842 | /* End PBXVariantGroup section */
843 |
844 | /* Begin XCBuildConfiguration section */
845 | 00E356F61AD99517003FC87E /* Debug */ = {
846 | isa = XCBuildConfiguration;
847 | buildSettings = {
848 | BUNDLE_LOADER = "$(TEST_HOST)";
849 | GCC_PREPROCESSOR_DEFINITIONS = (
850 | "DEBUG=1",
851 | "$(inherited)",
852 | );
853 | INFOPLIST_FILE = SampleRN20Tests/Info.plist;
854 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
855 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
856 | OTHER_LDFLAGS = (
857 | "-ObjC",
858 | "-lc++",
859 | );
860 | PRODUCT_NAME = "$(TARGET_NAME)";
861 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SampleRN20.app/SampleRN20";
862 | };
863 | name = Debug;
864 | };
865 | 00E356F71AD99517003FC87E /* Release */ = {
866 | isa = XCBuildConfiguration;
867 | buildSettings = {
868 | BUNDLE_LOADER = "$(TEST_HOST)";
869 | COPY_PHASE_STRIP = NO;
870 | INFOPLIST_FILE = SampleRN20Tests/Info.plist;
871 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
872 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
873 | OTHER_LDFLAGS = (
874 | "-ObjC",
875 | "-lc++",
876 | );
877 | PRODUCT_NAME = "$(TARGET_NAME)";
878 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SampleRN20.app/SampleRN20";
879 | };
880 | name = Release;
881 | };
882 | 13B07F941A680F5B00A75B9A /* Debug */ = {
883 | isa = XCBuildConfiguration;
884 | buildSettings = {
885 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
886 | CURRENT_PROJECT_VERSION = 1;
887 | DEAD_CODE_STRIPPING = NO;
888 | INFOPLIST_FILE = SampleRN20/Info.plist;
889 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
890 | OTHER_LDFLAGS = (
891 | "$(inherited)",
892 | "-ObjC",
893 | "-lc++",
894 | );
895 | PRODUCT_NAME = SampleRN20;
896 | VERSIONING_SYSTEM = "apple-generic";
897 | };
898 | name = Debug;
899 | };
900 | 13B07F951A680F5B00A75B9A /* Release */ = {
901 | isa = XCBuildConfiguration;
902 | buildSettings = {
903 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
904 | CURRENT_PROJECT_VERSION = 1;
905 | INFOPLIST_FILE = SampleRN20/Info.plist;
906 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
907 | OTHER_LDFLAGS = (
908 | "$(inherited)",
909 | "-ObjC",
910 | "-lc++",
911 | );
912 | PRODUCT_NAME = SampleRN20;
913 | VERSIONING_SYSTEM = "apple-generic";
914 | };
915 | name = Release;
916 | };
917 | 83CBBA201A601CBA00E9B192 /* Debug */ = {
918 | isa = XCBuildConfiguration;
919 | buildSettings = {
920 | ALWAYS_SEARCH_USER_PATHS = NO;
921 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
922 | CLANG_CXX_LIBRARY = "libc++";
923 | CLANG_ENABLE_MODULES = YES;
924 | CLANG_ENABLE_OBJC_ARC = YES;
925 | CLANG_WARN_BOOL_CONVERSION = YES;
926 | CLANG_WARN_CONSTANT_CONVERSION = YES;
927 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
928 | CLANG_WARN_EMPTY_BODY = YES;
929 | CLANG_WARN_ENUM_CONVERSION = YES;
930 | CLANG_WARN_INT_CONVERSION = YES;
931 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
932 | CLANG_WARN_UNREACHABLE_CODE = YES;
933 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
934 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
935 | COPY_PHASE_STRIP = NO;
936 | ENABLE_STRICT_OBJC_MSGSEND = YES;
937 | GCC_C_LANGUAGE_STANDARD = gnu99;
938 | GCC_DYNAMIC_NO_PIC = NO;
939 | GCC_OPTIMIZATION_LEVEL = 0;
940 | GCC_PREPROCESSOR_DEFINITIONS = (
941 | "DEBUG=1",
942 | "$(inherited)",
943 | );
944 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
945 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
946 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
947 | GCC_WARN_UNDECLARED_SELECTOR = YES;
948 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
949 | GCC_WARN_UNUSED_FUNCTION = YES;
950 | GCC_WARN_UNUSED_VARIABLE = YES;
951 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
952 | MTL_ENABLE_DEBUG_INFO = YES;
953 | ONLY_ACTIVE_ARCH = YES;
954 | SDKROOT = iphoneos;
955 | };
956 | name = Debug;
957 | };
958 | 83CBBA211A601CBA00E9B192 /* Release */ = {
959 | isa = XCBuildConfiguration;
960 | buildSettings = {
961 | ALWAYS_SEARCH_USER_PATHS = NO;
962 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
963 | CLANG_CXX_LIBRARY = "libc++";
964 | CLANG_ENABLE_MODULES = YES;
965 | CLANG_ENABLE_OBJC_ARC = YES;
966 | CLANG_WARN_BOOL_CONVERSION = YES;
967 | CLANG_WARN_CONSTANT_CONVERSION = YES;
968 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
969 | CLANG_WARN_EMPTY_BODY = YES;
970 | CLANG_WARN_ENUM_CONVERSION = YES;
971 | CLANG_WARN_INT_CONVERSION = YES;
972 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
973 | CLANG_WARN_UNREACHABLE_CODE = YES;
974 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
975 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
976 | COPY_PHASE_STRIP = YES;
977 | ENABLE_NS_ASSERTIONS = NO;
978 | ENABLE_STRICT_OBJC_MSGSEND = YES;
979 | GCC_C_LANGUAGE_STANDARD = gnu99;
980 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
981 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
982 | GCC_WARN_UNDECLARED_SELECTOR = YES;
983 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
984 | GCC_WARN_UNUSED_FUNCTION = YES;
985 | GCC_WARN_UNUSED_VARIABLE = YES;
986 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
987 | MTL_ENABLE_DEBUG_INFO = NO;
988 | SDKROOT = iphoneos;
989 | VALIDATE_PRODUCT = YES;
990 | };
991 | name = Release;
992 | };
993 | /* End XCBuildConfiguration section */
994 |
995 | /* Begin XCConfigurationList section */
996 | 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "SampleRN20Tests" */ = {
997 | isa = XCConfigurationList;
998 | buildConfigurations = (
999 | 00E356F61AD99517003FC87E /* Debug */,
1000 | 00E356F71AD99517003FC87E /* Release */,
1001 | );
1002 | defaultConfigurationIsVisible = 0;
1003 | defaultConfigurationName = Release;
1004 | };
1005 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "SampleRN20" */ = {
1006 | isa = XCConfigurationList;
1007 | buildConfigurations = (
1008 | 13B07F941A680F5B00A75B9A /* Debug */,
1009 | 13B07F951A680F5B00A75B9A /* Release */,
1010 | );
1011 | defaultConfigurationIsVisible = 0;
1012 | defaultConfigurationName = Release;
1013 | };
1014 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "SampleRN20" */ = {
1015 | isa = XCConfigurationList;
1016 | buildConfigurations = (
1017 | 83CBBA201A601CBA00E9B192 /* Debug */,
1018 | 83CBBA211A601CBA00E9B192 /* Release */,
1019 | );
1020 | defaultConfigurationIsVisible = 0;
1021 | defaultConfigurationName = Release;
1022 | };
1023 | /* End XCConfigurationList section */
1024 | };
1025 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
1026 | }
1027 |
--------------------------------------------------------------------------------
/example/ios/SampleRN20.xcodeproj/xcshareddata/xcschemes/SampleRN20-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
113 |
119 |
120 |
121 |
122 |
124 |
125 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/example/ios/SampleRN20.xcodeproj/xcshareddata/xcschemes/SampleRN20.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
113 |
119 |
120 |
121 |
122 |
124 |
125 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/example/ios/SampleRN20/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (nonatomic, strong) UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/example/ios/SampleRN20/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "AppDelegate.h"
11 |
12 | #import
13 | #import
14 |
15 | @implementation AppDelegate
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
18 | {
19 | NSURL *jsCodeLocation;
20 |
21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
22 |
23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
24 | moduleName:@"SampleRN20"
25 | initialProperties:nil
26 | launchOptions:launchOptions];
27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
28 |
29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
30 | UIViewController *rootViewController = [UIViewController new];
31 | rootViewController.view = rootView;
32 | self.window.rootViewController = rootViewController;
33 | [self.window makeKeyAndVisible];
34 | return YES;
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/example/ios/SampleRN20/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/example/ios/SampleRN20/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/example/ios/SampleRN20/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | SampleRN20
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UIViewControllerBasedStatusBarAppearance
40 |
41 | NSLocationWhenInUseUsageDescription
42 |
43 | NSAppTransportSecurity
44 |
45 |
46 | NSExceptionDomains
47 |
48 | localhost
49 |
50 | NSExceptionAllowsInsecureHTTPLoads
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/example/ios/SampleRN20/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "AppDelegate.h"
13 |
14 | int main(int argc, char * argv[]) {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/example/ios/SampleRN20Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/ios/SampleRN20Tests/SampleRN20Tests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #import
12 |
13 | #import
14 | #import
15 |
16 | #define TIMEOUT_SECONDS 600
17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
18 |
19 | @interface SampleRN20Tests : XCTestCase
20 |
21 | @end
22 |
23 | @implementation SampleRN20Tests
24 |
25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
26 | {
27 | if (test(view)) {
28 | return YES;
29 | }
30 | for (UIView *subview in [view subviews]) {
31 | if ([self findSubviewInView:subview matching:test]) {
32 | return YES;
33 | }
34 | }
35 | return NO;
36 | }
37 |
38 | - (void)testRendersWelcomeScreen
39 | {
40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
42 | BOOL foundElement = NO;
43 |
44 | __block NSString *redboxError = nil;
45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
46 | if (level >= RCTLogLevelError) {
47 | redboxError = message;
48 | }
49 | });
50 |
51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
54 |
55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
57 | return YES;
58 | }
59 | return NO;
60 | }];
61 | }
62 |
63 | RCTSetLogFunction(RCTDefaultLogFunction);
64 |
65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
67 | }
68 |
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SampleRN20",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node node_modules/react-native/local-cli/cli.js start"
7 | },
8 | "dependencies": {
9 | "react": "16.0.0-alpha.6",
10 | "react-native": "0.43.4",
11 | "react-native-webview-bridge": "file:../"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Hello test html
8 |
9 |
--------------------------------------------------------------------------------
/ios/RCTWebViewBridge.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * Copyright (c) 2015-present, Ali Najafizadeh (github.com/alinz)
6 | * All rights reserved
7 | *
8 | * This source code is licensed under the BSD-style license found in the
9 | * LICENSE file in the root directory of this source tree. An additional grant
10 | * of patent rights can be found in the PATENTS file in the same directory.
11 | */
12 |
13 | #if __has_include()
14 | #import
15 | #else
16 | #import "RCTView.h"
17 | #endif
18 |
19 | @class RCTWebViewBridge;
20 |
21 | /**
22 | * Special scheme used to pass messages to the injectedJavaScript
23 | * code without triggering a page load. Usage:
24 | *
25 | * window.location.href = RCTJSNavigationScheme + '://hello'
26 | */
27 | extern NSString *const RCTJSNavigationScheme;
28 |
29 | @protocol RCTWebViewBridgeDelegate
30 |
31 | - (BOOL)webView:(RCTWebViewBridge *)webView
32 | shouldStartLoadForRequest:(NSMutableDictionary *)request
33 | withCallback:(RCTDirectEventBlock)callback;
34 |
35 | @end
36 |
37 | @interface RCTWebViewBridge : RCTView
38 |
39 | @property (nonatomic, weak) id delegate;
40 |
41 | @property (nonatomic, copy) NSDictionary *source;
42 | @property (nonatomic, assign) UIEdgeInsets contentInset;
43 | @property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
44 | @property (nonatomic, assign) BOOL hideKeyboardAccessoryView;
45 | @property (nonatomic, copy) NSString *injectedJavaScript;
46 |
47 | - (void)goForward;
48 | - (void)goBack;
49 | - (void)reload;
50 | - (void)sendToBridge:(NSString *)message;
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/ios/RCTWebViewBridge.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * Copyright (c) 2015-present, Ali Najafizadeh (github.com/alinz)
6 | * All rights reserved
7 | *
8 | * This source code is licensed under the BSD-style license found in the
9 | * LICENSE file in the root directory of this source tree. An additional grant
10 | * of patent rights can be found in the PATENTS file in the same directory.
11 | */
12 |
13 | #import "RCTWebViewBridge.h"
14 |
15 | #import
16 |
17 | #if __has_include()
18 | #import
19 | #else
20 | #import "RCTAutoInsetsProtocol.h"
21 | #endif
22 |
23 | #if __has_include()
24 | #import
25 | #else
26 | #import "RCTConvert.h"
27 | #endif
28 |
29 | #if __has_include()
30 | #import
31 | #else
32 | #import "RCTEventDispatcher.h"
33 | #endif
34 |
35 | #if __has_include()
36 | #import
37 | #else
38 | #import "RCTLog.h"
39 | #endif
40 |
41 | #if __has_include()
42 | #import
43 | #else
44 | #import "RCTUtils.h"
45 | #endif
46 |
47 | #if __has_include()
48 | #import
49 | #else
50 | #import "UIView+React.h"
51 | #endif
52 |
53 | #import
54 |
55 | //This is a very elegent way of defining multiline string in objective-c.
56 | //source: http://stackoverflow.com/a/23387659/828487
57 | #define NSStringMultiline(...) [[NSString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
58 |
59 | //we don'e need this one since it has been defined in RCTWebView.m
60 | //NSString *const RCTJSNavigationScheme = @"react-js-navigation";
61 | NSString *const RCTWebViewBridgeSchema = @"wvb";
62 |
63 | // runtime trick to remove UIWebview keyboard default toolbar
64 | // see: http://stackoverflow.com/questions/19033292/ios-7-uiwebview-keyboard-issue/19042279#19042279
65 | @interface _SwizzleHelper : NSObject @end
66 | @implementation _SwizzleHelper
67 | -(id)inputAccessoryView
68 | {
69 | return nil;
70 | }
71 | @end
72 |
73 | @interface RCTWebViewBridge ()
74 |
75 | @property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
76 | @property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
77 | @property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
78 | @property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
79 | @property (nonatomic, copy) RCTDirectEventBlock onBridgeMessage;
80 |
81 | @end
82 |
83 | @implementation RCTWebViewBridge
84 | {
85 | UIWebView *_webView;
86 | NSString *_injectedJavaScript;
87 | }
88 |
89 | - (instancetype)initWithFrame:(CGRect)frame
90 | {
91 | if ((self = [super initWithFrame:frame])) {
92 | super.backgroundColor = [UIColor clearColor];
93 | _automaticallyAdjustContentInsets = YES;
94 | _contentInset = UIEdgeInsetsZero;
95 | _webView = [[UIWebView alloc] initWithFrame:self.bounds];
96 | _webView.delegate = self;
97 | [self addSubview:_webView];
98 | }
99 | return self;
100 | }
101 |
102 | RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
103 |
104 | - (void)goForward
105 | {
106 | [_webView goForward];
107 | }
108 |
109 | - (void)goBack
110 | {
111 | [_webView goBack];
112 | }
113 |
114 | - (void)reload
115 | {
116 | [_webView reload];
117 | }
118 |
119 | - (void)sendToBridge:(NSString *)message
120 | {
121 | //we are warpping the send message in a function to make sure that if
122 | //WebView is not injected, we don't crash the app.
123 | NSString *format = NSStringMultiline(
124 | (function(){
125 | if (WebViewBridge && WebViewBridge.__push__) {
126 | WebViewBridge.__push__('%@');
127 | }
128 | }());
129 | );
130 |
131 | NSString *command = [NSString stringWithFormat: format, message];
132 | [_webView stringByEvaluatingJavaScriptFromString:command];
133 | }
134 |
135 | - (NSURL *)URL
136 | {
137 | return _webView.request.URL;
138 | }
139 |
140 | - (void)setSource:(NSDictionary *)source
141 | {
142 | if (![_source isEqualToDictionary:source]) {
143 | _source = [source copy];
144 |
145 | // Check for a static html source first
146 | NSString *html = [RCTConvert NSString:source[@"html"]];
147 | if (html) {
148 | NSURL *baseURL = [RCTConvert NSURL:source[@"baseUrl"]];
149 | [_webView loadHTMLString:html baseURL:baseURL];
150 | return;
151 | }
152 |
153 | NSURLRequest *request = [RCTConvert NSURLRequest:source];
154 | // Because of the way React works, as pages redirect, we actually end up
155 | // passing the redirect urls back here, so we ignore them if trying to load
156 | // the same url. We'll expose a call to 'reload' to allow a user to load
157 | // the existing page.
158 | if ([request.URL isEqual:_webView.request.URL]) {
159 | return;
160 | }
161 | if (!request.URL) {
162 | // Clear the webview
163 | [_webView loadHTMLString:@"" baseURL:nil];
164 | return;
165 | }
166 | [_webView loadRequest:request];
167 | }
168 | }
169 |
170 | - (void)layoutSubviews
171 | {
172 | [super layoutSubviews];
173 | _webView.frame = self.bounds;
174 | }
175 |
176 | - (void)setContentInset:(UIEdgeInsets)contentInset
177 | {
178 | _contentInset = contentInset;
179 | [RCTView autoAdjustInsetsForView:self
180 | withScrollView:_webView.scrollView
181 | updateOffset:NO];
182 | }
183 |
184 | - (void)setBackgroundColor:(UIColor *)backgroundColor
185 | {
186 | CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
187 | self.opaque = _webView.opaque = (alpha == 1.0);
188 | _webView.backgroundColor = backgroundColor;
189 | }
190 |
191 | - (UIColor *)backgroundColor
192 | {
193 | return _webView.backgroundColor;
194 | }
195 |
196 | - (NSMutableDictionary *)baseEvent
197 | {
198 | NSMutableDictionary *event = [[NSMutableDictionary alloc] initWithDictionary:@{
199 | @"url": _webView.request.URL.absoluteString ?: @"",
200 | @"loading" : @(_webView.loading),
201 | @"title": [_webView stringByEvaluatingJavaScriptFromString:@"document.title"],
202 | @"canGoBack": @(_webView.canGoBack),
203 | @"canGoForward" : @(_webView.canGoForward),
204 | }];
205 |
206 | return event;
207 | }
208 |
209 | - (void)refreshContentInset
210 | {
211 | [RCTView autoAdjustInsetsForView:self
212 | withScrollView:_webView.scrollView
213 | updateOffset:YES];
214 | }
215 |
216 | -(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView
217 | {
218 | if (!hideKeyboardAccessoryView) {
219 | return;
220 | }
221 |
222 | UIView* subview;
223 | for (UIView* view in _webView.scrollView.subviews) {
224 | if([[view.class description] hasPrefix:@"UIWeb"])
225 | subview = view;
226 | }
227 |
228 | if(subview == nil) return;
229 |
230 | NSString* name = [NSString stringWithFormat:@"%@_SwizzleHelper", subview.class.superclass];
231 | Class newClass = NSClassFromString(name);
232 |
233 | if(newClass == nil)
234 | {
235 | newClass = objc_allocateClassPair(subview.class, [name cStringUsingEncoding:NSASCIIStringEncoding], 0);
236 | if(!newClass) return;
237 |
238 | Method method = class_getInstanceMethod([_SwizzleHelper class], @selector(inputAccessoryView));
239 | class_addMethod(newClass, @selector(inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method));
240 |
241 | objc_registerClassPair(newClass);
242 | }
243 |
244 | object_setClass(subview, newClass);
245 | }
246 |
247 | #pragma mark - UIWebViewDelegate methods
248 |
249 | - (BOOL)webView:(__unused UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
250 | navigationType:(UIWebViewNavigationType)navigationType
251 | {
252 | BOOL isJSNavigation = [request.URL.scheme isEqualToString:RCTJSNavigationScheme];
253 |
254 | if (!isJSNavigation && [request.URL.scheme isEqualToString:RCTWebViewBridgeSchema]) {
255 | NSString* message = [webView stringByEvaluatingJavaScriptFromString:@"WebViewBridge.__fetch__()"];
256 |
257 | NSMutableDictionary *onBridgeMessageEvent = [[NSMutableDictionary alloc] initWithDictionary:@{
258 | @"messages": [self stringArrayJsonToArray: message]
259 | }];
260 |
261 | _onBridgeMessage(onBridgeMessageEvent);
262 |
263 | isJSNavigation = YES;
264 | }
265 |
266 | // skip this for the JS Navigation handler
267 | if (!isJSNavigation && _onShouldStartLoadWithRequest) {
268 | NSMutableDictionary *event = [self baseEvent];
269 | [event addEntriesFromDictionary: @{
270 | @"url": (request.URL).absoluteString,
271 | @"navigationType": @(navigationType)
272 | }];
273 | if (![self.delegate webView:self
274 | shouldStartLoadForRequest:event
275 | withCallback:_onShouldStartLoadWithRequest]) {
276 | return NO;
277 | }
278 | }
279 |
280 | if (_onLoadingStart) {
281 | // We have this check to filter out iframe requests and whatnot
282 | BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
283 | if (isTopFrame) {
284 | NSMutableDictionary *event = [self baseEvent];
285 | [event addEntriesFromDictionary: @{
286 | @"url": (request.URL).absoluteString,
287 | @"navigationType": @(navigationType)
288 | }];
289 | _onLoadingStart(event);
290 | }
291 | }
292 |
293 | // JS Navigation handler
294 | return !isJSNavigation;
295 | }
296 |
297 | - (void)webView:(__unused UIWebView *)webView didFailLoadWithError:(NSError *)error
298 | {
299 | if (_onLoadingError) {
300 | if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) {
301 | // NSURLErrorCancelled is reported when a page has a redirect OR if you load
302 | // a new URL in the WebView before the previous one came back. We can just
303 | // ignore these since they aren't real errors.
304 | // http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os
305 | return;
306 | }
307 |
308 | NSMutableDictionary *event = [self baseEvent];
309 | [event addEntriesFromDictionary:@{
310 | @"domain": error.domain,
311 | @"code": @(error.code),
312 | @"description": error.localizedDescription,
313 | }];
314 | _onLoadingError(event);
315 | }
316 | }
317 |
318 | - (void)webViewDidFinishLoad:(UIWebView *)webView
319 | {
320 | //injecting WebViewBridge Script
321 | NSString *webViewBridgeScriptContent = [self webViewBridgeScript];
322 | [webView stringByEvaluatingJavaScriptFromString:webViewBridgeScriptContent];
323 | //////////////////////////////////////////////////////////////////////////////
324 |
325 | if (_injectedJavaScript != nil) {
326 | NSString *jsEvaluationValue = [webView stringByEvaluatingJavaScriptFromString:_injectedJavaScript];
327 |
328 | NSMutableDictionary *event = [self baseEvent];
329 | event[@"jsEvaluationValue"] = jsEvaluationValue;
330 |
331 | _onLoadingFinish(event);
332 | }
333 | // we only need the final 'finishLoad' call so only fire the event when we're actually done loading.
334 | else if (_onLoadingFinish && !webView.loading && ![webView.request.URL.absoluteString isEqualToString:@"about:blank"]) {
335 | _onLoadingFinish([self baseEvent]);
336 | }
337 | }
338 |
339 | - (NSArray*)stringArrayJsonToArray:(NSString *)message
340 | {
341 | return [NSJSONSerialization JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding]
342 | options:NSJSONReadingAllowFragments
343 | error:nil];
344 | }
345 |
346 | //since there is no easy way to load the static lib resource in ios,
347 | //we are loading the script from this method.
348 | - (NSString *)webViewBridgeScript {
349 | // NSBundle *bundle = [NSBundle mainBundle];
350 | // NSString *webViewBridgeScriptFile = [bundle pathForResource:@"webviewbridge"
351 | // ofType:@"js"];
352 | // NSString *webViewBridgeScriptContent = [NSString stringWithContentsOfFile:webViewBridgeScriptFile
353 | // encoding:NSUTF8StringEncoding
354 | // error:nil];
355 |
356 | return NSStringMultiline(
357 | (function (window) {
358 | 'use strict';
359 |
360 | //Make sure that if WebViewBridge already in scope we don't override it.
361 | if (window.WebViewBridge) {
362 | return;
363 | }
364 |
365 | var RNWBSchema = 'wvb';
366 | var sendQueue = [];
367 | var receiveQueue = [];
368 | var doc = window.document;
369 | var customEvent = doc.createEvent('Event');
370 |
371 | function callFunc(func, message) {
372 | if ('function' === typeof func) {
373 | func(message);
374 | }
375 | }
376 |
377 | function signalNative() {
378 | window.location = RNWBSchema + '://message' + new Date().getTime();
379 | }
380 |
381 | //I made the private function ugly signiture so user doesn't called them accidently.
382 | //if you do, then I have nothing to say. :(
383 | var WebViewBridge = {
384 | //this function will be called by native side to push a new message
385 | //to webview.
386 | __push__: function (message) {
387 | receiveQueue.push(message);
388 | //reason I need this setTmeout is to return this function as fast as
389 | //possible to release the native side thread.
390 | setTimeout(function () {
391 | var message = receiveQueue.pop();
392 | callFunc(WebViewBridge.onMessage, message);
393 | }, 15); //this magic number is just a random small value. I don't like 0.
394 | },
395 | __fetch__: function () {
396 | //since our sendQueue array only contains string, and our connection to native
397 | //can only accept string, we need to convert array of strings into single string.
398 | var messages = JSON.stringify(sendQueue);
399 |
400 | //we make sure that sendQueue is resets
401 | sendQueue = [];
402 |
403 | //return the messages back to native side.
404 | return messages;
405 | },
406 | //make sure message is string. because only string can be sent to native,
407 | //if you don't pass it as string, onError function will be called.
408 | send: function (message) {
409 | if ('string' !== typeof message) {
410 | callFunc(WebViewBridge.onError, "message is type '" + typeof message + "', and it needs to be string");
411 | return;
412 | }
413 |
414 | //we queue the messages to make sure that native can collects all of them in one shot.
415 | sendQueue.push(message);
416 | //signal the objective-c that there is a message in the queue
417 | signalNative();
418 | },
419 | onMessage: null,
420 | onError: null
421 | };
422 |
423 | window.WebViewBridge = WebViewBridge;
424 |
425 | //dispatch event
426 | customEvent.initEvent('WebViewBridge', true, true);
427 | doc.dispatchEvent(customEvent);
428 | }(window));
429 | );
430 | }
431 |
432 | @end
433 |
--------------------------------------------------------------------------------
/ios/RCTWebViewBridgeManager.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * Copyright (c) 2015-present, Ali Najafizadeh (github.com/alinz)
6 | * All rights reserved
7 | *
8 | * This source code is licensed under the BSD-style license found in the
9 | * LICENSE file in the root directory of this source tree. An additional grant
10 | * of patent rights can be found in the PATENTS file in the same directory.
11 | */
12 |
13 | #if __has_include()
14 | #import
15 | #else
16 | #import "RCTViewManager.h"
17 | #endif
18 |
19 | @interface RCTWebViewBridgeManager : RCTViewManager
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/ios/RCTWebViewBridgeManager.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * Copyright (c) 2015-present, Ali Najafizadeh (github.com/alinz)
6 | * All rights reserved
7 | *
8 | * This source code is licensed under the BSD-style license found in the
9 | * LICENSE file in the root directory of this source tree. An additional grant
10 | * of patent rights can be found in the PATENTS file in the same directory.
11 | */
12 |
13 | #import "RCTWebViewBridgeManager.h"
14 | #import "RCTWebViewBridge.h"
15 |
16 | #if __has_include()
17 | #import
18 | #else
19 | #import "RCTBridge.h"
20 | #endif
21 |
22 | #if __has_include()
23 | #import
24 | #else
25 | #import "RCTUIManager.h"
26 | #endif
27 |
28 | #if __has_include()
29 | #import
30 | #else
31 | #import "UIView+React.h"
32 | #endif
33 |
34 | @interface RCTWebViewBridgeManager ()
35 |
36 | @end
37 |
38 | @implementation RCTWebViewBridgeManager
39 | {
40 | NSConditionLock *_shouldStartLoadLock;
41 | BOOL _shouldStartLoad;
42 | }
43 |
44 | RCT_EXPORT_MODULE()
45 |
46 | - (UIView *)view
47 | {
48 | RCTWebViewBridge *webView = [RCTWebViewBridge new];
49 | webView.delegate = self;
50 | return webView;
51 | }
52 |
53 | RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
54 | RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL)
55 | RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL)
56 | RCT_REMAP_VIEW_PROPERTY(scalesPageToFit, _webView.scalesPageToFit, BOOL)
57 | RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
58 | RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
59 | RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
60 | RCT_EXPORT_VIEW_PROPERTY(hideKeyboardAccessoryView, BOOL)
61 | RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
62 | RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
63 | RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
64 | RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
65 | RCT_REMAP_VIEW_PROPERTY(allowsInlineMediaPlayback, _webView.allowsInlineMediaPlayback, BOOL)
66 | RCT_EXPORT_VIEW_PROPERTY(onBridgeMessage, RCTDirectEventBlock)
67 | RCT_REMAP_VIEW_PROPERTY(keyboardDisplayRequiresUserAction, _webView.keyboardDisplayRequiresUserAction, BOOL)
68 |
69 | - (NSDictionary *)constantsToExport
70 | {
71 | return @{
72 | @"JSNavigationScheme": RCTJSNavigationScheme,
73 | @"NavigationType": @{
74 | @"LinkClicked": @(UIWebViewNavigationTypeLinkClicked),
75 | @"FormSubmitted": @(UIWebViewNavigationTypeFormSubmitted),
76 | @"BackForward": @(UIWebViewNavigationTypeBackForward),
77 | @"Reload": @(UIWebViewNavigationTypeReload),
78 | @"FormResubmitted": @(UIWebViewNavigationTypeFormResubmitted),
79 | @"Other": @(UIWebViewNavigationTypeOther)
80 | },
81 | };
82 | }
83 |
84 | + (BOOL)requiresMainQueueSetup
85 | {
86 | return YES;
87 | }
88 |
89 | RCT_EXPORT_METHOD(goBack:(nonnull NSNumber *)reactTag)
90 | {
91 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
92 | RCTWebViewBridge *view = viewRegistry[reactTag];
93 | if (![view isKindOfClass:[RCTWebViewBridge class]]) {
94 | RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
95 | } else {
96 | [view goBack];
97 | }
98 | }];
99 | }
100 |
101 | RCT_EXPORT_METHOD(goForward:(nonnull NSNumber *)reactTag)
102 | {
103 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
104 | RCTWebViewBridge* view = viewRegistry[reactTag];
105 | if (![view isKindOfClass:[RCTWebViewBridge class]]) {
106 | RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
107 | } else {
108 | [view goForward];
109 | }
110 | }];
111 | }
112 |
113 | RCT_EXPORT_METHOD(reload:(nonnull NSNumber *)reactTag)
114 | {
115 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
116 | RCTWebViewBridge *view = viewRegistry[reactTag];
117 | if (![view isKindOfClass:[RCTWebViewBridge class]]) {
118 | RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
119 | } else {
120 | [view reload];
121 | }
122 | }];
123 | }
124 |
125 | RCT_EXPORT_METHOD(sendToBridge:(nonnull NSNumber *)reactTag
126 | value:(NSString*)message)
127 | {
128 | [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
129 | RCTWebViewBridge *view = viewRegistry[reactTag];
130 | if (![view isKindOfClass:[RCTWebViewBridge class]]) {
131 | RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
132 | } else {
133 | [view sendToBridge: message];
134 | }
135 | }];
136 | }
137 |
138 | #pragma mark - Exported synchronous methods
139 |
140 | - (BOOL)webView:(__unused RCTWebViewBridge *)webView
141 | shouldStartLoadForRequest:(NSMutableDictionary *)request
142 | withCallback:(RCTDirectEventBlock)callback
143 | {
144 | _shouldStartLoadLock = [[NSConditionLock alloc] initWithCondition:arc4random()];
145 | _shouldStartLoad = YES;
146 | request[@"lockIdentifier"] = @(_shouldStartLoadLock.condition);
147 | callback(request);
148 |
149 | // Block the main thread for a maximum of 250ms until the JS thread returns
150 | if ([_shouldStartLoadLock lockWhenCondition:0 beforeDate:[NSDate dateWithTimeIntervalSinceNow:.25]]) {
151 | BOOL returnValue = _shouldStartLoad;
152 | [_shouldStartLoadLock unlock];
153 | _shouldStartLoadLock = nil;
154 | return returnValue;
155 | } else {
156 | RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to YES");
157 | return YES;
158 | }
159 | }
160 |
161 | RCT_EXPORT_METHOD(startLoadWithResult:(BOOL)result lockIdentifier:(NSInteger)lockIdentifier)
162 | {
163 | if ([_shouldStartLoadLock tryLockWhenCondition:lockIdentifier]) {
164 | _shouldStartLoad = result;
165 | [_shouldStartLoadLock unlockWithCondition:0];
166 | } else {
167 | RCTLogWarn(@"startLoadWithResult invoked with invalid lockIdentifier: "
168 | "got %zd, expected %zd", lockIdentifier, _shouldStartLoadLock.condition);
169 | }
170 | }
171 |
172 | @end
173 |
--------------------------------------------------------------------------------
/ios/React-Native-Webview-Bridge.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 4114DC5C1C187CCB003CD988 /* RCTWebViewBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 4114DC591C187CCB003CD988 /* RCTWebViewBridge.m */; };
11 | 4114DC5D1C187CCB003CD988 /* RCTWebViewBridgeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4114DC5B1C187CCB003CD988 /* RCTWebViewBridgeManager.m */; };
12 | /* End PBXBuildFile section */
13 |
14 | /* Begin PBXCopyFilesBuildPhase section */
15 | 4114DC4A1C187C3A003CD988 /* CopyFiles */ = {
16 | isa = PBXCopyFilesBuildPhase;
17 | buildActionMask = 2147483647;
18 | dstPath = "include/$(PRODUCT_NAME)";
19 | dstSubfolderSpec = 16;
20 | files = (
21 | );
22 | runOnlyForDeploymentPostprocessing = 0;
23 | };
24 | /* End PBXCopyFilesBuildPhase section */
25 |
26 | /* Begin PBXFileReference section */
27 | 4114DC4C1C187C3A003CD988 /* libReact-Native-Webview-Bridge.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libReact-Native-Webview-Bridge.a"; sourceTree = BUILT_PRODUCTS_DIR; };
28 | 4114DC581C187CCB003CD988 /* RCTWebViewBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewBridge.h; sourceTree = SOURCE_ROOT; };
29 | 4114DC591C187CCB003CD988 /* RCTWebViewBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebViewBridge.m; sourceTree = SOURCE_ROOT; };
30 | 4114DC5A1C187CCB003CD988 /* RCTWebViewBridgeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewBridgeManager.h; sourceTree = SOURCE_ROOT; };
31 | 4114DC5B1C187CCB003CD988 /* RCTWebViewBridgeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebViewBridgeManager.m; sourceTree = SOURCE_ROOT; };
32 | 4114DC5F1C187CE4003CD988 /* webviewbridge.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = webviewbridge.js; sourceTree = ""; };
33 | /* End PBXFileReference section */
34 |
35 | /* Begin PBXFrameworksBuildPhase section */
36 | 4114DC491C187C3A003CD988 /* Frameworks */ = {
37 | isa = PBXFrameworksBuildPhase;
38 | buildActionMask = 2147483647;
39 | files = (
40 | );
41 | runOnlyForDeploymentPostprocessing = 0;
42 | };
43 | /* End PBXFrameworksBuildPhase section */
44 |
45 | /* Begin PBXGroup section */
46 | 4114DC431C187C3A003CD988 = {
47 | isa = PBXGroup;
48 | children = (
49 | 4114DC4E1C187C3A003CD988 /* React-Native-Webview-Bridge */,
50 | 4114DC5E1C187CE4003CD988 /* scripts */,
51 | 4114DC4D1C187C3A003CD988 /* Products */,
52 | );
53 | sourceTree = "";
54 | };
55 | 4114DC4D1C187C3A003CD988 /* Products */ = {
56 | isa = PBXGroup;
57 | children = (
58 | 4114DC4C1C187C3A003CD988 /* libReact-Native-Webview-Bridge.a */,
59 | );
60 | name = Products;
61 | sourceTree = "";
62 | };
63 | 4114DC4E1C187C3A003CD988 /* React-Native-Webview-Bridge */ = {
64 | isa = PBXGroup;
65 | children = (
66 | 4114DC581C187CCB003CD988 /* RCTWebViewBridge.h */,
67 | 4114DC591C187CCB003CD988 /* RCTWebViewBridge.m */,
68 | 4114DC5A1C187CCB003CD988 /* RCTWebViewBridgeManager.h */,
69 | 4114DC5B1C187CCB003CD988 /* RCTWebViewBridgeManager.m */,
70 | );
71 | path = "React-Native-Webview-Bridge";
72 | sourceTree = "";
73 | };
74 | 4114DC5E1C187CE4003CD988 /* scripts */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 4114DC5F1C187CE4003CD988 /* webviewbridge.js */,
78 | );
79 | name = scripts;
80 | path = ../scripts;
81 | sourceTree = "";
82 | };
83 | /* End PBXGroup section */
84 |
85 | /* Begin PBXNativeTarget section */
86 | 4114DC4B1C187C3A003CD988 /* React-Native-Webview-Bridge */ = {
87 | isa = PBXNativeTarget;
88 | buildConfigurationList = 4114DC551C187C3A003CD988 /* Build configuration list for PBXNativeTarget "React-Native-Webview-Bridge" */;
89 | buildPhases = (
90 | 4114DC481C187C3A003CD988 /* Sources */,
91 | 4114DC491C187C3A003CD988 /* Frameworks */,
92 | 4114DC4A1C187C3A003CD988 /* CopyFiles */,
93 | );
94 | buildRules = (
95 | );
96 | dependencies = (
97 | );
98 | name = "React-Native-Webview-Bridge";
99 | productName = "React-Native-Webview-Bridge";
100 | productReference = 4114DC4C1C187C3A003CD988 /* libReact-Native-Webview-Bridge.a */;
101 | productType = "com.apple.product-type.library.static";
102 | };
103 | /* End PBXNativeTarget section */
104 |
105 | /* Begin PBXProject section */
106 | 4114DC441C187C3A003CD988 /* Project object */ = {
107 | isa = PBXProject;
108 | attributes = {
109 | LastUpgradeCheck = 0710;
110 | ORGANIZATIONNAME = alinz;
111 | TargetAttributes = {
112 | 4114DC4B1C187C3A003CD988 = {
113 | CreatedOnToolsVersion = 7.1.1;
114 | };
115 | };
116 | };
117 | buildConfigurationList = 4114DC471C187C3A003CD988 /* Build configuration list for PBXProject "React-Native-Webview-Bridge" */;
118 | compatibilityVersion = "Xcode 3.2";
119 | developmentRegion = English;
120 | hasScannedForEncodings = 0;
121 | knownRegions = (
122 | en,
123 | );
124 | mainGroup = 4114DC431C187C3A003CD988;
125 | productRefGroup = 4114DC4D1C187C3A003CD988 /* Products */;
126 | projectDirPath = "";
127 | projectRoot = "";
128 | targets = (
129 | 4114DC4B1C187C3A003CD988 /* React-Native-Webview-Bridge */,
130 | );
131 | };
132 | /* End PBXProject section */
133 |
134 | /* Begin PBXSourcesBuildPhase section */
135 | 4114DC481C187C3A003CD988 /* Sources */ = {
136 | isa = PBXSourcesBuildPhase;
137 | buildActionMask = 2147483647;
138 | files = (
139 | 4114DC5D1C187CCB003CD988 /* RCTWebViewBridgeManager.m in Sources */,
140 | 4114DC5C1C187CCB003CD988 /* RCTWebViewBridge.m in Sources */,
141 | );
142 | runOnlyForDeploymentPostprocessing = 0;
143 | };
144 | /* End PBXSourcesBuildPhase section */
145 |
146 | /* Begin XCBuildConfiguration section */
147 | 4114DC531C187C3A003CD988 /* Debug */ = {
148 | isa = XCBuildConfiguration;
149 | buildSettings = {
150 | ALWAYS_SEARCH_USER_PATHS = NO;
151 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
152 | CLANG_CXX_LIBRARY = "libc++";
153 | CLANG_ENABLE_MODULES = YES;
154 | CLANG_ENABLE_OBJC_ARC = YES;
155 | CLANG_WARN_BOOL_CONVERSION = YES;
156 | CLANG_WARN_CONSTANT_CONVERSION = YES;
157 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
158 | CLANG_WARN_EMPTY_BODY = YES;
159 | CLANG_WARN_ENUM_CONVERSION = YES;
160 | CLANG_WARN_INT_CONVERSION = YES;
161 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
162 | CLANG_WARN_UNREACHABLE_CODE = YES;
163 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
164 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
165 | COPY_PHASE_STRIP = NO;
166 | DEBUG_INFORMATION_FORMAT = dwarf;
167 | ENABLE_STRICT_OBJC_MSGSEND = YES;
168 | ENABLE_TESTABILITY = YES;
169 | GCC_C_LANGUAGE_STANDARD = gnu99;
170 | GCC_DYNAMIC_NO_PIC = NO;
171 | GCC_NO_COMMON_BLOCKS = YES;
172 | GCC_OPTIMIZATION_LEVEL = 0;
173 | GCC_PREPROCESSOR_DEFINITIONS = (
174 | "DEBUG=1",
175 | "$(inherited)",
176 | );
177 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
178 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
179 | GCC_WARN_UNDECLARED_SELECTOR = YES;
180 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
181 | GCC_WARN_UNUSED_FUNCTION = YES;
182 | GCC_WARN_UNUSED_VARIABLE = YES;
183 | IPHONEOS_DEPLOYMENT_TARGET = 9.1;
184 | MTL_ENABLE_DEBUG_INFO = YES;
185 | ONLY_ACTIVE_ARCH = YES;
186 | SDKROOT = iphoneos;
187 | };
188 | name = Debug;
189 | };
190 | 4114DC541C187C3A003CD988 /* Release */ = {
191 | isa = XCBuildConfiguration;
192 | buildSettings = {
193 | ALWAYS_SEARCH_USER_PATHS = NO;
194 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
195 | CLANG_CXX_LIBRARY = "libc++";
196 | CLANG_ENABLE_MODULES = YES;
197 | CLANG_ENABLE_OBJC_ARC = YES;
198 | CLANG_WARN_BOOL_CONVERSION = YES;
199 | CLANG_WARN_CONSTANT_CONVERSION = YES;
200 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
201 | CLANG_WARN_EMPTY_BODY = YES;
202 | CLANG_WARN_ENUM_CONVERSION = YES;
203 | CLANG_WARN_INT_CONVERSION = YES;
204 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
205 | CLANG_WARN_UNREACHABLE_CODE = YES;
206 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
207 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
208 | COPY_PHASE_STRIP = NO;
209 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
210 | ENABLE_NS_ASSERTIONS = NO;
211 | ENABLE_STRICT_OBJC_MSGSEND = YES;
212 | GCC_C_LANGUAGE_STANDARD = gnu99;
213 | GCC_NO_COMMON_BLOCKS = YES;
214 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
215 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
216 | GCC_WARN_UNDECLARED_SELECTOR = YES;
217 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
218 | GCC_WARN_UNUSED_FUNCTION = YES;
219 | GCC_WARN_UNUSED_VARIABLE = YES;
220 | IPHONEOS_DEPLOYMENT_TARGET = 9.1;
221 | MTL_ENABLE_DEBUG_INFO = NO;
222 | SDKROOT = iphoneos;
223 | VALIDATE_PRODUCT = YES;
224 | };
225 | name = Release;
226 | };
227 | 4114DC561C187C3A003CD988 /* Debug */ = {
228 | isa = XCBuildConfiguration;
229 | buildSettings = {
230 | HEADER_SEARCH_PATHS = (
231 | "$(inhereted)",
232 | "$(SRCROOT)/../../../node_module/React/**",
233 | "$(SRCROOT)/../../../node_modules/react-native/React/**",
234 | );
235 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
236 | OTHER_LDFLAGS = "-ObjC";
237 | PRODUCT_NAME = "$(TARGET_NAME)";
238 | SKIP_INSTALL = YES;
239 | };
240 | name = Debug;
241 | };
242 | 4114DC571C187C3A003CD988 /* Release */ = {
243 | isa = XCBuildConfiguration;
244 | buildSettings = {
245 | HEADER_SEARCH_PATHS = (
246 | "$(inhereted)",
247 | "$(SRCROOT)/../../../node_module/React/**",
248 | "$(SRCROOT)/../../../node_modules/react-native/React/**",
249 | );
250 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
251 | OTHER_LDFLAGS = "-ObjC";
252 | PRODUCT_NAME = "$(TARGET_NAME)";
253 | SKIP_INSTALL = YES;
254 | };
255 | name = Release;
256 | };
257 | /* End XCBuildConfiguration section */
258 |
259 | /* Begin XCConfigurationList section */
260 | 4114DC471C187C3A003CD988 /* Build configuration list for PBXProject "React-Native-Webview-Bridge" */ = {
261 | isa = XCConfigurationList;
262 | buildConfigurations = (
263 | 4114DC531C187C3A003CD988 /* Debug */,
264 | 4114DC541C187C3A003CD988 /* Release */,
265 | );
266 | defaultConfigurationIsVisible = 0;
267 | defaultConfigurationName = Release;
268 | };
269 | 4114DC551C187C3A003CD988 /* Build configuration list for PBXNativeTarget "React-Native-Webview-Bridge" */ = {
270 | isa = XCConfigurationList;
271 | buildConfigurations = (
272 | 4114DC561C187C3A003CD988 /* Debug */,
273 | 4114DC571C187C3A003CD988 /* Release */,
274 | );
275 | defaultConfigurationIsVisible = 0;
276 | defaultConfigurationName = Release;
277 | };
278 | /* End XCConfigurationList section */
279 | };
280 | rootObject = 4114DC441C187C3A003CD988 /* Project object */;
281 | }
282 |
--------------------------------------------------------------------------------
/ios/React-Native-Webview-Bridge.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/React-Native-Webview-Bridge.xcodeproj/project.xcworkspace/xcuserdata/ali.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wix-playground/react-native-webview-bridge/ecbd800a1fd9df2de2bd84ec0ed7835e3e2164de/ios/React-Native-Webview-Bridge.xcodeproj/project.xcworkspace/xcuserdata/ali.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/ali.xcuserdatad/xcschemes/react-native-webview-bridge.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/ios/React-Native-Webview-Bridge.xcodeproj/xcuserdata/ali.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | React-Native-Webview-Bridge.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 4114DC4B1C187C3A003CD988
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-webview-bridge-updated",
3 | "version": "1.1.1",
4 | "description": "React Native WebView Javascript Bridge - updated",
5 | "license": "MIT",
6 | "author": "Ali Najafizadeh",
7 | "contributors": [
8 | "Daniel Zlotin ",
9 | "Yedidya Kennard "
10 | ],
11 | "directories": {
12 | "example": "examples",
13 | "lib": "webview-bridge"
14 | },
15 | "keywords": [
16 | "react-native",
17 | "react-component",
18 | "ios",
19 | "webview-bridge"
20 | ],
21 | "homepage": "https://github.com/wix/react-native-webview-bridge",
22 | "bugs": {
23 | "url": "https://github.com/wix/react-native-webview-bridge/issues"
24 | },
25 | "repository": {
26 | "type": "git",
27 | "url": "git@github.com:wix/react-native-webview-bridge.git"
28 | },
29 | "scripts": {
30 | "build": ":",
31 | "test": ":",
32 | "release": "npm version patch && npm publish && git push"
33 | },
34 | "main": "webview-bridge",
35 | "dependencies": {
36 | "invariant": "2.2.0",
37 | "keymirror": "0.1.1"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/scripts/webviewbridge.js:
--------------------------------------------------------------------------------
1 | (function (window) {
2 | 'use strict';
3 |
4 | //Make sure that if WebViewBridge already in scope we don't override it.
5 | if (window.WebViewBridge) {
6 | return;
7 | }
8 |
9 | var RNWBSchema = 'wvb';
10 | var sendQueue = [];
11 | var receiveQueue = [];
12 | var doc = window.document;
13 | var customEvent = doc.createEvent('Event');
14 |
15 | function callFunc(func, message) {
16 | if ('function' === typeof func) {
17 | func(message);
18 | }
19 | }
20 |
21 | function signalNative() {
22 | window.location = RNWBSchema + '://message' + new Date().getTime();
23 | }
24 |
25 | //I made the private function ugly signiture so user doesn't called them accidently.
26 | //if you do, then I have nothing to say. :(
27 | var WebViewBridge = {
28 | //this function will be called by native side to push a new message
29 | //to webview.
30 | __push__: function (message) {
31 | receiveQueue.push(message);
32 | //reason I need this setTmeout is to return this function as fast as
33 | //possible to release the native side thread.
34 | setTimeout(function () {
35 | var message = receiveQueue.pop();
36 | callFunc(WebViewBridge.onMessage, message);
37 | }, 15); //this magic number is just a random small value. I don't like 0.
38 | },
39 | __fetch__: function () {
40 | //since our sendQueue array only contains string, and our connection to native
41 | //can only accept string, we need to convert array of strings into single string.
42 | var messages = JSON.stringify(sendQueue);
43 |
44 | //we make sure that sendQueue is resets
45 | sendQueue = [];
46 |
47 | //return the messages back to native side.
48 | return messages;
49 | },
50 | //make sure message is string. because only string can be sent to native,
51 | //if you don't pass it as string, onError function will be called.
52 | send: function (message) {
53 | if ('string' !== typeof message) {
54 | callFunc(WebViewBridge.onError, "message is type '" + typeof message + "', and it needs to be string");
55 | return;
56 | }
57 |
58 | //we queue the messages to make sure that native can collects all of them in one shot.
59 | sendQueue.push(message);
60 | //signal the objective-c that there is a message in the queue
61 | signalNative();
62 | },
63 | onMessage: null,
64 | onError: null
65 | };
66 |
67 | window.WebViewBridge = WebViewBridge;
68 |
69 | //dispatch event
70 | customEvent.initEvent('WebViewBridge', true, true);
71 | doc.dispatchEvent(customEvent);
72 | }(window));
73 |
--------------------------------------------------------------------------------
/webview-bridge/index.android.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * Copyright (c) 2016-present, Ali Najafizadeh
6 | * All rights reserved.
7 | *
8 | * This source code is licensed under the BSD-style license found in the
9 | * LICENSE file in the root directory of this source tree. An additional grant
10 | * of patent rights can be found in the PATENTS file in the same directory.
11 | *
12 | * @providesModule WebViewBridge
13 | */
14 | 'use strict';
15 |
16 | var React = require('react');
17 | var PropTypes = require('prop-types');
18 | var createReactClass = require('create-react-class');
19 | var ReactNative = require('react-native');
20 | var invariant = require('invariant');
21 | var keyMirror = require('keymirror');
22 | var resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource');
23 |
24 | var {
25 | ReactNativeViewAttributes,
26 | UIManager,
27 | EdgeInsetsPropType,
28 | StyleSheet,
29 | Text,
30 | View,
31 | WebView,
32 | requireNativeComponent,
33 | DeviceEventEmitter,
34 | NativeModules: {
35 | WebViewBridgeManager
36 | }
37 | } = ReactNative;
38 |
39 | var RCT_WEBVIEWBRIDGE_REF = 'webviewbridge';
40 |
41 | var WebViewBridgeState = keyMirror({
42 | IDLE: null,
43 | LOADING: null,
44 | ERROR: null,
45 | });
46 |
47 | var RCTWebViewBridge = requireNativeComponent('RCTWebViewBridge', WebViewBridge);
48 |
49 | /**
50 | * Renders a native WebView.
51 | */
52 | var WebViewBridge = createReactClass({
53 |
54 | propTypes: {
55 | ...RCTWebViewBridge.propTypes,
56 |
57 | /**
58 | * Will be called once the message is being sent from webview
59 | */
60 | onBridgeMessage: PropTypes.func,
61 | },
62 |
63 | getInitialState: function() {
64 | return {
65 | viewState: WebViewBridgeState.IDLE,
66 | lastErrorEvent: null,
67 | startInLoadingState: true,
68 | };
69 | },
70 |
71 |
72 | componentWillMount: function() {
73 | DeviceEventEmitter.addListener("webViewBridgeMessage", (body) => {
74 | const { onBridgeMessage } = this.props;
75 | const message = body.message;
76 | if (onBridgeMessage) {
77 | onBridgeMessage(message);
78 | }
79 | });
80 |
81 | if (this.props.startInLoadingState) {
82 | this.setState({viewState: WebViewBridgeState.LOADING});
83 | }
84 | },
85 |
86 | render: function() {
87 | var otherView = null;
88 |
89 | if (this.state.viewState === WebViewBridgeState.LOADING) {
90 | otherView = this.props.renderLoading && this.props.renderLoading();
91 | } else if (this.state.viewState === WebViewBridgeState.ERROR) {
92 | var errorEvent = this.state.lastErrorEvent;
93 | otherView = this.props.renderError && this.props.renderError(
94 | errorEvent.domain,
95 | errorEvent.code,
96 | errorEvent.description);
97 | } else if (this.state.viewState !== WebViewBridgeState.IDLE) {
98 | console.error('RCTWebViewBridge invalid state encountered: ' + this.state.loading);
99 | }
100 |
101 | var webViewStyles = [styles.container, this.props.style];
102 | if (this.state.viewState === WebViewBridgeState.LOADING ||
103 | this.state.viewState === WebViewBridgeState.ERROR) {
104 | // if we're in either LOADING or ERROR states, don't show the webView
105 | webViewStyles.push(styles.hidden);
106 | }
107 |
108 | var {javaScriptEnabled, domStorageEnabled} = this.props;
109 | if (this.props.javaScriptEnabledAndroid) {
110 | console.warn('javaScriptEnabledAndroid is deprecated. Use javaScriptEnabled instead');
111 | javaScriptEnabled = this.props.javaScriptEnabledAndroid;
112 | }
113 | if (this.props.domStorageEnabledAndroid) {
114 | console.warn('domStorageEnabledAndroid is deprecated. Use domStorageEnabled instead');
115 | domStorageEnabled = this.props.domStorageEnabledAndroid;
116 | }
117 |
118 | let {source, ...props} = {...this.props};
119 |
120 | var webView =
121 | ;
133 |
134 | return (
135 |
136 | {webView}
137 | {otherView}
138 |
139 | );
140 | },
141 |
142 | onMessage(event) {
143 | if (this.props.onBridgeMessage != null && event.nativeEvent != null) {
144 | this.props.onBridgeMessage(event.nativeEvent.message)
145 | }
146 | },
147 |
148 | goForward: function() {
149 | UIManager.dispatchViewManagerCommand(
150 | this.getWebViewBridgeHandle(),
151 | UIManager.RCTWebViewBridge.Commands.goForward,
152 | null
153 | );
154 | },
155 |
156 | goBack: function() {
157 | UIManager.dispatchViewManagerCommand(
158 | this.getWebViewBridgeHandle(),
159 | UIManager.RCTWebViewBridge.Commands.goBack,
160 | null
161 | );
162 | },
163 |
164 | reload: function() {
165 | UIManager.dispatchViewManagerCommand(
166 | this.getWebViewBridgeHandle(),
167 | UIManager.RCTWebViewBridge.Commands.reload,
168 | null
169 | );
170 | },
171 |
172 | sendToBridge: function (message: string) {
173 | UIManager.dispatchViewManagerCommand(
174 | this.getWebViewBridgeHandle(),
175 | UIManager.RCTWebViewBridge.Commands.sendToBridge,
176 | [message]
177 | );
178 | },
179 |
180 | /**
181 | * We return an event with a bunch of fields including:
182 | * url, title, loading, canGoBack, canGoForward
183 | */
184 | updateNavigationState: function(event) {
185 | if (this.props.onNavigationStateChange) {
186 | this.props.onNavigationStateChange(event.nativeEvent);
187 | }
188 | },
189 |
190 | getWebViewBridgeHandle: function() {
191 | return ReactNative.findNodeHandle(this.refs[RCT_WEBVIEWBRIDGE_REF]);
192 | },
193 |
194 | onLoadingStart: function(event) {
195 | var onLoadStart = this.props.onLoadStart;
196 | onLoadStart && onLoadStart(event);
197 | this.updateNavigationState(event);
198 | },
199 |
200 | onLoadingError: function(event) {
201 | event.persist(); // persist this event because we need to store it
202 | var {onError, onLoadEnd} = this.props;
203 | onError && onError(event);
204 | onLoadEnd && onLoadEnd(event);
205 |
206 | this.setState({
207 | lastErrorEvent: event.nativeEvent,
208 | viewState: WebViewBridgeState.ERROR
209 | });
210 | },
211 |
212 | onLoadingFinish: function(event) {
213 | var {onLoad, onLoadEnd} = this.props;
214 | onLoad && onLoad(event);
215 | onLoadEnd && onLoadEnd(event);
216 | this.setState({
217 | viewState: WebViewBridgeState.IDLE,
218 | });
219 | this.updateNavigationState(event);
220 | },
221 | });
222 |
223 |
224 | var styles = StyleSheet.create({
225 | container: {
226 | flex: 1,
227 | },
228 | hidden: {
229 | height: 0,
230 | flex: 0, // disable 'flex:1' when hiding a View
231 | },
232 | });
233 |
234 | module.exports = WebViewBridge;
--------------------------------------------------------------------------------
/webview-bridge/index.ios.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * Copyright (c) 2016-present, Ali Najafizadeh
6 | * All rights reserved.
7 | *
8 | * This source code is licensed under the BSD-style license found in the
9 | * LICENSE file in the root directory of this source tree. An additional grant
10 | * of patent rights can be found in the PATENTS file in the same directory.
11 | *
12 | * @providesModule WebViewBridge
13 | * @flow
14 | */
15 | 'use strict';
16 |
17 |
18 | var React = require('react');
19 | var PropTypes = require('prop-types');
20 | var createReactClass = require('create-react-class');
21 | var ReactNative = require('react-native');
22 | var invariant = require('invariant');
23 | var keyMirror = require('keymirror');
24 | var resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource');
25 |
26 | var {
27 | ActivityIndicator,
28 | EdgeInsetsPropType,
29 | StyleSheet,
30 | Text,
31 | View,
32 | WebView,
33 | requireNativeComponent,
34 | UIManager,
35 | NativeModules: {
36 | WebViewBridgeManager
37 | }
38 | } = ReactNative;
39 |
40 | var BGWASH = 'rgba(255,255,255,0.8)';
41 | var RCT_WEBVIEWBRIDGE_REF = 'webviewbridge';
42 |
43 | var RCTWebViewBridgeManager = WebViewBridgeManager;
44 |
45 | var WebViewBridgeState = keyMirror({
46 | IDLE: null,
47 | LOADING: null,
48 | ERROR: null,
49 | });
50 |
51 | var NavigationType = {
52 | click: RCTWebViewBridgeManager.NavigationType.LinkClicked,
53 | formsubmit: RCTWebViewBridgeManager.NavigationType.FormSubmitted,
54 | backforward: RCTWebViewBridgeManager.NavigationType.BackForward,
55 | reload: RCTWebViewBridgeManager.NavigationType.Reload,
56 | formresubmit: RCTWebViewBridgeManager.NavigationType.FormResubmitted,
57 | other: RCTWebViewBridgeManager.NavigationType.Other,
58 | };
59 |
60 | var JSNavigationScheme = RCTWebViewBridgeManager.JSNavigationScheme;
61 |
62 | type ErrorEvent = {
63 | domain: any;
64 | code: any;
65 | description: any;
66 | }
67 |
68 | type Event = Object;
69 |
70 | var defaultRenderLoading = () => (
71 |
72 |
73 |
74 | );
75 | var defaultRenderError = (errorDomain, errorCode, errorDesc) => (
76 |
77 |
78 | Error loading page
79 |
80 |
81 | {'Domain: ' + errorDomain}
82 |
83 |
84 | {'Error Code: ' + errorCode}
85 |
86 |
87 | {'Description: ' + errorDesc}
88 |
89 |
90 | );
91 |
92 | /**
93 | * Renders a native WebView.
94 | */
95 | var WebViewBridge = createReactClass({
96 | statics: {
97 | JSNavigationScheme: JSNavigationScheme,
98 | NavigationType: NavigationType,
99 | },
100 |
101 | propTypes: {
102 | ...WebView.propTypes,
103 |
104 | /**
105 | * Will be called once the message is being sent from webview
106 | */
107 | onBridgeMessage: PropTypes.func,
108 |
109 | hideKeyboardAccessoryView: PropTypes.bool,
110 |
111 | keyboardDisplayRequiresUserAction: PropTypes.bool,
112 | },
113 |
114 | getInitialState: function() {
115 | return {
116 | viewState: WebViewBridgeState.IDLE,
117 | lastErrorEvent: (null: ?ErrorEvent),
118 | startInLoadingState: true,
119 | };
120 | },
121 |
122 | componentWillMount: function() {
123 | if (this.props.startInLoadingState) {
124 | this.setState({viewState: WebViewBridgeState.LOADING});
125 | }
126 | },
127 |
128 | render: function() {
129 | var otherView = null;
130 |
131 | if (this.state.viewState === WebViewBridgeState.LOADING) {
132 | otherView = (this.props.renderLoading || defaultRenderLoading)();
133 | } else if (this.state.viewState === WebViewBridgeState.ERROR) {
134 | var errorEvent = this.state.lastErrorEvent;
135 | invariant(
136 | errorEvent != null,
137 | 'lastErrorEvent expected to be non-null'
138 | );
139 | otherView = (this.props.renderError || defaultRenderError)(
140 | errorEvent.domain,
141 | errorEvent.code,
142 | errorEvent.description
143 | );
144 | } else if (this.state.viewState !== WebViewBridgeState.IDLE) {
145 | console.error(
146 | 'RCTWebViewBridge invalid state encountered: ' + this.state.loading
147 | );
148 | }
149 |
150 | var webViewStyles = [styles.container, styles.webView, this.props.style];
151 | if (this.state.viewState === WebViewBridgeState.LOADING ||
152 | this.state.viewState === WebViewBridgeState.ERROR) {
153 | // if we're in either LOADING or ERROR states, don't show the webView
154 | webViewStyles.push(styles.hidden);
155 | }
156 |
157 | var onShouldStartLoadWithRequest = this.props.onShouldStartLoadWithRequest && ((event: Event) => {
158 | var shouldStart = this.props.onShouldStartLoadWithRequest &&
159 | this.props.onShouldStartLoadWithRequest(event.nativeEvent);
160 | RCTWebViewBridgeManager.startLoadWithResult(!!shouldStart, event.nativeEvent.lockIdentifier);
161 | });
162 |
163 | var {javaScriptEnabled, domStorageEnabled} = this.props;
164 | if (this.props.javaScriptEnabledAndroid) {
165 | console.warn('javaScriptEnabledAndroid is deprecated. Use javaScriptEnabled instead');
166 | javaScriptEnabled = this.props.javaScriptEnabledAndroid;
167 | }
168 | if (this.props.domStorageEnabledAndroid) {
169 | console.warn('domStorageEnabledAndroid is deprecated. Use domStorageEnabled instead');
170 | domStorageEnabled = this.props.domStorageEnabledAndroid;
171 | }
172 |
173 | var onBridgeMessage = (event: Event) => {
174 | const onBridgeMessageCallback = this.props.onBridgeMessage;
175 | if (onBridgeMessageCallback) {
176 | const messages = event.nativeEvent.messages;
177 | messages.forEach((message) => {
178 | onBridgeMessageCallback(message);
179 | });
180 | }
181 | };
182 |
183 | let {source, ...props} = {...this.props};
184 | delete props.onBridgeMessage;
185 | delete props.onShouldStartLoadWithRequest;
186 |
187 | var webView =
188 | ;
200 |
201 | return (
202 |
203 | {webView}
204 | {otherView}
205 |
206 | );
207 | },
208 |
209 | goForward: function() {
210 | UIManager.dispatchViewManagerCommand(
211 | this.getWebViewBridgeHandle(),
212 | UIManager.RCTWebViewBridge.Commands.goForward,
213 | null
214 | );
215 | },
216 |
217 | goBack: function() {
218 | UIManager.dispatchViewManagerCommand(
219 | this.getWebViewBridgeHandle(),
220 | UIManager.RCTWebViewBridge.Commands.goBack,
221 | null
222 | );
223 | },
224 |
225 | reload: function() {
226 | UIManager.dispatchViewManagerCommand(
227 | this.getWebViewBridgeHandle(),
228 | UIManager.RCTWebViewBridge.Commands.reload,
229 | null
230 | );
231 | },
232 |
233 | sendToBridge: function (message: string) {
234 | WebViewBridgeManager.sendToBridge(this.getWebViewBridgeHandle(), message);
235 | },
236 |
237 | /**
238 | * We return an event with a bunch of fields including:
239 | * url, title, loading, canGoBack, canGoForward
240 | */
241 | updateNavigationState: function(event: Event) {
242 | if (this.props.onNavigationStateChange) {
243 | this.props.onNavigationStateChange(event.nativeEvent);
244 | }
245 | },
246 |
247 | getWebViewBridgeHandle: function(): any {
248 | return ReactNative.findNodeHandle(this.refs[RCT_WEBVIEWBRIDGE_REF]);
249 | },
250 |
251 | onLoadingStart: function(event: Event) {
252 | var onLoadStart = this.props.onLoadStart;
253 | onLoadStart && onLoadStart(event);
254 | this.updateNavigationState(event);
255 | },
256 |
257 | onLoadingError: function(event: Event) {
258 | event.persist(); // persist this event because we need to store it
259 | var {onError, onLoadEnd} = this.props;
260 | onError && onError(event);
261 | onLoadEnd && onLoadEnd(event);
262 | console.warn('Encountered an error loading page', event.nativeEvent);
263 |
264 | this.setState({
265 | lastErrorEvent: event.nativeEvent,
266 | viewState: WebViewBridgeState.ERROR
267 | });
268 | },
269 |
270 | onLoadingFinish: function(event: Event) {
271 | var {onLoad, onLoadEnd} = this.props;
272 | onLoad && onLoad(event);
273 | onLoadEnd && onLoadEnd(event);
274 | this.setState({
275 | viewState: WebViewBridgeState.IDLE,
276 | });
277 | this.updateNavigationState(event);
278 | },
279 | });
280 |
281 | var RCTWebViewBridge = requireNativeComponent('RCTWebViewBridge', WebViewBridge, {
282 | nativeOnly: {
283 | onLoadingStart: true,
284 | onLoadingError: true,
285 | onLoadingFinish: true,
286 | },
287 | });
288 |
289 | var styles = StyleSheet.create({
290 | container: {
291 | flex: 1,
292 | },
293 | errorContainer: {
294 | flex: 1,
295 | justifyContent: 'center',
296 | alignItems: 'center',
297 | backgroundColor: BGWASH,
298 | },
299 | errorText: {
300 | fontSize: 14,
301 | textAlign: 'center',
302 | marginBottom: 2,
303 | },
304 | errorTextTitle: {
305 | fontSize: 15,
306 | fontWeight: '500',
307 | marginBottom: 10,
308 | },
309 | hidden: {
310 | height: 0,
311 | flex: 0, // disable 'flex:1' when hiding a View
312 | },
313 | loadingView: {
314 | backgroundColor: BGWASH,
315 | flex: 1,
316 | justifyContent: 'center',
317 | alignItems: 'center',
318 | },
319 | webView: {
320 | backgroundColor: '#ffffff',
321 | }
322 | });
323 |
324 | module.exports = WebViewBridge;
325 |
--------------------------------------------------------------------------------