I am writing an application for Xamarin.iOS, but an answer in native iOS would suffice. After I download a file (image or pdf) I want to open it:
public void DidFinishDownloading(NSUrlSession session, NSUrlSessionDownloadTask downloadTask, NSUrl location)
{
// how to open location?
}
I tried UIApplication.SharedApplication.OpenUrl(location); but nothing happens.
I'm not sure whether you mind using WKWebView to load the local file, and if you store the file in Library/Caches/ of Application directories, you could use follow ways to load the downloaded file.
Get the cache path:
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
cache = Path.Combine(documents, "..", "Library", "Caches");
Console.WriteLine("path is : "+cache);
Load a tree.png in WKWebView:
webView = new WKWebView(View.Frame, new WKWebViewConfiguration());
View.AddSubview(webView);
NSUrl nSUrl = new NSUrl("file://" + cache + "/tree.png");
webView.LoadFileUrl(nSUrl, nSUrl);
Here is the output:
2020-10-28 10:27:47.303745+0800 IOSSplashScreen[4370:73093] path is : /Users/xxx/Library/Developer/CoreSimulator/Devices/C30029F0-379A-4255-B38B-27E2BAAC8CC1/data/Containers/Data/Application/5C7D7CA5-7394-414A-897F-8F1A278838A8/Documents/../Library/Caches
And effect:
Related
I am using this code and it works fine in simulator as I am getting a location and can get pdf file from there
async createPDF() {
let options = {
html: '<h1>PDF TEST</h1>',
fileName: 'test',
directory: 'Documents',
};
let file = await RNHTMLtoPDF.convert(options)
// console.log(file.filePath);
alert(file.filePath);
}
But the above code problem in the real iOS mobile as it is saving the pdf file somewhere. I don’t know where but I am not able to see that file in my mobile. So can anyone tell me how can I save my file in the downloads or documents in the iOS . So that I can see the downloaded file.
Found the answer to convert file in base64 string
You can solve this issue by using base64 as the following:
let options = {
html:
`
<h2 style="text-align: center">${'Some text and dynamic value'}</h2>
`,
fileName: 'TestingPDF',
directory: 'Documents',
base64: true
};
let file = await RNHTMLtoPDF.convert(options);
You shoud use 'react-native-file-access' to copy the file and move it to Downloads directory, so let's install it by: npm i react-native-file-access --save
Lets copy the file to the Downloads directory by the following:
const fileName = 'PMA_CurrentBalanceFile.pdf'; //whatever you want to call your file
const filePath = `${Dirs.DocumentDir}/${fileName}`;
const base64Data = file.base64; //our base64 encode file which done by RNHTMLtoPDF;
Then write the following code to do your job:
if (Platform.OS === 'android') {
const permissionGranted = await permissionWriteExternalStorage();
if (permissionGranted) {
await FileSystem.writeFile(filePath, base64Data, 'base64');
if (!FileSystem.exists(filePath)) return;// check to see if our filePath was created
await FileSystem.cpExternal(filePath, fileName,'downloads');// copies our file to the downloads folder/directory
// file should now be visible in the downloads folder
ToastAndroid.show("", "One File Downloaded", ToastAndroid.SHORT);
}
return;
}
if (Platform.OS === 'ios') {
// IOS version
await FileSystem.writeFile(filePath, base64Data, 'base64');
Alert.alert('', 'One File Downloaded');
}
I'm trying to make a mp3 player with ionic media plugin.
First I download song on local storage via path
let filePath;
if(this.platform.is('android'))
{
filePath = this.file.externalDataDirectory;
}
else
{
filePath = this.file.documentsDirectory;
}
filePath = filePath +'810.mp3';
after that we get such path
file:///var/mobile/Containers/Data/Application/5DC6D2D0-6336-4C6E-A39E-5D5FD7D8AF7B/Library/Cloud/810.mp3
So for example we have such an object
track = {
'name':'Name of Song',
'filePath': filePath
}
I create
const file:MediaObject = this.media.create(track.filePath);
and when time comes to play
file.play();
Whole app crashes without giving me a hint of error.
This plugin normally plays files on Android from both localPath and internetPath.
On iOS it plays only from internet but crashes when plays local files. Please help.
So I found the solution. It was here.
https://forum.ionicframework.com/t/ios-9-cant-play-audio-video-files-that-are-downloaded-to-device/37580
For example.
track = {
'name':'Name of Song',
'filePath': '';
}
if(this.platform.is('android'))
{
track.filePath = this.file.externalDataDirectory;
}
else
{
track.filePath = this.file.documentsDirectory;
}
track.filePath = track.filePath +'810.mp3';
const transfer = this.transfer.create();
let url = "http://someLink.com/someFileName.mp3";
transfer.download(url, track.filePath).then((entry)=>{
// **code here will be executed when track is downloaded**
// and only for ios local file system we need to create a special link to this file
// so that cordova media plugin could read this file and if necessary to delete it
// with cordova file plugin by this link also.
if(this.platform.is('ios'))
this.file.resolveLocalFilesystemUrl(track.filePath).then((entry)=>{
track.filePath = entry.toInternalURL;
});
Actually there was another way to make iOS play file by removinh file:// from beging of track.filePath but then you will face with another issue. You won't be able do delete it by this path later.
I am working on a wallpaper app in Flutter & Dart. Currently I'm working on the set wallpaper button where I need to check if the wallpaper file exists, download it if need to and then change the wallpaper.
This is what I have right now and I think I've done it right, please note that I'm and Android Java Developer with only about 6 months of experience so I am beyond the basics in Dart too but not too good.
DOWNLOAD WALLPAPER FUNCTION
static Future<int> downloadWallpaperFile(int wallpaperID,
{String path}) async {
///Prepare a url for downloading the wallpaper using the getWallpaperURL method and passing in fullSizedWallpaper string constant
String url = getWallpaperURL(WallpaperSize.fullWallpaper, wallpaperID);
///Log output
print('CallingDownloadWallpaper : ' + url);
///Visual Feedback
wallpaperDetailsPageScaffoldGlobalKey.currentState.showSnackBar(
new SnackBar(content: new Text('Starting Wallpaper Download...')));
///Start downloading the wallpaper file from the url
var data = http.readBytes(url);
///After download is completed
data.then((buffer) async {
///If filePath is not passed in as parameter
if (path == null) {
///Use getPathForWallpaperFile to get a path for a wallpaper file
path = await getPathForWallpaperFile(url);
}
///Create a new file at the path, the path also includes the name of the file which is the id of the wallpaper
File newFile = new File(path);
///Get write access to the newly created wallpaper file
RandomAccessFile rf = newFile.openSync(mode: FileMode.write);
///Write the downloaded data to the file synchronously
rf.writeFromSync(buffer);
///Save the file to the disk synchronously
rf.flushSync();
///Close access to file synchronously
rf.closeSync();
///Log output
print('DownloadWallpaperResult : Complete');
///Visual Feedback
wallpaperDetailsPageScaffoldGlobalKey.currentState.showSnackBar(
new SnackBar(content: new Text('Wallpaper Download Complete')));
});
return 0;
}
SET WALLPAPER FUNCTION
static setWallpaper(int wallpaperID) async {
///Prepare variables for setting wallpaper and download the wallpaper as well (if needed)
String url = getWallpaperURL(WallpaperSize.fullWallpaper, wallpaperID);
String path = await getPathForWallpaperFile(url);
bool fileExists = checkIfFileExists(path);
///If wallpaper file does not exist then download it
if (fileExists == false) {
///Download wallpaper then change wallpaper
await downloadWallpaperFile(wallpaperID, path: path).then((result) {
///Check if download was successful
if (result == 0) {
///Change wallpaper
AndroidInterface.setWallpaper(path);
}
});
} else {
///Wallpaper already downloaded
///Change wallpaper
AndroidInterface.setWallpaper(path);
}
}
The problem is that you are using then, which is non-blocking (basically the old way to use Futures without await).
Instead, use await:
static Future<int> downloadWallpaperFile(int wallpaperID, {String path}) async {
// ...
//Start downloading the wallpaper file from the url
final buffer = await http.readBytes(url);
//After download is completed
//If filePath is not passed in as parameter
if (path == null) {
//Use getPathForWallpaperFile to get a path for a wallpaper file
path = await getPathForWallpaperFile(url);
}
// ...
return 0;
}
Btw, /// is reserved for documentation on classes and fields, use // for in-method comments!
I'm also not sure if it is a good idea to use synchronous io actions. That will probably block the UI of the app, it would be better to use the async io api (again with await).
So I'm trying to cache an image if an upload fails, due to the current limitations of flutter I think I will have to save it to shared preferences as a base64 file, then get it from shared preferences, convert it back to an image then upload that to firebase storage. My current code looks like so:
void saveImageToCache(File image) async {
List<int> imageBytes = image.readAsBytesSync();
String base64Image = base64Encode(imageBytes); //convert image ready to be cached as a string
var cachedImageName = "image $fileName";
instance.setString(cachedImageName, base64Image); // set image name in shared preferences
var retrievedImage = instance.getString(cachedImageName);// once a connection has been established again, get the image file from the cache and send it to firebase storage as an image
storageReference.putData(retrievedImage, StorageMetadata(contentType: 'base64'));
var prefix = "data:image/png;base64,";
var bStr = retrievedImage.substring(prefix.length);
var bs = Base64Codec.codec.decodeString(bStr);
var file = new File("image.png");
file.writeAsBytesSync(bs.codeUnits);
uploadTask = storageReference.child(fileName).putFile(file, const StorageMetadata(contentLanguage: "en"));
}
This is failing for me at var bStr = retrievedImage.substring(prefix.length); with error type 'String' is not a subtype of type 'Uint8List' where and im still not sure if im doing the right thing.
Any help would be great thanks.
I wouldn't recommend storing binary files to shared preferences. Especially since you're building an image cache.
I'd just store them to a file.
Future<File> saveFile(File toBeSaved) async {
final filePath = '${(await getApplicationDocumentsDirectory()).path}/image_cache/image.jpg';
File(filePath)
..createSync(recursive: true)
..writeAsBytes(toBeSaved.readAsBytesSync());
}
This uses getApplicationDocumentsDirectory() from the path provider package.
I added TestXML.xml together with simple.xls file to my Resources folder. Now I want to display the xml styled according to the xsl file.
string fileName = "TestXML.xml";
string localDocUrl = Path.Combine (NSBundle.MainBundle.BundlePath, fileName);
NSUrl url = new NSUrl (localDocUrl, false);
NSData xml = NSData.FromUrl (url);
string contentDirectoryPath = NSBundle.MainBundle.BundlePath;
NSUrl baseURL = new NSUrl (contentDirectoryPath, true);
webView.LoadData (xml, "text/xml", "UTF-8", baseURL);
webView.ScalesPageToFit = false;
If I execute the code above I get an empty page. How do I load the styled XML file onto my UIWebView?
EDIT
Now I tried to load a web ressource:
string fileName = "http://www.w3schools.com/xml/simplexsl.xml";
NSUrl url = new NSUrl(fileName);
NSMutableUrlRequest request = new NSMutableUrlRequest (url, NSUrlRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData, 10);
webView.LoadRequest(request);
Here the xml file is correctly loaded with the xsl file. But how could I use a string or a local file for displaying it in the UIWebView?