itinance / react-native-fs

Native filesystem access for react-native
MIT License
4.95k stars 978 forks source link

copyAssetsVideoIOS not working properly. #572

Open BetterYouCode opened 5 years ago

BetterYouCode commented 5 years ago
"react": "16.3.1",
"react-native": "0.55.4",
"react-native-fs": "^2.9.12",
"react-native-gallery-manager": "^1.0.9",

Hello there, I've media picker screen like this, this, which allow user to select category & media (Images & Video). So, I'm fetching phone assets from CameraRoll using react-native-gallery-manager library. It's return me images & video URL like, assets-library://. this kind of URL can show images properly using <Image />, but to load/play video, I need URL like file:// for <Video /> & that's why I'm using this package, to fetch video's proper URL.

checkout my code.

// GalleryManager Usage
GalleryManager.getAssets({
  type: 'all',
  limit: 60,
  startFrom: this.state.images.length,
}).then(data => this.storeImages(data))

// storeImages Usage
storeImages(data) {

  const tempObj = data.assets;
  alert('total data get : ' + tempObj.length);
  if (tempObj.length > 0) {
    const imagesObj = tempObj.filter((tempValue) => tempValue.duration <= 90)
    if (Platform.OS === 'ios') {
      for (let i = 0; i < imagesObj.length; i++) {
        let tempData = imagesObj[i];
        if (tempData.type === 'video') {
          const res = await RNFS.copyAssetsVideoIOS(
            tempData.uri,
            `${RNFS.TemporaryDirectoryPath}${tempData.filename}`
          )
          tempData.uri = "file://" + res;
          imagesObj[i] = tempData;
        }
      }
      const imagesData = imagesObj.map(newData => ({
        imageLocation: newData.uri,
        fileType: newData.mimeType.split('/')[0]
      }));
      this.setState({
        images: [...images, ...imagesData]
      });
    } else {
      const imagesData = imagesObj.map(newData => ({
        imageLocation: newData.uri,
        fileType: newData.mimeType.split('/')[0]
      }));
      this.setState({
        images: [...images, ...imagesData]
      });
    }
  }

}

It's not showing me any output. checkout this images IPhone Xs max screenshot is of iPhone Xs max (IOS 12) real device (not of simulator) It's also showing me alert like : total data get : 60. however in simulator It's working fine.

if I comment entire for loop of my code, It's showing me images properly. checkout following snapshot. iPhone Xs max

Issue was clear for me that RNFS.copyAssetsVideoIOS is not working as expected. I think this happening because phone contain many 4K quality video & might be It's taking so much time to download video from iCloud as you guys have mentioned here. but It's not returning anything forever.

Thank you. Looking forward to your reply.

robyweb commented 5 years ago

I'm having a similar experience where I am calling copyAssetsVideoIOS on an iCloud file, and nothing is happening. No error, or anything, no promise created. Just silently continues.

Any idea on how to get around this?

juanluisgv1 commented 5 years ago

I'm having the exact same issue as mentioned by @BetterYouCode. I have been checking the native code and the problem seems to be related to this part of the code:

[[PHImageManager defaultManager] requestAVAssetForVideo:phAsset options:nil resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {

    // ==> asset is nil when the code arrives to this line 
    if ([asset isKindOfClass:[AVURLAsset class]]) {
      NSURL *url = [(AVURLAsset *)asset URL];
      NSLog(@"Final URL %@",url);
      NSData *videoData = [NSData dataWithContentsOfURL:url];

      BOOL writeResult = [videoData writeToFile:destination options:NSDataWritingAtomic error:&error];

      if(writeResult) {
        NSLog(@"video success");
      }
      else {
        NSLog(@"video failure");
      }
      dispatch_group_leave(group);
    }
  }];

I realised that first, the iCloud issues could be right and that the options weren't sent. After some research, I find out that adding this code fix the issue :)

…
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc]init];
options.version = PHVideoRequestOptionsVersionOriginal;
options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
options.networkAccessAllowed = YES;

[[PHImageManager defaultManager] requestAVAssetForVideo:phAsset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) { … }

Here a PR that should work https://github.com/itinance/react-native-fs/pull/601

EDIT I realised that @robyweb also did a PR (similar code) and you can find it here: https://github.com/itinance/react-native-fs/pull/599