Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does this work with React Native #96

Closed
acollazomayer opened this issue Feb 26, 2018 · 20 comments · Fixed by #132
Closed

Does this work with React Native #96

acollazomayer opened this issue Feb 26, 2018 · 20 comments · Fixed by #132

Comments

@acollazomayer
Copy link

Im building an app with react native and i want to know if this library works with react native

@kvz
Copy link
Member

kvz commented Feb 26, 2018

While I see no reason why it shouldn't, we haven't tested this yet and we'd be grateful if you could share your results with us!

@Acconut Acconut changed the title Does this work with react natvie Does this work with React Native May 7, 2018
@Acconut
Copy link
Member

Acconut commented May 7, 2018

A (now deleted) comment suggested that tus-js-client is not compatible with React Native because latter one lacks support for the Blob API, which is to my limited knowledge not true anymore: https://forums.expo.io/t/react-native-now-has-full-blob-support/7652

Therefore, I assume that tus-js-client is compatible until we are proven the other way :) Feel free to comment if you have a different experience.

@Acconut Acconut closed this as completed May 7, 2018
@michaelost
Copy link

I receive document is not defined error. this package is build by browserify ( a tool for using nodejs modules in browser env) react-native is not a browser.
I think it could be used if it was built by some other tool which will port it to react-native

@Acconut
Copy link
Member

Acconut commented Jun 16, 2018

I receive document is not defined error.

This error is unexpected, since tus-js-client never accesses the document object on its own. Would you mind sharing more details about this error, for example a stack trace?

I think it could be used if it was built by some other tool which will port it to react-native

I don't have much knowledge in the Reactive Native topic, so what are the other tools using which it would work?

@kvz
Copy link
Member

kvz commented Jul 9, 2018

We're trying to get tus-js-client to work with React Native now in #114 (comment). Just sharing in case it's still relevant to someone here.

@arturi
Copy link
Contributor

arturi commented Aug 6, 2018

I think the issue is here:

import resolve from "resolve-url";

And resolve-url is the one calling document:

https://github.com/lydell/resolve-url/blob/c99e0ad30108ccdf73e10eddbe7c8b2080c57740/resolve-url.js#L21-L22

img_5746

@arturi
Copy link
Contributor

arturi commented Aug 6, 2018

@Acconut
Copy link
Member

Acconut commented Aug 6, 2018

And resolve-url is the one calling document:

Ah, that makes sense and also explains the error that @michaelost was reporting. I believe it should be straightforward to replace resolve-url with Node's URL module (https://nodejs.org/api/url.html#url_url_resolve_from_to) in the browser. I can take care of that later this week.

Also stumbled upon https://www.npmjs.com/package/react-native-tus-client (https://github.com/vinzscam/react-native-tus-client), just so we are aware :)

That's cool, thanks, I will add it to https://tus.io/implementations.html

@Acconut Acconut reopened this Aug 6, 2018
@Acconut Acconut mentioned this issue Aug 6, 2018
Acconut added a commit that referenced this issue Aug 7, 2018
This should make tus-js-client compatible with React Native.
For more details on this, see
#96 (comment)
@Acconut
Copy link
Member

Acconut commented Aug 7, 2018

@arturi I pushed a fix to master which should remove the dependency on document. Would you mind trying it out?

@arturi
Copy link
Contributor

arturi commented Sep 8, 2018

Tried, sorry for the delay (vacation).

It works past that point now, thanks! But new challenges await:

15:19:25: Attempting a tus upload in React Native...
15:19:25: with file:  Object {
15:19:25:   "name": "photo.jpg",
15:19:25:   "type": "image",
15:19:25:   "uri": "file:///var/mobile/Containers/Data/Application/AC49A969-48D5-4F15-BA7F-5CCF2F02F86C/Library/Caches/ExponentExperienceData/%2540anonymous%252Fuppy-react-native-a2529c4e-cab0-4fd9-ace0-84147e9407ba/ImagePicker/05D11F93-C178-4B1C-83E0-5697EA29D5AB.jpg",
15:19:25: }
15:19:30: [Unhandled promise rejection: Error: source object may only be an instance of File or Blob in this environment]
- node_modules/tus-js-client/lib.es5/browser/source.js:43:18 in getSource
- node_modules/tus-js-client/lib.es5/upload.js:122:57 in start
* tus-test.js:27:2 in testUploadFileWithTus
* App.js:62:26 in addFileToUppy
* App.js:116:29 in <unknown>
- node_modules/promise/setimmediate/core.js:37:14 in tryCallOne
- node_modules/promise/setimmediate/core.js:123:25 in <unknown>
- ... 8 more stack frames from framework internals

