Ionic - Some functionnalities are not working while compiling on IOS - ios

Context:
Hello, I am working on a Ionic application (made in Typescript). In this application, I control a wifi camera via HTTP Request to the IP (http://192.72.1.1/myCommand to be precise).
Main actions I do with the camera:
Start recording
Stop recording
Get videos list
Download a video
When I use the Ionic DevApp:
With the Ionic DevApp, everything works perfectly, I can do all mains actions without a problem.
When I compile the application on IOS:
I compile with the command ionic cordova build ios --prod, then I archive with Xcode and send it to the AppStore to test it with Test Flight.
I got no errors while compiling / archive the application. But when I try it on my iPhone, I can start / stop recording, but can't download the video.
Problem:
Some commands are not working, but I don't know if it is getting the list or downloading the video, I have no logs. I don't understand why some commands are working but others no.
IOS is blocking download requests? How to solve my problem?
Notes:
I already tried all basic things like delete the IOS platform, recompile, uninstall, ...
I tried different Ionic HTTP plugins, same problem with all of them.
Some code:
Start / Stop the camera: (it is the same command to start / stop).
startCamera(){
var url = "http://192.72.1.1/changeRecordStatus";
var result = this.http.get(url);
result.subscribe(data => {
console.log("Works");
},
err => {
console.log("Error" + err);
}
);
}
Getting the name of the last video:
getLastVideo(){
var url = "http://192.72.1.1/listVideos";
this.http.get(url, {}, {})
.then(data => {
var xml = data.data
var xmlDOM = new DOMParser().parseFromString(xml, 'text/xml');
var temp = this.xmlToJson(xmlDOM); // function that convert XML to JSON
var resultArray = Object.keys(temp).map(function(i){
let ite = temp[i];
return ite;
});
resultArray = resultArray[0]['file'].reverse();
this.lastVideo = resultArray[0]['name']; // lastVideo is a global variable
},
(error) =>{
console.log("Error while getting the name of the last video" + error);
});
}
Downloading the file from the camera:
downloadFileFromCamera() {
this.getLastVideo();
var basename_file = this.lastVideo;
var url = "http://192.72.1.1" + basename_file;
this.fileTransfer.download(encodeURI(url), this.file.dataDirectory + '/videos/' + basename_file, true).then((entry) => {
this.video[this.counterVideos] = entry; // video is a global array
this.counterVideos +=1;
}, (error) => {
console.log("Error while downloading the last video" + error);
});
}
If someone knows how to solve my problem, I would be so grateful! Thanks in advance.

Related

Ionic 2 Cannot use audio file from resource on IOS Emulator

I have an Ionic 2 app that works fine on Android.
Now I need to build the IOS version. The app can stream and download audios from SoundCloud.
When the users click to download an audio, the audio is stored in the app's data directory provided by Cordova file plugin.
The logic I use to store and retrieve data does not matter because in Android it works. The problem is that I want to recover and play the audio in IOS.
This is the part of code where I create a MediaObject and later play, pause it:
var pathalone: string = '';
if (this.platform.is('ios')) {
pathalone = this.audio.filePath.replace(/^file:\/\//, '');
console.log("Pathalone: " + pathalone);
this.mediaPlayer = this.media.create(pathalone, onStatusUpdate, onSuccess, onError);
} else {
pathalone = this.audio.filePath.substring(8);
this.mediaPlayer = this.media.create(pathalone, onStatusUpdate, onSuccess, onError);
}
setTimeout(() => {
if (this.mediaPlayer) {
this.togglePlayPause();
this.updateTrackTime();
}
}, 1000);
In the Media plugin docs says if still having problems on IOS, first create the file. So I tried, but I still having the same problem:
this.file.createFile(cordova.file.dataDirectory, this.audio.fileName, true).then(() => {
pathalone = this.audio.filePath.replace(/^file:\/\//, '');
console.log("Pathalone: " + pathalone);
this.mediaPlayer = this.media.create(pathalone, onStatusUpdate, onSuccess, onError);
});
In console I get these logs:
console.log: Pathalone:
/Users/ivan/Library/Developer/CoreSimulator/Devices/0D75C1A9-591A-4112-BBE4-AB901953A38F/data/Containers/Data/Application/509D1136-86F6-4C9B-84B5-8E0D0D203DAC/Library/NoCloud/311409823.mp3
[14:07:48] console.log: Cannot use audio file from resource
'/Users/ivan/Library/Developer/CoreSimulator/Devices/0D75C1A9-591A-4112-BBE4-AB901953A38F/data/Containers/Data/Application/509D1136-86F6-4C9B-84B5-8E0D0D203DAC/Library/NoCloud/311409823.mp3'
Maybe It's happening on Emulator but will not happen on a real device? I can't test on iPhone because I haven't got one :/
PD:
A curious fact is that the SoundCloud api returns a redirect when making a GET to its api to download an audio.
The response has a status of 301, so I use the response.headers.Location to handle the redirect and there, I can perform the download.
And I'm noticing that in IOS it never performs the redirect, it goes directly on the 'positive' way and the console says 'downloaded'. Maybe it's never really downloaded...
You need indeed to create a file before creating the recorder media object. Recordings are possible even with the emulator on iOS and Android. The following illustrate how this is done with Ionic2+
First you need to import the following
import { NavController, Platform } from 'ionic-angular';
import { Media, MediaObject } from '#ionic-native/media';
import { File } from '#ionic-native/file';
Make sure that you injected the imports in your constructor as follows
constructor(public navCtrl: NavController, private media: Media, private file: File, public platform: Platform) {
// some more code here
}
Declare the required variables before the constructor as follows
filePath: string;
fileName: string;
audio: MediaObject;
The code for starting the recording in as follows
startRecord() {
if (this.platform.is('ios')) {
this.fileName = 'record' + new Date().getDate() + new Date().getMonth() + new Date().getFullYear() + new Date().getHours() + new Date().getMinutes() + new Date().getSeconds() + '.3gp';
this.filePath = this.file.dataDirectory;
this.file.createFile(this.filePath, this.fileName, true).then(() => {
this.audio = this.media.create(this.filePath.replace(/^file:\/\//, '') + this.fileName);
this.audio.startRecord();
});
} else if (this.platform.is('android')) {
this.fileName = 'record' + new Date().getDate() + new Date().getMonth() + new Date().getFullYear() + new Date().getHours() + new Date().getMinutes() + new Date().getSeconds() + '.3gp';
this.filePath = this.file.externalDataDirectory;
this.file.createFile(this.filePath, this.fileName, true).then(() => {
this.audio = this.media.create(this.filePath.replace(/^file:\/\//, '') + this.fileName);
this.audio.startRecord();
});
}
}
Notice the differences between using the path name "this.filePath" in createFile and media.create.
The code for stopping the recording is as follows
stopRecord() {
this.audio.stopRecord();
}

audio Blob not working in IOS / Safari

I am recording audio, sending it as a blob to a nodejs server. The nodejs server then sends it to all connected users that are not currently recording.
Sending the blob:
mediaRecorder.onstop = function(e) {
var blob = new Blob(this.chunks, { 'type' : 'audio/ogg; codecs=opus' });
socket.emit('radio', blob);
};
Server receiving the blob:
socket.on('radio', function(blob) {
socket.broadcast.emit('voice', blob);
});
Listener receiving the blob:
socket.on('voice', function(arrayBuffer) {
var blob = new Blob([arrayBuffer], { 'type' : 'audio/ogg; codecs=opus' });
var audio = document.getElementById('audio');
audio.src = window.URL.createObjectURL(blob);
audio.play();
});
This works in all browsers/devices except safari and any ios device. Taking it further with safari's inspector I found this:
Does safari require something else in its headers for blob objects to be interpreted properly? I've researched accepted audio types, tried aac/mp3/ogg without any success. Upon reading further I've heard references to the fact that there is a bug with streaming blob audio/video data in safari and IOS though I'm not too clear any the details.
Guidance in the rite direction would be very helpful!
EDIT: It looks like this line audio.src = window.URL.createObjectURL(blob); in the receiving blob is what is causing the blob errors (image i linked)
EDIT 2: I tried to see if using another format other than blob would work, opting for base64 encoded string. Looks like this works on all devices and browsers except for IOS and Safari. I'm getting the impression it has something to do with how IOS interprets/loads the data...
For me the solution was to insert a source element into the audio element, and use the sourceElement.src attribute to refer to the blob. I didn't even need to attach the audio-element to the DOM. Example below, hope it helps someone.
var audioElement = document.createElement('audio')
var sourceElement = document.createElement('source')
audioElement.appendChild(sourceElement)
sourceElement.src = '<your blob url>'
sourceElement.type = 'audio/mp3' // or whatever
audioElement.load()
audioElement.play()
I haven't been able to find a solution using an audio element, however the Web Audio Api seems to do the trick: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
var audioContext = new (window.AudioContext || window.webkitAudioContext);
socket.on('voice', function(arrayBuffer) {
audioContext.decodeAudioData(arrayBuffer, audioData => {
var source = audioContext.createBufferSource();
source.buffer = audioData;
source.connect(audioContext.destination);
source.start()
});
You may still have an issue on iOS as any audio/video must be triggered by a user action.
I had a similar problem this week. I was recording the audio on Safari and the audio blob was being generated just fine. But when I tried to send the blob to server, no data was getting there. The solution bellow reads the blob with File Reader to convert it to base64, and afterwards send it to server. Here is what worked for me:
const reader = new FileReader();
reader.readAsDataURL(audioBlob);
reader.onloadend = () => {
const base64data = reader.result;
const audioName = uuid.v4() + '.mp3';
this.http.post(this.app.cloudStorageEndpoint + '/audios/local?audioName=' + audioName, base64data , header).subscribe(
res => { resolve(audioName); },
err => { reject(err); }
);
};
I've tested with Safari 12 on both iPad and iPhone and it worked fine.

Cordova Media Plugin not working

I can't get the cordova media plugin to work, I get error code 1 which signals that the file is not getting loaded. I've tried a number of variations, but can't figure out which path is correct.
Currently my code looks like this:
function onDeviceMediaReady () {
var path = window.cordova.file.applicationDirectory + 'why.mp3';
console.log(path);
narrative = new Media(path, // success callback
function() {
console.log("playAudio():Audio Success");
},
// error callback
function(err) {
console.log("playAudio():Audio Error: "+ err.code);
});
}
this gives me a path that's file://var/cotainers/Bundle/Application/[GUID]/Cordova400.app/why.mp3
I don't get why I can't find it. the file is in the telerik appbuilder root directory.
Inside your 'WWW' folder place the file inside 'sound' folder & try following
var srcBookmark = "sound/yes.mp3"; //ios
var iOSPlayOptions = {
numberOfLoops: 1,
playAudioWhenScreenIsLocked : false
}
var media = $cordovaMedia.newMedia(srcBookmark);
//media.play(); //android
media.play(iOSPlayOptions); //ios
$timeout(function(){
media.stop();
media.release()
}, 500);
If you're using appBuilder to test your app te aplication folder is the telerik folder, you must deploy your app as APK and test the folder

Potential causes of Ionic function not working in Ionic View, but working on web

I am building a food delivery app using Ionic. And I am having problems getting the app to work on mobile for the address creation step. After creating an account the user must create a delivery address, at which point the app figures out what delivery location to use.
Address creation works in Chrome (ionic serve) and in iOS simulator (ionic run ios -l -c -s).
However, once I've uploaded the app to my Ionic View iOS app for testing, it gets stuck at the Address creation step.
But at the address creation step, the Ionic loading wheel starts but it doesn't go away and there is no state transition to the menu.
Here is the implementation in the controller.
Address.create($scope.newAddress, $scope.user)
.then(function(response) { // never gets a response back in Ionic View
console.log("address created");
user.save(null,
{ success: function(user) {
// success callback
}, error: function(error) {
// throw error
}
});
}, function(error) {
// throw error
});
The Address.create() method I have implemented is fairly lengthy:
...
.factory('Address', ['$http', '$q', 'PARSE_HEADERS'
function ($http, $q, PARSE_HEADERS) {
return {
create: function(data, userID) {
var deferred = $q.defer();
var zipArray = ['1111','22222','33333'];
var inZone = false;
var restaurantCoords = {
latitude: 11.11111, longitude: 22.22222
};
for (var i=0, bLen=zipBrooklyn.length; i<bLen; i++) {
if(data.zipCode==zipArray[i]) {
inZone = true;
}
}
if (inZone == true ) { // valid zip
function onSuccess(coords) {
var limit = 3041.66;
var meters = getDistance(coords, restaurantCoords);
if (meters < limit) {
$http.post('https://api.parse.com/1/classes/Address', data, {
headers: PARSE_HEADERS
})
.success(function(addressData) {
deferred.resolve(addressData);
})
.error(function(error, addressData) {
deferred.reject(error);
});
}
function onError() {
deferred.reject("Unable to Geocode the coordinates");
}
// GET COORDS
navigator.geocoder.geocodeString(onSuccess, onError, data.address1 + ',' + data.zipCode);
}
}
return deferred.promise;
}]);
I've stripped out all of the code that I believe was working.
So a valid answer for this question could take multiple forms:
I'd accept an answer giving a decent way to debug apps IN Ionic View.
Or, if someone could provide an answer as to why it might be working in the browser and in iOS Simulator, but not iOS itself, that would be appreciated even more.
Ionic view doesn't support all the plugins yet. please take a look at this link for the list of supported plugins.
Device is always better (First Option). If you have a ios device and apple developer account. You can create and configure the required certificate with the device id and run the app using 'ionic run ios'. Second option is iOS simulator. You can use the simulator for your whole app, though few tasks would need a device.
Even if you use the simulator for the whole development, it is always advisable to test in the device before launcing the app.

How to download picture with Phonegap Filetransfer to image gallery in iOS

This has been asked several times, but most of these questions are unanswered
I'm downloading a file like below, and it seems to work fine. However .. it does not show up in the iOS, ehm, gallery. That is, in the 'photos' application.
var fileTransfer = new FileTransfer();
var encurl = encodeURI(url);
var filename = url.split('/').slice(-1)[0];
var filepath = "foo/"+filename;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
var syspath = fileSystem.root.toURL() + '/' + filepath;
var fileTransfer = new FileTransfer();
fileTransfer.download(
encurl,
syspath,
function (entry) {
foo.debug("Download success "+syspath);
},
function (error) {
foo.error("Download failed with error "+error.code+' '+syspath);
}
);
}, function (evt) {
foo.error("Filesystem failed with error "+evt.target.error.code);
});
and the result is
[Log] Download success file:///var/mobile/Applications/68DE0AD9-FBD2-4D82-92C0-2B7634B218D5/Documents//foo/20141030-153810-editor.jpg (console-via-logger.js, line 173)
hurray. now, how do you open the download, using just your fingers, on ios ?
I would mark this as a duplicate of Phonegap - Save image from url into device photo gallery
I was happy with the answer by M165437 and my comments. That answered my question.
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
});

Resources