I'm using ngCordova inside an Ionic mobile app. In one of my services, I need to delete files I've written previously with $cordovaFile
remove: function (card) {
//remove a card from the store
var index = cardStore.indexOf(card);
if (index > -1) {
//remove the image files
$ionicPlatform.ready(function () {
if (card.imgFrontUrl) {
$cordovaFile.checkFile(cordova.file.externalRootDirectory, "vid-front-" + card.id + ".jpg").then(function () {
$cordovaFile.removeFile(cordova.file.externalRootDirectory, "vid-front-" + card.id + ".jpg").then(function (result) {
console.log("File '" + card.imgFrontUrl + "' deleted", JSON.stringify(result));
}, function (err) {
console.error("Failed to delete file '" + card.imgFrontUrl + "'", JSON.stringify(err));
});
}, function(err) {
console.log("File '" + card.imgFrontUrl + "' does not exist", JSON.stringify(err));
});
}
Everything claims to be successful. In my logs, I see:
14 337901 log File 'cdvfile://localhost/sdcard/vid-front-49444.jpg' deleted, {"success":true,"fileRemoved":{"isFile":true,"isDirectory":false,"name":"vid-front-49444.jpg","fullPath":"/vid-front-49444.jpg","filesystem":"<FileSystem: sdcard>","nativeURL":"file:///storage/emulated/0/vid-front-49444.jpg"}}
At this point I think it's a bug in $cordovaFile or other platform issue.
Any ideas out there?
Short answer: it works on the device. But if you're viewing the files on the device through MTP (e.g. mounted through Windows Explorer), you may not see the change reflected immediately or at all until a device restart. Use a file browser app on the device as a sanity check instead if you're facing this issue.
Related
I am trying to use $cordovaFile to delete files from an Android device. The file to be deleted was downloaded using $cordovaFileTransfer in the following location.
ft.download(url, cordova.file.externalDataDirectory + "episodes/" + episodeId + ".mp3",...);
Using the file manager on the device I can see that the file is located at file:///storage/emulated/0/Android/data/com.ionicframework.myapp123456/files/episodes/
`However when I try to use either of the following locations to delete the file I get error code 5 (ENCODING_ERR)
$cordovaFile.removeFile("file:///storage/emulated/0/Android/data/com.ionicframework.myapp123456/files/episodes/", "0.mp3")
$cordovaFile.removeFile(cordova.file.externalDataDirectory + "episodes/", "0.mp3")
That same error occurs when I try to use $cordovaFile.checkDir() so I used window.resolveLocalFileSystemURL() instead.
This issue was resolved by using the LocalFileSystem. It is not as elegent as the methods provided by the file plugin, but it works.
var uri = cordova.file.externalDataDirectory + "episodes/";
window.resolveLocalFileSystemURL(uri, function(dir) {
dir.getFile(episodeId + ".mp3", { create: false }, function(file) {
file.remove(successCallback, errorCallback);
});
}, errorCallback);
i am using cordova-ionic framework to build app. i am new to the iOS or iPhone
in my requirement, i have to read a file in the app. i am reading file in the android app but same code showing error (code: 5).
i am following code types:
in android:
$cordovaFile.writeFile(( 'user.json', data, {'append':false} )).then(function(result) {
alert('file created.');
alert(JSON.stringify(result));
}, function(err) {
// An error occured. Show a message to the user
alert('file writed');
alert(JSON.stringify(err));
});
i can create file, writing, reading data and removing the file but in ios phone i am not able to create file using the same code.
in iPhone:
var data = {"user":{"name":"errer","email":"sdsdff#gmail.com","username":"sdfsdfsd"}};
$cordovaFile.writeFile(( 'user.json', data, {'append':false} )).then(function(result) {
// Success!
alert('file created.');
alert(JSON.stringify(result));
}, function(err) {
// An error occured. Show a message to the user
alert('file writed');
alert(JSON.stringify(err));
});
i just change my directory is cordova.file.cacheDirecotry/cordova.file.applicationDirectory
$cordovaFile.createFile(( cordova.file.cacheDirecotry+'user.json', true )).then(function(result) {
// Success!
alert('file created.');
alert(JSON.stringify(result));
}, function(err) {
// An error occured. Show a message to the user
alert('file writed');
alert(JSON.stringify(err));
});
all way getting the error like code: 12 or code: 5
please help me to solve this or give me a idea to get application file path
I have some progression.
First, I alert my cordova.file.dataDirectory or cordova.file.documentsDirectory.
They are
file:///var/mobile/...../Library/NoCloud
and
file:///var/mobile/..../Documents
Then I create a File without the prefix and succeed. Referring to this https://github.com/driftyco/ng-cordova/issues/362
and the success message shows that the native url of the file is saved in
file:///var/mobile/...../Library/files
Which is quite strange. By the way, I add the
<preference name="iosPersistentFileLocation" value="Library" />
according to https://github.com/apache/cordova-plugin-file/blob/master/doc/index.md#ios-persistent-storage-location
All the tests are running on IOS, i haven't test for Android.
Updates
All the following code worked for me and give success response
$cordovaFile.checkFile('/test.data')
$cordovaFile.createFile('test.data',false)
$cordovaFile.checkDir('/')
Hope this can solve your problems.
/*
Here is what I am using for my Android and IOS apps
Keep attention to a couple of things:
- Android and IOS have other directorynames for files
- Android devices have different root (myFSRootDirectory1 = Samsung Tab 3, msFSRootDirectory2 = Samsung SII)
- $cordovaFile functions prefixes all pathnames with root
$cordovaFileTransfer functions needs absolute pathnames
Here I create the prefixes for File functions and FileTransfer functions for Android and IOS
*/
// The $ionicPlatform and ionic.Platorm are from Ionic framework
//
$ionicPlatform.ready(function() {
if (ionic.Platform.isAndroid()) {
// If running on Android
console.log('cordova.file.externalDataDirectory: ' + cordova.file.externalDataDirectory);
//
// I use cordova.file.externalDataDirectory because this url is for Android devices
// If you remove the app from the device these url are cleared too on the device. So keep it clean.
// Remove the root from cordova.file.externalDataDirectory
//
myFsRootDirectory1 = 'file:///storage/emulated/0/'; // path for tablet
myFsRootDirectory2 = 'file:///storage/sdcard0/'; // path for phone
fileTransferDir = cordova.file.externalDataDirectory;
if (fileTransferDir.indexOf(myFsRootDirectory1) === 0) {
fileDir = fileTransferDir.replace(myFsRootDirectory1, '');
}
if (fileTransferDir.indexOf(myFsRootDirectory2) === 0) {
fileDir = fileTransferDir.replace(myFsRootDirectory2, '');
}
console.log('Android FILETRANSFERDIR: ' + fileTransferDir);
console.log('Android FILEDIR: ' + fileDir);
}
if (ionic.Platform.isIOS()) {
// if running on IOS
console.log('cordova.file.documentsDirectory: ' + cordova.file.documentsDirectory);
// I use cordova.file.documentsDirectory because this url is for IOS (NOT backed on iCloud) devices
fileTransferDir = cordova.file.documentsDirectory;
fileDir = '';
console.log('IOS FILETRANSFERDIR: ' + fileTransferDir);
console.log('IOS FILEDIR: ' + fileDir);
}
if (ionic.Platform.isAndroid() || ionic.Platform.isIOS()) {
//
// Just functions from the list below one by one ( or chain them)
//
}
});
// Download file from 'http://www.yourdomain.com/test.jpg' to test/one/test.jpg on device Filesystem
var hostPath = 'http://www.yourdomain.com/test.jpg';
var clientPath = fileTransferDir + 'test/one/test.jpg';
var fileTransferOptions = {};
$cordovaFile.downloadFile(hostPath, clientPath, true, fileTransferOptions).then (function() {
});
// Create dir test
$cordovaFile.createDir(fileDir + 'test/').then( function(dirEntry) {
});
// Create dir aganin in dir test
$cordovaFile.createDir(fileDir + 'test/one/').then( function(dirEntry) {
});
// Create empty file test.txt in test/again/
$cordovaFile.createFile(fileDir + 'test/one/test.txt', true).then( function(fileEntry) {
});
// List of files in test/again
$cordovaFile.listDir(fileDir + 'test/one/').then( function(entries) {
console.log('list dir: ', entries);
});
// Write some text into file
$cordovaFile.writeFile(fileDir + 'test/one/test.txt', 'Some text te test filewrite', '').then( function(result) {
});
// Read text written in file
$cordovaFile.readAsText(fileDir + 'test/one/test.txt').then( function(result) {
console.log('readAsText: ', result);
});
Perhaps it's because of a typo? You have cordova.file.cacheDirecotry. Shouldn't that be : cordova.file.cacheDirectory ?
Refer to the original documentation :-
https://github.com/apache/cordova-plugin-file/blob/master/doc/index.md#ios-file-system-layout
iOS has some directories as read-only. Try changing your path.
Let me know if it does not work for you.
I'm implementing a Cordova application (3.2) where I want to use LeafletJS and a map tile provider together with a local filesystem cache of the tiles.
My approach in an overview is the following:
Extend the Leaflet TileLayer
Overwrite the _loadTile method to retrieve the tile either from local filesystem or from remote
My code:
var StorageTileLayer = L.TileLayer.extend({
log: function (text) {
if (this.options.log)
this.options.log(text);
else
console.log("[StorageTileLayer]: " + text);
},
_setUpTile: function (tile, key, value, cache) {
try {
tile._layer = this;
tile.onload = this._tileOnLoad;
tile.onerror = this._tileOnError;
this._adjustTilePoint(tile);
tile.src = value;
this.fire('tileloadstart', {
tile: tile,
url: tile.src
});
this.log("Setting url to " + tile.src);
}
catch (e) {
this.log("ERROR in setUpTile: " + e.message);
}
},
_loadTile: function (tile, tilePoint) {
this._adjustTilePoint(tilePoint);
var key = tilePoint.z + ',' + tilePoint.y + ',' + tilePoint.x;
var self = this;
var tileUrl = self.getTileUrl(tilePoint);
console.log(tileUrl);
console.log(typeof tileUrl);
if (this.options.storage) {
this.log("Load Tile with storage");
this.options.storage.get(key, tileUrl).then(function (value) {
self.log("Tile URL to load: " + value.url);
self._setUpTile(tile, key, value.url, true);
});
} else {
this.log("Load Tile without storage");
self._setUpTile(tile, key, tileUrl, false);
}
}
});
options.storage is a storage which has the method get(key, remoteUrl) and returns either the cached tile from local filestorage (this implementation actual works fine, so here is not the problem) or the remote url but downloads the tile in the background, so that it will be available from local file storage on the next call.
Unfortunately I can see on my device when I use Charles (Web Debugging Proxy) that although the local map tiles are loaded (I can see it from the logs) that there are still a couple of requests to the map tiles provider.
Does anyone have an idea what I am doing wrong and what else I have to overwrite in my StorageTileLayer to prevent the calls to the remote? The real problem is, that the map should work in offline mode as well, but it is not.
Thanks for your help.
Libraries in the environment:
Leaflet (0.7.3)
angularJS (1.2.16)
Cordova (3.2)
I basically fixed it with this code (angular js):
(function (window, L) {
var isDebug = false;
var StorageTileLayer = L.TileLayer.extend({
log: function (text) {
if (!isDebug)
return;
if (this.options.log)
this.options.log(text);
else
console.log("[StorageTileLayer]: " + text);
},
_setUpTile: function (tile, key, value, cache) {
try {
tile._layer = this;
tile.onload = this._tileOnLoad;
tile.onerror = this._tileOnError;
this._adjustTilePoint(tile);
tile.src = value;
this.fire('tileloadstart', {
tile: tile,
url: tile.src
});
}
catch (e) {
this.log("ERROR in setUpTile: " + e.message);
}
},
_loadTile: function (tile, tilePoint) {
this._adjustTilePoint(tilePoint);
var key = tilePoint.z + ',' + tilePoint.y + ',' + tilePoint.x;
var self = this;
var tileUrl = self.getTileUrl(tilePoint);
if (isNaN(tilePoint.x) || isNaN(tilePoint.y)) {
this.log("TilePoint x or y is nan: " + tilePoint.x + "-" + tilePoint.y);
return;
}
if (this.options.storage) {
this.options.storage.get(key, tileUrl).then(function (value) {
self.log("Tile URL to load: " + value.url);
self._setUpTile(tile, key, value.url, true);
});
} else {
this.log("Load Tile without storage");
self._setUpTile(tile, key, tileUrl, false);
}
}
});
window.StorageTileLayer = StorageTileLayer;
})(window, L);
Adding the tile layer to the leaflet map is the important part! you have to prevent the load balancer from getting different urls for each tile. I did it by setting the url of the tole layer to a fixed value:
var url = 'https://a.tiles.mapbox.com/v3/<<YOUR ACCESS CODE>>/{z}/{x}/{y}.png';
var layer = new StorageTileLayer(url, {
storage: TileStorage
});
Of course you still have to implement the TileStorage in my case it has a single method get(key, url) and returns a $q-defer which is resolved with either the local available file. If the file is not available in the local storage it will be downloaded and then the promise is resolved.
Unfortunately this TileStorage is not public available because its an in-house development of my company so I can't share it.
Nevertheless I hope this helps you.
I have implemented a app for android using phone Gap.
In the app I have two button one is Voice Enroll and another one is Voice Verification.
For Voice Enroll I implemented Record Function Using CaptureAudio in Phone Gap. It works Great.
Now I need to upload the Record file to server. I have Used Below Code.
function captureSuccess(mediaFiles) {
var i, len;
for (i = 0, len = mediaFiles.length; i < len; i += 1) {
alert(mediaFiles[i]);
uploadFile(mediaFiles[i]);
}
}
function captureError(error) {
var msg = 'An error occurred during capture: ' + error.code;
navigator.notification.alert(msg, null, 'Uh oh!');
}
function captureAudio() {
navigator.device.capture.captureAudio(captureSuccess, captureError, {limit: 3);
}
// Upload files to server
function uploadFile(mediaFile) {
var ft = new FileTransfer(),
recordingPath = mediaFile.fullPath,
name = mediaFile.name;
console.log('Path is: ' + recordingPath);
ft.upload(recordingPath,
"Webservice URL",
function(result) {
alert("Hi");
console.log('Upload success: ' + result.responseCode);
console.log(result.bytesSent + ' bytes sent');
},
function(error) {
alert("welcome");
console.log('Error uploading file ' + recordingPath + ': ' + error.code);
},
{ fileName: name });
alert(recordingPath);
}
When I alert that mediaFiles[i] is received "Object Object". I can't receive any response after uploading.
Once Success we receive some messages from server about the audio file.
I am also send the audio file name as 'utterence'. How can i done this using phonegap and jquery mobile?
I remember having a similar problem and in my case the problem was capture returned full path and upload required the file path in different format so I had to modify the full path in a format accepted by upload.
Also make sure you set mimeType in the upload function. It defaults to image/jpeg. I am not sure how your server behaves but if it has self signed certificates then you will have to set trustAllHosts to true.
Hope this helps
I googled _ctx is Null and I was shocked to find nothing relating to Android. I am hoping this pose will help someone if we find the right answer.
Here is a link to the ANE I am using: https://github.com/pozirk/AndroidInAppPurchase
I have no idea where to go from here. It once worked now its not. :(
I am trying to use Pozirk's InAppPurchase.ane - which I have used before but suddenly its not working. I am not sure what changed. It may be, the ANE, or something in google play. Not sure but now its not working and I keep on getting this error:
_ctx is null.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at com.pozirk.payment.android::InAppPurchase/init()[C:\Users\blah\blah\Android\com\pozirk\payment\android\InAppPurchase.as:46]
at hereWeGo_fla::MainTimeline/fl_MouseClickHandler()[hereWeGo_fla.MainTimeline::frame1:97]
import com.pozirk.payment.android.InAppPurchase;
import com.pozirk.payment.android.InAppPurchaseEvent;
import flash.display.MovieClip;
/**
* ...
* #author Ben Barnard
*/
var _iap:InAppPurchase;
_iap = new InAppPurchase();
_iap.addEventListener(InAppPurchaseEvent.INIT_SUCCESS, onInitSuccess);
_iap.addEventListener(InAppPurchaseEvent.INIT_ERROR, onInitError);
_iap.addEventListener(InAppPurchaseEvent.PURCHASE_SUCCESS, onPurchaseSuccess);
_iap.addEventListener(InAppPurchaseEvent.PURCHASE_ALREADY_OWNED, onPurchaseSuccess);
_iap.addEventListener(InAppPurchaseEvent.PURCHASE_ERROR, onPurchaseError);
_iap.addEventListener(InAppPurchaseEvent.CONSUME_SUCCESS, onConsumeSuccess);
_iap.addEventListener(InAppPurchaseEvent.CONSUME_ERROR, onConsumeError);
_iap.addEventListener(InAppPurchaseEvent.RESTORE_SUCCESS, onRestoreSuccess);
_iap.addEventListener(InAppPurchaseEvent.RESTORE_ERROR, onRestoreError);
// Liscense Key
function onRestoreError(e:InAppPurchaseEvent):void
{
trace("Restore Error - " + e.toString());
outputField.text = "Restore Error - " + e.toString() + e.data.toString();
}
function onConsumeError(e:InAppPurchaseEvent):void
{
trace("Consume Error - " + e.toString());
outputField.text = "Consume Error - " + e.toString() + e.data.toString();
}
function onConsumeSuccess(e:InAppPurchaseEvent):void
{
trace("Consume Success - " + e.toString());
outputField.text = "Consume Success - " + e.toString();
// ------------------------------- THIS LINE PROMPTS THE USER TO PURCHASE THE ITEM ------------------------------- //
_iap.purchase("android.test.purchased", InAppPurchase.TYPE_INAPP);
}
function onPurchaseError(e:InAppPurchaseEvent):void
{
trace("Purchase Error - " + e.toString());
outputField.text = "Purchase Error - " + e.toString();
}
function onRestoreSuccess(e:InAppPurchaseEvent):void
{
trace("Restore Success - " + e.toString());
// ------------------------------- THIS LINE CONSUMES THE "TEST" ITEM ------------------------------- //
_iap.consume("android.test.purchased");
}
function onPurchaseSuccess(e:InAppPurchaseEvent):void
{
trace("Purchase Successful - " + e.data.toString());
outputField.text = "Purchase Successful - " + e.data.toString();
}
function onInitError(e:InAppPurchaseEvent):void
{
trace("Init Error - " + e.toString());
outputField.text = "Init Error - " + e.toString();
}
function onInitSuccess(e:InAppPurchaseEvent):void
{
trace("Init Success - " + e.toString());
outputField.text = "Init Success - " + e.toString();
// ------------------------------- THIS LINE RESTORES ALL PURCHASED ITEMS ------------------------------- //
//_iap.restore(InAppPurchase.TYPE_INAPP);
}
init.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler);
function fl_MouseClickHandler(event:MouseEvent):void
{
_iap.init("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiM0Lpjf/S5JQOh0L5c3IQNawziFTT9WeJ9fAmQl5nXJdfVnRK9+mMCnHJlKz8omt9RljlrtLpOV4iy+/KUFgtZ/SCvF+Brpk9lAEe+SbifT2mNGNKgF3tCXSHTXX2Xuq9kw1CR0bDy0Jf36LE04zBo4jYV4RcWQ66ViS2JbTEXAugG5S71z+CJXo6o5uYG/mRZlHFRJkpp1ufDFg4dp8r2ApN3RXhMv9Rl3NCcwTk3R0/rmwCc80Uy94kX7hkgeBuj/AViFZMbzYzY8YLdx80cYYHPc/ofecXmCl6OorJiBC+GiMs/vBoyjr4EGeIqfp1WdZrxeaJzMzAWPNoY4mSwIDAQAB");
}
purchase.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler_2);
function fl_MouseClickHandler_2(event:MouseEvent):void
{
//_iap.restore(InAppPurchase.TYPE_INAPP);
_iap.purchase("android.test.purchased", InAppPurchase.TYPE_INAPP);
}
consume.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler_3);
function fl_MouseClickHandler_3(event:MouseEvent):void
{
//_iap.restore(InAppPurchase.TYPE_INAPP);
_iap.consume("android.test.purchased");
}
restore.addEventListener(MouseEvent.CLICK, rLove);
function rLove(event:MouseEvent):void
{
//_iap.restore(InAppPurchase.TYPE_INAPP);
_iap.restore(InAppPurchase.TYPE_INAPP);
}
You did not add ANE file to your project properly.
This question was already asked and answered:
http://inside.pozirk.com/2013/02/18/adobe-air-in-app-purchase-native-extensions/#comment-87
http://inside.pozirk.com/2013/02/18/adobe-air-in-app-purchase-native-extensions/#comment-89
My checklist, after tinkering FlashBuilder for 2 hours:
1) "project" > Properties > ActionScript Build Path > Native Extensions > Add ANE > "add InAppPurchase.ane"
2) "project" > Properties > ActionScript Build Packaging > Google Android > Native Extensions > "select package InAppPurchase.ane"
3) ... AS3 code uses the in-app-purchase API ...
4) The ANE seems to fail if you try to use it in debug mode; an exported APK should be used instead.
5) FlashBuilder > Project > Export Release Build:
Verify that the ANE is included in the package (Native Extensions)
Verify that your are using the correct signing certificate.
6) Copy the created APK to the Android device.
7) Install the APK using a file explorer.
8) The app finally runs, instead of crashing/hanging at startup.