visit
quasar create vue-firebase-image-upload
cd vue-firebase-image-upload
quasar dev -m android
You should get a basic working version that looks like this:You’ll have to add https: true in the devServer section of quasar.conf.js if running on android > 9
For more details on how to install and setup quasar, see
The way to store images in Firebase Cloud Storage is by saving the base-64 string of the image, using Firebase’s
putString
method. Notice that you have to remove the base64 prefix from the string before uploading, or Firebase will reject the string. To begin, we'll add a button that takes a picture using Cordova's camera plugin, and print the base64 string.cd src-cordova
cordova plugin add cordova-plugin-file
cordova plugin add cordova-plugin-camera
In order to take a picture, we’ll add some code in a new service file
src/services/cordova-camera.js
:async function getCameraFileObject() {
return new Promise((resolve, reject) => {
let camera = navigator.camera;
const options = {
quality: 50,
destinationType: camera.DestinationType.FILE_URI,
encodingType: camera.EncodingType.JPG,
mediaType: camera.MediaType.PICTURE,
saveToPhotoAlbum: true,
correctOrientation: true
};
camera.getPicture(imageURI => {
window.resolveLocalFileSystemURL(imageURI,
function (fileEntry) {
fileEntry.file(
function (fileObject) {
resolve(fileObject)
},
function (err) {
console.error(err);
reject(err);
}
);
},
function () { }
);
},
console.error,
options
);
})
}
async function getBase64FromFileObject(fileObject) {
return new Promise((resolve, reject) => {
var reader = new FileReader()
reader.onloadend = function (evt) {
var image = new Image()
image.onload = function (e) {
resolve(evt.target.result)
}
image.src = evt.target.result
}
reader.readAsDataURL(fileObject)
})
}
async function getBase64FromCamera() {
let fileObject = await getCameraFileObject();
let base64 = await getBase64FromFileObject(fileObject);
return base64;
}
export default {
getBase64FromCamera
}
resolveLocalFileSystemURL
function.Now let’s add a simple event bus. Add the file
src/services/event-bus.js
with content:import Vue from 'vue';
export const EventBus = new Vue();
Now in
src/layouts/MyLayout.vue
, we'll add a button in the toolbar for taking a picture, and use our event bus to send the handling to Index.vue
:<template>
...
<q-btn flat dense round @click="takePicture">
<q-icon name="camera" />
</q-btn>
...
</template>
<script>
import { EventBus } from "../services/event-bus.js";
export default {
...
methods: {
takePicture() {
EventBus.$emit('takePicture')
}
}
}
</script>
Finally we’ll catch the takePicture event in our main component:
Index.vue
, call the cordova-camera.js
service function and print the base64 result (which we'll later upload to firebase):Index.vue
file in the <script> section:import { EventBus } from "../services/event-bus";
import cordovaCamera from "../services/cordova-camera";
export default {
name: "PageIndex",
mounted() {
EventBus.$off("takePicture");
EventBus.$on("takePicture", this.uploadImageFromCamera);
},
methods: {
async uploadImageFromCamera() {
let base64 = await cordovaCamera.getBase64FromCamera();
console.log("base64", base64)
}
}
};
Running with
quasar dev -m android
, and looking at the chrome dev tools, we can see the base64 output as a long string printed in the console:yarn add firebase
Follow the instructions in the Firebase Cloud Storage . After the setup you should have a firebase project with Storage enabled. We’ll save the settings in a separate file:
firebase-config.js
(this file won't be committed to our repo). The contents should look something like this:export default {
firebase: {
apiKey: '<your-api-key>',
authDomain: '<your-auth-domain>',
databaseURL: '<your-database-url>',
storageBucket: '<your-storage-bucket-url>'
}
}
Add the file
src/services/cloud-storage.js
with content:import * as firebase from "firebase/app";
import 'firebase/storage';
import firebaseConfig from './firebase-config';
async function uploadBase64(imageData, storageId) {
return new Promise((resolve, reject) => {
let uploadTask = firebase.storage().ref().child(storageId).putString(imageData, "base64");
uploadTask.on(
"state_changed",
function (snapshot) {},
function (error) {
reject(error)
},
function () {
uploadTask.snapshot.ref
.getDownloadURL()
.then(function (downloadURL) {
console.log("Uploaded a blob or file!");
console.log("got downloadURL: ", downloadURL);
resolve(downloadURL);
});
}
);
});
}
function initialize() {
firebase.initializeApp(firebaseConfig.firebase)
}
export default {
uploadBase64,
initialize
}
The uploadBase64 function uploads imageData (the base64 string) using the putString method, under the Firebase child of storageId. You can have any ID you want, here I've chosen to use the unix datetime number as the child ID. After the uploading is done, we return the image URL using getDownloadURL function of the uploading task.
In our main
App.vue
file we'll call the initialize function when the app is mounted:import cloudStorage from './services/cloud-storage'
export default {
name: 'App',
mounted() {
cloudStorage.initialize();
}
}
Finally we’ll call the uploading function from
Index.vue
. This is now the content of
Index.vue
:<template>
<q-page>
<div class="row justify-center q-ma-md" v-for="(pic, idx) in pics" :key="idx">
<div class="col">
<q-card>
<q-img spinner-color="white" :src="pic" />
</q-card>
</div>
</div>
</q-page>
</template>
<script>
import { EventBus } from "../services/event-bus";
import cordovaCamera from "../services/cordova-camera";
import cloudStorage from "../services/cloud-storage";
export default {
name: "PageIndex",
data() {
return {
pics: []
};
},
mounted() {
EventBus.$off("takePicture");
EventBus.$on("takePicture", this.uploadImageFromCamera);
},
methods: {
removeBase64Prefix(base64Str) {
return base64Str.substr(base64Str.indexOf(",") + 1);
},
async uploadImageFromCamera() {
const base64 = await cordovaCamera.getBase64FromCamera();
const imageData = this.removeBase64Prefix(base64);
const storageId = new Date().getTime().toString();
const uploadedPic = await cloudStorage.uploadBase64(imageData, storageId);
this.pics.push(uploadedPic);
}
}
};
</script>
We’ve added the pics array to our component's data, containing URLs of all the pictures we uploaded. We've added a v-for that will show each picture in a quasar
q-img
component inside a q-card
component. We've also changes uploadImageFromCamera
to take a picture, get the base64 string (stripping the prefix so Firebase won't freak out), calculated the storageId using the current datetime, and called the uploading function. After it's uploaded, we add the resulting URL to the pics array.And we can now see the uploaded image: