I am trying to unzip a folder in cordova 3.4. But haven't been successful so far. I have seen many tutorials but none of them seems to work for me. Kindly suggest me some plugin or code if you have already done this and if its working.
File is successfully getting saved using http://weblogs.asp.net/soever/cordova-file-transfer-unzip-and-present-adventures, but unzip is not working.
Here is my code, calling for unzip.
document.getElementById("btnUnzip").onclick = function() {
var that = this,
App = new DownloadApp(),
fileName = "ft-p.zip",
folderName = "content";
console.log("zip button clicked");
App.unzip(folderName, fileName,
/*success*/function() { alert("Unzipped and assigned"); },
/*fail*/function(error) { alert("Unzip failed: " + error.code); }
);
};
Thanks.
Related
I have a small MAUI app i'm testing with. Im trying to read a file that was part of the deployment. I have the code below, which works great in a Windows deploy of the MAUI app, but crashes in Android. What is the proper cross-platform way to do this?
// TODO get from service or xml
var path = AppDomain.CurrentDomain.BaseDirectory;
//var path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
var fullpath = Path.Combine(path, "Services\\questions.json");
var json = File.ReadAllText(fullpath);
MAUI has a new way to access files included with the app: MauiAsset.
Described in blog Announcing .NET MAUI Preview 4, Raw Assets:
.NET MAUI now makes it very easy to add other assets to your project and reference them directly while retaining platform-native performance. For example, if you want to display a static HTML file in a WebView you can add the file to your project and annotate it as a MauiAsset in the properties.
<MauiAsset Include="Resources\Raw\index.html" />
Tip: you can also use wildcards to enable all files in a directory:
... Include="Resources\Raw\*" ...
Then you can use it in your application by filename.
<WebView Source="index.html" />
UPDATE
However, the feature MauiAsset apparently still needs improvement:
open issue - MauiAsset is very hard to use.
There we learn that for now:
Set BuildAction in each file's properties to MauiAsset.
That is, its not recommended to use the "wildcard" approach at this time. Set that build action on each file in solution explorer / your project / the file.
Accessing on Windows requires a work-around:
#if WINDOWS
var stream = await Microsoft.Maui.Essentials.FileSystem.OpenAppPackageFileAsync("Assets/" + filePath);
#else
var stream = await Microsoft.Maui.Essentials.FileSystem.OpenAppPackageFileAsync(filePath);
#endif
NOTE: This will be simplified at some point; follow that issue to see progress.
UPDATE
The current MAUI template is missing some platform-specific flags. For now, add your own flag to identify when the code is running on Windows:
Complete example in ToolmakerSteve - repo MauiSOAnswers. See MauiAssetPage.
MauiAssetPage.xaml:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiTests.MauiAssetPage">
<ContentPage.Content>
<!-- By the time Maui is released, this is all you will need. -->
<!-- The Init code-behind won't be needed. -->
<WebView x:Name="MyWebView" Source="TestWeb.html" />
</ContentPage.Content>
</ContentPage>
MauiAssetPage.xaml.cs:
using Microsoft.Maui.Controls;
using System.Threading.Tasks;
namespace MauiTests
{
public partial class MauiAssetPage : ContentPage
{
public MauiAssetPage()
{
InitializeComponent();
Device.BeginInvokeOnMainThread(async () =>
{
await InitAsync();
});
}
private async Task InitAsync()
{
string filePath = "TestWeb.html";
#if WINDOWS
var stream = await Microsoft.Maui.Essentials.FileSystem.OpenAppPackageFileAsync("Assets/" + filePath);
#else
var stream = await Microsoft.Maui.Essentials.FileSystem.OpenAppPackageFileAsync(filePath);
#endif
if (stream != null)
{
string s = (new System.IO.StreamReader(stream)).ReadToEnd();
this.MyWebView.Source = new HtmlWebViewSource { Html = s };
}
}
}
}
TestWeb.html:
(whatever html you want)
In Solution Explorer, add TestWeb.html to your project. In its Properties, select Build Action = MauiAsset.
I tried looking for a solution to this for months. I ended up hosting the file online then creating a method to download the file during runtime
public async Task DownloadFile(string fileName)
{
if (File.Exists(FileSystem.Current.AppDataDirectory + $"/{fileName}"))
{
return;
}
else
{
try
{
NetworkAccess networkAccess = Connectivity.Current.NetworkAccess;
if (networkAccess == NetworkAccess.Internet)
{
await Task.Run(() =>
{
var uri = new Uri($"https://myhostedfile.com/{fileName}");
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCallback2);//checking if download is complete
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(MaintainProgress);//event handler to check download progress
webClient.DownloadFileAsync(uri, FileSystem.Current.AppDataDirectory + $"/{fileName}");
});
}
else
await Shell.Current.DisplayAlert("No Internet", "Failed to get some files from the internet, confirm if your internet is" +
"working", "OK");
}
catch (Exception)
{
await Shell.Current.DisplayAlert("Error", "Failed to get some files from the internet, confirm if your internet is" +
"working", "OK");
}
}
}
Then you can access your file URL using:
string filePath = FileSystem.Current.AppDataDirectory + $"/myfile.pdf;
I am new to Unity and Android development, but please do not mark this as a duplicate - I've looked all over the stacks for an answer to this, but similar topics and questions haven't yielded any working solutions, or are wanting on details, or outdated, or seem not to fit my specific need.
Ok, I have a quiz app built from following part 1 & 2 of this tutorial. That link contains all the source files anyone might need for reference, and everything works fine on ios and in the unity editor, fyi.
The trouble is with the loadGameData function from the DataController script in Android. Again, everything works fine in iOS and the unity editor, but when I make an Android sdk, the quiz is blank and the console says the data couldn't be loaded.
Here is how the function is currently written (full file in tutorial link):
private void LoadGameData ()
{
string filePath = Path.Combine (Application.streamingAssetsPath, gameDataFileName);
if (File.Exists (result))
{
string dataAsJson = File.ReadAllText (result);
GameData loadedData = JsonUtility.FromJson<GameData> (dataAsJson);
allRoundData = loadedData.allRoundData;
} // #if(File.Exists...
else
{
Debug.LogError ("Cannot load game data!");
} // #else
} // #LoadGameData
If you check the same tutorial on youtube, you'll see lots of people have noted the same problem with the Android build and have been left unanswered. Same goes with unity forums - that's one reason why I don't think this question is a duplicate and could be helpful to others in a similar situation.
I've found that Android has always been sorta tricky with this and that there used to different ways of accessing a file based on platform, but these days "Application.streamingAssetsPath" should find the streaming assets directory on any platform, even Android.
What I've also learned is that in android, even if the path is correct, the file is compressed and will only return a url. So the url needs to be converted using unity's WWW class. I get that, but as of yet, I haven't been able to re-write my loadGameData function to work properly and load the allRoundData array.
Here's an example of some things I've tried:
IEnumerator androidData()
{
string filePath = Path.Combine (Application.streamingAssetsPath, gameDataFileName);
if (filePath.Contains("://"))
{
WWW www = new WWW(filePath);
yield return www;
result = www.text;
} // #if(filePath.Contains
} // #androidData
private void LoadGameData ()
{
androidData();
if (File.Exists (result))
{
string dataAsJson = File.ReadAllText (result);
GameData loadedData = JsonUtility.FromJson<GameData> (dataAsJson);
allRoundData = loadedData.allRoundData;
} // #if(File.Exists...
else
{
Debug.LogError ("Cannot load game data!");
} // #else
} // #LoadGameData
I know I'm close, and this is probably simple -- but I just can't seem to get to the finish line on this. Can some one help me figure out how to write the loadGameData function so it will load this allRoundData array on android?
An example code would be awesome and much appreciated, not just by me, but I'm sure many others would appreciate it also - Thank you!
UPDATE:
Based on the first answer, I've tested some code that works on the unity editor, but crashes in Android. In the Unity editor, I get the "file already exists" message. Here is the code I've tested:
Already had: private string gameDataFileName = "data.json";
I added the copyFile call above loadGameDate in Start() and wrote the copy file and loadGameData functions like so ..
int copyFileToPersistentDataPath(string gameDataFileName)
{
string persistentPath = Application.persistentDataPath + "/" + gameDataFileName;
try
{
//Copy only if gameDataFileName does not exist
if (!System.IO.File.Exists(persistentPath))
{
string path = System.IO.Path.Combine(Application.streamingAssetsPath, gameDataFileName);
WWW www = new WWW(path);
while (!www.isDone) { }
System.IO.File.WriteAllBytes(persistentPath, www.bytes);
Debug.Log(gameDataFileName + " Successfully Copied File to " + persistentPath);
return 1;
}
else
{
Debug.Log(gameDataFileName + " File already exist here. There is no need to copy it again");
return 0;
}
}
catch (Exception e)
{
Debug.Log(gameDataFileName + " Failed To Copy File. Reason: " + e.Message);
return -1;
}
}
private void LoadGameData ()
{
string tempPath = Path.Combine(Application.persistentDataPath, gameDataFileName);
string dataAsJson = File.ReadAllText(tempPath);
GameData loadedData = JsonUtility.FromJson<GameData>(dataAsJson);
allRoundData = loadedData.allRoundData;
} // #LoadGameData
This works with or without the call to copy the file in the editor, but crashes either way in Android.
I ended up putting the files in a Resources folder and going the resources.load a json file into a text asset and throw that into a string to parse route. I now have two different load functions, one that works in ios etc. and one that works in android. Here is the android function (the resourcesGameDataFile does not have the .json extension):
public void LoadDataForAndroid()
{
TextAsset dataFile = Resources.Load(resourcesGameDataFile) as TextAsset;
string dataAsJson = dataFile.ToString();
GameData loadedData = JsonUtility.FromJson<GameData>(dataAsJson);
allRoundData = loadedData.allRoundData;
Debug.Log ("Android data loaded with" + resourcesGameDataFile);
} // #LoadDataForAndroid
And this works in the unity editor and in Bluestacks (android simulator).
As for loading and saving games, this is a duplicate. I marked and remove this as a duplicate because the answer in the duplicated questions did not explain how to read from the StreamingAssets folder. It only talked about saving and loading data.
Make sure that Write Permission is set to External (SDCard).
The first thing to do is to copy the file from StreamingAssets to the persistentDataPath location.
I've found reading data from Application.streamingAssetsPath problematic but I use two methods to solve this.
int copyFileToPersistentDataPath(string fileNameWithExtensionName)
{
string persistentPath = Application.persistentDataPath + "/" + fileNameWithExtensionName;
try
{
//Copy only if fileNameWithExtensionName does not exist
if (!System.IO.File.Exists(persistentPath))
{
string path = System.IO.Path.Combine(Application.streamingAssetsPath, fileNameWithExtensionName);
WWW www = new WWW(path);
while (!www.isDone) { }
System.IO.File.WriteAllBytes(persistentPath, www.bytes);
Debug.Log(fileNameWithExtensionName + " Successfully Copied File to " + persistentPath);
return 1;
}
else
{
Debug.Log(fileNameWithExtensionName + " File already exist here. There is no need to copy it again");
return 0;
}
}
catch (Exception e)
{
Debug.Log(fileNameWithExtensionName + " Failed To Copy File. Reason: " + e.Message);
return -1;
}
}
If that does not work for you, use the method with WebClient below:
void copyFileToPersistentDataPath(string fileNameWithExtensionName)
{
string path = System.IO.Path.Combine(Application.streamingAssetsPath, fileNameWithExtensionName);
string persistentPath = Application.persistentDataPath + "/" + fileNameWithExtensionName;
Debug.Log("Dir: " + persistentPath);
WebClient webClient = new WebClient();
webClient.Proxy = null;
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(OnDownloadComplete);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnUpdateDownloadProgress);
Uri uri = new Uri(path);
webClient.DownloadFileAsync(uri, persistentPath);
}
void OnDownloadComplete(object sender, AsyncCompletedEventArgs e)
{
Debug.Log("Finished Downloading: " + e.Error.Message);
}
void OnUpdateDownloadProgress(object sender, DownloadProgressChangedEventArgs e)
{
Debug.Log("Uploading Progreess: " + e.ProgressPercentage);
}
File Copy Usage:
copyFileToPersistentDataPath("yourFileName.txt");
After copying the file, you can then read and convert it to Json like this:
string fileNameWithExtensionName = "questionfile.txt";
string tempPath = Path.Combine(Application.persistentDataPath, fileNameWithExtensionName);
string dataAsJson = File.ReadAllText(fileNameWithExtensionName);
GameData loadedData = JsonUtility.FromJson<GameData>(dataAsJson);
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 am developing a new Phonegap 3 application. I find the development process very slow. Each time I want to test a change in my app, I have to run in the console:
phonegap run android
This command takes about 30 seconds to run! Any idea on how to improve the time to test each change?
If you are developing for android using ecllipse you can use an android handset, connect it with your development machine with usb cable and install necessary drivers from here
.
Drivers are required mostly for windows in mac and linux it is usually not necessary. After set up it is just a matter of clicking run in your ide.
If you have a huge amount of files (libraries with demos, non-minified files, etc.), installing on the app can take a long long time.
I created this hook (added to before_prepare) which only copies the necessary files (specified in "requirements.json" in my project).
You need to run cd hooks/before_prepare && npm install ncp to install the dependency.
hooks/before_prepare/010copy_assets.js
#!/usr/bin/env node
console.log("=== Running copy required assets hook ===");
var fs = require('fs'),
path = require('path');
var mkdirSync = function(path) {
try {
fs.mkdirSync(path);
} catch (e) {
if (e.code != 'EEXIST') throw e;
}
}
var mkdirpSync = function(dirpath) {
var parts = dirpath.split(path.sep);
for (var i = 1; i <= parts.length; i++) {
mkdirSync(path.join.apply(null, parts.slice(0, i)));
}
}
try {
var ncp = require('ncp').ncp
var requirements = require('./../../myproject/requirements.json');
ncp.limit = 200;
ncp.stopOnErr = true;
requirements.forEach(function(requirement) {
var source = './myproject/' + requirement;
var destination = './www/' + requirement;
var folders = destination.split('/');
folders.pop();
mkdirpSync(path.normalize(folders.join('/')));
ncp(source, destination, function(err) {
if (err) {
console.log('====== Error! Did not copy asset from ' + source + ' to ' + destination + ' ======');
console.error(err);
process.exit(1001);
} else
console.log('====== Copied asset from ' + source + ' to ' + destination + ' ======');
});
});
} catch (e) {
console.error(e);
console.error(e.stack);
process.exit(1000);
}
example requirements.json
[
"js",
"css",
"img",
"index.html"
]
Note that you can move stuff directly into the build www directory (inside platforms) but they have different paths under ios and android