Asset support in React Native on Skygear


#1

Hi, want to discuss about the Asset in React Native

According to asset.js

else if (base64) {
      file = base64StringtoBlob(base64);
    }

seems that even if I supply a base64 string, it will create a Blob anyways, but Blob/File is not support in RN yet.

So I’ve spent some time digging into the source code and edited the database.js to make it work

function makeUploadAssetRequest(container, asset) {
  return new Promise(function (resolve, reject) {
    container.makeRequest('asset:put', {
      filename: asset.name,
      'content-type': asset.contentType,
      'content-size': asset.file.size || asset.uriFileSize
    }).then(function (res) {
      var newAsset = _asset2.default.fromJSON(res.result.asset);
      var postRequest = res.result['post-request'];

      
      var postUrl = postRequest.action;
      if (postUrl.indexOf('/') === 0) {
        postUrl = postUrl.substring(1);
      }
      if (postUrl.indexOf('http') !== 0) {
        postUrl = container.url + postUrl;
      }

      if(navigator.product === 'ReactNative'){

        const data = new FormData();
        _.forEach(postRequest['extra-fields'], function (value, key) {
          data.append(key, value);
        });
        data.append('file', {
          uri: asset.file,
          type: asset.contentType
        });

        fetch(postUrl, {
          method: 'post',
          headers: {'X-Skygear-API-Key': container.apiKey},
          body: data
        })
        .then(function (res){
          resolve(newAsset);
        })
        .catch(function (err) {
          if (err) {
            reject(err);
            return;
          }
        });


      }else{

        var _request = container.request.post(postUrl).set('X-Skygear-API-Key', container.apiKey);
        if (postRequest['extra-fields']) {
          _.forEach(postRequest['extra-fields'], function (value, key) {
            _request = _request.field(key, value);
          });
        }

        _request.attach('file', asset.file).end(function (err) {
          if (err) {
            reject(err);
            return;
          }

          resolve(newAsset);
        });
      }

    }, function (err) {
      reject(err);
    });
  });
}

Basically I’m detecting if RN and then use the RN’s fetch() method instead of the default superagent, it seems to be working fine on my local settings.

p.s. I’m just putting the local file uri string (file://) into the file field when creating skygear.Asset, so I’ve added uriFileSize to asset.js for the asset:put action.

Not really a JS developer yet, just a quick hack, please help refractor/restructure the above workaround or give guidance on a proper pull request? May be you prefer overriding? inside dist/react-native


#2

Oh, didn’t know XMLHttpRequest supports uri for uploading file also, ignore the above suggestion.

Solution for uploading file in RN should be: https://gist.github.com/tenwy/709546562c7eb962e04300c5a06ed191

Thanks Ten


#3

Great! I will add it back to the doc :slight_smile: