How to save file with Capacitor on iOS? - ios

I have the following code (adapted from this tutorial) that I use for saving files from backend:
import { FilesystemDirectory, Plugins } from '#capacitor/core';
const { Filesystem } = Plugins;
await Filesystem.writeFile({
path: "filename.txt",
data: "base64 data",
directory: FilesystemDirectory.Documents,
});
This codes works fine on Android, even creates the Documents directory in the root of internal storage. Unfortunately, on iOS no file is created, no mater what directory I use (I've tested it with Documents, Data and ExternalStorage).
When I put this code block inside try..catch, nothing is thrown, so the operation is supposedly completed successfully, just no file is saved. Tested on one Android device and two iOS.

iOS doesn't allow accessing file storage directly. I made it work with Ionic-native's FileOpener like this:
import { FileOpener } from '#ionic-native/file-opener/ngx';
import { FilesystemDirectory, Plugins } from '#capacitor/core';
const { Filesystem } = Plugins;
const result = await Filesystem.writeFile({
path: "filename.txt",
data: "base64 data",
directory: FilesystemDirectory.Documents,
});
this.fileOpener.showOpenWithDialog(result.uri, 'application/json')
It opens a dialog where you can select where to save your file. It's a bit confusing as the function's description is "Opens with system modal to open file with an already installed app" but saving works with it as well.
You need to also install cordova-plugin-file-opener2 and put ionic FileOpener to providers in app.module.ts. If you are not using Cordova otherwise, you don't need to do Cordova setups, it works alongside Capacitor as a separate plugin. As far as I'm aware, Capacitor doesn't provide a solution for downloading in iOS.

I've encountered the same problem (while having capacitor 4.2.0 only) and solved it by adding the following permissions in my Info.plist:
<key>UIFileSharingEnabled</key>
<string>YES</string>
<key>LSSupportsOpeningDocumentsInPlace</key>
<string>YES</string>
After this, using directory Directory.Documents has made me visible a Documents directory with the name of the app under the Files App.
Hope it helps.

Related

Why is TestFlight app different from local development?

I have a React Native app with a custom native plugin.
The app works fine when I test it with Xcode on my device.
I uploaded the exact same app to the App Store and it got broken.
On my iPhone it doesn't actually start and on my iPad it is buggy:
I have to tap buttons twice
Code order is wrong (may threading / rendering)
Events from the plugin sometimes get fired and sometimes not. Totally random. (could also be rendering issue)
Unfortunately, I can't debug the TestFlight App.
Does someone have a starting point why this could happen?
I found the problem. It was in my Plugin and how I expose it. My index.ts file looked like this:
import { NativeModules } from 'react-native';
const { MyPlugin } = NativeModules;
export default MyPlugin;
Better with no default export:
import { NativeModules } from 'react-native';
export const { MyPlugin } = NativeModules;
I don't know why a default export doesn't work in release mode. I tried all release flags to be the same as default, but it was the same result.
So, just changing the way of export was fixing it.

The file "test.pdf" could not be opened on mac. [Ionic-iOS]

I am trying to save the pdf in iOS using the Ionic Filesystem. I am using the below functions for writing the files.
Filesystem.writeFile({
path: 'test',
data: EStatementConstant.BinData,
directory: Directory.Documents,
encoding: Encoding.UTF8,
});
Where EStatementConstant.BinData is my base64 data [validated] which I am getting directly from the API service.
The problem is that I am unable to open the file on a Mac. I didn't find any function to decode.
I am using capacitor v-3.
https://capacitorjs.com/docs/apis/filesystem?_gl=11i199tw_gaMTYzMjY4MzAzMi4xNjM0ODQxNDI4_ga_REH9TJF6KF*MTY0ODgwMzI4NS40OS4wLjE2NDg4MDMyODUuMA..#type-401
Note:- I am unable to save the pdf data without encoding in iOS. Also, I can not use the Cordova plugin. I am struggling with this for the last few days. Please help.

Trouble storing and loading images locally in Nativescript on IOS

1) Storing images locally to be displayed later via the html, most all of the docs say to store them like in ~/images/image1.png. Typescript/Nativescript says to store these by doing this:
fileSystemModule.knownFolders.currentApp(), then join the "/images/image1.png and write the file. This works great on IOS and Android in debug mode and the simulators, but it doesn't work in a Release version of IOS. IOS gives an error saying you can't access this folder. The nativescript documentation clearly says for currentApp that " iOS - this folder is read-only and contains the app and all its resources.".
Thus, if it's IOS, I do what the doc for the Filesystem/IOS module says:
var dirPath;
if (isIOS) {
dirPath = fileSystemModule.knownFolders.ios.library();
dirPath = fileSystemModule.path.join(fileSystemModule.knownFolders.ios.library().path, '/Application Support/myapp/images/image1.png');
I'm able to write and read files from here from TS code fine. However,
2) For displaying these in my page, for an image in my html, I have src='~./Library/Application Support/myapp/images/image1.png' and it's not able to find them. Any suggestions appreciated.
There are a lot of docs saying how to write files locally using currentApp(), but none talk about how this doesn't work in the Release version of IOS.

Ionic Geolocation Permission issue on iOS

I have a problem with the GeoLocation Plugin at ionic3.
I added all the import stuff. The <edit-config> part too. I can see this in my plist file:
<key>NSLocationWhenInUseUsageDescription</key>
<string>Get Position</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Get position</string>
So I think it works. But it doesn't; it works for Android but not for iOS.
I call this method:
this.geolocation.getCurrentPosition().then((resp) => {
alert("geo " + resp.coords.latitude);
// resp.coords.latitude
// resp.coords.longitude
}).catch((error) => {
alert(error.code);
alert(error.message);
});
I got the Error.code 2 and the Error.message: "Origin does not have permission to use Geolocation service".
What should I do?
I had this exact problem -- I had to manually add this privacy setting in the *.plist file in XCode itself (found in resources/).
Under Key you type Privacy - Location When In Use Usage Description, or at least start typing it, and it will autocomplete. Type should be String and Value should be the message you want to popup to the user explaining why you need access to location data.
I had the same problem. I used Ionic v4 with React, Cordova v9, cordova-ios v4.5.5. The problem in my case happened because I didn't inject the Cordova JS script to the webview. To fix it, I added the following Bash script to Cordova's before prepare hooks ((cordova root)/hooks/before_prepare/inject_cordova.js):
#!/bin/bash
set -e
sed -E -i "" -e "s_(<head[^>]*>)_\1<script src=\"cordova.js\"></script>_" www/index.html
Where www/index.html is the path to your application main HTML file relative to the cordova project root.
The last line adds a <script src="cordova.js"></script> tag to the end of the HTML file when you run cordova prepare ios. As a result, the webview starts loading the Cordova scripts including the geolocation plugin and the application starts asking a permission to use the geolocation.

File Folder error when using camera

I have followed this docs in implementing in taking a photo and picking a photo in Xamarin. I was able to implement and worked in picking a photo but I have error in using the function TakePhotoAsync() which is used to open the camera to take picture. I have googling for possible solutions but nothing works for me. I did not modify any permission or add from the current which work on Picking a photo.
It crashes in this line:
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium
});
I am testing in the emulator: AVD_for_Galaxy_Nexus(Android 6.0 - API 23)
Exception:
System.ArgumentException: Unable to get file location. This most likely means that the file provider information is not set in your Android Manifest file. Please check documentation on how to set this up in your project.
By the way, I did solve the error by downgrading the version of the plugin to Xam.Plugin.Media 3.1.2 from Xam.Plugin.Media 3.1.3. I didn't change anything in my codes.

Resources