Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

React Native comes with [WebView](http://facebook.github.io/react-native/docs/webview.html) component, which uses UIWebView on iOS. This component uses [WKWebView](http://nshipster.com/wkwebkit/) introduced in iOS 8 with all the performance boost.

**Deployment Target >= iOS 8.0 is required** *(which is React Native's current minimum deployment target anyway).*
**Deployment Target >= iOS 8.0 is required** _(which is React Native's current minimum deployment target anyway)._

### Install

Expand All @@ -17,10 +17,9 @@ React Native comes with [WebView](http://facebook.github.io/react-native/docs/we
2. In the XCode's "Project navigator", right click on your project's Libraries folder ➜ Add Files to <...>
3. Go to node_modules ➜ react-native-wkwebview-reborn ➜ ios ➜ select `RCTWKWebView.xcodeproj`
4. Go your build target ➜ Build Phases ➜ Link Binary With Libraries, click "+" and select `libRCTWkWebView.a` (see the following screenshot for reference)
![Linking](https://user-images.githubusercontent.com/608221/28060167-0650e3f4-6659-11e7-8085-7a8c2615f90f.png)
![Linking](https://user-images.githubusercontent.com/608221/28060167-0650e3f4-6659-11e7-8085-7a8c2615f90f.png)
5. Compile and profit (Remember to set Minimum Deployment Target = 8.0)


### Usage

```js
Expand All @@ -29,7 +28,7 @@ import WKWebView from 'react-native-wkwebview-reborn';

Try replacing your existing `WebView` with `WKWebView` and it should work in most cases.

For React Native >= 0.57, use version 2.x; for React Native < 0.40, use version 0.x.
For React Native >= 0.57, use version 2.x; for React Native < 0.57, use version 1.x; for React Native < 0.40, use version 0.x.

### Compatibility with UIWebView

Expand All @@ -44,7 +43,7 @@ WKWebView aims to be a drop-in replacement for UIWebView. However, some legacy U
A callback to get the loading progress of WKWebView. Derived from [`estimatedProgress`](https://developer.apple.com/library/ios/documentation/WebKit/Reference/WKWebView_Ref/#//apple_ref/occ/instp/WKWebView/estimatedProgress) property.

```js
<WKWebView onProgress={(progress) => console.log(progress)} />
<WKWebView onProgress={progress => console.log(progress)} />
```

`progress` is a double between 0 and 1.
Expand All @@ -59,15 +58,20 @@ If set to true, links with `target="_blank"` or `window.open` will be opened in

- **sendCookies**

Set `sendCookies` to true to copy cookies from `sharedHTTPCookieStorage` when calling loadRequest. This emulates the behavior of react-native's `WebView` component. You can set cookies using `react-native-cookies` Default is false.
Set `sendCookies` to true to copy cookies from `sharedHTTPCookieStorage` when calling loadRequest. This emulates the behavior of react-native's `WebView` component. You can set cookies using `react-native-cookies` Default is false.

- **source={{file: '', allowingReadAccessToURL: '' }}**

This allows WKWebView loads a local HTML file. Please note the underlying API is only introduced in iOS 9+. So in iOS 8, it will simple ignores these two properties.
It allows you to provide a fallback URL for iOS 8 users.

```js
<WKWebView source={{ file: RNFS.MainBundlePath + '/data/index.html', allowingReadAccessToURL: RNFS.MainBundlePath }} />
<WKWebView
source={{
file: RNFS.MainBundlePath + '/data/index.html',
allowingReadAccessToURL: RNFS.MainBundlePath,
}}
/>
```

You can also use the `require` syntax (sendCookies and userAgent will be ignored)
Expand All @@ -94,7 +98,7 @@ This property specifies how the safe area insets are used to modify the content

- **keyboardDisplayRequiresUserAction**

Enables focusing an input inside a webview and showing the keyboard *programatically*. **New in 1.20.0**
Enables focusing an input inside a webview and showing the keyboard _programatically_. **New in 1.20.0**

- **keyboardDismissMode**

Expand Down Expand Up @@ -135,39 +139,38 @@ Enable horizontal swipe gestures will trigger back-forward navigations. Derived
- pagingEnabled
- scrollEnabled
- directionalLockEnabled
- scalesPageToFit

#### Unsupported props are:
#### Unsupported props are:

- mediaPlaybackRequiresUserAction
- scalesPageToFit
- domStorageEnabled
- javaScriptEnabled
- allowsInlineMediaPlayback
- decelerationRate

### Advanced Communication between React Native and WkWebView


#### Communication from WKWebview to React Native

- **onMessage**

This utilizes the message handlers in WKWebView and allows you to post message from webview to React Native. For example:

```js
<WKWebView onMessage={(e) => console.log(e)} />
<WKWebView onMessage={e => console.log(e)} />
```

Then in your webview, you can post message to React Native using

```js
window.webkit.messageHandlers.reactNative.postMessage({message: 'hello!'});
window.webkit.messageHandlers.reactNative.postMessage({ message: 'hello!' });
```

or (since 1.14.0)

```js
window.postMessage({message: 'hello!'});
window.postMessage({ message: 'hello!' });
```

Then you can access the nativeEvent in React Native using the event object returned
Expand Down Expand Up @@ -198,7 +201,7 @@ you can define a callback method on your WebView:
window.receivedMessageFromReactNative = function(data) {
// Code here
console.log(data);
}
};
```

Then you can send message from React Native with this method call:
Expand Down
102 changes: 48 additions & 54 deletions WKWebView.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ReactNative, {
ViewPropTypes,
NativeModules,
Text,
ActivityIndicator
ActivityIndicator,
} from 'react-native';

import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
Expand Down Expand Up @@ -40,10 +40,10 @@ const NavigationType = keyMirror({
const JSNavigationScheme = 'react-js-navigation';

type ErrorEvent = {
domain: any;
code: any;
description: any;
}
domain: any,
code: any,
description: any,
};

type Event = Object;

Expand All @@ -54,18 +54,10 @@ const defaultRenderLoading = () => (
);
const 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>
<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>
);

Expand All @@ -80,15 +72,9 @@ class WKWebView extends React.Component {
static propTypes = {
...ViewPropTypes,

html: deprecatedPropType(
PropTypes.string,
'Use the `source` prop instead.'
),
html: deprecatedPropType(PropTypes.string, 'Use the `source` prop instead.'),

url: deprecatedPropType(
PropTypes.string,
'Use the `source` prop instead.'
),
url: deprecatedPropType(PropTypes.string, 'Use the `source` prop instead.'),

/**
* Loads static html or a uri (with optional headers) in the WebView.
Expand Down Expand Up @@ -252,16 +238,16 @@ class WKWebView extends React.Component {
allowsLinkPreview: PropTypes.bool,
/**
* Sets the customized user agent by using of the WKWebView
*/
*/
customUserAgent: PropTypes.string,
userAgent: PropTypes.string,
/**
* A Boolean value that determines whether paging is enabled for the scroll view.
*/
*/
pagingEnabled: PropTypes.bool,
/**
* A Boolean value that sets whether diagonal scrolling is allowed.
*/
*/
directionalLockEnabled: PropTypes.bool,
/*
* The manner in which the keyboard is dismissed when a drag begins in the
Expand All @@ -272,6 +258,10 @@ class WKWebView extends React.Component {
'on-drag',
'interactive', // iOS only
]),
/**
* Scale webview to match the device viewport.
*/
scalesPageToFit: PropTypes.bool,
};

state = {
Expand All @@ -293,39 +283,39 @@ class WKWebView extends React.Component {
otherView = (this.props.renderLoading || defaultRenderLoading)();
} else if (this.state.viewState === WebViewState.ERROR) {
const errorEvent = this.state.lastErrorEvent;
invariant(
errorEvent != null,
'lastErrorEvent expected to be non-null'
);
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(
'CRAWKWebView invalid state encountered: ' + this.state.loading
);
console.error('CRAWKWebView invalid state encountered: ' + this.state.loading);
}

const webViewStyles = [styles.container, styles.webView, this.props.style];
if (this.state.viewState === WebViewState.LOADING ||
this.state.viewState === WebViewState.ERROR) {
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);
}

const onShouldStartLoadWithRequest = this.props.onShouldStartLoadWithRequest && ((event: Event) => {
const shouldStart = this.props.onShouldStartLoadWithRequest &&
this.props.onShouldStartLoadWithRequest(event.nativeEvent);
WKWebViewManager.startLoadWithResult(!!shouldStart, event.nativeEvent.lockIdentifier);
});
const onShouldStartLoadWithRequest =
this.props.onShouldStartLoadWithRequest &&
((event: Event) => {
const shouldStart =
this.props.onShouldStartLoadWithRequest &&
this.props.onShouldStartLoadWithRequest(event.nativeEvent);
WKWebViewManager.startLoadWithResult(!!shouldStart, event.nativeEvent.lockIdentifier);
});

let source = this.props.source;
if (this.props.source && typeof this.props.source === 'object') {
source = Object.assign({}, this.props.source, {
sendCookies: this.props.sendCookies,
customUserAgent: this.props.customUserAgent || this.props.userAgent
customUserAgent: this.props.customUserAgent || this.props.userAgent,
});

if (this.props.html) {
Expand All @@ -337,9 +327,11 @@ class WKWebView extends React.Component {

const messagingEnabled = typeof this.props.onMessage === 'function';

const webView =
const webView = (
<CRAWKWebView
ref={ref => { this.webview = ref; }}
ref={ref => {
this.webview = ref;
}}
key="webViewKey"
style={webViewStyles}
contentInsetAdjustmentBehavior={this.props.contentInsetAdjustmentBehavior}
Expand Down Expand Up @@ -369,7 +361,9 @@ class WKWebView extends React.Component {
directionalLockEnabled={this.props.directionalLockEnabled}
onNavigationResponse={this._onNavigationResponse}
keyboardDismissMode={this.props.keyboardDismissMode}
/>;
scalesPageToFit={this.props.scalesPageToFit}
/>
);

return (
<View style={styles.container}>
Expand Down Expand Up @@ -435,7 +429,7 @@ class WKWebView extends React.Component {
this.getWebViewHandle(),
UIManager.CRAWKWebView.Commands.stopLoading,
null
)
);
};

/**
Expand All @@ -448,15 +442,15 @@ class WKWebView extends React.Component {
* document.addEventListener('message', e => { document.title = e.data; });
* ```
*/
postMessage = (data) => {
postMessage = data => {
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
UIManager.CRAWKWebView.Commands.postMessage,
[String(data)]
);
};

evaluateJavaScript = (js) => {
evaluateJavaScript = js => {
return WKWebViewManager.evaluateJavaScript(this.getWebViewHandle(), js);
};

Expand Down Expand Up @@ -492,7 +486,7 @@ class WKWebView extends React.Component {

this.setState({
lastErrorEvent: event.nativeEvent,
viewState: WebViewState.ERROR
viewState: WebViewState.ERROR,
});
};

Expand Down Expand Up @@ -523,8 +517,8 @@ class WKWebView extends React.Component {

_onNavigationResponse = (event: Event) => {
const { onNavigationResponse } = this.props;
onNavigationResponse && onNavigationResponse(event)
}
onNavigationResponse && onNavigationResponse(event);
};
}

const CRAWKWebView = requireNativeComponent('CRAWKWebView', WKWebView, {
Expand All @@ -534,7 +528,7 @@ const CRAWKWebView = requireNativeComponent('CRAWKWebView', WKWebView, {
onLoadingFinish: true,
onMessage: true,
messagingEnabled: PropTypes.bool,
}
},
});

const styles = StyleSheet.create({
Expand Down Expand Up @@ -570,7 +564,7 @@ const styles = StyleSheet.create({
},
webView: {
backgroundColor: '#ffffff',
}
},
});

export default WKWebView;
1 change: 1 addition & 0 deletions ios/RCTWKWebView/CRAWKWebView.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
@property (nonatomic, assign) UIEdgeInsets contentInset;
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
@property (nonatomic, assign) BOOL messagingEnabled;
@property (nonatomic, assign) BOOL scalesPageToFit;
@property (nonatomic, assign) BOOL allowsLinkPreview;
@property (nonatomic, assign) BOOL openNewWindowInWebView;
@property (nonatomic, assign) BOOL injectJavaScriptForMainFrameOnly;
Expand Down
Loading