Downloaded image not shown in iOS gallery while shown in android phone gallery - ios

I used telerik app builder platform to create application. I created download image functionality. This functionality is working on android device, but not on iOS. I don't know why it is not working.
When the user downloads an image using application in android device, then cordova filesystem creates directory and saves image into that directory and image was also shown in gallery. While user performs same action in iOS then it does not create any directory and the image is not shown in gallery. I haven't found where to save this image.
Please give suggestion on how to save downloaded image in iOS gallery.
My code is below
function onDeviceReady() {
var that = this,
App = new downloadApp(),
fileName = "sample.png",
uri = encodeURI("http://www.telerik.com/sfimages/default-source/logos/app_builder.png"),
folderName = "test";
navigator.splashscreen.hide();
App.run(uri, fileName, folderName);
}
downloadApp.prototype = {
run: function (uri, fileName, folderName) {
var that = this,
filePath = "";
document.getElementById("download").addEventListener("click", function () {
that.getFilesystem(
function (fileSystem) {
console.log(fileSystem);
that.getFolder(fileSystem, folderName, function (folder) {
filePath = folder.toURL() + "\/" + fileName;
console.log(filePath);
that.transferFile(uri, filePath)
}, function () {
console.log("failed to get folder");
});
},
function () {
console.log("failed to get filesystem");
}
);
});
},
getFilesystem: function (success, fail) {
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, success, fail);
},
getFolder: function (fileSystem, folderName, success, fail) {
fileSystem.root.getDirectory(folderName, { create: true, exclusive: false }, success, fail)
},
transferFile: function (uri, filePath) {
var transfer = new FileTransfer();
transfer.download(
uri,
filePath,
function (entry) {
var targetPath = entry.toURL();
},
function (error) {
console.log(error)
}
);
},

Try to download by using https://www.npmjs.com/package/com-cordova-image-save-to-gallery plugin. It will download a picture from a given URL and save it to IOS Photo Gallery.
Cordova plugin add https://github.com/valwinjose007/cordova-image-save-to-gallery.git
How to use:
declare var CordovaImageSaveToGallery: any;
CordovaImageSaveToGallery.downloadFromUrl('https://picsum.photos/200/300',(res)=>{
//download success
},(err)=>{
//error on download
});

Related

Titanium add photo to specific gallery

So I have the following which works real nice as is:
button.addEventListener("click", function(e){
Titanium.Media.showCamera({
success:function(e){
if(e.mediaType === Titanium.Media.MEDIA_TYPE_PHOTO){
var imageView = Titanium.UI.createImageView({
image: e.media,
width: 'auto',
height: 'auto',
top: 50,
zIndex: 1
});
win.add(imageView);
} else {
alert("Only Photos aloud");
}
},
error:function(e){
alert("There was an error");
},
cancel:function(e){
alert("The event was cancelled");
},
allowEditing: true,
saveToPhotoGallery: true,
mediaTypes:[Titanium.Media.MEDIA_TYPE_PHOTO,Titanium.Media.MEDIA_TYPE_VIDEO],
videoQuality:Titanium.Media.QUALITY_HIGH
});
});
saveToPhotoGallery just adds the taken photo to the default gallery in the iOS Photos App.
I need to add the photo to a specific folder in the iOS Photos App though.
Has anyone an idea how I could do this from with Titanium ?
I have been searching the intewebs but have not found anything on how to add a taken photo to a specific folder.
Thank for the help guys
Chris
But, let me specify that the file can be save in the Application Directory only in IOS but in android you can save it in the externalStorage. You can have look at the documentation through the below link :
https://docs.appcelerator.com/platform/latest/#!/guide/Filesystem_Access_and_Storage
You can easily save the file to your folder using the following code :
if (OS_ANDROID) {
var f12 = Titanium.Filesystem.getFile(Titanium.Filesystem.externalStorageDirectory);
} else {
var f12 = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory);
}
var galleryImg = e.media;
var fileToSave = null;
var fileName = 'IMG' + todayDate + "HB" + Ti.App.Properties.getInt('imgCounter') + '.jpg';
if (OS_ANDROID) {
fileToSave = Titanium.Filesystem.getFile(f12.resolve(), fileName);
} else {
fileToSave = Titanium.Filesystem.getFile(f12.resolve(), fileName);
}
fileToSave.write(galleryImg);
If you want to create a subDirectory then use the following code :
var dir = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory,'mysubdir');
dir.createDirectory(); // this creates the directory
But, let me specify that the file can be save in the Application Directory only in IOS but in android you can save it in the externalStorage. You can have look at the documentation through the below link :
https://docs.appcelerator.com/platform/latest/#!/guide/Filesystem_Access_and_Storage
EDIT
You Could do it this way :
// get the TiBlob
var blob = img_view.toImage();
// try to save the image the image
Ti.Media.saveToPhotoGallery(blob,{
success: function(e){
if (callback == undefined) {
alert('Saved image to gallery');
} else {
callback();
}
},
error: function(e){
alert("Error saving the image");
}
});
Good Luck, Cheers

Cordova - write to and read from File

I am running into a problem with my cordova app where after an app update, localStorage is cleared. I am now attempting to save some basic user data to a text file instead, using cordova's FileWriter and FileReader.
At some point cordova updated and these methods and now requires a plugin to read and write files: https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/index.html
Because my live iOS application uses the old version of cordova, it must write with FileWriter. My app update (not live) uses a newer version of cordova and therefore must use the plugin.
------ Possible workaround found, see update below ------
When trying to read the file, I am seeing the following error in xcode:
017-01-26 17:58:52.990 MyApp[40355:2892997] ERROR: Method 'hello there' not defined in Plugin 'File'
2017-01-26 17:58:52.991 MyApp[40355:2892997] -[CDVCommandQueue executePending] [Line 142] FAILED pluginJSON = ["File1875336264","File","hello there",["cdvfile://localhost/persistent/player_data.txt",null,null]]
Note: I'm running the following code in Safari console while the iOS simulator is running, just for convenience
My code for writing the file
(function() {
var onFail = function(err) {
alert('write action failed!');
alert(err.code);
};
var onGotFS = function(fileSystem) {
alert( 'gotFS' );
fileSystem.root.getFile("player_data.txt", {create: true}, onGotFileEntry, onFail);
};
var onGotFileEntry = function(fileEntry) {
alert( 'gotFileEntry, path: ' + fileEntry.fullPath );
fileEntry.createWriter(onGotFileWriter, onFail);
};
var onGotFileWriter = function(writer) {
alert( 'gotFileWriter' );
writer.onwrite = onFileWritten;
writer.onerror = onFail;
var data = "hello there";
alert( 'writing data: ' + data );
writer.write( data );
};
var onFileWritten = function(evt) {
alert( "saveTokenToFile SUCCESS!" );
};
// start process of looking up file system and writing
alert( 'requesting file system ...' );
window.requestFileSystem(LocalFileSystem.PERSISTENT, 1024, onGotFS, onFail);
})();
My code for reading the file:
(function() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
fs.root.getFile("player_data.txt", { create: true }, function (fileEntry) {
fileEntry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function() {
alert("Success");
console.log(evt.target.result);
};
reader.onerror = function() {
console.log("reader error");
};
reader.readAsText(file);
}, onErrorReadFile);
});
}, onErrorLoadFs);
var onErrorReadFile = function(){
console.log("error reading file");
}
var onErrorLoadFs = function() {
console.log("request file system has failed to load.");
}
})();
UPDATE
In case anyone else runs into this, I did find a way to read the saved file. The fileEntry object has a URL path to the saved file. To access the data on the file, I'm passing that URL to jQuery.getJSON, which gives us back some readable json.
readDataFromFile: function(){
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
fs.root.getFile("player_data.txt", {}, function (fileEntry) {
var entryURL = fileEntry.nativeURL;
jQuery.getJSON(entryURL, function(data) {
console.log(data);
}).fail(function(){
console.log("file found, but contents were empty");
});
}, onErrorGetFile);
}, onErrorLoadFs);
var onErrorLoadFs = function() {
console.log("request file system has failed to load.");
};
var onErrorGetFile = function() {
console.log("requested file can not be read or does not exist");
};
}

Cordova: What is the right location to store recorded Audio files in iOS?

I am using media plugin to record sounds.
var my_media = new Media('test.wav');
my_media.startRecord();
my_media.stopRecord() // after few seconds
my_media.release();
my_media.play();//works fine
// But when I try to Check if test.wav file exist I always get false as status.
//File name of our important data file we didn't ship with the app
var fileName = "test.wav";
function init() {
console.log("Checking for data file.");
//Check for the file.
window.resolveLocalFileSystemURL(fileName, onSuccess, onFail);
}
function onSuccess() {
console.log("Great! This file exists");
}
function onFail() {
console.log('Sorry! File not Found');
}
// I always get this message: Sorry! File not Found
What is right way to do this? After recording I want user to be able to see list of available recorded sounds and user should be able to play it. For that I need to check if file exists or not.
So how should we implement that?
You can display list of recorded files as:
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {
fileSystem.root.getDirectory(YOUR_PATH, {
create: true
}, function(directory) {
root_path = fileSystem.root.toURL();
var directoryReader = directory.createReader();
directoryReader.readEntries(function(entries) {
var i;
for (i = 0; i < entries.length; i++) {
//Get file URL as: entries[i].toURL()); & display using creating dynamic tag.
}
}, function(error) {
alert(error.code);
});
});
}, function(error) {
alert("can't even get the file system: " + error.code);
});

Cordova / Ionic - Download file from InAppBrowser

