mirror of
https://github.com/status-im/react-native-webview-bridge.git
synced 2026-08-31 13:21:15 +00:00
bring webview from core to plugin
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTView.h"
|
||||
|
||||
@class RCTEventDispatcher;
|
||||
|
||||
@interface WebViewEx : RCTView
|
||||
|
||||
@property (nonatomic, strong) NSURL *URL;
|
||||
@property (nonatomic, assign) UIEdgeInsets contentInset;
|
||||
@property (nonatomic, assign) BOOL shouldInjectAJAXHandler;
|
||||
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)goForward;
|
||||
- (void)goBack;
|
||||
- (void)reload;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "WebViewEx.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTAutoInsetsProtocol.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "RCTView.h"
|
||||
#import "UIView+React.h"
|
||||
|
||||
@interface WebViewEx () <UIWebViewDelegate, RCTAutoInsetsProtocol>
|
||||
|
||||
@end
|
||||
|
||||
@implementation WebViewEx
|
||||
{
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
UIWebView *_webView;
|
||||
}
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if ((self = [super initWithFrame:CGRectZero])) {
|
||||
super.backgroundColor = [UIColor clearColor];
|
||||
_automaticallyAdjustContentInsets = YES;
|
||||
_contentInset = UIEdgeInsetsZero;
|
||||
_eventDispatcher = eventDispatcher;
|
||||
_webView = [[UIWebView alloc] initWithFrame:self.bounds];
|
||||
_webView.delegate = self;
|
||||
[self addSubview:_webView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)goForward
|
||||
{
|
||||
[_webView goForward];
|
||||
}
|
||||
|
||||
- (void)goBack
|
||||
{
|
||||
[_webView goBack];
|
||||
}
|
||||
|
||||
- (void)reload
|
||||
{
|
||||
[_webView reload];
|
||||
}
|
||||
|
||||
- (void)setURL:(NSURL *)URL
|
||||
{
|
||||
// Because of the way React works, as pages redirect, we actually end up
|
||||
// passing the redirect urls back here, so we ignore them if trying to load
|
||||
// the same url. We'll expose a call to 'reload' to allow a user to load
|
||||
// the existing page.
|
||||
if ([URL isEqual:_webView.request.URL]) {
|
||||
return;
|
||||
}
|
||||
if (!URL) {
|
||||
// Clear the webview
|
||||
[_webView loadHTMLString:nil baseURL:nil];
|
||||
return;
|
||||
}
|
||||
[_webView loadRequest:[NSURLRequest requestWithURL:URL]];
|
||||
}
|
||||
|
||||
- (void)setHTML:(NSString *)HTML
|
||||
{
|
||||
[_webView loadHTMLString:HTML baseURL:nil];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
_webView.frame = self.bounds;
|
||||
[RCTView autoAdjustInsetsForView:self
|
||||
withScrollView:_webView.scrollView
|
||||
updateOffset:YES];
|
||||
}
|
||||
|
||||
- (void)setContentInset:(UIEdgeInsets)contentInset
|
||||
{
|
||||
_contentInset = contentInset;
|
||||
[RCTView autoAdjustInsetsForView:self
|
||||
withScrollView:_webView.scrollView
|
||||
updateOffset:NO];
|
||||
}
|
||||
|
||||
- (void)setBackgroundColor:(UIColor *)backgroundColor
|
||||
{
|
||||
CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
|
||||
self.opaque = _webView.opaque = (alpha == 1.0);
|
||||
_webView.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
- (UIColor *)backgroundColor
|
||||
{
|
||||
return _webView.backgroundColor;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)baseEvent
|
||||
{
|
||||
NSURL *url = _webView.request.URL;
|
||||
NSString *title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"];
|
||||
NSMutableDictionary *event = [[NSMutableDictionary alloc] initWithDictionary: @{
|
||||
@"target": self.reactTag,
|
||||
@"url": url ? [url absoluteString] : @"",
|
||||
@"loading" : @(_webView.loading),
|
||||
@"title": title,
|
||||
@"canGoBack": @([_webView canGoBack]),
|
||||
@"canGoForward" : @([_webView canGoForward]),
|
||||
}];
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
#pragma mark - UIWebViewDelegate methods
|
||||
|
||||
static NSString *const RCTJSAJAXScheme = @"react-ajax";
|
||||
|
||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
|
||||
navigationType:(UIWebViewNavigationType)navigationType
|
||||
{
|
||||
// We have this check to filter out iframe requests and whatnot
|
||||
BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
|
||||
if (isTopFrame) {
|
||||
NSMutableDictionary *event = [self baseEvent];
|
||||
[event addEntriesFromDictionary: @{
|
||||
@"url": [request.URL absoluteString],
|
||||
@"navigationType": @(navigationType)
|
||||
}];
|
||||
[_eventDispatcher sendInputEventWithName:@"topLoadingStart" body:event];
|
||||
}
|
||||
|
||||
// AJAX handler
|
||||
return ![request.URL.scheme isEqualToString:RCTJSAJAXScheme];
|
||||
}
|
||||
|
||||
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
|
||||
{
|
||||
if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) {
|
||||
// NSURLErrorCancelled is reported when a page has a redirect OR if you load
|
||||
// a new URL in the WebView before the previous one came back. We can just
|
||||
// ignore these since they aren't real errors.
|
||||
// http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableDictionary *event = [self baseEvent];
|
||||
[event addEntriesFromDictionary: @{
|
||||
@"domain": error.domain,
|
||||
@"code": @(error.code),
|
||||
@"description": [error localizedDescription],
|
||||
}];
|
||||
[_eventDispatcher sendInputEventWithName:@"topLoadingError" body:event];
|
||||
}
|
||||
|
||||
- (void)webViewDidFinishLoad:(UIWebView *)webView
|
||||
{
|
||||
if (_shouldInjectAJAXHandler) {
|
||||
|
||||
// From http://stackoverflow.com/questions/5353278/uiwebviewdelegate-not-monitoring-xmlhttprequest
|
||||
|
||||
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"\
|
||||
var s_ajaxListener = new Object(); \n\
|
||||
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open; \n\
|
||||
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send; \n\
|
||||
s_ajaxListener.callback = function() { \n\
|
||||
window.location.href = '%@://' + this.url; \n\
|
||||
} \n\
|
||||
XMLHttpRequest.prototype.open = function(a,b) { \n\
|
||||
s_ajaxListener.tempOpen.apply(this, arguments); \n\
|
||||
s_ajaxListener.method = a; \n\
|
||||
s_ajaxListener.url = b; \n\
|
||||
if (a.toLowerCase() === 'get') { \n\
|
||||
s_ajaxListener.data = (b.split('?'))[1]; \n\
|
||||
} \n\
|
||||
} \n\
|
||||
XMLHttpRequest.prototype.send = function(a,b) { \n\
|
||||
s_ajaxListener.tempSend.apply(this, arguments); \n\
|
||||
if (s_ajaxListener.method.toLowerCase() === 'post') { \n\
|
||||
s_ajaxListener.data = a; \n\
|
||||
} \n\
|
||||
s_ajaxListener.callback(); \n\
|
||||
} \n\
|
||||
", RCTJSAJAXScheme]];
|
||||
}
|
||||
|
||||
// we only need the final 'finishLoad' call so only fire the event when we're actually done loading.
|
||||
if (!webView.loading && ![webView.request.URL.absoluteString isEqualToString:@"about:blank"]) {
|
||||
[_eventDispatcher sendInputEventWithName:@"topLoadingFinish" body:[self baseEvent]];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTViewManager.h"
|
||||
|
||||
@interface WebViewExManager : RCTViewManager
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "WebViewExManager.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTSparseArray.h"
|
||||
#import "RCTUIManager.h"
|
||||
#import "RCTWebView.h"
|
||||
|
||||
@implementation WebViewExManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTWebView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
|
||||
}
|
||||
|
||||
RCT_REMAP_VIEW_PROPERTY(url, URL, NSURL);
|
||||
RCT_REMAP_VIEW_PROPERTY(html, HTML, NSString);
|
||||
RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL);
|
||||
RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL);
|
||||
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets);
|
||||
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL);
|
||||
RCT_EXPORT_VIEW_PROPERTY(shouldInjectAJAXHandler, BOOL);
|
||||
|
||||
- (NSDictionary *)constantsToExport
|
||||
{
|
||||
return @{
|
||||
@"NavigationType": @{
|
||||
@"LinkClicked": @(UIWebViewNavigationTypeLinkClicked),
|
||||
@"FormSubmitted": @(UIWebViewNavigationTypeFormSubmitted),
|
||||
@"BackForward": @(UIWebViewNavigationTypeBackForward),
|
||||
@"Reload": @(UIWebViewNavigationTypeReload),
|
||||
@"FormResubmitted": @(UIWebViewNavigationTypeFormResubmitted),
|
||||
@"Other": @(UIWebViewNavigationTypeOther)
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(goBack:(NSNumber *)reactTag)
|
||||
{
|
||||
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||
RCTWebView *view = viewRegistry[reactTag];
|
||||
if (![view isKindOfClass:[RCTWebView class]]) {
|
||||
RCTLogError(@"Invalid view returned from registry, expecting RKWebView, got: %@", view);
|
||||
}
|
||||
[view goBack];
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(goForward:(NSNumber *)reactTag)
|
||||
{
|
||||
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||
id view = viewRegistry[reactTag];
|
||||
if (![view isKindOfClass:[RCTWebView class]]) {
|
||||
RCTLogError(@"Invalid view returned from registry, expecting RKWebView, got: %@", view);
|
||||
}
|
||||
[view goForward];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
RCT_EXPORT_METHOD(reload:(NSNumber *)reactTag)
|
||||
{
|
||||
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||
RCTWebView *view = viewRegistry[reactTag];
|
||||
if (![view isKindOfClass:[RCTWebView class]]) {
|
||||
RCTLogMustFix(@"Invalid view returned from registry, expecting RKWebView, got: %@", view);
|
||||
}
|
||||
[view reload];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
+4
-13
@@ -5,28 +5,19 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var WebViewEx = require('./webviewex.js');
|
||||
|
||||
var {
|
||||
AppRegistry,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
View
|
||||
} = React;
|
||||
|
||||
var webview = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.welcome}>
|
||||
Welcome to React Native!
|
||||
</Text>
|
||||
<Text style={styles.instructions}>
|
||||
To get started, edit index.ios.js
|
||||
</Text>
|
||||
<Text style={styles.instructions}>
|
||||
Press Cmd+R to reload,{'\n'}
|
||||
Cmd+D or shake for dev menu
|
||||
</Text>
|
||||
</View>
|
||||
<WebViewEx style={{flex: 1}} url="http://google.com"/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule WebViewEx
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ActivityIndicatorIOS = require('ActivityIndicatorIOS');
|
||||
var EdgeInsetsPropType = require('EdgeInsetsPropType');
|
||||
var React = require('React');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var Text = require('Text');
|
||||
var View = require('View');
|
||||
|
||||
var invariant = require('invariant');
|
||||
var keyMirror = require('keyMirror');
|
||||
var requireNativeComponent = require('requireNativeComponent');
|
||||
|
||||
var PropTypes = React.PropTypes;
|
||||
var WebViewExManager = require('NativeModules').WebViewExManager;
|
||||
|
||||
var BGWASH = 'rgba(255,255,255,0.8)';
|
||||
var RCT_WEBVIEW_REF = 'webviewex';
|
||||
|
||||
var WebViewState = keyMirror({
|
||||
IDLE: null,
|
||||
LOADING: null,
|
||||
ERROR: null,
|
||||
});
|
||||
|
||||
var NavigationType = {
|
||||
click: WebViewExManager.NavigationType.LinkClicked,
|
||||
formsubmit: WebViewExManager.NavigationType.FormSubmitted,
|
||||
backforward: WebViewExManager.NavigationType.BackForward,
|
||||
reload: WebViewExManager.NavigationType.Reload,
|
||||
formresubmit: WebViewExManager.NavigationType.FormResubmitted,
|
||||
other: WebViewExManager.NavigationType.Other,
|
||||
};
|
||||
|
||||
type ErrorEvent = {
|
||||
domain: any;
|
||||
code: any;
|
||||
description: any;
|
||||
}
|
||||
|
||||
type Event = Object;
|
||||
|
||||
var defaultRenderLoading = () => (
|
||||
<View style={styles.loadingView}>
|
||||
<ActivityIndicatorIOS />
|
||||
</View>
|
||||
);
|
||||
var defaultRenderError = (errorDomain, errorCode, errorDesc) => (
|
||||
<View style={styles.errorContainer}>
|
||||
<Text style={styles.errorTextTitle}>
|
||||
Error loading page
|
||||
</Text>
|
||||
<Text style={styles.errorText}>
|
||||
{'Domain: ' + errorDomain}
|
||||
</Text>
|
||||
<Text style={styles.errorText}>
|
||||
{'Error Code: ' + errorCode}
|
||||
</Text>
|
||||
<Text style={styles.errorText}>
|
||||
{'Description: ' + errorDesc}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
var WebViewEx = React.createClass({
|
||||
statics: {
|
||||
NavigationType: NavigationType,
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
url: PropTypes.string,
|
||||
html: PropTypes.string,
|
||||
renderError: PropTypes.func, // view to show if there's an error
|
||||
renderLoading: PropTypes.func, // loading indicator to show
|
||||
bounces: PropTypes.bool,
|
||||
scrollEnabled: PropTypes.bool,
|
||||
automaticallyAdjustContentInsets: PropTypes.bool,
|
||||
shouldInjectAJAXHandler: PropTypes.bool,
|
||||
contentInset: EdgeInsetsPropType,
|
||||
onNavigationStateChange: PropTypes.func,
|
||||
startInLoadingState: PropTypes.bool, // force WebViewEx to show loadingView on first load
|
||||
style: View.propTypes.style,
|
||||
/**
|
||||
* Used for android only, JS is enabled by default for WebViewEx on iOS
|
||||
*/
|
||||
javaScriptEnabledAndroid: PropTypes.bool,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
viewState: WebViewState.IDLE,
|
||||
lastErrorEvent: (null: ?ErrorEvent),
|
||||
startInLoadingState: true,
|
||||
};
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
if (this.props.startInLoadingState) {
|
||||
this.setState({viewState: WebViewState.LOADING});
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var otherView = null;
|
||||
|
||||
if (this.state.viewState === WebViewState.LOADING) {
|
||||
otherView = (this.props.renderLoading || defaultRenderLoading)();
|
||||
} else if (this.state.viewState === WebViewState.ERROR) {
|
||||
var errorEvent = this.state.lastErrorEvent;
|
||||
invariant(
|
||||
errorEvent != null,
|
||||
'lastErrorEvent expected to be non-null'
|
||||
);
|
||||
otherView = (this.props.renderError || defaultRenderError)(
|
||||
errorEvent.domain,
|
||||
errorEvent.code,
|
||||
errorEvent.description
|
||||
);
|
||||
} else if (this.state.viewState !== WebViewState.IDLE) {
|
||||
console.error(
|
||||
'WebViewEx invalid state encountered: ' + this.state.loading
|
||||
);
|
||||
}
|
||||
|
||||
var webViewStyles = [styles.container, styles.webView, this.props.style];
|
||||
if (this.state.viewState === WebViewState.LOADING ||
|
||||
this.state.viewState === WebViewState.ERROR) {
|
||||
// if we're in either LOADING or ERROR states, don't show the webView
|
||||
webViewStyles.push(styles.hidden);
|
||||
}
|
||||
|
||||
var webView =
|
||||
<WebViewEx
|
||||
ref={RCT_WEBVIEW_REF}
|
||||
key="webViewKey"
|
||||
style={webViewStyles}
|
||||
url={this.props.url}
|
||||
html={this.props.html}
|
||||
bounces={this.props.bounces}
|
||||
scrollEnabled={this.props.scrollEnabled}
|
||||
shouldInjectAJAXHandler={this.props.shouldInjectAJAXHandler}
|
||||
contentInset={this.props.contentInset}
|
||||
automaticallyAdjustContentInsets={this.props.automaticallyAdjustContentInsets}
|
||||
onLoadingStart={this.onLoadingStart}
|
||||
onLoadingFinish={this.onLoadingFinish}
|
||||
onLoadingError={this.onLoadingError}
|
||||
/>;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{webView}
|
||||
{otherView}
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
goForward: function() {
|
||||
WebViewExManager.goForward(this.getWebWiewHandle());
|
||||
},
|
||||
|
||||
goBack: function() {
|
||||
WebViewExManager.goBack(this.getWebWiewHandle());
|
||||
},
|
||||
|
||||
reload: function() {
|
||||
WebViewExManager.reload(this.getWebWiewHandle());
|
||||
},
|
||||
|
||||
/**
|
||||
* We return an event with a bunch of fields including:
|
||||
* url, title, loading, canGoBack, canGoForward
|
||||
*/
|
||||
updateNavigationState: function(event: Event) {
|
||||
if (this.props.onNavigationStateChange) {
|
||||
this.props.onNavigationStateChange(event.nativeEvent);
|
||||
}
|
||||
},
|
||||
|
||||
getWebWiewHandle: function(): any {
|
||||
return React.findNodeHandle(this.refs[RCT_WEBVIEW_REF]);
|
||||
},
|
||||
|
||||
onLoadingStart: function(event: Event) {
|
||||
this.updateNavigationState(event);
|
||||
},
|
||||
|
||||
onLoadingError: function(event: Event) {
|
||||
event.persist(); // persist this event because we need to store it
|
||||
console.error('Encountered an error loading page', event.nativeEvent);
|
||||
|
||||
this.setState({
|
||||
lastErrorEvent: event.nativeEvent,
|
||||
viewState: WebViewState.ERROR
|
||||
});
|
||||
},
|
||||
|
||||
onLoadingFinish: function(event: Event) {
|
||||
this.setState({
|
||||
viewState: WebViewState.IDLE,
|
||||
});
|
||||
this.updateNavigationState(event);
|
||||
},
|
||||
});
|
||||
|
||||
var WebViewEx = requireNativeComponent('WebViewEx', WebViewEx);
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
errorContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: BGWASH,
|
||||
},
|
||||
errorText: {
|
||||
fontSize: 14,
|
||||
textAlign: 'center',
|
||||
marginBottom: 2,
|
||||
},
|
||||
errorTextTitle: {
|
||||
fontSize: 15,
|
||||
fontWeight: '500',
|
||||
marginBottom: 10,
|
||||
},
|
||||
hidden: {
|
||||
height: 0,
|
||||
flex: 0, // disable 'flex:1' when hiding a View
|
||||
},
|
||||
loadingView: {
|
||||
backgroundColor: BGWASH,
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
webView: {
|
||||
backgroundColor: '#ffffff',
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = WebViewEx;
|
||||
@@ -22,6 +22,9 @@
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
|
||||
41117F301B25EB7800342843 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 41117F2F1B25EB7800342843 /* WebViewJavascriptBridge.m */; };
|
||||
41117F3D1B25ED7700342843 /* WebViewExManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 41117F3C1B25ED7700342843 /* WebViewExManager.m */; };
|
||||
41117F401B260BBB00342843 /* WebViewEx.m in Sources */ = {isa = PBXBuildFile; fileRef = 41117F3F1B260BBB00342843 /* WebViewEx.m */; };
|
||||
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@@ -107,16 +110,16 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = main.jsbundle; path = iOS/main.jsbundle; sourceTree = "<group>"; };
|
||||
00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = "<group>"; };
|
||||
00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
|
||||
00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = node_modules/react-native/Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
|
||||
00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
|
||||
00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = "<group>"; };
|
||||
00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = "<group>"; };
|
||||
00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = "<group>"; };
|
||||
00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = "<group>"; };
|
||||
00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = "<group>"; };
|
||||
00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = "<group>"; };
|
||||
00E356EE1AD99517003FC87E /* webviewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = webviewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
00E356F21AD99517003FC87E /* webviewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = webviewTests.m; sourceTree = "<group>"; };
|
||||
139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj; sourceTree = "<group>"; };
|
||||
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = "<group>"; };
|
||||
139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = "<group>"; };
|
||||
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = "<group>"; };
|
||||
13B07F961A680F5B00A75B9A /* webview.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = webview.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = iOS/AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = iOS/AppDelegate.m; sourceTree = "<group>"; };
|
||||
@@ -124,9 +127,15 @@
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = iOS/Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = iOS/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = iOS/main.m; sourceTree = "<group>"; };
|
||||
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = node_modules/react-native/React/React.xcodeproj; sourceTree = "<group>"; };
|
||||
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = "<group>"; };
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = node_modules/react-native/Libraries/Text/RCTText.xcodeproj; sourceTree = "<group>"; };
|
||||
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
|
||||
41117F2E1B25EB7800342843 /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = "<group>"; };
|
||||
41117F2F1B25EB7800342843 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = "<group>"; };
|
||||
41117F3B1B25ED7700342843 /* WebViewExManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewExManager.h; sourceTree = "<group>"; };
|
||||
41117F3C1B25ED7700342843 /* WebViewExManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewExManager.m; sourceTree = "<group>"; };
|
||||
41117F3E1B260BBB00342843 /* WebViewEx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewEx.h; sourceTree = "<group>"; };
|
||||
41117F3F1B260BBB00342843 /* WebViewEx.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewEx.m; sourceTree = "<group>"; };
|
||||
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -252,6 +261,19 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
41117F2D1B25EB7800342843 /* WebViewJavascriptBridge */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
41117F2E1B25EB7800342843 /* WebViewJavascriptBridge.h */,
|
||||
41117F2F1B25EB7800342843 /* WebViewJavascriptBridge.m */,
|
||||
41117F3B1B25ED7700342843 /* WebViewExManager.h */,
|
||||
41117F3C1B25ED7700342843 /* WebViewExManager.m */,
|
||||
41117F3E1B260BBB00342843 /* WebViewEx.h */,
|
||||
41117F3F1B260BBB00342843 /* WebViewEx.m */,
|
||||
);
|
||||
path = WebViewJavascriptBridge;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
78C398B11ACF4ADC00677621 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -288,6 +310,7 @@
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
41117F2D1B25EB7800342843 /* WebViewJavascriptBridge */,
|
||||
13B07FAE1A68108700A75B9A /* webview */,
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
||||
00E356EF1AD99517003FC87E /* webviewTests */,
|
||||
@@ -526,8 +549,11 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
41117F3D1B25ED7700342843 /* WebViewExManager.m in Sources */,
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
|
||||
41117F301B25EB7800342843 /* WebViewJavascriptBridge.m in Sources */,
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
||||
41117F401B260BBB00342843 /* WebViewEx.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
Generated
BIN
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
type = "1"
|
||||
version = "2.0">
|
||||
</Bucket>
|
||||
Reference in New Issue
Block a user