├── .gitignore
├── BridgeableWebView.ios.js
├── LICENSE
├── README.md
├── RNBridgeableWebView.h
├── RNBridgeableWebView.m
├── RNBridgeableWebViewManager.h
├── RNBridgeableWebViewManager.m
├── RNBridgeableWebview.xcodeproj
└── project.pbxproj
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | RNBridgeableWebview.xcodeproj/xcuserdata/**/*
3 | RNBridgeableWebview.xcodeproj/project.xcworkspace/**/*
4 | npm-debug.log
--------------------------------------------------------------------------------
/BridgeableWebView.ios.js:
--------------------------------------------------------------------------------
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 | * @flow
9 | */
10 | 'use strict';
11 |
12 | var ActivityIndicatorIOS = require('ActivityIndicatorIOS');
13 | var EdgeInsetsPropType = require('EdgeInsetsPropType');
14 | var React = require('React');
15 | var StyleSheet = require('StyleSheet');
16 | var Text = require('Text');
17 | var View = require('View');
18 |
19 | var invariant = require('invariant');
20 | var keyMirror = require('keyMirror');
21 | var requireNativeComponent = require('requireNativeComponent');
22 |
23 | var PropTypes = React.PropTypes;
24 | var RCTWebViewManager = require('NativeModules').RNBridgeableWebViewManager;
25 | var BGWASH = 'rgba(255,255,255,0.8)';
26 | var RCT_WEBVIEW_REF = 'webview';
27 |
28 | var WebViewState = keyMirror({
29 | IDLE: null,
30 | LOADING: null,
31 | ERROR: null,
32 | });
33 |
34 | var NavigationType = {
35 | click: RCTWebViewManager.NavigationType.LinkClicked,
36 | formsubmit: RCTWebViewManager.NavigationType.FormSubmitted,
37 | backforward: RCTWebViewManager.NavigationType.BackForward,
38 | reload: RCTWebViewManager.NavigationType.Reload,
39 | formresubmit: RCTWebViewManager.NavigationType.FormResubmitted,
40 | other: RCTWebViewManager.NavigationType.Other,
41 | };
42 |
43 | type ErrorEvent = {
44 | domain: any;
45 | code: any;
46 | description: any;
47 | }
48 |
49 | type Event = Object;
50 |
51 | var defaultRenderLoading = () => (
52 |
53 |
54 |
55 | );
56 | var defaultRenderError = (errorDomain, errorCode, errorDesc) => (
57 |
58 |
59 | Error loading page
60 |
61 |
62 | {'Domain: ' + errorDomain}
63 |
64 |
65 | {'Error Code: ' + errorCode}
66 |
67 |
68 | {'Description: ' + errorDesc}
69 |
70 |
71 | );
72 |
73 | var WebView = React.createClass({
74 | statics: {
75 | NavigationType: NavigationType,
76 | },
77 |
78 | propTypes: {
79 | url: PropTypes.string,
80 | html: PropTypes.string,
81 | renderError: PropTypes.func, // view to show if there's an error
82 | renderLoading: PropTypes.func, // loading indicator to show
83 | bounces: PropTypes.bool,
84 | scrollEnabled: PropTypes.bool,
85 | automaticallyAdjustContentInsets: PropTypes.bool,
86 | shouldInjectAJAXHandler: PropTypes.bool,
87 | contentInset: EdgeInsetsPropType,
88 | onNavigationStateChange: PropTypes.func,
89 | onWebviewMessageSent: PropTypes.func,
90 | startInLoadingState: PropTypes.bool, // force WebView to show loadingView on first load
91 | style: View.propTypes.style,
92 | /**
93 | * Used for android only, JS is enabled by default for WebView on iOS
94 | */
95 | javaScriptEnabledAndroid: PropTypes.bool,
96 | },
97 |
98 | getInitialState: function() {
99 | return {
100 | viewState: WebViewState.IDLE,
101 | lastErrorEvent: (null: ?ErrorEvent),
102 | startInLoadingState: true,
103 | };
104 | },
105 |
106 | componentWillMount: function() {
107 | if (this.props.startInLoadingState) {
108 | this.setState({viewState: WebViewState.LOADING});
109 | }
110 | },
111 |
112 | render: function() {
113 | var otherView = null;
114 |
115 | if (this.state.viewState === WebViewState.LOADING) {
116 | otherView = (this.props.renderLoading || defaultRenderLoading)();
117 | } else if (this.state.viewState === WebViewState.ERROR) {
118 | var errorEvent = this.state.lastErrorEvent;
119 | invariant(
120 | errorEvent != null,
121 | 'lastErrorEvent expected to be non-null'
122 | );
123 | otherView = (this.props.renderError || defaultRenderError)(
124 | errorEvent.domain,
125 | errorEvent.code,
126 | errorEvent.description
127 | );
128 | } else if (this.state.viewState !== WebViewState.IDLE) {
129 | console.error(
130 | 'RNBridgeableWebView invalid state encountered: ' + this.state.loading
131 | );
132 | }
133 |
134 | var webViewStyles = [styles.container, styles.webView, this.props.style];
135 | if (this.state.viewState === WebViewState.LOADING ||
136 | this.state.viewState === WebViewState.ERROR) {
137 | // if we're in either LOADING or ERROR states, don't show the webView
138 | webViewStyles.push(styles.hidden);
139 | }
140 |
141 | var webView =
142 | ;
158 |
159 | return (
160 |
161 | {webView}
162 | {otherView}
163 |
164 | );
165 | },
166 |
167 | goForward: function() {
168 | RCTWebViewManager.goForward(this.getWebWiewHandle());
169 | },
170 |
171 | goBack: function() {
172 | RCTWebViewManager.goBack(this.getWebWiewHandle());
173 | },
174 |
175 | reload: function() {
176 | RCTWebViewManager.reload(this.getWebWiewHandle());
177 | },
178 |
179 | /**
180 | * We return an event with a bunch of fields including:
181 | * url, title, loading, canGoBack, canGoForward
182 | */
183 | updateNavigationState: function(event: Event) {
184 | if (this.props.onNavigationStateChange) {
185 | this.props.onNavigationStateChange(event.nativeEvent);
186 | }
187 | },
188 |
189 | getWebWiewHandle: function(): any {
190 | return React.findNodeHandle(this.refs[RCT_WEBVIEW_REF]);
191 | },
192 |
193 | onLoadingStart: function(event: Event) {
194 | this.updateNavigationState(event);
195 | },
196 |
197 | onLoadingError: function(event: Event) {
198 | event.persist(); // persist this event because we need to store it
199 | console.error('Encountered an error loading page', event.nativeEvent);
200 |
201 | this.setState({
202 | lastErrorEvent: event.nativeEvent,
203 | viewState: WebViewState.ERROR
204 | });
205 | },
206 |
207 | onLoadingFinish: function(event: Event) {
208 | this.setState({
209 | viewState: WebViewState.IDLE,
210 | });
211 | this.updateNavigationState(event);
212 | },
213 |
214 | onWebViewMessageSent: function(event: Event) {
215 | if (this.props.onWebViewMessageSent) {
216 | this.props.onWebViewMessageSent(event.nativeEvent);
217 | }
218 | }
219 | });
220 |
221 | var RNBridgeableWebView = requireNativeComponent('RNBridgeableWebView', WebView);
222 |
223 | var styles = StyleSheet.create({
224 | container: {
225 | flex: 1,
226 | },
227 | errorContainer: {
228 | flex: 1,
229 | justifyContent: 'center',
230 | alignItems: 'center',
231 | backgroundColor: BGWASH,
232 | },
233 | errorText: {
234 | fontSize: 14,
235 | textAlign: 'center',
236 | marginBottom: 2,
237 | },
238 | errorTextTitle: {
239 | fontSize: 15,
240 | fontWeight: '500',
241 | marginBottom: 10,
242 | },
243 | hidden: {
244 | height: 0,
245 | flex: 0, // disable 'flex:1' when hiding a View
246 | },
247 | loadingView: {
248 | backgroundColor: BGWASH,
249 | flex: 1,
250 | justifyContent: 'center',
251 | alignItems: 'center',
252 | },
253 | webView: {
254 | backgroundColor: '#ffffff',
255 | }
256 | });
257 |
258 | module.exports = WebView;
259 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Tom Hastjarjanto
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, 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,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## react-native-bridgeable-webview
2 |
3 | A `` component replacement for react-native
4 |
5 | Requires react-native == 0.6
6 |
7 | ### Add it to your project
8 |
9 | 1. Run `npm install react-native-bridgeable-webview --save`
10 | 2. Open your project in XCode, right click on `Libraries` and click `Add Files to "Your Project Name"`
11 | *   (use the RNBridgeableWebview project rather than the one pictured in screenshot).
12 | 3. Add `libRNBridgeableWebview.a` to `Build Phases -> Link Binary With Libraries`
13 | .
14 | 5. Whenever you want to use it within React code now you can: `var WebView = require('react-native-bridgeable-webview');`
15 |
16 |
17 | ## Usage
18 | ```
19 | var WebView = require('react-native-bridgeable-webview');
20 | ```
21 |
22 | It is the exact same component as `WebView` except it offers a custom url scheme that acts as message bridge and a method `onWebViewMessageSent` to respond to calls made from the webview.
23 |
24 | In your react-native code you can include the following snippet as a `WebView` replacement:
25 |
26 | ```jsx
27 |
37 | ```
38 |
--------------------------------------------------------------------------------
/RNBridgeableWebView.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 "RCTView.h"
11 |
12 | extern NSString *const RNBridgeableWebViewMessageSent;
13 |
14 | @class RCTEventDispatcher;
15 |
16 | @interface RNBridgeableWebView : RCTView
17 |
18 | @property (nonatomic, strong) NSURL *URL;
19 | @property (nonatomic, assign) UIEdgeInsets contentInset;
20 | @property (nonatomic, assign) BOOL shouldInjectAJAXHandler;
21 | @property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
22 |
23 | - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
24 |
25 | - (void)goForward;
26 | - (void)goBack;
27 | - (void)reload;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/RNBridgeableWebView.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 "RNBridgeableWebView.h"
11 |
12 | #import
13 |
14 | #import "RCTAutoInsetsProtocol.h"
15 | #import "RCTEventDispatcher.h"
16 | #import "RCTLog.h"
17 | #import "RCTUtils.h"
18 | #import "RCTView.h"
19 | #import "UIView+React.h"
20 |
21 | @interface RNBridgeableWebView ()
22 |
23 | @end
24 |
25 | NSString *const RNBridgeableWebViewMessageSent = @"messageSent";
26 |
27 | @implementation RNBridgeableWebView
28 | {
29 | RCTEventDispatcher *_eventDispatcher;
30 | UIWebView *_webView;
31 | }
32 |
33 | - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
34 | {
35 | if ((self = [super initWithFrame:CGRectZero])) {
36 | super.backgroundColor = [UIColor clearColor];
37 | _automaticallyAdjustContentInsets = YES;
38 | _contentInset = UIEdgeInsetsZero;
39 | _eventDispatcher = eventDispatcher;
40 | _webView = [[UIWebView alloc] initWithFrame:self.bounds];
41 | _webView.delegate = self;
42 | [self addSubview:_webView];
43 | }
44 | return self;
45 | }
46 |
47 | - (void)goForward
48 | {
49 | [_webView goForward];
50 | }
51 |
52 | - (void)goBack
53 | {
54 | [_webView goBack];
55 | }
56 |
57 | - (void)reload
58 | {
59 | [_webView reload];
60 | }
61 |
62 | - (void)setURL:(NSURL *)URL
63 | {
64 | // Because of the way React works, as pages redirect, we actually end up
65 | // passing the redirect urls back here, so we ignore them if trying to load
66 | // the same url. We'll expose a call to 'reload' to allow a user to load
67 | // the existing page.
68 | if ([URL isEqual:_webView.request.URL]) {
69 | return;
70 | }
71 | if (!URL) {
72 | // Clear the webview
73 | [_webView loadHTMLString:nil baseURL:nil];
74 | return;
75 | }
76 | [_webView loadRequest:[NSURLRequest requestWithURL:URL]];
77 | }
78 |
79 | - (void)setHTML:(NSString *)HTML
80 | {
81 | [_webView loadHTMLString:HTML baseURL:nil];
82 | }
83 |
84 | - (void)layoutSubviews
85 | {
86 | [super layoutSubviews];
87 | _webView.frame = self.bounds;
88 | [RCTView autoAdjustInsetsForView:self
89 | withScrollView:_webView.scrollView
90 | updateOffset:YES];
91 | }
92 |
93 | - (void)setContentInset:(UIEdgeInsets)contentInset
94 | {
95 | _contentInset = contentInset;
96 | [RCTView autoAdjustInsetsForView:self
97 | withScrollView:_webView.scrollView
98 | updateOffset:NO];
99 | }
100 |
101 | - (void)setBackgroundColor:(UIColor *)backgroundColor
102 | {
103 | CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
104 | self.opaque = _webView.opaque = (alpha == 1.0);
105 | _webView.backgroundColor = backgroundColor;
106 | }
107 |
108 | - (UIColor *)backgroundColor
109 | {
110 | return _webView.backgroundColor;
111 | }
112 |
113 | - (NSMutableDictionary *)baseEvent
114 | {
115 | NSURL *url = _webView.request.URL;
116 | NSString *title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"];
117 | NSMutableDictionary *event = [[NSMutableDictionary alloc] initWithDictionary: @{
118 | @"target": self.reactTag,
119 | @"url": url ? [url absoluteString] : @"",
120 | @"loading" : @(_webView.loading),
121 | @"title": title,
122 | @"canGoBack": @([_webView canGoBack]),
123 | @"canGoForward" : @([_webView canGoForward]),
124 | }];
125 |
126 | return event;
127 | }
128 |
129 | #pragma mark - UIWebViewDelegate methods
130 |
131 | static NSString *const RCTJSAJAXScheme = @"react-ajax";
132 | static NSString *const RNBridgeScheme = @"react-message";
133 |
134 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
135 | navigationType:(UIWebViewNavigationType)navigationType
136 | {
137 | if ([request.URL.scheme isEqualToString:RNBridgeScheme]) {
138 | NSMutableDictionary *event = [self baseEvent];
139 | [event addEntriesFromDictionary: @{
140 | @"url": [request.URL absoluteString],
141 | @"navigationType": @(navigationType)
142 | }];
143 | [_eventDispatcher sendInputEventWithName:RNBridgeableWebViewMessageSent body:event];
144 | return false;
145 | }
146 |
147 | // We have this check to filter out iframe requests and whatnot
148 | BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
149 | if (isTopFrame) {
150 | NSMutableDictionary *event = [self baseEvent];
151 | [event addEntriesFromDictionary: @{
152 | @"url": [request.URL absoluteString],
153 | @"navigationType": @(navigationType)
154 | }];
155 | [_eventDispatcher sendInputEventWithName:@"topLoadingStart" body:event];
156 | }
157 |
158 | // AJAX handler
159 | return ![request.URL.scheme isEqualToString:RCTJSAJAXScheme];
160 | }
161 |
162 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
163 | {
164 | if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) {
165 | // NSURLErrorCancelled is reported when a page has a redirect OR if you load
166 | // a new URL in the WebView before the previous one came back. We can just
167 | // ignore these since they aren't real errors.
168 | // http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os
169 | return;
170 | }
171 |
172 | NSMutableDictionary *event = [self baseEvent];
173 | [event addEntriesFromDictionary: @{
174 | @"domain": error.domain,
175 | @"code": @(error.code),
176 | @"description": [error localizedDescription],
177 | }];
178 | [_eventDispatcher sendInputEventWithName:@"topLoadingError" body:event];
179 | }
180 |
181 | - (void)webViewDidFinishLoad:(UIWebView *)webView
182 | {
183 | if (_shouldInjectAJAXHandler) {
184 |
185 | // From http://stackoverflow.com/questions/5353278/uiwebviewdelegate-not-monitoring-xmlhttprequest
186 |
187 | [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"\
188 | var s_ajaxListener = new Object(); \n\
189 | s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open; \n\
190 | s_ajaxListener.tempSend = XMLHttpRequest.prototype.send; \n\
191 | s_ajaxListener.callback = function() { \n\
192 | window.location.href = '%@://' + this.url; \n\
193 | } \n\
194 | XMLHttpRequest.prototype.open = function(a,b) { \n\
195 | s_ajaxListener.tempOpen.apply(this, arguments); \n\
196 | s_ajaxListener.method = a; \n\
197 | s_ajaxListener.url = b; \n\
198 | if (a.toLowerCase() === 'get') { \n\
199 | s_ajaxListener.data = (b.split('?'))[1]; \n\
200 | } \n\
201 | } \n\
202 | XMLHttpRequest.prototype.send = function(a,b) { \n\
203 | s_ajaxListener.tempSend.apply(this, arguments); \n\
204 | if (s_ajaxListener.method.toLowerCase() === 'post') { \n\
205 | s_ajaxListener.data = a; \n\
206 | } \n\
207 | s_ajaxListener.callback(); \n\
208 | } \n\
209 | ", RCTJSAJAXScheme]];
210 | }
211 |
212 | // we only need the final 'finishLoad' call so only fire the event when we're actually done loading.
213 | if (!webView.loading && ![webView.request.URL.absoluteString isEqualToString:@"about:blank"]) {
214 | [_eventDispatcher sendInputEventWithName:@"topLoadingFinish" body:[self baseEvent]];
215 | }
216 | }
217 |
218 | @end
219 |
--------------------------------------------------------------------------------
/RNBridgeableWebViewManager.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 "RCTViewManager.h"
11 |
12 | @interface RNBridgeableWebViewManager : RCTViewManager
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/RNBridgeableWebViewManager.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 "RNBridgeableWebViewManager.h"
11 |
12 | #import "RCTBridge.h"
13 | #import "RCTSparseArray.h"
14 | #import "RCTUIManager.h"
15 | #import "RNBridgeableWebView.h"
16 |
17 | @implementation RNBridgeableWebViewManager
18 |
19 | RCT_EXPORT_MODULE()
20 |
21 | - (UIView *)view
22 | {
23 | return [[RNBridgeableWebView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
24 | }
25 |
26 | RCT_REMAP_VIEW_PROPERTY(url, URL, NSURL);
27 | RCT_REMAP_VIEW_PROPERTY(html, HTML, NSString);
28 | RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL);
29 | RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL);
30 | RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets);
31 | RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL);
32 | RCT_EXPORT_VIEW_PROPERTY(shouldInjectAJAXHandler, BOOL);
33 |
34 | - (NSDictionary *)customDirectEventTypes
35 | {
36 | return @{
37 | RNBridgeableWebViewMessageSent: @{
38 | @"registrationName": @"onWebViewMessageSent"
39 | }
40 | };
41 | }
42 |
43 | - (NSDictionary *)constantsToExport
44 | {
45 | return @{
46 | @"NavigationType": @{
47 | @"LinkClicked": @(UIWebViewNavigationTypeLinkClicked),
48 | @"FormSubmitted": @(UIWebViewNavigationTypeFormSubmitted),
49 | @"BackForward": @(UIWebViewNavigationTypeBackForward),
50 | @"Reload": @(UIWebViewNavigationTypeReload),
51 | @"FormResubmitted": @(UIWebViewNavigationTypeFormResubmitted),
52 | @"Other": @(UIWebViewNavigationTypeOther)
53 | },
54 | };
55 | }
56 |
57 | RCT_EXPORT_METHOD(goBack:(NSNumber *)reactTag)
58 | {
59 | [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
60 | RNBridgeableWebView *view = viewRegistry[reactTag];
61 | if (![view isKindOfClass:[RNBridgeableWebView class]]) {
62 | RCTLogError(@"Invalid view returned from registry, expecting RKWebView, got: %@", view);
63 | }
64 | [view goBack];
65 | }];
66 | }
67 |
68 | RCT_EXPORT_METHOD(goForward:(NSNumber *)reactTag)
69 | {
70 | [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
71 | id view = viewRegistry[reactTag];
72 | if (![view isKindOfClass:[RNBridgeableWebView class]]) {
73 | RCTLogError(@"Invalid view returned from registry, expecting RKWebView, got: %@", view);
74 | }
75 | [view goForward];
76 | }];
77 | }
78 |
79 |
80 | RCT_EXPORT_METHOD(reload:(NSNumber *)reactTag)
81 | {
82 | [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
83 | RNBridgeableWebView *view = viewRegistry[reactTag];
84 | if (![view isKindOfClass:[RNBridgeableWebView class]]) {
85 | RCTLogMustFix(@"Invalid view returned from registry, expecting RKWebView, got: %@", view);
86 | }
87 | [view reload];
88 | }];
89 | }
90 |
91 | @end
92 |
--------------------------------------------------------------------------------
/RNBridgeableWebview.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | E29EA2601B374B2000EE4B2B /* RNBridgeableWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = E29EA25D1B374B2000EE4B2B /* RNBridgeableWebView.m */; };
11 | E29EA2611B374B2000EE4B2B /* RNBridgeableWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E29EA25F1B374B2000EE4B2B /* RNBridgeableWebViewManager.m */; };
12 | /* End PBXBuildFile section */
13 |
14 | /* Begin PBXCopyFilesBuildPhase section */
15 | E29EA2341B33517A00EE4B2B /* 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 | E29EA2361B33517A00EE4B2B /* libRNBridgeableWebview.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNBridgeableWebview.a; sourceTree = BUILT_PRODUCTS_DIR; };
28 | E29EA25C1B374B2000EE4B2B /* RNBridgeableWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBridgeableWebView.h; sourceTree = ""; };
29 | E29EA25D1B374B2000EE4B2B /* RNBridgeableWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNBridgeableWebView.m; sourceTree = ""; };
30 | E29EA25E1B374B2000EE4B2B /* RNBridgeableWebViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBridgeableWebViewManager.h; sourceTree = ""; };
31 | E29EA25F1B374B2000EE4B2B /* RNBridgeableWebViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNBridgeableWebViewManager.m; sourceTree = ""; };
32 | /* End PBXFileReference section */
33 |
34 | /* Begin PBXFrameworksBuildPhase section */
35 | E29EA2331B33517A00EE4B2B /* Frameworks */ = {
36 | isa = PBXFrameworksBuildPhase;
37 | buildActionMask = 2147483647;
38 | files = (
39 | );
40 | runOnlyForDeploymentPostprocessing = 0;
41 | };
42 | /* End PBXFrameworksBuildPhase section */
43 |
44 | /* Begin PBXGroup section */
45 | E29EA22D1B33517A00EE4B2B = {
46 | isa = PBXGroup;
47 | children = (
48 | E29EA25C1B374B2000EE4B2B /* RNBridgeableWebView.h */,
49 | E29EA25D1B374B2000EE4B2B /* RNBridgeableWebView.m */,
50 | E29EA25E1B374B2000EE4B2B /* RNBridgeableWebViewManager.h */,
51 | E29EA25F1B374B2000EE4B2B /* RNBridgeableWebViewManager.m */,
52 | E29EA2371B33517A00EE4B2B /* Products */,
53 | );
54 | sourceTree = "";
55 | };
56 | E29EA2371B33517A00EE4B2B /* Products */ = {
57 | isa = PBXGroup;
58 | children = (
59 | E29EA2361B33517A00EE4B2B /* libRNBridgeableWebview.a */,
60 | );
61 | name = Products;
62 | sourceTree = "";
63 | };
64 | /* End PBXGroup section */
65 |
66 | /* Begin PBXNativeTarget section */
67 | E29EA2351B33517A00EE4B2B /* RNBridgeableWebview */ = {
68 | isa = PBXNativeTarget;
69 | buildConfigurationList = E29EA24A1B33517A00EE4B2B /* Build configuration list for PBXNativeTarget "RNBridgeableWebview" */;
70 | buildPhases = (
71 | E29EA2321B33517A00EE4B2B /* Sources */,
72 | E29EA2331B33517A00EE4B2B /* Frameworks */,
73 | E29EA2341B33517A00EE4B2B /* CopyFiles */,
74 | );
75 | buildRules = (
76 | );
77 | dependencies = (
78 | );
79 | name = RNBridgeableWebview;
80 | productName = RNBridgeableWebview;
81 | productReference = E29EA2361B33517A00EE4B2B /* libRNBridgeableWebview.a */;
82 | productType = "com.apple.product-type.library.static";
83 | };
84 | /* End PBXNativeTarget section */
85 |
86 | /* Begin PBXProject section */
87 | E29EA22E1B33517A00EE4B2B /* Project object */ = {
88 | isa = PBXProject;
89 | attributes = {
90 | LastUpgradeCheck = 0630;
91 | ORGANIZATIONNAME = "Tom Hastjarjanto";
92 | TargetAttributes = {
93 | E29EA2351B33517A00EE4B2B = {
94 | CreatedOnToolsVersion = 6.3.2;
95 | };
96 | };
97 | };
98 | buildConfigurationList = E29EA2311B33517A00EE4B2B /* Build configuration list for PBXProject "RNBridgeableWebview" */;
99 | compatibilityVersion = "Xcode 3.2";
100 | developmentRegion = English;
101 | hasScannedForEncodings = 0;
102 | knownRegions = (
103 | en,
104 | );
105 | mainGroup = E29EA22D1B33517A00EE4B2B;
106 | productRefGroup = E29EA2371B33517A00EE4B2B /* Products */;
107 | projectDirPath = "";
108 | projectRoot = "";
109 | targets = (
110 | E29EA2351B33517A00EE4B2B /* RNBridgeableWebview */,
111 | );
112 | };
113 | /* End PBXProject section */
114 |
115 | /* Begin PBXSourcesBuildPhase section */
116 | E29EA2321B33517A00EE4B2B /* Sources */ = {
117 | isa = PBXSourcesBuildPhase;
118 | buildActionMask = 2147483647;
119 | files = (
120 | E29EA2601B374B2000EE4B2B /* RNBridgeableWebView.m in Sources */,
121 | E29EA2611B374B2000EE4B2B /* RNBridgeableWebViewManager.m in Sources */,
122 | );
123 | runOnlyForDeploymentPostprocessing = 0;
124 | };
125 | /* End PBXSourcesBuildPhase section */
126 |
127 | /* Begin XCBuildConfiguration section */
128 | E29EA2481B33517A00EE4B2B /* Debug */ = {
129 | isa = XCBuildConfiguration;
130 | buildSettings = {
131 | ALWAYS_SEARCH_USER_PATHS = NO;
132 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
133 | CLANG_CXX_LIBRARY = "libc++";
134 | CLANG_ENABLE_MODULES = YES;
135 | CLANG_ENABLE_OBJC_ARC = YES;
136 | CLANG_WARN_BOOL_CONVERSION = YES;
137 | CLANG_WARN_CONSTANT_CONVERSION = YES;
138 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
139 | CLANG_WARN_EMPTY_BODY = YES;
140 | CLANG_WARN_ENUM_CONVERSION = YES;
141 | CLANG_WARN_INT_CONVERSION = YES;
142 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
143 | CLANG_WARN_UNREACHABLE_CODE = YES;
144 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
145 | COPY_PHASE_STRIP = NO;
146 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
147 | ENABLE_STRICT_OBJC_MSGSEND = YES;
148 | GCC_C_LANGUAGE_STANDARD = gnu99;
149 | GCC_DYNAMIC_NO_PIC = NO;
150 | GCC_NO_COMMON_BLOCKS = YES;
151 | GCC_OPTIMIZATION_LEVEL = 0;
152 | GCC_PREPROCESSOR_DEFINITIONS = (
153 | "DEBUG=1",
154 | "$(inherited)",
155 | );
156 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
157 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
158 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
159 | GCC_WARN_UNDECLARED_SELECTOR = YES;
160 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
161 | GCC_WARN_UNUSED_FUNCTION = YES;
162 | GCC_WARN_UNUSED_VARIABLE = YES;
163 | HEADER_SEARCH_PATHS = (
164 | "$(inherited)",
165 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
166 | "$(SRCROOT)/../react-native/React/**",
167 | "$(SRCROOT)/node_modules/react-native/React/**",
168 | );
169 | IPHONEOS_DEPLOYMENT_TARGET = 8.3;
170 | MTL_ENABLE_DEBUG_INFO = YES;
171 | ONLY_ACTIVE_ARCH = YES;
172 | SDKROOT = iphoneos;
173 | };
174 | name = Debug;
175 | };
176 | E29EA2491B33517A00EE4B2B /* Release */ = {
177 | isa = XCBuildConfiguration;
178 | buildSettings = {
179 | ALWAYS_SEARCH_USER_PATHS = NO;
180 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
181 | CLANG_CXX_LIBRARY = "libc++";
182 | CLANG_ENABLE_MODULES = YES;
183 | CLANG_ENABLE_OBJC_ARC = YES;
184 | CLANG_WARN_BOOL_CONVERSION = YES;
185 | CLANG_WARN_CONSTANT_CONVERSION = YES;
186 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
187 | CLANG_WARN_EMPTY_BODY = YES;
188 | CLANG_WARN_ENUM_CONVERSION = YES;
189 | CLANG_WARN_INT_CONVERSION = YES;
190 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
191 | CLANG_WARN_UNREACHABLE_CODE = YES;
192 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
193 | COPY_PHASE_STRIP = NO;
194 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
195 | ENABLE_NS_ASSERTIONS = NO;
196 | ENABLE_STRICT_OBJC_MSGSEND = YES;
197 | GCC_C_LANGUAGE_STANDARD = gnu99;
198 | GCC_NO_COMMON_BLOCKS = YES;
199 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
200 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
201 | GCC_WARN_UNDECLARED_SELECTOR = YES;
202 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
203 | GCC_WARN_UNUSED_FUNCTION = YES;
204 | GCC_WARN_UNUSED_VARIABLE = YES;
205 | HEADER_SEARCH_PATHS = (
206 | "$(inherited)",
207 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
208 | "$(SRCROOT)/../react-native/React/**",
209 | "$(SRCROOT)/node_modules/react-native/React/**",
210 | );
211 | IPHONEOS_DEPLOYMENT_TARGET = 8.3;
212 | MTL_ENABLE_DEBUG_INFO = NO;
213 | SDKROOT = iphoneos;
214 | VALIDATE_PRODUCT = YES;
215 | };
216 | name = Release;
217 | };
218 | E29EA24B1B33517A00EE4B2B /* Debug */ = {
219 | isa = XCBuildConfiguration;
220 | buildSettings = {
221 | OTHER_LDFLAGS = "-ObjC";
222 | PRODUCT_NAME = "$(TARGET_NAME)";
223 | SKIP_INSTALL = YES;
224 | };
225 | name = Debug;
226 | };
227 | E29EA24C1B33517A00EE4B2B /* Release */ = {
228 | isa = XCBuildConfiguration;
229 | buildSettings = {
230 | OTHER_LDFLAGS = "-ObjC";
231 | PRODUCT_NAME = "$(TARGET_NAME)";
232 | SKIP_INSTALL = YES;
233 | };
234 | name = Release;
235 | };
236 | /* End XCBuildConfiguration section */
237 |
238 | /* Begin XCConfigurationList section */
239 | E29EA2311B33517A00EE4B2B /* Build configuration list for PBXProject "RNBridgeableWebview" */ = {
240 | isa = XCConfigurationList;
241 | buildConfigurations = (
242 | E29EA2481B33517A00EE4B2B /* Debug */,
243 | E29EA2491B33517A00EE4B2B /* Release */,
244 | );
245 | defaultConfigurationIsVisible = 0;
246 | defaultConfigurationName = Release;
247 | };
248 | E29EA24A1B33517A00EE4B2B /* Build configuration list for PBXNativeTarget "RNBridgeableWebview" */ = {
249 | isa = XCConfigurationList;
250 | buildConfigurations = (
251 | E29EA24B1B33517A00EE4B2B /* Debug */,
252 | E29EA24C1B33517A00EE4B2B /* Release */,
253 | );
254 | defaultConfigurationIsVisible = 0;
255 | defaultConfigurationName = Release;
256 | };
257 | /* End XCConfigurationList section */
258 | };
259 | rootObject = E29EA22E1B33517A00EE4B2B /* Project object */;
260 | }
261 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-bridgeable-webview",
3 | "version": "0.0.7",
4 | "description": "A react-native webview with bridge to react-native code",
5 | "main": "BridgeableWebView.ios.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/Intellicode/react-native-bridgeable-webview.git"
12 | },
13 | "author": "Tom Hastjarjanto",
14 | "license": "MIT",
15 | "bugs": {
16 | "url": "https://github.com/Intellicode/react-native-bridgeable-webview/issues"
17 | },
18 | "homepage": "https://github.com/Intellicode/react-native-bridgeable-webview#readme",
19 | "devDependencies": {
20 | "react-native": "^0.6.0"
21 | },
22 | "peerDependencies": {
23 | "react-native": "^0.6.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------