because this:

export function getSource(input) {
// Since we emulate the Blob type in our tests (not all target browsers
// support it), we cannot use `instanceof` for testing whether the input value
// can be handled. Instead, we simply check is the slice() function and the
// size property are available.
if (typeof input.slice === "function" && typeof input.size !== "undefined") {
return new FileSource(input);
}
throw new Error("source object may only be an instance of File or Blob in this environment");
}

I wonder what the correct solution is, uploading with xhr works with React Native’s “fake blob”.

file object is what I receive from React Native’s image picker the uri contains the path to the file, and if I use this photo object with uri in it, instead of the real File/Blob instance, the upload just works:

    var photo = {
      uri: file.uri,
      type: file.type,
      name: 'photo.jpg',
    }

    this.uppy.addFile({
      source: 'React Native',
      name: 'photo.jpg',
      type: file.type,
      data: photo
    })

There’s https://github.com/itinance/react-native-fs, so we could utilize that, I guess, to convert this absolute path uri into a blob?

Just wanted to drop some thoughts in here and get some feedback. If I understand correctly, tus-js-client needs to split the file blob into chunks before uploading, so we can’t just use the uri and wait till it’s magically uploaded somehow, as with regular xhr uploads.

Also looking through https://github.com/vinzscam/react-native-tus-client/blob/master/dist/index.js:

import { Upload } from 'react-native-tus-client';
 
const absoluteFilePath = // absolute path to your file;
const upload = new Upload(absoluteFilePath, {
  endpoint: 'https://master.tus.io/files/', // use your tus server endpoint instead
  onError: error => console.log('error', error),
  onSuccess: () => {
    console.log('Upload completed! File url:', upload.url);
  },
  onProgress: (uploaded, total) => console.log(
    `Progress: ${(uploaded/total*100)|0}%`)
});
upload.start();

@Acconut
Copy link
Member

Acconut commented Sep 18, 2018

@arturi Thanks for reporting back. What image picker are you using for React Native? And what type/object are getting exactly back from it?

@arturi
Copy link
Contributor

arturi commented Sep 18, 2018

@Acconut Using ImagePicker in Expo: https://docs.expo.io/versions/v28.0.0/sdk/imagepicker#__next, here’s how I’m using it: https://github.com/transloadit/uppy/pull/988/files#diff-4f1024053febb37a1923a977beb49123R110.

Other “official“ pickers seem to have similar API https://github.com/react-community/react-native-image-picker#usage.

file object is what I receive from React Native’s image picker the uri contains the path to the file

From Expo ImagePicker docs:

Otherwise, returns { cancelled: false, uri, width, height, type } where uri is a URI to the local media file (useable as the source for an Image/Video element), width, height specify the dimensions of the media and type is one of image or video telling what kind of media has been chosen. Images can contain also base64 and exif keys. base64 is included if the base64 option was truthy, and is a string containing the JPEG data of the image in Base64--prepend that with 'data:image/jpeg;base64,' to get a data URI, which you can use as the source for an Image element for example. exif is included if the exif option was truthy, and is an object containing EXIF data for the image--the names of its properties are EXIF tags and their values are the values for those tags. If a video has been picked the return object contains an additional key duration specifying the video's duration in miliseconds.

I previously tried to use base64 option to convert that into a blob (which seems like it will only work for images, while we’d want to support any file in the future), but that didn’t work, maybe I was doing something wrong.

I guess reading an absolute path into a blob before passing to tus-js-client is the way to go here, but wanted to discuss, cause there’s different treatment for the browser vs node environment in tus-js-client, maybe that’s where we should be handling absolute paths as well. Found this: https://medium.com/@davidjsehl/react-native-and-the-infamous-blob-uploading-images-to-firebase-b1a440f9e078. And this: react-native-image-picker/react-native-image-picker#564.

