Download Word .docx as Blob file from Angular on mobile devices - android

I am trying to download .docx file from REST API (.NET Core FileContentResult) in Angular application. Everything is working fine on PC, but there is problem with downloading .docx files in VMware Workspace ONE Web browser (didn't try standard browsers like Chrome or Safari, it looks like there is just Android WebView). It is company application and this browser is the only one allowed.
The problem is only with .docx files. Files like PDF, .doc and .xlsx (created by ClosedXML) are working fine.
REST API call (also tried with 'arraybuffer' instead of 'blob' and created Blob object in client, but problem persists)
this.httpClient.get(requestUrl, {
responseType: 'blob',
observe: 'response'
});
Then I save response body with FileSaver.
generateDocument(file: string | Blob, name: string): void {
FileSaver.saveAs(file, name);
}
I also tried approach that creates link and click on it (it does not work).
Solution with using window.open(blobUrl) is not working.
EDIT:
I got information that it is not working at all in iOS with same browser. Users get error message "Link is invalid."
Can someone help me with this issue? Thanks.

If you can retrieve obtain an ArrayBuffer, this could be used to initiate the download with those bytes:
Test here: https://batman.dev/static/70085191/
async function downloadUrl(url) {
downloadBuffer(
await (await fetch(url)).arrayBuffer()
)
}
function downloadBuffer(arrayBuffer) {
const a = document.createElement('a')
a.href = URL.createObjectURL(new Blob(
[ arrayBuffer ],
{ type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }
))
a.download = 'my-file.docx'
a.click()
}

Related

Flutter: cannot download file from object url in webview

I need to download, from a mobile app developed in flutter 1.22.2, a file generated by a php script. The file is available in blob format.
The javascript code in the web page is:
response.blob()
.then(blob => URL.createObjectURL(blob))
.then(url => {
let a = document.createElement('a');
a.href = url;
a.download = 'modulo-' + JobRiskIden + '.pdf';
a.target = '_blank';
document.body.appendChild(a);
a.click()
a.remove();
})
Where "response" variable is the response from a fetch to a php page that generates the file.
I followed the instructions from this stackoverflow question:
Flutter WebView blob pdf download
The download works fine on iOS but an issue is present on Android (test done with compileSdkVersion 29): when I tap on the download link the debugger prints this message:
{message: Not allowed to load local resource: blob:https://apps.badgebox.com/62edb40f-4407-4d3b-8427-587ea133b778, messageLevel: 3}
Can someone help me to solve this issue?

Uploading Audio to Cloudinary

this is my first Stack Overflow post so please go easy on me!
I'm building an audio recording app using EXPO as the SDK with React Native. One of the main features of the app is to be able to to record live audio as well as uploading audio from the client's device. By leveraging Expo's Audio API and FileSystem, I'm successfully able to record and save live audio and then retrieve it via FileSystem to upload, however I'm running in an error when I try to pass the localUri to upload to my Cloudinary database. There is very little documentation in regards to audio and audio uploads to cloudinary are clumped into video uploads so there's nothing audio specific to really point me in the right direction. I've tried converting the URI to base64 as well as a variety of MIME types but the response from Cloudinary with a secure url returns empty/undefined. I've successfully uploaded images with this method so you can imagine how frustrating it is. Here's my code that grabs a recording and tries to upload it to Cloudinary:
DocumentPicker.getDocumentAsync({
type: '*/*',
copyToCacheDirectory: true,
base64: true
})
.then(succ => {
//check out the saved info
console.log(succ, `path: ${succ.uri}, type: ${succ.type}, name: ${succ.id}, size: ${succ.size}`)
let Base64 = {/* Truncated Base64 object*/};
let base64Aud = `data:audio/x-wav;base64, ${Base64.encode(succ.uri)}`;
let cloud = `https://api.cloudinary.com/v1_1/${CLOUD_NAME}/upload`;
const data = {
'file': base64Aud,
'upload_preset': CLOUDINARY_UPLOAD_PRESET,
'resource_type': 'video',
}
fetch(cloud, {
body: JSON.stringify(data),
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
method: 'POST',
})
.then(async r => {
let data = await r.json()
console.log('cloudinary url:', data.secure_url)
return data.secure_url
})
.catch(err => console.log(err))
}
This call prints the following to the console:
Object {
"name": "20200117_143416.mp4",
"size": 519612343,
"type": "success",
"uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Faloud-aaf24bff-8000-47f0-9d1c-0893b81c3cbc/DocumentPicker/c922deb7-fd4f-42d9-9c28-d4f1b4990a4c.mp4",
} path: file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Faloud-aaf24bff-8000-47f0-9d1c-0893b81c3cbc/DocumentPicker/c922deb7-fd4f-42d9-9c28-d4f1b4990a4c.mp4, type: success, name: undefined, size: 519612343
data:audio/x-wav;base64, ZmlsZTovLy9kYXRhL3VzZXIvMC9ob3N0LmV4cC5leHBvbmVudC9jYWNoZS9FeHBlcmllbmNlRGF0YS8lMjU0MGFub255bW91cyUyNTJGYWxvdWQtYWFmMjRiZmYtODAwMC00N2YwLTlkMWMtMDg5M2I4MWMzY2JjL0RvY3VtZW50UGlja2VyL2M5MjJkZWI3LWZkNGYtNDJkOS05YzI4LWQ0ZjFiNDk5MGE0Yy5tcDQ=
cloudinary url: undefined
Does anyone see any glaring issues or have any insight on this issue? Better yet, successfully uploaded audio to Cloudinary from the client using Expo & React Native? Thanks!
While I can't say for certain why the uploads fail in your case without seeing the error returned by Cloudinary, I have created a working JSFiddle which you can use to upload a Base64 data URI encoded audio file (1-second audio in my example to keep it short). Just replace your cloud name in the API endpoint URL and set the upload preset. Once that uploads successfully in your account you can replace the example with your Base64 Data URI and see if it works or not. That will tell you if the issue is with the Base64 String itself. Having said that, sharing the error returned by Cloudinary would be the best indicator.
Example code below:
var fd = new FormData();
fd.append("file", "data:audio/mpeg;base64,SUQzBAAAAAABBFRYWFgAAAASAAADbWFqb3JfYnJhbmQ...");
fd.append("upload_preset", "");
fd.append("resource_type", "video")
fetch('https://api.cloudinary.com/v1_1/cloud_name_here/upload',
{
method: 'POST',
body: fd
}
);

How can I retrieve a file from the file system using React Native, for conversion to base64 and http posting as JSON?

I am using the react native template from this article. The code is all available on Github here.
You can use the app to record audio and save to the file system. I figured out how to retrieve the file URIs, but I'm finding it impossible to get the actual contents of the file itself. All I want to do is retrieve the actual file contents as a binary or ascii or hex string or whatever (it's a .m4a file), so I can convert it to base64 encoding and then post it as JSON to my server. Here's what my code looks like:
/src/screens/RecordAudioScreen/RecordAudioScreenContainer.js
onEndRecording: props => async () => {
try {
// here is the URI
console.log("HERE IS THE URI!!");
const audio_data = "URI: " + props.recording._uri;
// Help needed here
// retrieve file contents from the Android/iOS file system
// Encode as base64
audio_data = ... // ???????
// this works already, posts to the server
fetch("https://myserver.com/accept_file",
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify({user_id: 1, audio_data: audio_data})
})
.then(function(res){ console.log(res) })
.catch(function(res){ console.log(res) });
console.log("FINISHED POST REQUEST!!!")
await props.recording.stopAndUnloadAsync();
await props.setAudioMode({ allowsRecordingIOS: false });
} catch (error) {
console.log(error); // eslint-disable-line
}
if (props.recording) {
const fileUrl = props.recording.getURI();
props.recording.setOnRecordingStatusUpdate(null);
props.setState({ recording: null, fileUrl });
}
},
I've already tried a bunch of stuff with no success. Ideally I just get the file contents from the File system, convert to base64 and post it off all in this method just in javascript, but this is seemingly very difficult for what should be a pretty standard thing to do in an app based framework.
Here's some stack overflow questions on React Native Fetch Blob which I couldn't make work Fetch Blob 1 Fetch Blob 2
I've tried using React Native Fs, but I can't get it to load properly, I got super bogged down in stuff I didn't understand after trying to eject the app. I'd prefer a plain React Native solution if possible.
I've also tried some code using FormData but couldn't get that to work either.
Maybe the answer is kind of like this question about retrieving images from firebase? I don't know, this is my first attempt at doing anything in React.
It might also have something to do with the "file://" prefix in the URI that gets generated because there's a lot of questions discussing removing that (only for Android, or only for iOS I'm not too clear).
Converting to base64 will be done with something like this, but I need the actual file contents first:
Very appreciative of any help.
Some time ago I wrote a simple example of a record voice app.
To get the files I used this method:
import RNFS from 'react-native-fs';
(...)
getFiles() {
RNFS.readDir(AudioUtils.DocumentDirectoryPath)
.then((result) => {
this.setState({recordedFiles: result});
return Promise.all([RNFS.stat(result[0].path), result[0].path]);
})
.catch((err) => {
console.log(err.message, err.code);
});
}
It worked just fine.
Here's the full example https://github.com/soutot/react-native-voice-record-app
Let me know if it helped. Otherwise we can try a different approach

