Phonegap/Cordova ... delete temporary filesystem after taking a picture - ios

I've discovered that my Phonegap/Cordova app on iOS is saving all the pictures I take with the camera and uploading them to a server.
In iPhone settings under the "use" tap there is my app and the disk size it needs is increasing, even after quitting the app.
So how could I delete these temporary files, or the picture itself, after it was uploaded to my server? I use the pictureURI to locate it for uploading.
EDIT: thanks. I've implemented the code and now it looks like this:
In my fileupload function I've added this line:
window.resolveLocalFileSystemURI(fileURI, onResolveSuccess, faillocal);
and the other functions look like:
function onResolveSuccess(fileEntry) {
console.log(fileEntry.name);
entry.remove(entrysuccess, failresolve);
}
function entrysuccess(entry) {
console.log("Removal succeeded");
}
function failresolve(error) {
alert('Error removing directory: ' + error.code);
}
function faillocal(evt) {
console.log(evt.target.error.code);
}
But it doesn't work. File is uploaded, but no alert, no console writing, no deleting at all...

You should be able to take the picture URI and pass it to window.resolveLocalFileSystemURI and then in the success callback of this method you will get a FileEntry object which you can call the remove method on.

I'm not sure which version of PhoneGap / Cordova this cleanup method was introduced, but it looks to do what you need, with a lot less code: http://docs.phonegap.com/en/2.2.0/cordova_camera_camera.cleanup.md.html#camera.cleanup

Related

find and share a downloaded video on Flutter ios without going through picker?

