瀏覽代碼

autoheightwebview; disable scrollbar in android webview;

iou90 7 年之前
父節點
當前提交
a4833a6bf9

+ 42
- 0
.gitignore 查看文件

@@ -0,0 +1,42 @@
1
+# OSX
2
+#
3
+.DS_Store
4
+
5
+# Xcode
6
+#
7
+build/
8
+*.pbxuser
9
+!default.pbxuser
10
+*.mode1v3
11
+!default.mode1v3
12
+*.mode2v3
13
+!default.mode2v3
14
+*.perspectivev3
15
+!default.perspectivev3
16
+xcuserdata
17
+*.xccheckout
18
+*.moved-aside
19
+DerivedData
20
+*.hmap
21
+*.ipa
22
+*.xcuserstate
23
+project.xcworkspace
24
+
25
+# Android/IJ
26
+#
27
+*.iml
28
+.idea
29
+.gradle
30
+local.properties
31
+
32
+# node.js
33
+#
34
+node_modules/
35
+npm-debug.log
36
+
37
+# BUCK
38
+buck-out/
39
+\.buckd/
40
+android/app/libs
41
+android/keystores/debug.keystore
42
+

+ 32
- 0
android/build.gradle 查看文件

@@ -0,0 +1,32 @@
1
+apply plugin: 'com.android.library'
2
+
3
+android {
4
+    compileSdkVersion 23
5
+    buildToolsVersion "23.0.1"
6
+
7
+    defaultConfig {
8
+        minSdkVersion 16
9
+        targetSdkVersion 22
10
+        versionCode 1
11
+        versionName "1.0"
12
+
13
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14
+
15
+    }
16
+    buildTypes {
17
+        release {
18
+            minifyEnabled false
19
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20
+        }
21
+    }
22
+}
23
+
24
+dependencies {
25
+    compile fileTree(dir: 'libs', include: ['*.jar'])
26
+    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27
+        exclude group: 'com.android.support', module: 'support-annotations'
28
+    })
29
+    compile 'com.android.support:appcompat-v7:25.0.1'
30
+    compile "com.facebook.react:react-native:+"  // From node_modules
31
+    testCompile 'junit:junit:4.12'
32
+}

+ 17
- 0
android/proguard-rules.pro 查看文件

@@ -0,0 +1,17 @@
1
+# Add project specific ProGuard rules here.
2
+# By default, the flags in this file are appended to flags specified
3
+# in /Users/iou90/Library/Android/sdk/tools/proguard/proguard-android.txt
4
+# You can edit the include path and order by changing the proguardFiles
5
+# directive in build.gradle.
6
+#
7
+# For more details, see
8
+#   http://developer.android.com/guide/developing/tools/proguard.html
9
+
10
+# Add any project specific keep options here:
11
+
12
+# If your project uses WebView with JS, uncomment the following
13
+# and specify the fully qualified class name to the JavaScript interface
14
+# class:
15
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16
+#   public *;
17
+#}

+ 26
- 0
android/src/androidTest/java/com/dscj/autoheightwebview/ExampleInstrumentedTest.java 查看文件

@@ -0,0 +1,26 @@
1
+package com.dscj.autoheightwebview;
2
+
3
+import android.content.Context;
4
+import android.support.test.InstrumentationRegistry;
5
+import android.support.test.runner.AndroidJUnit4;
6
+
7
+import org.junit.Test;
8
+import org.junit.runner.RunWith;
9
+
10
+import static org.junit.Assert.*;
11
+
12
+/**
13
+ * Instrumentation test, which will execute on an Android device.
14
+ *
15
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
16
+ */
17
+@RunWith(AndroidJUnit4.class)
18
+public class ExampleInstrumentedTest {
19
+    @Test
20
+    public void useAppContext() throws Exception {
21
+        // Context of the app under test.
22
+        Context appContext = InstrumentationRegistry.getTargetContext();
23
+
24
+        assertEquals("com.dscj.autoheightwebview.test", appContext.getPackageName());
25
+    }
26
+}

+ 11
- 0
android/src/main/AndroidManifest.xml 查看文件