Show PDF downloaded from API in Ionic / Angular

I need to hit an API endpoint, which returns a pdf file (not a url to a pdf, but the actual data), then somehow display this pdf in my ionic application. Ideally, I'd like to just give it to some other application like the phone's mobile web browser but I'd be open to trying to embed it within my app as well. On iOS, I just use $window.open(url) and mobile safari knows to download and display the pdf that is returned. However, Android tries to download the file then tells me that it can't be opened when I try to open it.
I've also tried embedding it in the app with <embed> but nothing gets embedded. However, a similar method works with images in <img ng-src="url">.
I've also tried messing around with cordova FileOpener2 but am having a lot of trouble getting anything to work in that. If that's the right way to do this, I'd be open to re-visiting that method.
The closest I've gotten is definitely just sending it to the devices mobile browser as that works perfectly on iOS.
I solved it using filetransfer and fileopener2. My code is below. The main issues I ran into was not having <access origin="cdvfile://*" /> in my config.xml file and not having ngCordova installed correctly.
if (ionic.Platform.isIOS())
$window.open(APIUrl, '_blank', 'location=no');
else if (ionic.Platform.isAndroid()) {
var fileExtension = filename.substr(filename.lastIndexOf('.')+1);
//I have a dictionary with this somewhere else
var MIMEType = extToMime[fileExtension];
var uri = encodeURI(APIurl);
var fileURL = "cdvfile://localhost/persistent/file."+fileExtension;
$cordovaFileTransfer.download(uri, fileURL, {}, true)
.then(function(result) {
$cordovaFileOpener2.open(
fileURL,
MIMEType
).then(function() {
console.log("SUCCESS");
}, function(e) {
console.log("ERROR");
console.log(JSON.stringify(e));
});
}, function(e) {
console.log("Error: " + JSON.stringify(e));
});
}