Whenever I find a solution to uploading from React Native, it comes down to “just pass the uri as if it was a blob”, because React Native’s FormData thing understands absolute paths: react-native-image-picker/react-native-image-picker#798.

@Acconut
Copy link
Member

Acconut commented Sep 18, 2018

@arturi Thanks for the details, now I understood that the file picker simply return a URI to you. It's nice that this works seamlessly with FormData but we need a blob (or something similar) which we can slice as we want. Do you know if it's a viable option to use https://github.com/itinance/react-native-fs (or similar) to get a Blob from the URI?

@Acconut
Copy link
Member

Acconut commented Sep 19, 2018

@arturi I have dug a bit more into this topic and it seems like there is no simple and easy way to fully support React Native in tus-js-client. It may be possible but there is definitely some more work involved.

However, there is https://github.com/vinzscam/react-native-tus-client which builds upon tus-android-client and TUSKit to provide a JavaScript API similar to tus-js-client. Maybe it's possible to use https://github.com/tleunen/babel-plugin-module-resolver in order to rewrite Uppy's dependency of tus-js-client to react-native-tus-client.

Let me know if this sounds possible to you.

@Acconut
Copy link
Member

Acconut commented Nov 6, 2018

For Expo applications we might be able to use Expo.FileSystem.readAsStringAsync (https://docs.expo.io/versions/latest/sdk/filesystem#expofilesystemreadasstringasyncfileuri-options) with its length and position options for reading chunks of the upload. However, this is an Expo-specific API which is not available when you not use Expo (I guess? I am not exactly sure how this React Native ecosystem looks like currently).

For non-Expo we would then need to resort to https://github.com/itinance/react-native-fs (or similar) which requires building a native extension AFAIK.

It would be nice to have a solution which works for all React Native use cases but I am too unexperienced in this ecosystem to judge that.

@kvz Would you be OK if I allocate a bigger chunk of my time to deep-dive into React Native to figure this properly out?

@kvz
Copy link
Member

kvz commented Nov 6, 2018

@kvz Would you be OK if I allocate a bigger chunk of my time to deep-dive into React Native to figure this properly out?

Figuring this out is clearly hard, but/so that also means there is great value in it for others if we succeed dealing with the ugly realities and consuming devs can just npm install uppy or npm install tus-js-client and be on their way, regardless of Node/Browser/React Native. Whether that's really even possible remains to be seen but the closer we get to an abstraction like that, the better. Seeing as this is currently the big blocker for getting Uppy to 1.0, I would be very happy if you're able to get involved in a deeper way 👌

@Acconut
Copy link
Member

Acconut commented Dec 10, 2018

A small status update: tus-js-client is now fully compatible with React Native and can be used without additional work. Please see the README for more details: https://github.com/tus/tus-js-client#react-native-support

@Ectsang
Copy link

Ectsang commented May 13, 2020

Hi @Acconut I'm still having problems with getting the error:
Upload error [Error: source object may only be an instance of File, Blob, or Reader in this environment]

The image picker I used was
"expo-image-picker": "~8.1.0",

The tus js client version:
"tus-js-client": "^2.0.0-1"

I'm testing on an Android device with expo

The image picker returns the absolute path to the mp4 video I selected:
file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540goodmeta%252Fpace-universal-app/ImagePicker/10d9da36-7e81-4b20-9e2a-536cbc227eb5.mp4

Any hints/things you see I'm doing wrong? Thanks!

@Acconut
Copy link
Member

Acconut commented May 15, 2020

@Ectsang Are you passing in the file URI directly to the Upload constructor? If so, that's not correct and you need to pass it an object:

new tus.Upload({
  uri: "file:///...",
  ...
});

See https://github.com/tus/tus-js-client/blob/master/docs/installation.md#react-native-support for more details.

@Tanush-J
Copy link

Tanush-J commented May 9, 2024

@Acconut in the React Native demo

new tus.Upload({
  uri: "file:///...",
  ...
});

This part is not updated, it still shows to pass the file in upload constructor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants