Skip to content

Instantly share code, notes, and snippets.

@dillonhafer
Created July 9, 2018 19:31
Show Gist options
  • Select an option

  • Save dillonhafer/04936dda21f7f0331167c8ff1cc9c5eb to your computer and use it in GitHub Desktop.

Select an option

Save dillonhafer/04936dda21f7f0331167c8ff1cc9c5eb to your computer and use it in GitHub Desktop.
Expo Document Picker workaround
import React, { Component } from 'react';
import {
View,
Text,
TouchableOpacity,
} from 'react-native';
import WebViewHack from './WebViewHack';
class ImportFileScreen extends Component {
selectFile = async () => {
try {
const file = await DocumentPicker.getDocumentAsync({ type: 'text/csv' });
if (file.type === 'success') {
this.parseFile(file.uri);
}
} catch (err) {
// Expo didn't build with iCloud, expo turtle fallback
this.webview.injectJavaScript('selectFile()');
}
};
onSelectFile = event => {
const base64file = event.nativeEvent.data;
this.parseFile(base64file);
};
parseFile(file) {
// do something with the file
}
render() {
return (
<View>
<TouchableOpacity onPress={this.selectFile}>
<Text>Attach File</Text>
</TouchableOpacity>
<WebViewHack
ref={webview => {
if (webview && webview.webview) {
this.webview = webview.webview;
}
}}
onSelectFile={this.onSelectFile}
/>
</View>
)
}
}
import React, { PureComponent } from 'react';
import { WebView } from 'react-native';
const html = `
<input id='csv' type="file" accept="text/csv,text/plain">
<script>
function selectFile(event) {
document.getElementById('csv').click();
}
function getBase64(e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
window.postMessage(reader.result)
};
reader.onerror = function (error) {
console.log("Something went wrong:", error)
};
}
document.getElementById('csv').addEventListener('change', getBase64)
</script>
`;
class WebViewHack extends PureComponent {
render() {
const { onSelectFile } = this.props;
return (
<WebView
ref={webview => (this.webview = webview)}
onMessage={onSelectFile}
style={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
width: 0,
height: 0,
}}
source={{
html,
}}
/>
);
}
}
export default WebViewHack;
@ernest-okot
Copy link

This is awesome, gonna try it our soon!

@mynameisthunder
Copy link

same def doing this

@ernest-okot
Copy link

Doesn't work on Android. Webview doesn't support uploads, can't get it to do so

@dillonhafer
Copy link
Author

The DocumentPicker.getDocumentAsync call should work fine on Android, this is an iOS only fallback for when you misconfigure iCloud containers. You should not ever send files like this over the bridge, let alone a webview. This is called a hack because it is literally a hack, and should not be used professionally.

@ernest-okot
Copy link

The problem with DocumentPicker doesn't support multiple files and I need to eject to use other document picker libraries

@mynameisthunder
Copy link

mynameisthunder commented Oct 10, 2019 via email

@VictorPulzz
Copy link

The DocumentPicker.getDocumentAsync call should work fine on Android, this is an iOS only fallback for when you misconfigure iCloud containers. You should not ever send files like this over the bridge, let alone a webview. This is called a hack because it is literally a hack, and should not be used professionally.

Hello, You no what are the alternatives? I work this expo react-native

@spanwair
Copy link

spanwair commented Oct 25, 2020

this worked for me for expo

const html = `
      <label for="input" style="">
        <div style="
          width: 100%;
          background-color: blue;
          border: 1px solid blue;
          display: flex;
          justify-content: center;
          padding: 50px;
          border-radius: 10px;
        ">
          <span style="
            font-size: 45px;
            font-weight: 500;
            color: white;
          ">
            text
          </span>
        </div>
      </label>
      <input
        id="input"
        accept="*/*"
        type="file"
        multiple
        style="display: none;"
      >
      <script>
        const fileToRead = document.getElementById("input");

        fileToRead.addEventListener("change", function(event) {
          const filesBase64 = [];
          for (let i = 0; i < event.target.files.length; i++) {
            const file = event.target.files[i];
            const reader = new FileReader();
            reader.onload = function () {
              filesBase64.push({result: reader.result, len: event.target.files.length});
              window.ReactNativeWebView.postMessage(JSON.stringify(filesBase64))
            };
            reader.readAsDataURL(file);
          }
        });
      </script>
    `;

<WebView
          style={{width: '100%', height: 60}}
          javaScriptEnabled
          domStorageEnabled
          onMessage={event => this.pickedFiles((event.nativeEvent as unknown) as PickedFile)}
          source={{html}}
/>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment