Hello I am having trouble writing logs to file on Android device using Xamarin.Forms (.NET Core shared project) and Serilog.
So far I have installed Serilog in Shared project. Installed Serilog, Serilog.Sinks.File, and Serilog.Sinks.Xamarin to my Android project and initialized logger in MainActivity:
Log.Logger = new LoggerConfiguration()
.WriteTo.File(Path.Combine(Environment.ExternalStorageDirectory.AbsolutePath,"XamarinLib-{Date}.txt"),
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] [{SourceContext}] {Message}{NewLine}{Exception}",
fileSizeLimitBytes: 100000000,
rollingInterval: RollingInterval.Day,
rollOnFileSizeLimit: true,
shared: false,
retainedFileCountLimit: 31,
encoding: Encoding.UTF8)
.WriteTo.AndroidLog()
.CreateLogger();
Afterwards I call the logger from shared project like:
Log.Information("Test writing to log file");
I can see the log command being executed in Visual Studio debug output, but the file is simply not created.
I've tried multiple locations on both emulator and actual device (no root access).
I've also tried to use RollingFile sink in similar manner with no success.
Any ideas?
First, you have to allow permissions in your AndroidManifest.xml file.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Next, The user either must, approve that on runtime in which you have to code this in your code behind. NOTE Remember to add Plugin.Permissions on your NUGET package:
InitializeComponent();
Task.Run(async () =>
{
try
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage);
if (status != PermissionStatus.Granted)
{
var accepted = await DisplayAlert("Storage Permission Required",
"Please enable your storage permission, it will be used to store logs and crashes",
"ACCEPT",
"CANCEL");
if(accepted)
{
var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Storage);
status = results[Permission.Storage];
}
}
}
catch (Exception ex)
{
await DisplayAlert("Exception ex", "Exception ex", "OK");
}
});
OR
let them change the permissions in the settings -> app -> permissions.
Finally,
change the filename that will link to the storage/emulated/0/[your added directory].
After the closing the app, you can see it in the Android File Manager.
as pointed out by Ruben Bartelink the problem is that Android can't simply write to external storage (ie /storage/emulated/0... etc..).
I was able to log to a file on a Xamarin.Forms project in both Android and iOS.
_Tmp = System.IO.Path.GetTempPath();
_Path = System.IO.Path.Combine(_Tmp, "Serilog.txt");
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File(_Path, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7)
.CreateLogger();
Log.Information("Started new serilogger {SERILOG} on file {FILE}", this, _Path);
Log.CloseAndFlush();
//test
foreach (string log in System.IO.Directory.GetFiles(_Tmp, "*.txt"))
{
string test = System.IO.File.ReadAllText(log);
System.Diagnostics.Debug.WriteLine($"Test[{log}] -> {test}");
}
which printed on the debug console:
[0:] Test[/data/user/0/com.******/cache/Serilog20190819.txt] -> 2019-08-19 16:00:36.997 +02:00 [INF] Started new serilogger ******.Functions.Serilogger on file /data/user/0/com.******/cache/Serilog.txt
Related
I'm making a new cross-platform MAUI App,and I tried to simply create a json file.the source code looks like this:
private async void WriteSomething()
{
#if ANDROID
FileStream fs = new(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) + "/test.json", FileMode.Create);
StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
await sw.WriteAsync(str);
sw.Close();
fs.Close();
#elif WINDOWS
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\test.json";
FileStream fs = new(path, FileMode.Create);
StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
await sw.WriteAsync(str);
sw.Close();
fs.Close();
#endif
}
The program runs well on windows machine,but the program throws System.UnauthorizedAccessException on android emulator.
I've searched this problem on StackOverflow,but most of the questions about this is on Xamarin platform.(Xamarin.Android or Xamarin.Forms)
According to the answers,I should request the storage permission like this:
First,add the following code to my AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Second,check if the target android version is Android M or above.If the answer is true,then invoke RequestPermissions method:
#if ANDROID
private void CheckAppPermissions()
{
if ((int)Build.VERSION.SdkInt < 23)
{
return;
}
else
{
if (PackageManager.CheckPermission(Manifest.Permission.ReadExternalStorage, PackageName) != Permission.Granted
&& PackageManager.CheckPermission(Manifest.Permission.WriteExternalStorage, PackageName) != Permission.Granted)
{
var permissions = new string[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage };
RequestPermissions(permissions, 1);
}
}
}
#endif
However,I found there is no such method in Android namespace.
CS0103 the name "RequestPermissions" does not exist in the current
context.
I guess it exists only in Xamarin platform.Or it acctually exists in another namespace.And that means I can't get the read and write permission I need.
A brand-new solution of the permission problem is needed.
**Note:**My English is poor.And I have little programming experience.Please forgive me.
Thanks in advance.
Actually, if you just operate the file in the System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) path, it shouldn't need any storage permissions. Because it's the app's own private folder. And I have tested your code in a new project, the josn file was created successfully.
In addition, if you want to request the permission in the maui, you need to use the api in the maui. You can use the following code instead of the yours.
PermissionStatus statusread = await Permissions.RequestAsync<Permissions.StorageRead>();
PermissionStatus statuswrite = await Permissions.RequestAsync<Permissions.StorageWrite>();
Finally, you can also use the permission Mahesh mentioned, but it should be used if necessary. And if you still want to it, you can try to add the following code in the MainActivity to grant the permission by the user.
protected override void OnCreate(Bundle savedInstanceState)
{
if (!Android.OS.Environment.IsExternalStorageManager)
{
Intent intent = new Intent();
intent.SetAction(Android.Provider.Settings.ActionManageAppAllFilesAccessPermission);
Android.Net.Uri uri = Android.Net.Uri.FromParts("package", this.PackageName, null);
intent.SetData(uri);
StartActivity(intent);
}
base.OnCreate(savedInstanceState);
}
use this permission, hope it's helps, check once with give manually permission.
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
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 have an app using Ionic and Capacitor with target API 29, but I need to change to API 30 because of PlayStore rules.
My problem with this transition is with capacitor filesystem, which is not finding files in my device. I need to read these files to import in the map in my app.
I tried to read files and directories, tried to create some random files and use stat to get files information, but sometimes I can read these files and sometimes I don't. I tried to find a pattern in this errors with some tests, but I couldn't find or understand the pattern.
Initially I thought that this problem was caused by external storage permissions, so I added in the manifest the relevant parameters, even so the errors persisted in my app. I started to think that this can be related to Android Unix Permissions, but I can't say if that is true. I tried to use checkPermissions() of Capacitor, but I received the 'granted' response.
External Storage parameters in AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I tried to research for permission problems related to capacitor filesystem, but the only question I found is my own about the same subject, created a while ago. This question have an answer, but it is but not applicable for API 30.
I also tried to research about filesystem android permissions too, I found one answer about this subject, but this only tell me that I can't modify the FS permission properties.
Some things I tried to do:
First I tried to use readFile() in a file on external storage:
this.fs.readFile('Download/test.kml', true).then(response => {
console.log(response)
});
readFile() function inside FS service:
/** Read a file and returns a string as base 64 */
readFile(path: string, needDirectory: boolean = false, dir: string = 'ExternalStorage'): Promise<string> {
let options: ReadFileOptions;
if (needDirectory) {
options = {
path: path,
directory: Directory[dir]
}
} else {
options = {
path: path
}
}
return Filesystem.readFile(options).then(result => {
return result.data;
});
}
But it didn't work, then I tried to create some files using writeFile(), in tree different directories:
this.fs.writeFile('Download/', 'test.kml', "<xml version='1.0' encoding='utf-8'></xml>", true, undefined, true);
this.fs.writeFile('/', 'test.kml', "<xml version='1.0' encoding='utf-8'></xml>", true, 'External', true);
this.fs.writeFile('/', 'test.kml', "<xml version='1.0' encoding='utf-8'></xml>", true, 'Documents', true);
writeFile() function inside FS service:
/** Write a file, content in base64, Pass encoding to true to write data as string */
writeFile(path: string, filename: string, content: any, recursive: boolean = false, dir: string = 'ExternalStorage', encoding: boolean = false): Promise<boolean> {
let options: WriteFileOptions = {
path: path + filename,
data: content,
directory: Directory[dir],
recursive: recursive
}
if (encoding) {
options.encoding = Encoding.UTF8
}
return Filesystem.writeFile(options).then(result => {
if (result) {
return true;
} else {
return false;
}
})
}
This worked! Then I tried to read all these newly created files:
this.fs.readFile('Download/test.kml', true);
this.fs.readFile('test.kml', true, 'External');
this.fs.readFile('test.kml', true, 'Documents');
This worked too!, Now, in my head the problem is with the files that aren't created by my app, but the files that already exist in FS or are moved by the user. So I tried to use readDir to test what the app sees:
this.fs.readDir('/', undefined, true)
this.fs.readDir('/', 'External', true)
this.fs.readDir('/', 'Documents', true)
readDir function into de fs service:
/** Read dir and list this files */
readDir(path: string, dir: string = 'ExternalStorage', needDirectory: boolean = true): Promise<ReaddirResult> {
let options: ReaddirOptions;
if (needDirectory) {
options = {
path: path,
directory: Directory[dir]
}
} else {
options = {
path: path
}
}
return Filesystem.readdir(options).then(files => {
return files;
}).catch(e => {
console.log(e);
let resultError: ReaddirResult = {
files: []
};
return resultError;
})
}
The readDir() returns me only the folders that my app created, but there are others files in this directory, those that were created manually didn't appear. Then I tried to use the stat() function in one of this files that my app didn't saw:
this.fs.getStat('USO.kml', 'Documents')
this.fs.getStat('USO.kml')
getStat() function inside FS service:
/**
* Get file information's: type, size, ctime(Create time), mtime(Last modification), uri
* #param path path of file
* #param dir directory where is file
*/
getStat(path: string, dir: string = 'ExternalStorage'): Promise<StatResult> {
return Filesystem.stat({
path: path,
directory: Directory[dir]
}).then(result => {
return result;
});
}
I can't understand, because the file USO.kml in Documents directory appear in stat function, but another one in external storage returns me an error File does not exist. I don't understand why it's happening. How can I correctly read the files using Capacitor FS and API 30?
Edit
Just to clarify: The file is moved externally by the user and saved inside this directory through Android explorer. I need to import this file to my app to get the information inside.
I just used NUGET and installed Xam.Plugin.Media so that I can take photos using my mobile app.
I wrote the following code in the click event of the button as per the sample code in the xamarin component website:
private async void btnTake1_Clicked(object sender, EventArgs e)
{
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", ":( No camera avaialble.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "Sample",
Name = "test.jpg"
});
if (file == null)
return;
await DisplayAlert("File Location", file.Path, "OK");
imgPhoto1.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
}
All went well and the Solution is building successfully, I am running only UWP now. But when I click the button it breaks at some location in
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
Can somebody help me with this?
Thanks in advance.
Sarin Gopalan
As per your comment the following applies to Xamarin.Forms and UWP
In your forms project, wherever it is you want to dispaly the gallery picker (we are doing it from a button click) you would use something like the below:
private async void ChooseExistingClicked(object sender, EventArgs e)
{
bool hasPermission = false;
try
{
await CrossMedia.Current.Initialize();
hasPermission = CrossMedia.Current.IsPickPhotoSupported;
}
catch (Exception genEx)
{
var Error = genEx;
}
if (!hasPermission)
{
await DisplayAlert("Photos Not Supported", ":( Permission not granted to photos.", "OK");
return;
}
var file = await CrossMedia.Current.PickPhotoAsync();
if (file == null)
return;
image = file;
imagePanel.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
return stream;
});
}
You also need to set the permissions up correctly. So in your UWP project, you will see a file called 'Package.appxmanifext' double click on this, and select 'Capabilities' and make sure that 'Picture Library' in the list is ticked.
That's it, that should be all you need to do.
EDIT: As requested below are the places you would need to set permissions for the native platforms to access the photo gallery.
In your iOS project you will need to open the code of the 'Info.plist' file which will show you an XML sheet. you need to add:
<key>NSCameraUsageDescription</key>
<string></string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This is used to upload an image of concern along with your report</string>
<key>NSMicrophoneUsageDescription</key>
<string></string>
anywhere in between the tags.
For your Android project you need to right click the project and select 'properties' this will open a new window, and on the left you need to select 'Android Manifest' then ensure that 'CAMERA', 'READ_EXTERNAL_STORAGE', and 'WRITE_EXTERNAL_STORAGE'. I believe those are the main one's for both gallery and camera access.
Have you tried to InitializeComponent like the documentation on github?
await CrossMedia.Current.Initialize();
https://github.com/jamesmontemagno/MediaPlugin
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.