Browse Source

Merge branch 'master' into docs/nav-state-changes

Jamon Holmgren 6 years ago
parent
commit
6b80a5fda4
No account linked to committer's email address

+ 4
- 0
.gitignore View File

48
 !.vscode/tasks.json
48
 !.vscode/tasks.json
49
 !.vscode/launch.json
49
 !.vscode/launch.json
50
 !.vscode/extensions.json
50
 !.vscode/extensions.json
51
+
52
+android/gradle
53
+android/gradlew
54
+android/gradlew.bat

+ 13
- 6
README.md View File

8
 - [x] Android
8
 - [x] Android
9
 - [ ] Windows 10 (coming soon)
9
 - [ ] Windows 10 (coming soon)
10
 
10
 
11
+_Note: React Native WebView is not currently supported by Expo unless you "eject"._
12
+
11
 ## Versioning
13
 ## Versioning
12
 
14
 
13
 If you need the exact same WebView as the one from react-native, please use version **2.0.0**. Future versions will follow [semantic versioning](https://semver.org/).
15
 If you need the exact same WebView as the one from react-native, please use version **2.0.0**. Future versions will follow [semantic versioning](https://semver.org/).
26
 Import the `WebView` component from `react-native-webview` and use it like so:
28
 Import the `WebView` component from `react-native-webview` and use it like so:
27
 
29
 
28
 ```jsx
30
 ```jsx
29
-import React, { Component } from 'react';
30
-import { StyleSheet, Text, View } from 'react-native';
31
-import { WebView } from 'react-native-webview';
31
+import React, { Component } from "react";
32
+import { StyleSheet, Text, View } from "react-native";
33
+import { WebView } from "react-native-webview";
32
 
34
 
33
 // ...
35
 // ...
34
 class MyWebComponent extends Component {
36
 class MyWebComponent extends Component {
35
   render() {
37
   render() {
36
     return (
38
     return (
37
       <WebView
39
       <WebView
38
-        source={{ uri: 'https://infinite.red/react-native' }}
40
+        source={{ uri: "https://infinite.red/react-native" }}
39
         style={{ marginTop: 20 }}
41
         style={{ marginTop: 20 }}
40
-        onLoadProgress={e=>console.log(e.nativeEvent.progress)}
42
+        onLoadProgress={e => console.log(e.nativeEvent.progress)}
41
       />
43
       />
42
     );
44
     );
43
   }
45
   }
44
 }
46
 }
45
 ```
47
 ```
46
 
48
 
47
-For more, read the [API Reference](./docs/Reference.md) and [Guide](./docs/Guide.md).
49
+For more, read the [API Reference](./docs/Reference.md) and [Guide](./docs/Guide.md). If you're interested in contributing, check out the [Contributing Guide](./docs/Contributing.md).
48
 
50
 
49
 ## Migrate from React Native core WebView to React Native WebView
51
 ## Migrate from React Native core WebView to React Native WebView
50
 
52
 
51
 Simply install React Native WebView and then use it in place of the core WebView. Their APIs are currently identical, except that this package defaults `useWebKit={true}` unlike the built-in WebView.
53
 Simply install React Native WebView and then use it in place of the core WebView. Their APIs are currently identical, except that this package defaults `useWebKit={true}` unlike the built-in WebView.
52
 
54
 
55
+## Troubleshooting
56
+
57
+- If you're getting `Invariant Violation: Native component for "RNCWKWebView does not exist"` it likely means you forgot to run `react-native link` or there was some error with the linking process
58
+
53
 ### Contributor Notes
59
 ### Contributor Notes
54
 
60
 
55
 - I've removed all PropTypes for now. Instead, we'll be using Flow types. TypeScript types will be added at a later date.
61
 - I've removed all PropTypes for now. Instead, we'll be using Flow types. TypeScript types will be added at a later date.
65
 
71
 
66
 - [Jamon Holmgren](https://github.com/jamonholmgren) ([Twitter @jamonholmgren](https://twitter.com/jamonholmgren)) from [Infinite Red](https://infinite.red/react-native)
72
 - [Jamon Holmgren](https://github.com/jamonholmgren) ([Twitter @jamonholmgren](https://twitter.com/jamonholmgren)) from [Infinite Red](https://infinite.red/react-native)
67
 - [Thibault Malbranche](https://github.com/Titozzz) ([Twitter @titozzz](https://twitter.com/titozzz)) from [Brigad](https://brigad.co/about)
73
 - [Thibault Malbranche](https://github.com/Titozzz) ([Twitter @titozzz](https://twitter.com/titozzz)) from [Brigad](https://brigad.co/about)
74
+- [Empyrical](https://github.com/empyrical) ([Twitter @empyrical](https://twitter.com/empyrical))
68
 
75
 
69
 ## License
76
 ## License
70
 
77
 

+ 78
- 9
android/build.gradle View File

1
+buildscript {
2
+    ext.kotlin_version = '1.2.71'
3
+    repositories {
4
+        google()
5
+        jcenter()
6
+        maven {
7
+            url 'https://maven.fabric.io/public'
8
+        }
9
+    }
10
+    dependencies {
11
+        classpath 'com.android.tools.build:gradle:3.2.1'
12
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
13
+    }
14
+}
15
+
1
 apply plugin: 'com.android.library'
16
 apply plugin: 'com.android.library'
17
+apply plugin: 'kotlin-android'
2
 
18
 
3
-def DEFAULT_COMPILE_SDK_VERSION             = 27
4
-def DEFAULT_BUILD_TOOLS_VERSION             = "27.0.3"
5
-def DEFAULT_MIN_SDK_VERSION                 = 16
6
-def DEFAULT_TARGET_SDK_VERSION              = 26
7
 
19
 
8
-android {
9
-    compileSdkVersion rootProject.findProperty('compileSdkVersion') ?: DEFAULT_COMPILE_SDK_VERSION
10
-    buildToolsVersion rootProject.findProperty('buildToolsVersion') ?: DEFAULT_BUILD_TOOLS_VERSION
20
+def DEFAULT_COMPILE_SDK_VERSION = 27
21
+def DEFAULT_BUILD_TOOLS_VERSION = "28.0.3"
22
+def DEFAULT_TARGET_SDK_VERSION = 27
11
 
23
 
24
+android {
25
+    compileSdkVersion rootProject.hasProperty('compileSdkVersion') ? rootProject.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION
26
+    buildToolsVersion rootProject.hasProperty('buildToolsVersion') ? rootProject.buildToolsVersion : DEFAULT_BUILD_TOOLS_VERSION
12
     defaultConfig {
27
     defaultConfig {
13
-        minSdkVersion rootProject.findProperty('minSdkVersion') ?: DEFAULT_MIN_SDK_VERSION
14
-        targetSdkVersion rootProject.findProperty('targetSdkVersion') ?: DEFAULT_TARGET_SDK_VERSION
28
+        minSdkVersion 16
29
+        targetSdkVersion rootProject.hasProperty('targetSdkVersion') ? rootProject.targetSdkVersion : DEFAULT_TARGET_SDK_VERSION
15
         versionCode 1
30
         versionCode 1
16
         versionName "1.0"
31
         versionName "1.0"
17
     }
32
     }
33
+    buildTypes {
34
+        release {
35
+            minifyEnabled false
36
+        }
37
+    }
38
+    productFlavors {
39
+    }
40
+    lintOptions {
41
+        disable 'GradleCompatible'
42
+    }
43
+    compileOptions {
44
+        sourceCompatibility JavaVersion.VERSION_1_8
45
+        targetCompatibility JavaVersion.VERSION_1_8
46
+    }
47
+}
48
+
49
+repositories {
50
+    mavenCentral()
51
+    maven {
52
+        url 'https://maven.google.com/'
53
+        name 'Google'
54
+    }
55
+
56
+    // Stolen from react-native-firebase, thanks dudes!
57
+    def found = false
58
+    def parentDir = rootProject.projectDir
59
+    def reactNativeAndroidName = 'React Native (Node Modules)'
60
+
61
+    1.upto(4, {
62
+        if (found) return true
63
+        parentDir = parentDir.parentFile
64
+        def reactNativeAndroid = new File(
65
+                parentDir,
66
+                'node_modules/react-native/android'
67
+        )
68
+
69
+        if (reactNativeAndroid.exists()) {
70
+            maven {
71
+                url reactNativeAndroid.toString()
72
+                name reactNativeAndroidName
73
+            }
74
+
75
+            println "${project.name}: using React Native sources from ${reactNativeAndroid.toString()}"
76
+            found = true
77
+        }
78
+    })
79
+
80
+    if (!found) {
81
+        throw new GradleException(
82
+                "${project.name}: unable to locate React Native Android sources, " +
83
+                        "ensure you have you installed React Native as a dependency and try again."
84
+        )
85
+    }
18
 }
86
 }
19
 
87
 
20
 dependencies {
88
 dependencies {
21
     implementation 'com.facebook.react:react-native:+'
89
     implementation 'com.facebook.react:react-native:+'
90
+    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
22
 }
91
 }

+ 1
- 6
android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java View File

56
 import com.reactnativecommunity.webview.events.TopLoadingStartEvent;
56
 import com.reactnativecommunity.webview.events.TopLoadingStartEvent;
57
 import com.reactnativecommunity.webview.events.TopMessageEvent;
57
 import com.reactnativecommunity.webview.events.TopMessageEvent;
58
 import com.reactnativecommunity.webview.events.TopLoadingProgressEvent;
58
 import com.reactnativecommunity.webview.events.TopLoadingProgressEvent;
59
-import java.io.UnsupportedEncodingException;
60
-import java.util.ArrayList;
61
-import java.util.HashMap;
62
-import java.util.Locale;
63
-import java.util.Map;
64
-import javax.annotation.Nullable;
65
 import org.json.JSONException;
59
 import org.json.JSONException;
66
 import org.json.JSONObject;
60
 import org.json.JSONObject;
67
 
61
 
510
     }
504
     }
511
   }
505
   }
512
 
506
 
507
+  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
513
   @ReactProp(name = "mediaPlaybackRequiresUserAction")
508
   @ReactProp(name = "mediaPlaybackRequiresUserAction")
514
   public void setMediaPlaybackRequiresUserAction(WebView view, boolean requires) {
509
   public void setMediaPlaybackRequiresUserAction(WebView view, boolean requires) {
515
     view.getSettings().setMediaPlaybackRequiresUserGesture(requires);
510
     view.getSettings().setMediaPlaybackRequiresUserGesture(requires);

+ 0
- 40
android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingErrorEvent.java View File

1
-package com.reactnativecommunity.webview.events;
2
-
3
-import com.facebook.react.bridge.WritableMap;
4
-import com.facebook.react.uimanager.events.Event;
5
-import com.facebook.react.uimanager.events.RCTEventEmitter;
6
-
7
-/**
8
- * Event emitted when there is an error in loading.
9
- */
10
-public class TopLoadingErrorEvent extends Event<TopLoadingErrorEvent> {
11
-
12
-  public static final String EVENT_NAME = "topLoadingError";
13
-  private WritableMap mEventData;
14
-
15
-  public TopLoadingErrorEvent(int viewId, WritableMap eventData) {
16
-    super(viewId);
17
-    mEventData = eventData;
18
-  }
19
-
20
-  @Override
21
-  public String getEventName() {
22
-    return EVENT_NAME;
23
-  }
24
-
25
-  @Override
26
-  public boolean canCoalesce() {
27
-    return false;
28
-  }
29
-
30
-  @Override
31
-  public short getCoalescingKey() {
32
-    // All events for a given view can be coalesced.
33
-    return 0;
34
-  }
35
-
36
-  @Override
37
-  public void dispatch(RCTEventEmitter rctEventEmitter) {
38
-    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
39
-  }
40
-}

+ 25
- 0
android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingErrorEvent.kt View File

1
+package com.reactnativecommunity.webview.events
2
+
3
+import com.facebook.react.bridge.WritableMap
4
+import com.facebook.react.uimanager.events.Event
5
+import com.facebook.react.uimanager.events.RCTEventEmitter
6
+
7
+/**
8
+ * Event emitted when there is an error in loading.
9
+ */
10
+class TopLoadingErrorEvent(viewId: Int, private val mEventData: WritableMap) :
11
+    Event<TopLoadingErrorEvent>(viewId) {
12
+    companion object {
13
+        const val EVENT_NAME = "topLoadingError"
14
+    }
15
+
16
+    override fun getEventName(): String = EVENT_NAME
17
+
18
+    override fun canCoalesce(): Boolean = false
19
+
20
+    override fun getCoalescingKey(): Short = 0
21
+
22
+    override fun dispatch(rctEventEmitter: RCTEventEmitter) =
23
+        rctEventEmitter.receiveEvent(viewTag, eventName, mEventData)
24
+
25
+}

+ 0
- 40
android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingFinishEvent.java View File

1
-package com.reactnativecommunity.webview.events;
2
-
3
-import com.facebook.react.bridge.WritableMap;
4
-import com.facebook.react.uimanager.events.Event;
5
-import com.facebook.react.uimanager.events.RCTEventEmitter;
6
-
7
-/**
8
- * Event emitted when loading is completed.
9
- */
10
-public class TopLoadingFinishEvent extends Event<TopLoadingFinishEvent> {
11
-
12
-  public static final String EVENT_NAME = "topLoadingFinish";
13
-  private WritableMap mEventData;
14
-
15
-  public TopLoadingFinishEvent(int viewId, WritableMap eventData) {
16
-    super(viewId);
17
-    mEventData = eventData;
18
-  }
19
-
20
-  @Override
21
-  public String getEventName() {
22
-    return EVENT_NAME;
23
-  }
24
-
25
-  @Override
26
-  public boolean canCoalesce() {
27
-    return false;
28
-  }
29
-
30
-  @Override
31
-  public short getCoalescingKey() {
32
-    // All events for a given view can be coalesced.
33
-    return 0;
34
-  }
35
-
36
-  @Override
37
-  public void dispatch(RCTEventEmitter rctEventEmitter) {
38
-    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
39
-  }
40
-}

+ 24
- 0
android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingFinishEvent.kt View File

1
+package com.reactnativecommunity.webview.events
2
+
3
+import com.facebook.react.bridge.WritableMap
4
+import com.facebook.react.uimanager.events.Event
5
+import com.facebook.react.uimanager.events.RCTEventEmitter
6
+
7
+/**
8
+ * Event emitted when loading is completed.
9
+ */
10
+class TopLoadingFinishEvent(viewId: Int, private val mEventData: WritableMap) :
11
+    Event<TopLoadingFinishEvent>(viewId) {
12
+    companion object {
13
+        const val EVENT_NAME = "topLoadingFinish"
14
+    }
15
+
16
+    override fun getEventName(): String = EVENT_NAME
17
+
18
+    override fun canCoalesce(): Boolean = false
19
+
20
+    override fun getCoalescingKey(): Short = 0
21
+
22
+    override fun dispatch(rctEventEmitter: RCTEventEmitter) =
23
+        rctEventEmitter.receiveEvent(viewTag, eventName, mEventData)
24
+}

+ 0
- 36
android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingProgressEvent.java View File

1
-package com.reactnativecommunity.webview.events;
2
-
3
-import com.facebook.react.bridge.WritableMap;
4
-import com.facebook.react.uimanager.events.Event;
5
-import com.facebook.react.uimanager.events.RCTEventEmitter;
6
-
7
-public class TopLoadingProgressEvent extends Event<TopLoadingProgressEvent> {
8
-    public static final String EVENT_NAME = "topLoadingProgress";
9
-    private WritableMap mEventData;
10
-
11
-    public TopLoadingProgressEvent(int viewId, WritableMap eventData) {
12
-        super(viewId);
13
-        mEventData = eventData;
14
-    }
15
-
16
-    @Override
17
-    public String getEventName() {
18
-        return EVENT_NAME;
19
-    }
20
-
21
-    @Override
22
-    public boolean canCoalesce() {
23
-        return false;
24
-    }
25
-
26
-    @Override
27
-    public short getCoalescingKey() {
28
-        // All events for a given view can be coalesced.
29
-        return 0;
30
-    }
31
-
32
-    @Override
33
-    public void dispatch(RCTEventEmitter rctEventEmitter) {
34
-        rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
35
-    }
36
-}

+ 24
- 0
android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingProgressEvent.kt View File

1
+package com.reactnativecommunity.webview.events
2
+
3
+import com.facebook.react.bridge.WritableMap
4
+import com.facebook.react.uimanager.events.Event
5
+import com.facebook.react.uimanager.events.RCTEventEmitter
6
+
7
+/**
8
+ * Event emitted when there is a loading progress event.
9
+ */
10
+class TopLoadingProgressEvent(viewId: Int, private val mEventData: WritableMap) :
11
+    Event<TopLoadingProgressEvent>(viewId) {
12
+    companion object {
13
+        const val EVENT_NAME = "topLoadingProgress"
14
+    }
15
+
16
+    override fun getEventName(): String = EVENT_NAME
17
+
18
+    override fun canCoalesce(): Boolean = false
19
+
20
+    override fun getCoalescingKey(): Short = 0
21
+
22
+    override fun dispatch(rctEventEmitter: RCTEventEmitter) =
23
+        rctEventEmitter.receiveEvent(viewTag, eventName, mEventData)
24
+}

+ 0
- 40
android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingStartEvent.java View File

1
-package com.reactnativecommunity.webview.events;
2
-
3
-import com.facebook.react.bridge.WritableMap;
4
-import com.facebook.react.uimanager.events.Event;
5
-import com.facebook.react.uimanager.events.RCTEventEmitter;
6
-
7
-/**
8
- * Event emitted when loading has started
9
- */
10
-public class TopLoadingStartEvent extends Event<TopLoadingStartEvent> {
11
-
12
-  public static final String EVENT_NAME = "topLoadingStart";
13
-  private WritableMap mEventData;
14
-
15
-  public TopLoadingStartEvent(int viewId, WritableMap eventData) {
16
-    super(viewId);
17
-    mEventData = eventData;
18
-  }
19
-
20
-  @Override
21
-  public String getEventName() {
22
-    return EVENT_NAME;
23
-  }
24
-
25
-  @Override
26
-  public boolean canCoalesce() {
27
-    return false;
28
-  }
29
-
30
-  @Override
31
-  public short getCoalescingKey() {
32
-    // All events for a given view can be coalesced.
33
-    return 0;
34
-  }
35
-
36
-  @Override
37
-  public void dispatch(RCTEventEmitter rctEventEmitter) {
38
-    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
39
-  }
40
-}

+ 25
- 0
android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingStartEvent.kt View File

1
+package com.reactnativecommunity.webview.events
2
+
3
+import com.facebook.react.bridge.WritableMap
4
+import com.facebook.react.uimanager.events.Event
5
+import com.facebook.react.uimanager.events.RCTEventEmitter
6
+
7
+/**
8
+ * Event emitted when loading has started
9
+ */
10
+class TopLoadingStartEvent(viewId: Int, private val mEventData: WritableMap) :
11
+    Event<TopLoadingStartEvent>(viewId) {
12
+    companion object {
13
+        const val EVENT_NAME = "topLoadingStart"
14
+    }
15
+
16
+    override fun getEventName(): String = EVENT_NAME
17
+
18
+    override fun canCoalesce(): Boolean = false
19
+
20
+    override fun getCoalescingKey(): Short = 0
21
+
22
+    override fun dispatch(rctEventEmitter: RCTEventEmitter) =
23
+        rctEventEmitter.receiveEvent(viewTag, eventName, mEventData)
24
+
25
+}

+ 0
- 43
android/src/main/java/com/reactnativecommunity/webview/events/TopMessageEvent.java View File

1
-package com.reactnativecommunity.webview.events;
2
-
3
-import com.facebook.react.bridge.WritableMap;
4
-import com.facebook.react.bridge.Arguments;
5
-import com.facebook.react.uimanager.events.Event;
6
-import com.facebook.react.uimanager.events.RCTEventEmitter;
7
-
8
-/**
9
- * Event emitted when there is an error in loading.
10
- */
11
-public class TopMessageEvent extends Event<TopMessageEvent> {
12
-
13
-  public static final String EVENT_NAME = "topMessage";
14
-  private final String mData;
15
-
16
-  public TopMessageEvent(int viewId, String data) {
17
-    super(viewId);
18
-    mData = data;
19
-  }
20
-
21
-  @Override
22
-  public String getEventName() {
23
-    return EVENT_NAME;
24
-  }
25
-
26
-  @Override
27
-  public boolean canCoalesce() {
28
-    return false;
29
-  }
30
-
31
-  @Override
32
-  public short getCoalescingKey() {
33
-    // All events for a given view can be coalesced.
34
-    return 0;
35
-  }
36
-
37
-  @Override
38
-  public void dispatch(RCTEventEmitter rctEventEmitter) {
39
-    WritableMap data = Arguments.createMap();
40
-    data.putString("data", mData);
41
-    rctEventEmitter.receiveEvent(getViewTag(), EVENT_NAME, data);
42
-  }
43
-}

+ 26
- 0
android/src/main/java/com/reactnativecommunity/webview/events/TopMessageEvent.kt View File

1
+package com.reactnativecommunity.webview.events
2
+
3
+import com.facebook.react.bridge.Arguments
4
+import com.facebook.react.uimanager.events.Event
5
+import com.facebook.react.uimanager.events.RCTEventEmitter
6
+
7
+/**
8
+ * Event emitted when there is an error in loading.
9
+ */
10
+class TopMessageEvent(viewId: Int, private val mData: String) : Event<TopMessageEvent>(viewId) {
11
+    companion object {
12
+        const val EVENT_NAME = "topMessage"
13
+    }
14
+
15
+    override fun getEventName(): String = EVENT_NAME
16
+
17
+    override fun canCoalesce(): Boolean = false
18
+
19
+    override fun getCoalescingKey(): Short = 0
20
+
21
+    override fun dispatch(rctEventEmitter: RCTEventEmitter) {
22
+        val data = Arguments.createMap()
23
+        data.putString("data", mData)
24
+        rctEventEmitter.receiveEvent(viewTag, EVENT_NAME, data)
25
+    }
26
+}

+ 54
- 0
docs/Contributing.md View File

1
+# Contributing to React Native WebView
2
+
3
+First off, _thank you_ for considering contributing to the React Native Community. The community-supported packages are only possible because of amazing people like you.
4
+
5
+Secondly, we'd like the contribution experience to be as good as possible. While we are a small all-volunteer team, we are happy to hear feedback about your experience, and if we can make the docs or experience better please let us know.
6
+
7
+## How to test changes
8
+
9
+After you fork the repo, clone it to your machine, and make your changes, you'll want to test them in an app.
10
+
11
+In a new `react-native init` project, do this:
12
+
13
+```
14
+$ yarn add ../react-native-webview
15
+$ react-native link react-native-webview
16
+```
17
+
18
+You may run into a problem where the `jest-haste-map` module map says react-native was added twice:
19
+
20
+```
21
+Loading dependency graph...(node:32651) UnhandledPromiseRejectionWarning: Error: jest-haste-map: Haste module naming collision:
22
+  Duplicate module name: react-native
23
+  Paths: /Users/myuser/TestApp/node_modules/react-native/package.json collides with /Users/myuser/TestApp/node_modules/react-native-webview/node_modules/react-native/package.json
24
+```
25
+
26
+Just remove the second path like this:
27
+
28
+```
29
+$ rm -rf ./node_modules/react-native-webview/node_modules/react-native
30
+```
31
+
32
+And then re-run the packager:
33
+
34
+```
35
+$ react-native start --reset-cache
36
+```
37
+
38
+When you make a change, you'll probably need to unlink, remove, re-add, and re-link `react-native-webview`:
39
+
40
+```
41
+$ react-native unlink react-native-webview && yarn remove react-native-webview
42
+$ yarn add ../react-native-webview && react-native link react-native-webview
43
+```
44
+
45
+## Notes
46
+
47
+- We use Flow types. TypeScript types will probably be added at a later date.
48
+- We don't intend to support UIWebView and will remove it soon.
49
+- After pulling this repo and installing all dependencies, you can run flow on iOS and Android-specific files using the commands:
50
+  - `yarn test:ios:flow` for iOS
51
+  - `yarn test:android:flow` for Android
52
+- If you want to add another React Native platform to this repository, you will need to create another `.flowconfig` for it. If your platform is `example`, copy the main flowconfig and rename it to `.flowconfig.example`. Then edit the config to ignore other platforms, and add `.*/*[.]example.js` to the ignore lists of the other platforms. Then add an entry to `package.json` like this:
53
+  - `"test:example:flow": "flow check --flowconfig-name .flowconfig.example"`
54
+- Currently you need to install React Native 0.57 to be able to test these types - `flow check` will not pass against 0.56.

+ 23
- 2
docs/Reference.md View File

44
 - [`html`](Reference.md#html)
44
 - [`html`](Reference.md#html)
45
 - [`hideKeyboardAccessoryView`](Reference.md#hidekeyboardaccessoryview)
45
 - [`hideKeyboardAccessoryView`](Reference.md#hidekeyboardaccessoryview)
46
 - [`allowsBackForwardNavigationGestures`](Reference.md#allowsbackforwardnavigationgestures)
46
 - [`allowsBackForwardNavigationGestures`](Reference.md#allowsbackforwardnavigationgestures)
47
+- [`allowFileAccess`](Reference.md#allowFileAccess)
48
+- [`saveFormDataDisabled`](Reference.md#saveFormDataDisabled)
47
 
49
 
48
 ## Methods Index
50
 ## Methods Index
49
 
51
 
108
 
110
 
109
 ### `mediaPlaybackRequiresUserAction`
111
 ### `mediaPlaybackRequiresUserAction`
110
 
112
 
111
-Boolean that determines whether HTML5 audio and video requires the user to tap them before they start playing. The default value is `true`.
113
+Boolean that determines whether HTML5 audio and video requires the user to tap them before they start playing. The default value is `true`. (Android API minimum version 17)
112
 
114
 
113
 | Type | Required |
115
 | Type | Required |
114
 | ---- | -------- |
116
 | ---- | -------- |
495
 | ------- | -------- | -------- |
497
 | ------- | -------- | -------- |
496
 | boolean | No       | iOS      |
498
 | boolean | No       | iOS      |
497
 
499
 
500
+---
501
+
502
+### `allowFileAccess`
503
+
504
+If true, this will allow access to the file system via `file://` URI's. The default value is `false`.
505
+
506
+| Type    | Required | Platform |
507
+| ------- | -------- | -------- |
508
+| boolean | No       | Android  |
509
+
510
+---
511
+
512
+### `saveFormDataDisabled`
513
+
514
+Sets whether the WebView should disable saving form data. The default value is `false`. This function does not have any effect from Android API level 26 onwards as there is an Autofill feature which stores form data.
515
+
516
+| Type    | Required | Platform |
517
+| ------- | -------- | -------- |
518
+| boolean | No       | Android  |
498
 
519
 
499
 ## Methods
520
 ## Methods
500
 
521
 
539
 ### `injectJavaScript(str)`
560
 ### `injectJavaScript(str)`
540
 
561
 
541
 ```javascript
562
 ```javascript
542
-injectJavaScript("... javascript string ...");
563
+injectJavaScript('... javascript string ...');
543
 ```
564
 ```
544
 
565
 
545
 Executes the JavaScript string.
566
 Executes the JavaScript string.

+ 44
- 9
ios/RNCWKWebView.m View File

11
 
11
 
12
 #import "objc/runtime.h"
12
 #import "objc/runtime.h"
13
 
13
 
14
+static NSTimer *keyboardTimer;
14
 static NSString *const MessageHanderName = @"ReactNative";
15
 static NSString *const MessageHanderName = @"ReactNative";
15
 
16
 
16
 // runtime trick to remove WKWebView keyboard default toolbar
17
 // runtime trick to remove WKWebView keyboard default toolbar
74
     _automaticallyAdjustContentInsets = YES;
75
     _automaticallyAdjustContentInsets = YES;
75
     _contentInset = UIEdgeInsetsZero;
76
     _contentInset = UIEdgeInsetsZero;
76
   }
77
   }
78
+    
79
+  // Workaround for a keyboard dismissal bug present in iOS 12
80
+  // https://openradar.appspot.com/radar?id=5018321736957952
81
+  if (@available(iOS 12.0, *)) {
82
+    [[NSNotificationCenter defaultCenter]
83
+      addObserver:self
84
+      selector:@selector(keyboardWillHide)
85
+      name:UIKeyboardWillHideNotification object:nil];
86
+    [[NSNotificationCenter defaultCenter]
87
+      addObserver:self
88
+      selector:@selector(keyboardWillShow)
89
+      name:UIKeyboardWillShowNotification object:nil];
90
+  }
77
   return self;
91
   return self;
78
 }
92
 }
79
 
93
 
92
     wkWebViewConfig.mediaTypesRequiringUserActionForPlayback = _mediaPlaybackRequiresUserAction
106
     wkWebViewConfig.mediaTypesRequiringUserActionForPlayback = _mediaPlaybackRequiresUserAction
93
       ? WKAudiovisualMediaTypeAll
107
       ? WKAudiovisualMediaTypeAll
94
       : WKAudiovisualMediaTypeNone;
108
       : WKAudiovisualMediaTypeNone;
95
-   wkWebViewConfig.dataDetectorTypes = _dataDetectorTypes;
109
+    wkWebViewConfig.dataDetectorTypes = _dataDetectorTypes;
110
+#else
111
+    wkWebViewConfig.mediaPlaybackRequiresUserAction = _mediaPlaybackRequiresUserAction;
96
 #endif
112
 #endif
97
 
113
 
98
     _webView = [[WKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
114
     _webView = [[WKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
120
   }
136
   }
121
 }
137
 }
122
 
138
 
139
+-(void)keyboardWillHide
140
+{
141
+    keyboardTimer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(keyboardDisplacementFix) userInfo:nil repeats:false];
142
+    [[NSRunLoop mainRunLoop] addTimer:keyboardTimer forMode:NSRunLoopCommonModes];
143
+}
144
+-(void)keyboardWillShow
145
+{
146
+    if (keyboardTimer != nil) {
147
+        [keyboardTimer invalidate];
148
+    }
149
+}
150
+-(void)keyboardDisplacementFix
151
+{
152
+    // https://stackoverflow.com/a/9637807/824966
153
+    [UIView animateWithDuration:.25 animations:^{
154
+        self.webView.scrollView.contentOffset = CGPointMake(0, 0);
155
+    }];
156
+}
157
+
123
 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
158
 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
124
     if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) {
159
     if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) {
125
         if(_onLoadingProgress){
160
         if(_onLoadingProgress){
216
 
251
 
217
 -(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView
252
 -(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView
218
 {
253
 {
219
-    
254
+
220
     if (_webView == nil) {
255
     if (_webView == nil) {
221
         _savedHideKeyboardAccessoryView = hideKeyboardAccessoryView;
256
         _savedHideKeyboardAccessoryView = hideKeyboardAccessoryView;
222
         return;
257
         return;
225
     if (_savedHideKeyboardAccessoryView == false) {
260
     if (_savedHideKeyboardAccessoryView == false) {
226
         return;
261
         return;
227
     }
262
     }
228
-    
263
+
229
     UIView* subview;
264
     UIView* subview;
230
     for (UIView* view in _webView.scrollView.subviews) {
265
     for (UIView* view in _webView.scrollView.subviews) {
231
         if([[view.class description] hasPrefix:@"WK"])
266
         if([[view.class description] hasPrefix:@"WK"])
232
             subview = view;
267
             subview = view;
233
     }
268
     }
234
-    
269
+
235
     if(subview == nil) return;
270
     if(subview == nil) return;
236
-    
271
+
237
     NSString* name = [NSString stringWithFormat:@"%@_SwizzleHelperWK", subview.class.superclass];
272
     NSString* name = [NSString stringWithFormat:@"%@_SwizzleHelperWK", subview.class.superclass];
238
     Class newClass = NSClassFromString(name);
273
     Class newClass = NSClassFromString(name);
239
-    
274
+
240
     if(newClass == nil)
275
     if(newClass == nil)
241
     {
276
     {
242
         newClass = objc_allocateClassPair(subview.class, [name cStringUsingEncoding:NSASCIIStringEncoding], 0);
277
         newClass = objc_allocateClassPair(subview.class, [name cStringUsingEncoding:NSASCIIStringEncoding], 0);
243
         if(!newClass) return;
278
         if(!newClass) return;
244
-        
279
+
245
         Method method = class_getInstanceMethod([_SwizzleHelperWK class], @selector(inputAccessoryView));
280
         Method method = class_getInstanceMethod([_SwizzleHelperWK class], @selector(inputAccessoryView));
246
         class_addMethod(newClass, @selector(inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method));
281
         class_addMethod(newClass, @selector(inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method));
247
-        
282
+
248
         objc_registerClassPair(newClass);
283
         objc_registerClassPair(newClass);
249
     }
284
     }
250
-    
285
+
251
     object_setClass(subview, newClass);
286
     object_setClass(subview, newClass);
252
 }
287
 }
253
 
288
 

+ 1
- 1
package.json View File

8
     "Thibault Malbranche <malbranche.thibault@gmail.com>"
8
     "Thibault Malbranche <malbranche.thibault@gmail.com>"
9
   ],
9
   ],
10
   "license": "MIT",
10
   "license": "MIT",
11
-  "version": "2.7.0",
11
+  "version": "2.8.0",
12
   "homepage": "https://github.com/react-native-community/react-native-webview#readme",
12
   "homepage": "https://github.com/react-native-community/react-native-webview#readme",
13
   "scripts": {
13
   "scripts": {
14
     "test:ios:flow": "flow check",
14
     "test:ios:flow": "flow check",