@@ -0,0 +1,11 @@
1
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+          package="com.dscj.autoheightwebview">
3
+
4
+    <application android:allowBackup="true"
5
+                 android:label="@string/app_name"
6
+                 android:supportsRtl="true"
7
+    >
8
+
9
+    </application>
10
+
11
+</manifest>

+ 27
- 0
android/src/main/java/com/dscj/autoheightwebview/AutoHeightWebViewManager.java 查看文件

@@ -0,0 +1,27 @@
1
+package com.dscj.autoheightwebview;
2
+
3
+import android.webkit.WebView;
4
+
5
+import com.facebook.react.uimanager.ThemedReactContext;
6
+import com.facebook.react.views.webview.ReactWebViewManager;
7
+
8
+/**
9
+ * Created by iou90 on 09/01/2017.
10
+ */
11
+
12
+public class AutoHeightWebViewManager extends ReactWebViewManager {
13
+    private static final String REACT_CLASS = "RCTAutoHeightWebView";
14
+
15
+    @Override
16
+    public String getName() {
17
+        return REACT_CLASS;
18
+    }
19
+
20
+    @Override
21
+    protected WebView createViewInstance(ThemedReactContext reactContext) {
22
+        WebView webview = super.createViewInstance(reactContext);
23
+        webview.setVerticalScrollBarEnabled(false);
24
+        webview.setHorizontalScrollBarEnabled(false);
25
+        return webview;
26
+    }
27
+}

+ 34
- 0
android/src/main/java/com/dscj/autoheightwebview/AutoHeightWebViewPackage.java 查看文件

@@ -0,0 +1,34 @@
1
+package com.dscj.autoheightwebview;
2
+
3
+import com.facebook.react.ReactPackage;
4
+import com.facebook.react.bridge.JavaScriptModule;
5
+import com.facebook.react.bridge.NativeModule;
6
+import com.facebook.react.bridge.ReactApplicationContext;
7
+import com.facebook.react.uimanager.ViewManager;
8
+
9
+import java.util.ArrayList;
10
+import java.util.Arrays;
11
+import java.util.List;
12
+
13
+/**
14
+ * Created by iou90 on 09/01/2017.
15
+ */
16
+
17
+public class AutoHeightWebViewPackage implements ReactPackage {
18
+    @Override
19
+    public List<NativeModule> createNativeModules(ReactApplicationContext reactApplicationContext) {
20
+        return new ArrayList<>();
21
+    }
22
+
23
+    @Override
24
+    public List<ViewManager> createViewManagers(ReactApplicationContext reactApplicationContext) {
25
+        return Arrays.<ViewManager>asList(
26
+                new AutoHeightWebViewManager()
27
+        );
28
+    }
29
+
30
+    @Override
31
+    public List<Class<? extends JavaScriptModule>> createJSModules() {
32
+        return Arrays.asList();
33
+    }
34
+}

+ 3
- 0
android/src/main/res/values/strings.xml 查看文件

@@ -0,0 +1,3 @@
1
+<resources>
2
+    <string name="app_name">RCTAutoHeightWebView</string>
3
+</resources>

+ 17
- 0
android/src/test/java/com/dscj/autoheightwebview/ExampleUnitTest.java 查看文件

@@ -0,0 +1,17 @@
1
+package com.dscj.autoheightwebview;
2
+
3
+import org.junit.Test;
4
+
5
+import static org.junit.Assert.*;
6
+
7
+/**
8
+ * Example local unit test, which will execute on the development machine (host).
9
+ *
10
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
11
+ */
12
+public class ExampleUnitTest {
13
+    @Test
14
+    public void addition_isCorrect() throws Exception {
15
+        assertEquals(4, 2 + 2);
16
+    }
17
+}

+ 116
- 0
autoHeightWebView/index.android.js 查看文件

@@ -0,0 +1,116 @@
1
+'use strict'
2
+
3
+import React, {
4
+    Component,
5
+    PropTypes
6
+} from 'react';
7
+
8
+import {
9
+    requireNativeComponent,
10
+    View,
11
+    WebView
12
+} from 'react-native';
13
+
14
+export default class AutoHeightWebView extends Component {
15
+    constructor(props) {
16
+        super(props);
17
+        this.handleNavigationStateChange = this.handleNavigationStateChange.bind(this);
18
+        const initialScript = props.files ? this.appendFilesToHead(props.files, BaseScript) : BaseScript;
19
+        this.state = {
20
+            height: 0,
21
+            script: initialScript
22
+        };
23
+    }
24
+
25
+    componentWillReceiveProps(nextProps) {
26
+        let currentScript = BaseScript;
27
+        if ((nextProps.files && !this.props.files) || (nextProps.files && this.props.files && JSON.stringify(nextProps.files) !== JSON.stringify(this.props.files))) {
28
+            currentScript = this.appendFilesToHead(nextProps.files, BaseScript);
29
+        }
30
+        this.setState({ script: currentScript });
31
+    }
32
+
33
+    appendFilesToHead(files, script) {
34
+        if (!files) {
35
+            return script;
36
+        }
37
+        for (let file of files) {
38
+            script =
39
+                `
40
+                var link  = document.createElement('link');
41
+                link.rel  = '` + file.rel + `';
42
+                link.type = '` + file.type + `';
43
+                link.href = '` + file.href + `';
44
+                document.head.appendChild(link);
45
+                `+ script;
46
+        }
47
+        return script;
48
+    }
49
+
50
+    handleNavigationStateChange(navState) {
51
+        const height = Number(navState.title);
52
+        this.setState({ height });
53
+        if (this.props.onHeightUpdated) {
54
+            this.props.onHeightUpdated(height);
55
+        }
56
+    }
57
+
58
+    render() {
59
+        const source = this.props.enableBaseUrl ? {
60
+            html: this.props.html,
61
+            baseUrl: 'file:///android_asset/web/'
62
+        } : { html: this.props.html };
63
+        return (
64
+            <View style={[{
65
+                height: this.state.height + this.props.heightOffset
66
+            }, this.props.style]}>
67
+                <RCTAutoHeightWebView
68
+                    injectedJavaScript={this.state.script + this.props.customScript}
69
+                    scrollEnabled={false}
70
+                    source={source}
71
+                    onNavigationStateChange={this.handleNavigationStateChange} />
72
+            </View>
73
+        );
74
+    }
75
+}
76
+
77
+AutoHeightWebView.propTypes = {
78
+    html: PropTypes.string,
79
+    onHeightUpdated: PropTypes.func,
80
+    customScript: PropTypes.string,
81
+    style: View.propTypes.style,
82
+    // offset rn webview margin
83
+    heightOffset: PropTypes.number,
84
+    // baseUrl not work in android 4.3 or below version
85
+    enableBaseUrl: PropTypes.bool,
86
+    // add web/files... to android/app/src/assets/
87
+    files: PropTypes.arrayOf(PropTypes.shape({
88
+        href: PropTypes.string,
89
+        type: PropTypes.string,
90
+        rel: PropTypes.string
91
+    }))
92
+}
93
+
94
+const RCTAutoHeightWebView = requireNativeComponent('RCTAutoHeightWebView', AutoHeightWebView);
95
+
96
+const BaseScript =
97
+    `
98
+    ; (function () {
99
+        var wrapper = document.createElement('div');
100
+        wrapper.id = 'height-wrapper';
101
+        while (document.body.firstChild) {
102
+            wrapper.appendChild(document.body.firstChild);
103
+        }
104
+        document.body.appendChild(wrapper);
105
+        var i = 0;
106
+        function updateHeight() {
107
+            document.title = wrapper.clientHeight;
108
+            window.location.hash = ++i;
109
+        }
110
+        updateHeight();
111
+        window.addEventListener('load', function () {
112
+            updateHeight();
113
+        });
114
+        window.addEventListener('resize', updateHeight);
115
+    } ());
116
+    `;

+ 114
- 0
autoHeightWebView/index.ios.js 查看文件