I have a Flutter app that can view mp4 files from a URL. (Using a video controller playing directly from the URL.) I want the user to be able to share them if they wish. As best I can tell the file has to actually exist on the device so I have broken down the steps for now into download file, invoke share.
I'm using this guide: https://retroportalstudio.medium.com/saving-files-to-application-folder-and-gallery-in-flutter-e9be2ebee92a
I need to work on ios and android. The problem is that on ios neither the filename I get from the dio downloader nor the ImageGallerySaver seem to "work" when passed to the system ShareSheet.
I'm using the flutter extensions dio, share_plus, cross_file, image_gallery_saver as I've seen recommended in various places.
File saveFile = File(directory.path + "/$fileName");
developer.log("starting download...");
await dio.download(url, saveFile.path,
onReceiveProgress: (value1, value2) {
developer.log("got progress " + value1.toString());
setState(() {
downloadProgress = value1 / value2;
});
});
_permaFile = saveFile.path;
if (Platform.isIOS) {
var galleryResult = await ImageGallerySaver.saveFile(saveFile.path,
isReturnPathOfIOS: true);
developer.log("gallery save result = " + galleryResult.toString());
_permaFile = galleryResult['filePath'];
}
After getting a directory we use dio to download the file, do some log chirping, and then save the name to an object member called _permaFile.
Then the share button triggers:
void _shareAction() async {
final box = context.findRenderObject() as RenderBox?;
final files = <XFile>[];
if (_permaFile == null) {
return;
}
developer.log("sharing file: " + _permaFile.toString());
files.add(XFile(_permaFile!));
await Share.shareXFiles(files,
text: "Event",
// subject: "Subject for Event",
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size);
}
This works on android device... after I download I hit share, and I can share the video to a third-party app like WhatsApp.
On ios the ShareSheet is invoked but when I share I only get the text "Event", not the video file that goes along with it.
Note that I have tried both results... setting the _permaFile to be what comes back from ImageGallerySaver but also just using what the dio downloader gives back.
Note also that the ImageGallerySaver seems to work: the video really does land and is there in the ios video lib. If I go into the Photos app I can share from there to WhatsApp and have the video get sent.
In each case I get errors like this:
[ShareSheet] error fetching item for URL:file:/var/mobile/Media/DCIM/100APPLE/IMG_0021.MP4 -- file:/// : (null)
[ShareSheet] error fetching file provider domain for URL:file:/var/mobile/Media/DCIM/100APPLE/IMG_0021.MP4 -- file:/// : (null)
[ShareSheet] error loading metadata for
documentURL:file:/var/mobile/Media/DCIM/100APPLE/IMG_0021.MP4 --
file:/// error:Error Domain=NSFileProviderInternalErrorDomain Code=0
"No valid file provider found from URL
file:/var/mobile/Media/DCIM/100APPLE/IMG_0021.MP4 -- file:///."
UserInfo={NSLocalizedDescription=No valid file provider found from URL
file:/var/mobile/Media/DCIM/100APPLE/IMG_0021.MP4 -- file:///.}
In order to test this further I built the share_plus demo app:
https://github.com/fluttercommunity/plus_plugins/tree/main/packages/share_plus/share_plus
I modified it to share videos to see what was different. The share plus example (sp_example) works for sharing videos that have been selected by the picker.
For this reason I think the problem is something I'm missing about ios video filenames/formats and possibly a built-in conversion step that happens.
Here are what the filenames look like that I see in my app:
dio download result:
file:///var/mobile/Containers/Data/Application/223BF2B9-DDF0-490E-932F-09D5F03B98B3/Library/Caches/test.mp4
ImageGallerySaver result:
file:///var/mobile/Media/DCIM/100APPLE/IMG_0019.MP4
This is what video filenames look like when they are picked and shared in sp_example:
/private/var/mobile/Containers/Data/Application/E5CB4D7C-6CDF-4AA2-8134-C4322ED7C886/tmp/trim.E6633D68-44E3-4853-A29E-A71AC95A0913.MOV
Note that it has been converted to MOV extension and the user gets trim step right in the picker that results in trim in the name.
For my purposes I don't want to go through the picker, the user is on the screen showing the video and they shouldnt have to repick, so where do I get the post-conversion ios filename that references what I just saved?

React Native HTML to PDF not displaying local images

In case you guys don't know, there was a problem previously with this library not rendering local images on Android as well, but apparently it was solved. Now, I'm facing the exact same issue on iOS, with a difference that I can use static images like assets/src/assets/images/logo.png. But when the images start with something like file:///, storage://, ph:// it simply does not get rendered.
What I'm doing is trying to generate a PDF report file, which must be generated independently the user has an internet connection or not. That is the reason why I have to use local images.
The static image is the logo of the company, and the local image which is not getting rendered is an image saved to the phone's storage through Image Picker or Camera Roll. The React Native Image component displays the image perfectly, so I don't think I'm using a wrong path.
What I have tried so far:
Removing the file:/// or storage:// or ph:// from the beginning of the path string;
In some cases, when I save an image to the phone's library with Camera Roll, it will return a path that starts with ph:// but without an extension, such as .jpg or .png. I tried to put the extension manually, and still does not make any difference;
I tried to convert the image to base64 using rn-fetch-blob (with RNFetchBlob.fs.base64.encode(path)), but still got no success.
Devices:
iPhone SE with iOS 14 (also simulator iPhone 11 with iOS 15)
MacBook Air 2017 Core i5 1.8GHz and 8gb RAM (macOS Big Sur 11.5.2)
Environment
node: 12.22.7
npm: 6.14.15
react: 16.9.0
react-native: 0.61.5
react-native-html-to-pdf: ^0.11.0 (updating it to 0.12.0 also got me the same result)
Code:
sharePDF = async () => {
try {
this.changeVisibilityOptions(false);
this.changeVisibilityLoading('Gerando PDF...');
let htmlTemplate = '';
htmlTemplate = await getPDFDespesa(this.state);
const pdfOptions = {
html: htmlTemplate,
fileName: 'RelatorioDespesas',
directory: 'Relatorios'
};
let pdfFile = await RNHTMLtoPDF.convert(pdfOptions);
this.changeVisibilityLoading(false);
const shareOptions = {
title: 'Compartilhar com:',
url: `file://${pdfFile.filePath}`,
type: 'application/pdf',
failOnCancel: false
};
const ShareResponse = await Share.open(shareOptions);
} catch (error) {
this.setState({ visibilityLoadingScreen: false });
console.log('Error =>', error);
}
}
Final thoughts:
Well, since the code is stored at a private repository, I can't show the whole thing here for ethical reasons. But I'm doing my best to give you as much details as possible.
The output the code produces an almost complete PDF, with the only point that I see broken image icons where the images were supposed to be. For Android it works perfectly now.
I think this might be an issue related to WebView, since react-native-html-to-pdf uses WebView to generate the PDF from HTML code. I reached this conclusion after another developer at my job was trying to create a screen with a preview of the PDF before it could be shared got the very same problem for both Android and iOS. The library he used was react-native-webview.
Update with solution
Alright guys, after a long time of research, me and a colleague got to a solution which may not be the best but does what we expected.
First of all, one thing that was discovered is that we have to divide the problem in two, because we actually had two problems.
Images from react-native-image-picker: After a long time trying to find the problem which was preventing the local images from getting rendered, I tried updating the library to version 4.7.3 (latest version at that day) and did a number of required changes to the code, as the version we were using was considerably aged. Well, it happened to work out for my surprise, even with the response uri's format not being changed;
Images from #react-native-community/cameraroll: This one was a bit more complicated. It took me some time to realize that the iOS' PHAsset was not supported in the WebView or react-native-html-to-pdf (which uses WebView in background). So, after some research, me and my colleague found a workaround that lead us to a relatively easy solution. Basically we used react-native-fs to copy the PHAsset media file to a temporary directory, which would return a uri that started with file:// and could be rendered by WebView. That's the code we used to do this:
export default function getImageNameFromUrl(imageUrl = "") {
if (imageUrl) {
const splittedImageUrl = imageUrl.split('/');
return splittedImageUrl.pop();
}
return null;
};
export default async function copyAssetsFileIOSAndReturnURI(remoteURL = '', localURI = '') {
try {
if (remoteURL && localURI) {
const imageName = getImageNameFromUrl(remoteURL);
const imgPath = await RNFS.copyAssetsFileIOS(localURI, RNFS.TemporaryDirectoryPath+imageName, 0, 0);
return imgPath;
}
return null;
} catch (err) {
console.log(err);
return null;
}
}

How to move/copy a file from one one location to the other using phonegap

I am using the Phonegap File API but am having trouble copying a file from one location to the other.
my targeted device is iOS(ipad)
my iOS version is 9.2.1
I am working on windows platform
I am using phonegap build
my requirement :
I am capturing a video and its getting saved in some temp folder by default here is the location where its getting saved (/private/var/mobile/Containers/Data/Application/2183897E-3660-4145-A822-76F5B763E48D/tmp/capture-T0x17e7cae0.tmp.avqBi2/capturedvideo.MOV)
So I just want to move this (capturedvideo.MOV) video to photo album location in my ipad
This is my code which i am trying to make it work.
function success(entry) {
console.log("New Path: " + entry.fullPath);
}
function fail(error) {
alert(error.code);
}
function moveDir(entry) {
var parent = document.getElementById('parent').value,
parentName = parent.substring(parent.lastIndexOf('/')+1),
newName = document.getElementById('newName').value,
parentEntry = new DirectoryEntry(parentName, parent);
// move the directory to a new directory and rename it
entry.moveTo(saveToPhotoAlbum, newName, success, fail);
}
Any help or working examples would be great.
Thanks
Nik`
This is simply not possible on iOS, because Apple does not allow to move videos, images or any other files out of the app sandbox to other folders. The reason that the standard-camera on the iPad/iPhone is able to place pictures there is simply because this is a built-in feature that has special permissions which your third-party app will not be able to get.
This is of course only true as long as the device is not jailbroken.
For more infos, especially concerning the file-system layout and what you are allowed to store, you should take a look at the cordova-file-plugin Readme on Github:https://github.com/apache/cordova-plugin-file

Cordova PushPlugin onNotificationAPN(e) callback not working or defined

I am working with Cordova / PhoneGap plugin PushPlugin and I have it setup pretty well and working, including a test .php and .pem file on my local server using a live device (iPhone 5). IOS 8. There are a couple of issues, with the main one being the call to this function in index.html:
function onNotificationAPN(event) {
console.log(event);
if (event.alert) {
$("#app-status-ul").append('<li>push-notification: ' + event.alert + '</li>');
// showing an alert also requires the org.apache.cordova.dialogs plugin
navigator.notification.alert(event.alert);
}
if (event.sound) {
// playing a sound also requires the org.apache.cordova.media plugin
var snd = new Media(event.sound);
snd.play();
}
if (event.badge) {
pushNotification.setApplicationIconBadgeNumber(successHandler, event.badge);
}
}
The console output for event is:
{"event":"message","payload":{"aps":{"alert":"My first push notification!","sound":"default"}},"foreground":true}
When the App is in the foreground the function onNotificationAPN(event) doesn't fire. "event" appears to be returned in or is converted to JSON format.
The IOS registration line is:
pushNotification.register(tokenHandler, errorHandler, {"badge":"true","sound":"true","alert":"true","ecb":"onNotificationAPN"});
How can I modify the code to decode the JSON format and display the alert, play sound, set the badge when the application is in the foreground. There must also be some documentation about the formats that the callback can take and the various options. Otherwise, seems to be working.
After a little playing around I guess that the callback "event" is actually already a JSON object:
console.log(e.event);
console.log(e.payload.aps.alert);
console.log(e.payload.aps.sound);
console.log(e.foreground);
prints out message, My first push notification!, default and true in the log.

(IOS) Cordova Camera Plugin Referring to deleted images

I'm building a cordova app (primarily for IOS & Android) in which the user can take an image, retake (, etc.) it and save it locally.
I'm currently struggling with the cordova cameraPlugin. So, here a short description of the problem.
When the user takes an image, it's saved locally in the apps temp folder and the user is able to view in in the UIWebView. On retaking, the image will be deleted from the temp folder and should not be available any longer (in RAM and local FS).
It works as long as the user doesn't retakes the image 2 or more times, if he does instead of the last image the first image will be referenced/rendered in WebView. After reopening the app, the image is displayed correctly.
An Example:
The user takes the first image. ==> cdv_photo_001.png
The second. ==> cdv_photo_002.png and the first one will be deleted (which seems to work correctly)
And the third. ==> cdv_photo_001.png and the second image will be deleted.
The third image will look the same as the deleted first one. This happens with every image after the third one.
It works fine after restarting the app
I've already tried to disable the App-Cache, delete the app cache before updating the image, refreshing the page and looking for answers online.
I'm getting an error when opening the camera UI, but I could not find a solution for it either.
Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before
snapshotting or snapshot after screen updates.
The code for the camera Call:
function getPhoto() {
navigator.camera.getPicture(getPhotoOnSuccess, getPhotoOnFail, {
quality: 25,
destinationType: Camera.DestinationType.FILE_URL,
correctOrientation: true,
encodingType: Camera.EncodingType.PNG
});
}
In getPhotoOnSuccess I'm basically saving the image path to a db and appending it with jQuery to the view.
And the code to delete the image: (sidenote I`m new to Objective C)
- (void) deleteImageByPath:(NSString *)imagePath withSelector:(SEL)selector{
NSError *error = nil;
NSFileManager *mgr = [NSFileManager defaultManager];
NSString *tempFolder = NSTemporaryDirectory();
if([mgr removeItemAtPath: imagePath error:&error] == NO) {
NSLog(#"File deleted");
}
//The files can be edited as well, so there can be two files in different directories
if(error != nil){
NSString *imgEl = tempFolder;
imgEl = [imgEl stringByAppendingPathComponent:imagePath.lastPathComponent];
if(![mgr removeItemAtPath:imgEl error:&error]){
NSLog(#"Old element couln't be deleted.");
}
}
[self performSelector:selector withObject:error];
}
The file is not in the directory anymore after deleting it, so I guess it works.
An important detail could be, that I wrote my own IOS cordova plugin, because the method for the file system access provided by cordova sucks.
So thats it.
The specific question is: Why and how is this happening and is there a chance to change this behavior? If yes, how should I proceed?
By the way, I`m using cordova 3.1.0 and the build target is IOS 7.
Thanks in advance.
Ok folks, I finally got it.
The whole problem was not related to my code or any of the cordova code.
So why did it happen? ==> I don't exactly know that, for it seems that this bug or whatever you might call it, has occurred to many people.
And they all tried to delete or deactivate the cache as I did, some of their problems are very close to my own but most aren't, so it took a while til I found a solution.
I read this thread and tried to append a timestamp to the image path and it worked!
My conclusion to this it, that there might be a problem with the UIWebView and the cache management.
Or it might proof as a general WebView problem, I will be able to check that in a few days on an Adroid device.

Resources