Capacitor Filesystem returns error while using main functions - ionic-framework

I created a new app using capacitor 3, in this app I used the Filesystem to perform some functions. I created a service to handle everything related to the filesystem, but when I went to use the functions I had some problems.
When using Android 11 to create a directory using the mkdir() function I get the following error:
Unable to create directory, unknow reason.
Also on Android 11, when I try to create a file using only writeFile() it returns the following error:
FILE_NOTCREATED
For Android 10 and below the mkdir() function works correctly, but the writeFile() function causes the app to crash without any errors. Also, if I try to change the Diretory.ExternalStorage to Diretory.External I can create a directory in Android 11, but it still crashes when writing a file.
Using Android 11, I tried to write a txt file with a simple string and with also with a small base64 string. When using Diretory.External I can write the base64 string in a new file, but when using the Diretory.ExternalStorage I got the FILE_NOTCREATED error.
I did all the configurations and followed the steps in the documentation to set up AndroidManifest.xml.
Several tests have been done on emulators and phones with different versions of Android.
Tests with writeFile()
Android 11
base64 + Diretory.External = success
string + Diretory.External = crash
base64 + Diretory.ExternalStorage = error
string + ExternalStorage = error
Android 10 and below
base64 + Diretory.External = success
string + Diretory.External = crash
base64 + Diretory.ExternalStorage = success
string + ExternalStorage = crash
Android XML
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:requestLegacyExternalStorage="true"
>
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" android:required="true" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
MainFunction.ts
testeFilesystem(): void {
let path: string = 'test/project';
this.filesystem.checkAndCreateDir(path).then(_ => {
this.filesystem.writeFile(path, 'test.txt', 'test').then(_ => {
this.uicontroller.presentToast('file saved');
});
})
}
FilesystemService.ts
checkAndCreateDir(path: string): Promise<boolean> {
return Filesystem.readdir({
path: path,
directory: Directory.ExternalStorage
}).then(_ => {
return true;
}).catch(_ => {
return Filesystem.mkdir({
path: path,
directory: Directory.ExternalStorage,
recursive: true
}).then(_ => {
return true;
});
});
}
writeFile(path: string, filename: string, content: string): Promise<boolean> {
return Filesystem.writeFile({
path: path + filename,
data: content,
directory: Directory.ExternalStorage
}).then(result => {
if (result) {
return true;
} else {
return false;
}
});
}
Ionic Info
Ionic CLI : 6.16.1 C:\Users\User\AppData\Roaming\npm\node_modules#ionic\cli
Ionic Framework : #ionic/angular 5.6.7
#angular-devkit/build-angular : 0.1102.10
#angular-devkit/schematics : 11.2.13
#angular/cli : 11.2.13
#ionic/angular-toolkit : 3.1.1
Capacitor:
Capacitor CLI : 3.0.0
#capacitor/android : 3.0.0
#capacitor/core : 3.0.0
#capacitor/ios : not installed
Utility:
cordova-res : 0.15.3
native-run : 1.3.0
System:
NodeJS : v14.16.1 (C:\Program Files (x86)\nodejs\node.exe)
npm : 6.14.12
OS : Windows 10

Got the same error ('FILE_NOTCREATED') on Android 12 using the following code after some writes:
// Save to filesystem
const resp = await Filesystem.writeFile({
path: fileName,
data, // base64 pdf
directory: Directory.Documents,
});
The error occurs because of the same filename. After adding the current date with the following way, the error was solved:
const currentDate = new Date().toLocaleString().replace(/[,:\s\/]/g, '-');
const fileName = `myFile-${currentDate}.pdf`;
Be aware to replace all slashes because if not it will create sub-directories and if 'recursive: true' is not added the following error occurs on android:
Parent folder not found.

I found this issue on capacitor's github, maybe it can help you, in short it says:
If you target SDK 30, then android:requestLegacyExternalStorage="true" will not work on Android 11+ devices.
Google doesn't allow to programmatically access external shared files anymore. (Documents and ExternalStorage)
https://developer.android.com/training/data-storage/use-cases#opt-out-in-production-app

Related

Trying to delete an audio file but giving exception in flutter

I'm trying to delete song file but it is unable to delete and throws an exception of permission denied but permissions are already granted using permission_handler and required storage permissions are added in AndroidManifest.xml as well. I have also checked path is valid and file exist before delete which return true. Would anyone help me to solve this.
Error on file.delete() line.
Unhandled Exception: FileSystemException: Deletion failed, path = '/storage/0E15-2E06/Music/Call Sound Effect.mp3' (OS Error: Permission denied, errno = 13)
AndroidManifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<application
android:label="Example"
android:name="${applicationName}"
android:icon="#mipmap/ic_launcher"
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true" >
Code snippet:
if (await Permission.storage.request().isGranted) {
// Either the permission was already granted before or the user just granted it.
// permission was granted
if (song != null) {
String? path = song.data;
File file = File(path);
bool isExist = await file.exists();
if (isExist) {
await file.delete(recursive: true);
}
}
}
You have to use the permission_handler(https://pub.dev/packages/permission_handler) package and have to mention some permissions in the Androidmanifest.xml file.
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Also, you have to ask Permission of storage before doing storage related operation(In your case deletion of audio file).
final _permissionStatus = await Permission.storage.request();
if(_permissionStatus = PermissionStatus.isGranted){
/// Delete audio file
}else{
/// Permission Denied.
}

How to wire up an Share intent in MAUI for Android?

I'm trying to work out how to wire up a Share intent in Android using MAUI.
Am I running into preview bugs, or am I not doing it correctly?
I'm running MAUI Preview 10, with Visual Studio 17.1.0 Preview 1.0.
Version 1
I've added the share intent to the AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
<application android:allowBackup="true" android:icon="#mipmap/appicon" android:roundIcon="#mipmap/appicon_round" android:supportsRtl="true">
<activity android:name="SomeLongName.MainActivity" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
And then by adding a Name property to the MainActivity class:
[Activity(Name = "SomeLongName.MainActivity", Theme = "#style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
public class MainActivity : MauiAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
if (Intent.Type == "text/plain")
{
}
}
}
When I debug the application in MAUI, the app builds correctly and the Output says that the app has deployed. However, in Visual Studio, the debugger fails to run, and there is no evidence of the app on the emulator.
Version 2
In version 2, I've tried to create a separate activity for the Share intent:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
<application android:allowBackup="true" android:icon="#mipmap/appicon" android:roundIcon="#mipmap/appicon_round" android:supportsRtl="true">
<activity android:name="SomeLongName.ShareActivity" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
[Activity(Name = "SomeLongName.ShareActivity")]
public class ShareActivity : MauiAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
if (Intent.Type == "text/plain" && Intent.Action == "android.intent.action.SEND")
{
//handleSendUrl();
}
base.OnCreate(savedInstanceState);
}
I can now successfully debug the application, but when I try to share to the application, I get an exception on the base.OnCreate call:
Java.Lang.IllegalStateException: 'The specified child already has a parent. You must call removeView() on the child's parent first.'
Seems the issue centres around themes. The solution is in the original question, apply Version 2. With some minor updates. In the MainApplication class add an attribute defining the theme (same as in MainActivity class but could be different).
[Application(Theme = "#style/Maui.SplashTheme")]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
This both works without error and enables debugging.
Without the MainApplication theme setting, when sharing to the android app (incoming), an error thrown:
Java.Lang.IllegalArgumentException: 'The style on this component requires your app theme to be Theme.MaterialComponents (or a descendant).'
In my secondary activity, the Activity attribute sets the Theme, but is ignored and error still shown, hence the Application level needed. Not sure why.
[Activity(Theme = "#android:style/Theme.MaterialComponents.Light", Name = "com.somename.receiveurlactivity", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
public class ReceiveUrlActivity : MauiAppCompatActivity
{
//.... etc

Get files from the directory - Flutter

I'm trying to fetch some files from the local directory by using the dependency path_provider: ^1.6.27, but was getting an error stating as Unhandled Exception: MissingPluginException(No implementation found for method getExtStorageData on channel path_provider_ex)
The code where I'm fetching
getFiles() async {
directory = (Directory('storage/emulated/0/FolderName')).path;
setState(() {
file = io.Directory('$directory/${widget.folderName}').listSync();
});
List<StorageInfo> storageInfo = await PathProviderEx.getStorageInfo();
}
Getting the error in the line List<StorageInfo> storageInfo = await PathProviderEx.getStorageInfo();
Have mentioned the permissions in the manifest file
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:requestLegacyExternalStorage="true"/>
If you have just added the plugin this may help you.
MissingPluginException

Manifest merger ionic 3

I am facing build error after installing cordova-plugin-qrscanner
i have installed QR scanner using this command bellow
ionic cordova plugin add cordova-plugin-qrscanner
npm install #ionic-native/qr-scanner
I have also import this to my app module
but after this when i am building apk, getting err
F:\Project 2\EzeeAccess\platforms\android\app\src\main\AndroidManifest.xml:44:5-90 Error:
Element uses-permission#android.permission.CAMERA at AndroidManifest.xml:44:5-90 duplicated with element declared at AndroidManifest.xml:41:5-65
:app:processDebugManifest
See http://g.co/androidstudio/manifest-merger for more information about the manifest merger.
:app:processDebugManifest FAILED
28 actionable tasks: 2 executed, 26 up-to-date
F:\Project 2\EzeeAccess\platforms\android\app\src\main\AndroidManifest.xml:45:5-85 Error:
Element uses-feature#android.hardware.camera at AndroidManifest.xml:45:5-85 duplicated with element declared at AndroidManifest.xml:43:5-84
F:\Project 2\EzeeAccess\platforms\android\app\src\main\AndroidManifest.xml Error:
Validation failed, exiting
FAILURE: Build failed with an exception.
I have also installed cordova Camera plugin
Probably these lines causing the problem in AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-permission android:name="android.permission.CAMERA" android:required="false" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
and this is my android.json
{
"xml": "<uses-permission android:name=\"android.permission.CAMERA\" android:required=\"false\" />",
"count": 1
},
{
"xml": "<uses-permission android:name=\"android.permission.CAMERA\" />",
"count": 1
},
{
"xml": "<uses-feature android:name=\"android.hardware.camera\" android:required=\"true\" />",
"count": 1
},
{
"xml": "<uses-feature android:name=\"android.hardware.camera\" android:required=\"false\" />",
"count": 1
},
{
"xml": "<uses-feature android:name=\"android.hardware.camera.front\" android:required=\"false\" />",
"count": 1
}
please help

nativescript-contacts throw error

Error: Error: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{c896ebc 5117:org.nativescript.Jztong/u0a11
1} (pid=5117, uid=10111) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS
Add this lines in your app/App_Resources/Android/AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
If you are using android v6 you should requires permission at runtime, you can use nativescript-permissions plugin.
var perm = permissions.requestPermission(android.Manifest.permission.WRITE_CONTACTS, "I need write Contact permission!");
perm.then(() => {
//addContact();
}).catch(() => {
alert("Oops, No permissions to write contact!");
});