upload image file from jquery to node.js

I am trying to upload a file from andriod application, using Jquery to node.js using express..
My client side code is:
function uploadData(win) {
var padI = imagedata.length-1
while( '=' == imagedata[padI] ) {
padI--
}
var padding = imagedata.length - padI - 1
var user = load('user')
$.ajax({
url:'http://'+server+'/lifestream/api/user/'+user.username+'/upload',
type:'POST',
contentType: false,
processdata:false,
data:imagedata,
success:win,
error:function(err){
showalert('Upload','Could not upload picture.')
},
})
}
I have used post form without any content type because if i use multipart/form-data it says error about boundary ..
my server side code using node.js is:
function upload(req,res) {
var picid=uuid()
console.log('Got here..' + __dirname)
//console.log('Image file is here ' + req.files.file.path)
// console.log('local name: ' + req.files.file.name)
var serverPath = __dirname+'/images/' + picid+'.jpg'
fs.rename(
req.files.file.path,
serverPath,
function(error) {
if (error) {
console.log('Error '+error)
res.contentType('text/plain')
res.send(JSON.stringify({error: 'Something went wrong saving to server'}))
return;
}
// delete the /tmp/xxxxxxxxx file created during download
fs.unlink(req.files.file.path, function() { })
res.send(picid)
}
)
}
when the file comes to server, it gives an error of res.files.file is undefined ..
I have searched alot of forums, they say that res.files.file is only access when contenttype is multipart/form-data but then the boundary problem occurs
Any help on that is highly appreciated
Boundary is a special sequence of characters that separates your binary data.
You should submit MIME type as multipart/form-data, as well as set your imagedata to FormData() type (from your snippet it's not clear if it is FormData type).
Here are similar issues and solutions:
How to set a boundary on a multipart/form-data request while using jquery ajax FormData() with multiple files
jQuery AJAX 'multipart/form-data' Not Sending Data?
A great alternative to writing this code is to use filepicker.io This allows you to connect to yoru own s3 bucket. When the file is saved, you get back a callback with the S3 url, you can then simply pass that url to your node api, and save it. I have used this to avoid having to write extra server code for handling file uploads. Extra bonus, if you need to do this with images, and want users to be able to edit the images, you can use Aviary which allows an image to be edited locally, and you then get back another s3 url, that you can then save to your server..

Categories

Resources