I am trying to implement a feature to let the user upload a file in my NativeScript Angular Project. NativeScript does not seem to have a native implementation of a file picker and there are limited plugins available that can do the job. Plus they have their own set of problems. The closest I have come to a workable solution is using the nativescript-mediafilepicker and that opens a blank page like the one below instead of the file explorer.
I exactly followed the documentation and can't figure out why it's not working. Here is the service I wrote:
payload.service.ts
import { Injectable } from '#angular/core';
import { Mediafilepicker, ImagePickerOptions, VideoPickerOptions, AudioPickerOptions,
FilePickerOptions } from 'nativescript-mediafilepicker';
#Injectable({
providedIn: 'root'
})
export class PayloadService {
constructor() { }
pickFile(){
console.log('Pick File Payload Service requested');
const extensions = ['pdf'];
let options: FilePickerOptions = {
android: {
extensions: extensions,
maxNumberFiles: 1
},
ios: {
extensions: extensions,
multipleSelection: false
}
};
let mediafilepicker = new Mediafilepicker();
mediafilepicker.openFilePicker(options);
mediafilepicker.on("getFiles", function (res) {
let results = res.object.get('results');
console.dir('File Pick Success: ',results);
});
mediafilepicker.on("error", function (res) {
let msg = res.object.get('msg');
console.log('File Pick Error: ',msg);
});
mediafilepicker.on("cancel", function (res) {
let msg = res.object.get('msg');
console.log('File Pick Cancel: ',msg);
});
}
}
Can someone help me fix this or rather provide me with a native implementation? I don't need much customization options and user will only upload one file at a time.
Related
I'm trying to save a base64 encoded image in iOS using react-native-share and also Share module from React Native. But both fail when trying the Save Image option.
React Native Share
try {
const sharedResponse = await Share.open({ url: dataUri });
console.log(sharedRes);
} catch (error) {
console.log(error);
}
Share Module
try {
const sharedResponse = await Share.share({ url: dataUri });
console.log(sharedRes);
} catch (error) {
console.log(error);
}
Options other than Save image such as copy, and save to files are working fine.
I have added the following in Info.plist as well
<key>NSPhotoLibraryAddUsageDescription</key>
<string>APP wants to save to photos</string>
This is working fine on the first try in the app's lifetime (When it's asking the permissions from the user). After that this functionality doesn't work.
For some reason you need to write the file to the temp directory first before sharing. I'm not sure the reasoning behind this... but it did fix the issue for me.
const filename = `snapshot.jpeg`; // or some other way to generate filename
const filepath = `${FileSystem.cacheDirectory}/${filename}`;
await FileSystem.writeAsStringAsync(filepath, res.data, { encoding: 'base64' });
const isSharingAvailable = await isAvailableAsync();
if (!isSharingAvailable) {
showAlert('Error', 'Sharing is not available.')
return;
}
if (Platform.OS === 'ios') {
//sharing just the file allows for more applications to be shared too. Adding a message seems to remove many apps from the sharing list
await Share.share({ url: filepath });
}
This strange behaviour had happened because I'm trying to open the Share pop-up above a React Native Modal. The issue didn't occur if I try to hide the Modal before the Share pop-up comes up.
I resolved the issue when storing the image locally before opening the Share Modal.
To store the image i used the npm package 'react-native-fs' and then use it just like this:
import RNFS from "react-native-fs";
function storeFileLocally(url: string): Promise<string> {
const localFile = `${RNFS.DocumentDirectoryPath}/tempFile.jpeg`;
const options: RNFS.DownloadFileOptions = {
fromUrl: url,
toFile: localFile
};
return RNFS.copyFile(url, localFile)
.then(() => 'file://'+localFile)
.catch((error) => {
console.error(error);
return null;
});
}
Unable to save pdf file on android which is created using PDFMake library.
In my ionic app, I am not able to download pdf which I created using PDFMake library even it log success. Here I am trying to writeFile using file module, when user click on generatePdf button
Since last two days I am trying to achieve this.. but no luck, so now I am looking for some help here.
component.html
<ion-button (click)="generatePdf()">generatePdf</ion-button>
component.ts
generatePdf() {
let self = this;
const pdfData = {
content: [
'First paragraph',
'Another paragraph',
],
};
let pdfDocGenerator = pdfMake.createPdf(pdfData);
pdfDocGenerator.getBuffer((buffer) => {
let utf8 = new Uint8Array(buffer);
let binaryArray = utf8.buffer;
self.saveToDevice(binaryArray, 'first.pdf');
});
}
saveToDevice(data: any, savefile: any) {
let self = this;
self.file.writeFile(self.file.externalApplicationStorageDirectory, savefile, data, { replace: false
})
.then(() => {
console.log('success...');
})
.catch((err) => {
console.log('error...');
});
}
I've saved the file i want to share locally using FileSystem.downloadAsync
Share.share works fine for iOS. How can I share an image I have saved locally on Android?
I've tried
https://github.com/lucasferreira/react-native-send-intent
https://github.com/react-native-community/react-native-share
Both these solutions do not seem to work with Expo.
I'm using react-native version : https://github.com/expo/react-native/archive/sdk-31.0.0.tar.gz
FileSystem.downloadAsync(url, FileSystem.documentDirectory+filename).then(({uri})=>{
if(Platform.OS == "android"){
// ???
}
else{
Share.share({url:uri});
}
})
Is there something i'm missing?
Since SDK33, you can use Expo Sharing to share any type of file to other apps that can handle its file type even if you're on Android.
See : https://docs.expo.io/versions/latest/sdk/sharing/
Usage is pretty simple :
import * as Sharing from 'expo-sharing'; // Import the library
Sharing.shareAsync(url) // And share your file !
In order for users to share content saved within our (Expo) app, we structured it like this. (This is working across iOS & Android).
IMPORT SHARING:
import * as FileSystem from 'expo-file-system';
import * as Sharing from 'expo-sharing';
ADD ONPRESS TO BUTTON (OR WHEREVER):
<Button
name="share"
onPress={() =>
openShareDialogAsync(media, {
video: media.meta.fileType === 'video',
})
}
/>
SHARE VIDEO OR IMAGE TO ANY APP IN USERS HANDSET
const openShareDialogAsync = async (mediaProp, options) => {
const fileDetails = {
extension: options.video ? '.mp4' : '.jpg',
shareOptions: {
mimeType: options.video ? 'video/mp4' : 'image/jpeg',
dialosTitle: options.video
? 'Check out this video!'
: 'Check out this image!',
UTI: options.video ? 'video/mp4' : 'image/jpeg',
},
};
const downloadPath = `${FileSystem.cacheDirectory}${mediaProp.media_id}${fileDetails.extension}`;
const { uri: localUrl } = await FileSystem.downloadAsync(
mediaProp.url,
downloadPath
);
if (!(await Sharing.isAvailableAsync())) {
showMessage({
message: 'Sharing is not available',
description: 'Your device does not allow sharing',
type: 'danger',
});
return;
}
await Sharing.shareAsync(localUrl, fileDetails.shareOptions);
};
Hope this helps :]
So developing this IONIC 2 app, I discoverd that sending SMS to multiple recipients isnt so trivial at it should be.
After a long research I've found this post where people trys to deal with multiple SMS. But even using their specs it doesnt work properly.
They say we can use an array of strings representing multiple phone numbers. So far so good, except it works only for the first number.
If someone has now details on this functionality I would love to hear about it.
Thanks
import { SMS } from '#ionic-native/sms';
constructor( private sms: SMS ){
this.sendSMS();
}
sendSMS() {
var MultiNumber = [ '1234567890' , '9876543210' ];
this.sms.send(MultiNumber, 'hello all this is testing message');
}
try this it is working for me, Hope it is working for you too.
So after ages of research over internet I got this litle jam called cordova-plugin-sms ( dont confuse it with cordova-sms-plugin ).
As it says in their documentation they have a function sendSMS which reeeally sends messages to multiple recipients.
So my solution for integrating it in IONIC 2 is as follows :
ionic cordova plugin add cordova-plugin-sms
and my Ionic 2 class is :
import { Component } from '#angular/core';
import { NavController, ToastController } from 'ionic-angular';
import { Http, Response } from "#angular/http";
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
declare let window: any;
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(private toastCtrl: ToastController, public navCtrl: NavController, public http: Http ) { }
ionViewDidLoad() {
this.startWhatchSMS();
}
// Android ONLY
startWhatchSMS() {
if (window.SMS) {
window.SMS.startWatch(() => {
//console.log("startWatch");
}, error => {
//console.log(error);
//console.log("error startWatch");
});
}
document.addEventListener('onSMSArrive', this.smsArived);
}
// Android ONLY
smsArived = (result: any) => {
//console.log(result);
let sms = result.data;
// put your code here...
}
sendTextMessage( ) {
window.SMS.sendSMS([ '1234567890' , '0987654321' ], 'Text message for multiple recipients',
(result) => {
console.log(result); // should be 'OK' string
}, (error) => {
console.log(error);
});
}
}
The sendTextMessage() function is called from the template by clicking an button.
Well thats it ... for me is working and hope will work for you too.
Cheers
I'm currently working on a Ionic/Cordova application, a to-do application. I am using the ngCordova library for an easier use of the cordova plugins. I'm also using the Sqlite plugin by litehelpers (GitHub page).
My problem is about the correct understanding of the JavaScript's promises behavior. I have a Angular service called "Projects", which make use of the SQLite plugin, and a "Tasks" controller which is delegated to it.
angular.module('myapp.services', [])
.factory("Projects", ["$ionicPlatform", "$cordovaSQLite", "$window", "$q",
function($ionicPlatform, $cordovaSQLite, $window, $q) {
return {
// SOME FUNCTIONS..
getCurrentProject: function() {
var q = $q.defer();
$ionicPlatform.ready(function() {
$cordovaSQLite.execute(db,
"SELECT id_project, name FROM projects WHERE active = 1").then(
function(res) {
q.resolve(res.rows.item(0));
}, function(err) {
q.reject(err);
console.error(err.message);
});
});
return q.promise;
}
};
}
]);
I want to make this function return an object, which is the result of my query.
The promises and callback keywords are confusing me.
I've tried a few ways to solve my problem, but when I call (in my controller):
var currentProject = Projects.getCurrentProject();
And then trying to check its values with:
console.log("ID -> " + currentProject.id_project);
console.log("NAME -> " + currentProject.name);
I always get undefined. How do I handle a promise in a Ionic/Cordova Application?
Solved
#bardzusny's answer totally made me realize where i was wrong, thank you all :)
Promises are designed to be chainable with error handling and final behavior (optional), like so:
Projects.getCurrentProject()
.then (project) -> currentProject = project
.catch (err) -> console.error err
.finally () -> wrapUpFn()
So you would need to use .then to make the assignment. Otherwise you're assigning currentProject to the promise object, not the result of the promise object (which is what you want).
EDIT
Now in javascript :)
var currentProject
Projects.getCurrentProject()
.then(function(project) {
currentProject = project
})
.catch(function(err) {
console.error(err)
})
.finally(function() {
wrapUpFn()
})
As an aside, promise objects are great because you can just keep on chaining down the line with .thens, and still keep your error handling and final behaviors clear. This lets you create simple flows that are ordered within the crazy world of javascript.