The scenario goes like this: I open a website in InAppBrowser, after the user ends with the work over there, the site generates a .pdf for the user to download, the problem is that the pdf does not download, it opens it in the browser.
Is there a way to make it download from the InAppBrowser? I'm currently working on an iOS app, so the solution would be better for iOS.
Thanks in advance.
Following #jcesarmobile advices this is what I came up with:
First I had to install the cordova-plugin-file-transfer
Open URL
var url = "http://mi-fancy-url.com";
var windowref = window.open(url, '_blank', 'location=no,closebuttoncaption=Cerrar,toolbar=yes,enableViewportScale=yes');
Create a listener on that windowref for a loadstart event and check if what's being loaded is a pdf (that's my case).
windowref.addEventListener('loadstart', function(e) {
var url = e.url;
var extension = url.substr(url.length - 4);
if (extension == '.pdf') {
var targetPath = cordova.file.documentsDirectory + "receipt.pdf";
var options = {};
var args = {
url: url,
targetPath: targetPath,
options: options
};
windowref.close(); // close window or you get exception
document.addEventListener('deviceready', function () {
setTimeout(function() {
downloadReceipt(args); // call the function which will download the file 1s after the window is closed, just in case..
}, 1000);
});
}
});
Create the function that will handle the file download and then open it:
function downloadReceipt(args) {
var fileTransfer = new FileTransfer();
var uri = encodeURI(args.url);
fileTransfer.download(
uri, // file's uri
args.targetPath, // where will be saved
function(entry) {
console.log("download complete: " + entry.toURL());
window.open(entry.toURL(), '_blank', 'location=no,closebuttoncaption=Cerrar,toolbar=yes,enableViewportScale=yes');
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
true,
args.options
);
}
The problem i'm facing now is the path where it downloads, I just can't open it. But well, at least file is now downloaded. I will have to create a localStorage item to save the paths for different files.
Many validations are missing in this steps, this was just an example I made quickly to check if it works. Further validations are needed.
Open you window using IAB plugin and add an event listener
ref = window.open(url, "_blank");
ref.addEventListener('loadstop', loadStopCallBack);
In the InAppBrowser window call the action using https://xxx.pdf">documentName
Implement the loadStopCallBack function
function loadStopCallBack(refTemp) {
if(refTemp.url.includes('downloadDoc')) {
rtaParam = getURLParams('downloadDoc', refTemp.url);
if(rtaParam != null)
downloadFileFromServer(rtaParam);
return;
}
}
function getURLParams( name, url ) {
try {
if (!url)
url = location.href;
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(url);
return results == null ? null : results[1];
} catch (e) {
showSMS(e);
return null;
}
}
After create a download method
function downloadFileFromServer(fileServerURL){
try {
var Downloader = window.plugins.Downloader;
var fileName = fileServerURL.substring(fileServerURL.lastIndexOf("/") + 1);
var downloadSuccessCallback = function(result) {
console.log(result.path);
};
var downloadErrorCallback = function(error) {
// error: string
console.log(error);
};
//TODO cordova.file.documentsDirectory for iOS
var options = {
title: 'Descarga de '+ fileName, // Download Notification Title
url: fileServerURL, // File Url
path: fileName, // The File Name with extension
description: 'La descarga del archivo esta lista', // Download description Notification String
visible: true, // This download is visible and shows in the notifications while in progress and after completion.
folder: "Download" // Folder to save the downloaded file, if not exist it will be created
};
Downloader.download(options, downloadSuccessCallback, downloadErrorCallback);
} catch (e) {
console.log(e);
}
}
you can get the plugin here https://github.com/ogarzonm85/cordova-plugin-downloader
it Works and was too easy

iOS callback not triggered after file upload from $cordovaCamera

I'm building a hybrid app in ionic, which runs over cordova. I use the $cordovaCamera plugin to capture images from the phone, either by selecting from the phone's gallery or by using the camera to take a picture.
I then send that image using Restangular to my server, and when that action finishes, I want to display a status message on the screen.
My problem: All of the above works perfectly on Android. On iOS, it is working only when the image is selected from the gallery, but not when the image is directly captured from the phone. In that case, the image is correctly transferred to the server, the request returns a 201 Created just as it should - but the then() callback function is never entered.
If anyone can explain this behavior, that would be awesome...my second best would be to capture the image on the iPhone, save to gallery, and then attempt to retrieve the last saved image, but I haven't been able to figure out how to yet and I'd rather just get this working.
Update: I've narrowed it down to the Restangular part - if instead of calling the Restangular upload function, I use $http, the callback is triggered as expected and all is good...so that's what I'm going to do, but if anyone can tell me what the problem was I'd be grateful.
Relevant code:
/** cameraService functions **/
//when the user chooses to snap a picture from the camera
takePicture: function(){
var options = {
quality: 50,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.CAMERA,
encodingType: Camera.EncodingType.JPEG,
popoverOptions: CameraPopoverOptions
};
return $cordovaCamera.getPicture(options).then(
function(imageData) {
return imageData;
},
function(err) {
console.log("error", err);
});
},
//when the user chooses to select image from the gallery
choosePicture: function(){
var options = {
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY
};
return $cordovaCamera.getPicture(options).then(
function(imageData) {
return imageData;
},
function(err) {
console.log("error", err);
});
},
uploadPicture: function(imageSource, caption, is_logo){
if (typeof is_logo == 'undefined') is_logo = false;
var upload_object = {
caption: caption,
source: imageSource,
is_logo: is_logo
};
//apiService is my wrapper for Restangular
return apiService.uploadFile(loadingService.getClientUrl('images'), upload_object);
},
/**apiService uploadFile - apparently the problem is here ***/
uploadFile: function(baseElem, object, route, path){
var headers = apiFunctions.setHeaders({'Content-Type': undefined});
//this DOES NOT WORK (on iPhone with image from camera) - request completes but callback not triggered
return Restangular.all(baseElem).customPOST(object, path, route, headers);
//this works fine:
return $http.post('https://api.mysite.dev/v1/clients/'+localStorageService.getValue('client_id')+'/images', JSON.stringify(object), {headers:headers}
);
},
/** controller functions **/
$scope.takePicture = function () {
cameraService.takePicture().then(function (imageData) {
$scope.data.imageSource = imageData;
});
};
$scope.choosePicture = function () {
cameraService.choosePicture().then(function (imageData) {
$scope.data.imageSource = imageData;
});
};
$scope.uploadPicture = function () {
cameraService.uploadPicture($scope.data.imageSource, $scope.data.caption)
.then(function (response) { //this is never entered if image is captured from camera on iPhone
$ionicScrollDelegate.scrollTop();
$scope.data.caption = '';
$scope.data.imageSource = '';
if (response.data.response.is_success.data_value == true) {
$scope.messages.success.push("Photo uploaded successfully");
} else {
$scope.messages.failure.push("Error uploading photo.");
}
});
}

Resources