@@ -0,0 +1,114 @@
1
+'use strict'
2
+
3
+import React, {
4
+    Component,
5
+    PropTypes
6
+} from 'react';
7
+
8
+import {
9
+    View,
10
+    WebView
11
+} from 'react-native';
12
+
13
+export default class AutoHeightWebView extends Component {
14
+    constructor(props) {
15
+        super(props);
16
+        this.handleNavigationStateChange = this.handleNavigationStateChange.bind(this);
17
+        const initialScript = props.files ? this.appendFilesToHead(props.files, BaseScript) : BaseScript;
18
+        this.state = {
19
+            height: 0,
20
+            script: initialScript
21
+        };
22
+    }
23
+
24
+    componentWillReceiveProps(nextProps) {
25
+        let currentScript = BaseScript;
26
+        if ((nextProps.files && !this.props.files) || (nextProps.files && this.props.files && JSON.stringify(nextProps.files) !== JSON.stringify(this.props.files))) {
27
+            currentScript = this.appendFilesToHead(nextProps.files, BaseScript);
28
+        }
29
+        this.setState({ script: currentScript });
30
+    }
31
+
32
+    appendFilesToHead(files, script) {
33
+        if (!files) {
34
+            return script;
35
+        }
36
+        for (let file of files) {
37
+            script =
38
+                `
39
+                var link  = document.createElement('link');
40
+                link.rel  = '` + file.rel + `';
41
+                link.type = '` + file.type + `';
42
+                link.href = '` + file.href + `';
43
+                document.head.appendChild(link);
44
+                `+ script;
45
+        }
46
+        return script;
47
+    }
48
+
49
+    handleNavigationStateChange(navState) {
50
+        const height = Number(navState.title);
51
+        this.setState({ height });
52
+        if (this.props.onHeightUpdated) {
53
+            this.props.onHeightUpdated(height);
54
+        }
55
+    }
56
+
57
+    render() {
58
+        return (
59
+            <View style={[{
60
+                height: this.state.height + this.props.heightOffset,
61
+            }, this.props.style]}>
62
+                <WebView
63
+                    injectedJavaScript={this.state.script + this.props.customScript}
64
+                    scrollEnabled={false}
65
+                    source={{
66
+                        html: this.props.html,
67
+                        baseUrl: 'web/'
68
+                    }}
69
+                    onNavigationStateChange={this.handleNavigationStateChange} />
70
+            </View>
71
+        );
72
+    }
73
+}
74
+
75
+AutoHeightWebView.propTypes = {
76
+    html: PropTypes.string,
77
+    onHeightUpdated: PropTypes.func,
78
+    customScript: PropTypes.string,
79
+    // offset rn webview margin
80
+    heightOffset: PropTypes.number,
81
+    style: View.propTypes.style,
82
+    // add web/files... to project root
83
+    files: PropTypes.arrayOf(PropTypes.shape({
84
+        href: PropTypes.string,
85
+        type: PropTypes.string,
86
+        rel: PropTypes.string
87
+    }))
88
+}
89
+
90
+AutoHeightWebView.defaultProps = {
91
+    heightOffset: 12
92
+}
93
+
94
+const BaseScript =
95
+    `
96
+    ; (function () {
97
+        var wrapper = document.createElement('div');
98
+        wrapper.id = 'height-wrapper';
99
+        while (document.body.firstChild) {
100
+            wrapper.appendChild(document.body.firstChild);
101
+        }
102
+        document.body.appendChild(wrapper);
103
+        var i = 0;
104
+        function updateHeight() {
105
+            document.title = wrapper.clientHeight;
106
+            window.location.hash = ++i;
107
+        }
108
+        updateHeight();
109
+        window.addEventListener('load', function () {
110
+            updateHeight();
111
+        });
112
+        window.addEventListener('resize', updateHeight);
113
+    } ());
114
+    `;

+ 19
- 0
package.json 查看文件

@@ -0,0 +1,19 @@
1
+{
2
+  "name": "react-native-autoheightwebview",
3
+  "version": "0.0.1",
4
+  "description": "An auto height webview for React Native",
5
+  "main": "autoHeightWebView",
6
+  "scripts": {
7
+    "test": "echo \"Error: no test specified\" && exit 1"
8
+  },
9
+  "repository": {
10
+    "type": "git",
11
+    "url": "git+https://github.com/iou90/react-native-autoheightwebview.git"
12
+  },
13
+  "author": "iou90",
14
+  "license": "ISC",
15
+  "bugs": {
16
+    "url": "https://github.com/iou90/react-native-autoheightwebview/issues"
17
+  },
18
+  "homepage": "https://github.com/iou90/react-native-autoheightwebview#readme"
19
+}