HOW TO SETUP A QUASAR-VUE CAPACITOR ANDROID PROJECT
Feb 2025
There are a number of steps you need to perform to properly scaffold and configure your Quasar-Capacitor project for creating Android apps using Vue.js.
This guide assumes, You Are:
I have attempted to show Information that has been directly gleaned from the internet and then "cut-n-pasted" incorporated into this guide between sets of lines and "Per research".
This guide is intended for someone who is starting out on their journey (like me). Experienced developers will likely find most of the information, well, superfluous.
There are very probably egregious errors, omissions, and mistakes in this guide. If you find them, blame a couple things:
-The existing documentation on the Quasar and Capacitor websites (as of Feb 2025).
--The Quasar web site does have info about Capacitor, but it's not very extensive, and it's difficult find any comprehensive implementations of a capacitor plugin out there on the internet.
. https://quasar.dev/quasar-cli-vite/developing-capacitor-apps/introduction
--And the Capacitor website really doesn't have much to say about Quasar.
If there was more documentation on how to properly integrate these two frameworks, I would not have found putting this guide together worth the effort in the first place.
-Oh, and also blame the fact there is so much to learn about both Quasar, Capacitor and Vue!...and I'm just learning.
The following image pretty much captures the experience of trying to get a clean install of a Quasar-Capacitor-Android project: What a headache.
Quasar and Capacitor are truly wonderful, but I've found it a bit difficult to get them to behave, so hence this guide. At the end of all this you should behold the following desktop configuration!
Here's a few links to relevant information
https://quasar.dev/
.
. https://quasar.dev/quasar-cli-vite/developing-capacitor-apps/introduction
Note of Why Quasar?
Take the notes below with a grain-of-salt...some of it is pure opinion. Do your own reasearch!
There are other frameworks out there besides Quasar that will help develop cross platform apps with one code base to target multiple platforms, such as Flutter, React Native, and Xamarin, and Ionic.
Flutter is a Google thing...and Google simply abandons products without a second thought. I've been burned so many times relying on a Google platform or framework that simply disappeared, that I would never adopt anything they make unless forced too by their market monopoly power, such as Google Maps.
React Native...well you have to learn React. But it supposedly renders native UI components instead of using WebView12. This results in apps that are supposedly indistinguishable from those built using native languages like Objective-C or Java.
.Xamarin... this is a Microsoft framework, requires C# and .NET. Yuck. I'd probably have to buy a windows machine. More Yuck. But, It compiles directly to native code, avoiding the use of WebView.
Ionic looks pretty good, but it's just a javascript/typescript thing? I don't really know, but as of 2025 it's more popular than Quasar, so that does say something.
Quasar - so far, given that I'm primarily developing with Vue.js, I haven't found a better framework to develop in.
Some more notes Per research further discussion:
Ionic and Quasar are both popular frameworks for cross-platform app development, but they have some key differences:
Performance and Rendering
Ionic relies on WebView for app rendering, which can sometimes result in performance issues1. Quasar, on the other hand, takes advantage of platform-specific features, potentially offering better performance and a more native feel1.
Challenges of WebView-Based Frameworks
Performance Limitations: WebViews may not match the speed or responsiveness of fully native apps due to additional rendering layers24.
Device Compatibility Issues: Variations in WebView implementations across operating systems can lead to inconsistent behavior4.
Limited Access to Native Features: While plugins can bridge some gaps, certain advanced device functionalities may not be accessible26.
User Experience Concerns: Apps relying heavily on WebViews may feel less fluid compared to native applications7.
Platform Support
While Ionic primarily focuses on hybrid mobile applications, Quasar targets a broader range of platforms including mobile (iOS, Android) using Capacitor, desktop (Windows, Mac, Linux) using Electron, and web applications including SPA and SSR 12.
UI Components and Design
Ionic offers pre-built UI components following Material Design and Apple's Human Interface Guidelines1. (Ionic seems to have an Apple bias)
Quasar provides a more extensive set of components and styling options, offering both Material Design and iOS-style components12.
Framework Base
Ionic can be used with various JavaScript frameworks, while Quasar is built specifically on Vue.js, offering seamless integration with Vue's ecosystem13.
Development Experience
Quasar is often praised for its comprehensive toolset, which includes a wide range of UI components, layout elements, and helpers2. It also offers features like code splitting, lazy loading, and server-side rendering out of the box2.
Community and Ecosystem
Ionic has a larger, more established community with extensive documentation and a broad range of plugins1.
Quasar, while newer, has a growing community and offers a collection of ready-to-use plugins and integrations13.
Performance Optimization
Quasar emphasizes performance with built-in features like code minification, source mapping, and tree shaking2.
Customization and Theming
Quasar offers more extensive theming capabilities, including support for right-to-left (RTL) languages2.
In summary, while various frameworks have their strengths, Quasar seems to offer more flexibility in terms of platform support and potentially better performance, especially for Vue.js developers. However, Ionic's larger community and ecosystem might be advantageous for some projects.
This guide is divided into seven major parts:
Prerequisites for a Quasar / Vue project
Setting up your development environment
Project Planning link
What you should consider before starting
Project Setup & Scaffold Steps link
Detailed configuration steps with thorough explanations
Launch as SPA web app link
Launching Your Android Application in Dev link
Getting your development environment running
Installing Capacitor Plugins link
Installing the geolocation plugin
Creating a Hello World page link
Creating a page that uses the plugin link
A very basic geolocation plugin page
Oh, and some credits are at the end...
There are 3 steps:
-have Node, nvm and npm installed
-verify Android Studio install
-set android environment variables
First, let's verify the development environment
==Important DO NOT IGNORE: ==
As of Feb 2025, default Quasar & Capacitor (v6) required Node v18.
This will probably change, hence why having node version manager (nvm) is essential.
Terminal commands:
node --version # Should be >=18.0.0
npm --version # Should be >=6.13.4
nvm --version # Check if nvm is installed
If nvm is not installed:
# For macOS using brew
brew install nvm
After installation, add these lines to your ~/.zshrc or ~/.bash_profile:
export NVM_DIR="$HOME/.nvm"
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"
Reload your terminal configuration:
source ~/.zshrc # or source ~/.bash_profile
Verify nvm installation:
nvm --version
If Node.js version is not 18:
# Install Node.js 18
nvm install 18
# Use Node.js 18
nvm use 18
# Verify the version
node --version # Should show v18.x.x (for Capacitor v6)
To use a specific version directly, use the terminal command:
nvm use <version>
npm and npx are both tools used in Node.js development, but they serve different purposes:
npm (Node Package Manager)
npm install <package>
npx (Node Package Execute)
npx <package>
I have more notes in some section Part 3F - Sync Your Project on npx
The node_modules folder plays a crucial role in your Quasar and Capacitor project, as it does in most Node.js-based applications:
Dependency Storage:
node_modules is where all the external libraries and packages that your project depends on are stored15. This includes Quasar, Capacitor, and any other packages you've installed using npm or yarn.
Local Package Access:
When you import a package in your code, Node.js looks for it in the node_modules folder1. This allows your application to use these dependencies without needing to specify their full path.
Project-Specific Dependencies:
Each project has its own node_modules folder, ensuring that different projects can use different versions of the same package without conflicts.
Automatic Management:
When you run npm install or yarn install, the package manager reads your package.json file and downloads all the required dependencies into the node_modules folder.
Exclusion from Version Control:
The node_modules folder is typically not included in version control systems like Git due to its large size35. Instead, developers share the package.json file, which lists all the dependencies.
Recreating Dependencies:
Other developers can recreate the node_modules folder on their machines by running npm install or yarn install, using the package.json as a reference.
For Quasar and Capacitor specifically:
Open Android Studio and verify the following:
Go to Tools > SDK Manager
Under "SDK Platforms" ensure you have:
Under "SDK Tools" verify you have:
Add to ~/.zshrc or ~/.bash_profile:
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/platform-tools
Following is on a MacBook
Here’s how to do it:
1. Open Terminal.
2. Open your .zshrc
file in a text editor.
You can use nano
, which is simple and built-in:
nano ~/.zshrc
.
3. Add the lines shown above to the end of the file
4. Save and close the file.
If using nano
, press Control + X
, then Y
to confirm, and Enter
to save.
.
To apply these changes immediately after editing .zshrc, run:
source ~/.zshrc
This will reload your shell configuration and make the environment variables available in your current terminal session.
What These Lines Do:
export ANDROID_HOME=$HOME/Library/Android/sdk
:
export PATH=$PATH:$ANDROID_HOME/tools
:
export PATH=$PATH:$ANDROID_HOME/platform-tools
:
Why This Is Important:
How It Works in Practice:
After adding these lines to your .zshrc, you can:
Before you begin scaffolding Quasar, think carefully about the following names:
Plan the naming of your project name-directory-folder.
Product Name ("productName" in root package.json):
Capacitor App ID (appId in capacitor.config.json):
Capacitor App Name (appName in capacitor.config.json):
This section provides detailed instructions for setting up your Quasar project with Capacitor for Android development. Follow these steps in order:
Installation and configuration of the Quasar Command Line Interface link
Creating the base Quasar & Vue project structure link
Integrating Capacitor framework with your Quasar project link
Setting up the Android platform configuration link
Preparing the distribution directory for your application link
Synchronizing Quasar and Capacitor configurations link
Each step will be covered in detail in its own section. Follow the steps sequentially to ensure proper setup of your development environment.
In your project directory, first check the install of the Quasar CLI:
quasar --version
The above command will return the CLI version if installed, something like:
@quasar/cli 2.4.1
Run the Quasar CLI install command if not already installed:
npm i -g @quasar/cli
Note also that you can run the following command:
quasar info
This will show a complete report of your Quasar project (if the Quasar framework project has been scaffolded).
To initialize and scaffold the Quasar and Vue.js project:
-Create Quasar project
-Install and verify
-Test initial build
Run this command:
npm init quasar@latest
Or run this command:
npm create quasar
The above command seems to take a long time to run...you just have to wait.
As of Feb 2025, I can't determine definitively which of the above commands is better. Either command will then prompt the same set of selection options: see note below.
The command "npm init quasar@latest"
will often hang on this last step:
✔ Install project dependencies? (recommended) › Yes, use npm
It may fail with this message:
npm error code UNABLE_TO_GET_ISSUER_CERT_LOCALLY
npm error errno UNABLE_TO_GET_ISSUER_CERT_LOCALLY
npm error request to https://registry.npmjs.org/@eslint%2fjs failed, reason: unable to get local issuer certificate
When this happens, you'll see:
Quasar • ⚠️ Could not auto install dependencies. Probably a temporary npm registry issue?
Quasar • Initialized Git repository 🚀
To get started:
`cd yourprojectfolder`
yarn #or:` `npm install`
yarn lint --fix # or: `npm run lint -- --fix`
quasar dev # or: yarn quasar dev # or: `npx quasar dev`
Documentation can be found at: https://quasar.dev
If it simply hangs, you can Cntrl-C to end the terminal command, then cd into your project and run npm install
. Note there doesn't seem to be any harm in running the command multiple times. Below is a screen shot of what this looks like:
<your project folder name>
<whatever you need-could be project folder name>
Must start with letter if building mobile apps
(e.g., My Quasar App)<script setup>
After running npm init quasar@latest
your project structure should look something like this:
your-project/
├── .quasar <-quasar
├── node_modules
├── src/ <- src/ folder Vue project.
│ ├── assets
│ ├── components/
│ │ └── EssentialLink.vue
│ ├── css
│ ├──layouts/
│ │ └── MainLayout.vue
│ ├── pages/
│ │ ├── IndexPage.vue
│ │ └── ErrorNotFound.vue
│ ├── router/
│ │ ├── index.js
│ │ └── routes.js
│ └── App.vue
├── index.html
├── package-lock.json
├── package.json <- Pay close attention to dependency versions
└── quasar.config.js <-quasar
The above /src
folder should look familiar to a Vue.js developer.
The package.json in the project root
will have a dependency list similar to the following:
{
"dependencies": {
"@quasar/extras": "^1.16.4", <-quasar
"axios": "^1.2.1",
"pinia": "^3.0.1",
"quasar": "^2.16.0", <-quasar
"vue": "^3.4.18",
"vue-router": "^4.0.0"
},
"devDependencies": {
"@eslint/js": "^9.14.0",
"@quasar/app-vite": "^2.1.0", <-quasar
"autoprefixer": "^10.4.2",
"eslint": "^9.14.0",
"eslint-plugin-vue": "^9.30.0",
"globals": "^15.12.0",
"postcss": "^8.4.14",
"vite-plugin-checker": "^0.8.0"
}
}
Note there are no Capacitor-related elements yet.
Change directories into the project root:
cd <your project folder>
Then run:
npm install
Verify the terminal output resulting from the install
Running "npm install" performs the following actions:
Installs Dependencies:
Creates or Updates package-lock.json:
Also run in your project root:
quasar info
following is when my project was pretty much fully scaffoled/configured
Operating System - Darwin(23.5.0) - darwin/arm64
NodeJs - 18.20.6
Global packages
NPM - 10.8.2
yarn - Not installed
pnpm - Not installed
bun - Not installed
@quasar/cli - 2.4.1
@quasar/icongenie - Not installed
cordova - Not installed
Important local packages
quasar - 2.17.7 -- Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
@quasar/app-vite - 2.1.0-- Quasar Framework App CLI with Vite
@quasar/extras - 1.16.17 -- Quasar Framework fonts, icons and animations
eslint-plugin-quasar - Not installed
vue - 3.5.13 -- The progressive JavaScript framework for building modern web UI.
vue-router - 4.5.0
pinia - 3.0.1 -- Intuitive, type safe and flexible Store for Vue
vite - 6.1.0 -- Native-ESM powered web dev build tool
vite-plugin-checker - Not installed
eslint - 9.20.1 -- An AST-based pattern checker for JavaScript.
esbuild - 0.24.2 -- An extremely fast JavaScript and CSS bundler and minifier.
typescript - Not installed
workbox-build - Not installed
register-service-worker - Not installed
electron - Not installed
@electron/packager - Not installed
electron-builder - Not installed
@capacitor/core - 6.0.0-- Capacitor: Cross-platform apps with JavaScript and the web
@capacitor/cli - 6.2.0-- Capacitor: Cross-platform apps with JavaScript and the web
@capacitor/android - 6.0.0-- Capacitor: Cross-platform apps with JavaScript and the web
@capacitor/ios - Not installed
Quasar App Extensions
None installed
Networking
Host - abcdefgh-MacBook-Air.local
en0 - 10.0.0.125
You will now want to make sure Quasar (and Vue) are working as a plain SPA web app.
npm run dev # Should open development server
You should launch a spa web page similar to below...be sure to enable dev tools and look for any problems.
So, in summary to Part 3B, to initially scaffold the Quasar project, run these 3 commands:
npm i -g @quasar/cli
npm init quasar@latest
npm install
The above 3 commands will:
There are a couple steps to install capacitor to a Quasar project.
-Add capacitor structures to project using Quasar command
-Add capacitor config to project root
using npm commands
-Verify installation
Run the following Quasar command in your project root
folder:
quasar mode add capacitor
The above Quasar command will prompt for:
What is the Capacitor app id? (org.capacitor.quasar.app)
The app id is reverse domain name notation (ref project planning notes)
The folder /src-capcitor
will then be created in your project and the app id will go into the capacitor.config.json
file.
The newly created src-capacitor
structure will also hold the android structures in subsequent steps.
I recommend you review each of the notes below after running quasar mode add capacitor
.
Running quasar mode add capacitor
will probably default in older versions of capacitor (v6), as shown in the package.json
in /src-capacitor
folder (as of Feb 2025). But by the time you read this, who knows? You will just have to fight the version dependency battle.
Research indicates the Quasar team have the command quasar mode add capacitor
default in a supposedly more stable versions of capacitor at v6 (but Capacitor plugins, as of Feb 2025, are at v7)
The version is crucial!
Subsequent steps to install @capacitor/android
and other capacitor plugins can run into version issues, because version 7 of @capacitor/android
will default in, which will conflict with @capacitor/core at v6.
You may see an error msg such as this:
[warn] @capacitor/core@6.2.0 version doesn't match @capacitor/android@7.0.1 version.
Consider updating to a matching version, e.g. w/ npm install @capacitor/core@7.0.1
Attempts to upgrade capacitor/core might drag you down a rabbit hole of chained updates to your entire project, including Node.js.
It appears that (as of Feb 2025) Capacitor v6 requires Node v18.
-But Capacitor v7 requires Node v20.
-But Node v20 doesn't apparently work with the Quasar version that is defaulted in my npm create quasar.
So I recommend avoiding to attempts to upgrade individually. And note: I was never able to land a clean working v7 Capacitor into my Quasar project. Again: there seems to be no comprehensive versioning guide to install a Node-Vue-Quasar-Capacitor-Android-plugin stack.
here's some links to other notes ranting about version dependencies:
P3D Step 1 Notes
P3G Step 1 Note 1 Versioning Challenges read
Running command quasar mode add capacitor
in project root does of course negate the need to run specific NPM commands in a /src-capacitor
folder:
npm install @capacitor/core
npm install @capacitor/cli
Per research:
Running "quasar mode add capacitor"
does more than just installing the Capacitor core package.
Here's why it's important:
"/src-capacitor"
folder in your Quasar project, which contains the necessary configuration files for Capacitor.Simply running "npm install @capacitor/core"
(in project root) would only install the core package without integrating it properly into your Quasar project structure or setting up the necessary configurations. The "quasar mode add capacitor"
command provides a more comprehensive and streamlined setup for using Capacitor with Quasar
Rant Alert: But, why running "quasar mode add capacitor" also does not update the package.json
and node_mooules in the Quasar project root is simply inexplicable and exasperating. It should, as this just creates extra steps and opportunities for error and confusion.
If your floundering around the internet attempting to figure out how to land a clean install of Quasar-Capacitor-Android, you will probably come across the cmnd:
npx cap init
This command npx cap init
will create a completely new scaffold of your project right on-top of everything you've done with "quasar mode add capacitor"
. Thus you will either duplicate files and directories, or over-write files and directories...either way it's kind-of-mess. If using quasar to install capacitor, I recommend avoiding also using "npx cap init".
At the end of scaffolding capacitor when using the Quasar command quasar mode add capacitor
, the project structure should look something like this:
your-project/
├── .quasar
├── node_modules
├── src/
├── src-capacitor/ <- new folder created
│ ├── node_modules <- more node_modules
│ ├── www
│ ├── capacitor.config.json
│ ├── package-lock.json
│ └── package.json <- Yet another package.json file!
├── index.html
├── package-lock.json
├── package.json
└── quasar.config.js
The package.json
file under /src-capactor
folder should look something like this:
{
"name": "gmap9",
"version": "0.0.1",
"description": "A Quasar Google Map test",
"author": "abcdefg2 <abcdefg2@icloud.com>",
"private": true,
"dependencies": {
"@capacitor/app": "^6.0.0", <- v6!!!
"@capacitor/cli": "^6.0.0", <- v6!!!
"@capacitor/core": "^6.0.0". <- v6!!!
}
}
Special Note: Notice above that Quasar defaulted in v6 capacitor!!!
Each of the files perform different function (duh)
@capacitor/app
This is a specific Capacitor plugin that provides functionality related to the app itself.
It offers methods for handling app-level events and information, such as:
root
package.json.@capacitor/core:
This is the main package that provides the core functionality and APIs for Capacitor.
It contains the JavaScript runtime that allows web apps to interact with native platform features.
It's used in your web application code to access Capacitor's APIs and plugins.
It provides a consistent API layer that works across all platforms (iOS, Android, and web).
NOTE: @capacitor/core does need a separate step to install in the root
package.json
@capacitor/cli
The @capacitor/cli is the Command Line Interface for Capacitor, a crucial tool for managing Capacitor projects. It provides several key functionalities:
Project initialization: The CLI allows you to initialize new Capacitor projects with the "npx cap init" command5.
. Platform management: It enables adding native platforms to your project, such as iOS and Android, using commands like "npx cap add android" or "npx cap add ios"5.
. Project synchronization: The CLI facilitates syncing your web app with native projects using "npx cap sync"1.
Plugin management: It helps in adding, removing, and updating Capacitor plugins3.
Build and run: The CLI assists in building and running your app on different platforms3.
Project configuration: It allows you to manage and update your project's configuration settings3.
Code copying: The CLI handles copying your web app's code to native platforms and updating plugin code in native projects3.
NOTE: @capacitor/cli does need a separate step to install in the root
package.json
The Capacitor CLI is typically installed as a development dependency in your project, ensuring that different projects can use different CLI versions if needed**
The capacitor.config.json
file will probably initially look something like this:
{
"appId": "com.abcdefg2.org",
"appName": "My Gmap9 Test",
"webDir": "www"
}
The webDir
will probably need to be changed at some point to "dist/spa"
.
The dist/spa
directory is created in a following step.
As far as I can determine, the "www"
is a default webpack configuration,
and "dist/spa"
is a Quasar thing.
If you don't change the webDir
, you will might get a common bug that results in a white-screen on android.
There is a specific section, Part 3 E Create /dist directory which will discuss the webDir
in more detail.
You MUST manually install the @capacitor/cli
and the @capacitor/core
modules in the project root! ***Make sure root install matches the version in /scr-capacitor
Change directories to your project root.
In your project root directory first run:
npm install @capacitor/cli@6
Then run:
npm install @capacitor/core@6
CRUCIAL!!! DO NOT IGNORE THIS NOTE!!!
Add Capacitor cli and core to the package.json file in Root Directory for Vite web build.
Running "quasar mode add capacitor"
in the root directory only creates src-capacitor folder and the capacitor related files configurations in the /src-capcitor
directory.
The command "quasar mode add capacitor"
does not however update the package.json
file or update the node_modules in the project root, which turns out to be (as of Feb 2025) absolutely crucial.
Per research:
Point 1
Why@capacitor/core
Must Be Installed in the Root of the Quasar Project.
Ensures Compatibility with Quasar's Web Build System
@capacitor/core
is not in root node_modules, Quasar's Webpack build may not resolve, leading to "module not found" errors.Point 2: Install in Project Root? Or just in /src-capacitor
?
Which capacitor plugins features-plugins-components-api (what ever you want to call them) do you need to install in the project root so it just updates the root package.json
and the node_modules?
And which capacitor plugins to only install into the /src-capacitor
folder so it only updates the package.json
file and node_modules in the /src-capacitor
folder?
It turns out this is nearly pure guess-work.
There is no definitive chart or guide. As of Feb 2025, here's a little bit of what I've learned through arduous trial and error and endless floundering around on the internet.
The heuristic rule of thumb seems to be:
/src-capacitor
.Examples:
Install in both project root and src-capacitor:
@capacitor/core
@capacitor/geolocation
Install in just /src-capacitor
:
@capacitor/android
The package.json
file dependencies in the project root should subsequently look something like the json file below. Note the addition of the capacitor cli and core.
{
"dependencies": {
"@capacitor/cli": "^6.2.0", <- match package.json in src-capacitor
"@capacitor/core": "^6.2.0", <- match package.json in src-capacitor
"@quasar/extras": "^1.16.4",
"axios": "^1.2.1",
"pinia": "^3.0.1",
"quasar": "^2.16.0",
"vue": "^3.4.18",
"vue-router": "^4.0.0"
},
"devDependencies": {
"@eslint/js": "^9.14.0",
"@quasar/app-vite": "^2.1.0",
"autoprefixer": "^10.4.2",
"eslint": "^9.14.0",
"eslint-plugin-vue": "^9.30.0",
"globals": "^15.12.0",
"postcss": "^8.4.14",
"vite-plugin-checker": "^0.8.0"
}
}
Check the capacitor CLI version in project root
:
npx cap --version
Change directories into the /src-capacitor folder:
cd src-capacitor
Then run to check capacitor in /src-capacitor
:
npm list @capacitor/core
The capacitor core version, which should match package.json.
Now we can start configuring things to actually create an Android app. These steps will allow Android Studio to launch.
NOTE: The @capacitor/android
is native and only needs installed in the /src-capacitor
folder.
The install of capacitor android is a two step process. As an analogy: think about this as repairing your car:
The step is like going to the automotive store to get your car parts.
Be sure and change directories into the /src-capacitor
directory-folder:
cd src-capacitor
then
npm install @capacitor/android@6.0.0
The package.json
file in /src-capacitor
folder should then look something like this:
{
"name": "gmap9",
"version": "0.0.1",
"description": "A Quasar Google Map test",
"author": "abcdefg2 <abcdefg2@icloud.com>",
"private": true,
"dependencies": {
"@capacitor/android": "^6.0.0", <- android added
"@capacitor/app": "^6.0.0",
"@capacitor/cli": "^6.0.0",
"@capacitor/core": "^6.0.0"
}
}
Warning Note:
Just running the following will default in android v7.
npm install @capacitor/android
This v7 android will conflict with the the v6 capacitor/core that Quasar defaulted.
Check your package.json
file in /src-capacitor
Run following command to stay compatible with package.json versions in src-capacitor folder, if of course your cli
and core
are at v6:
npm install @capacitor/android@6.0.0
Link to other notes & rantsabout versioning issues:
P3C Step 1 Notes
P3G Step 1 Note 1 Versioning Challenges read
Here is a link to the official Capacitor documentation on the @capacitor/android
package, (and it really doesn't tell you much about versioning):
https://capacitorjs.com/docs/android#adding-the-android-platform
/src-capacitor
Per research:
Unlike @capacitor/core, which is needed in both the web and native contexts, @capacitor/android is a native platform package that is only needed by the Android project inside src-capacitor.
🚨 Problems If Installed in the Root:
Per research:
Why @capacitor/whateverplugin
usually needs to be Installed In just /src-capacitor
:
(a) Native Runtime Dependency for Capacitor's Native Code
(b) Ensures Proper Dependency Resolution for Native Plugins
Some Capacitor plugins rely on @capacitor/core being locally available inside src-capacitor to properly initialize.
npx cap sync
or npx cap run
could have errors where native plugins cannot find Capacitor core runtime(c) There are exceptions (of course) to installing plugins in the project root: native platform package. (meaning: if the plugin is native android, probably don't install in project root).
This step is like actually bolting the car parts to your car.
Run the following in the /src-capacitor
folder:
npx cap add android
The above command npx cap add android
will actually create the /android
folder-directory within the /src-capacitor
folder.
When you run npx cap add android
, Capacitor is looking at the capacitor.config.json
file.
your-project/
├── .quasar
├── node_modules
├── src/
├── src-capacitor/
│ ├── node_modules
│ ├── www
│ ├── android/ <- location of android
│ ├── capacitor.config.json
│ ├── package-lock.json
│ └── package.json
├── index.html
├── package-lock.json
├── package.json
└── quasar.config.js
Note 1: Android Project Structure
Inside the /src-capacitor
folder:
After running npx cap add android
, the generated /android
folder follows a standard Android project structure that should look something like this:
android/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/com/example/app/
│ │ │ │ ├── MainActivity.kt
│ │ │ ├── AndroidManifest.xml <- update capacitor plugins
│ │ │ ├── res/
│ │ │ │ ├── drawable/
│ │ │ │ ├── layout/
│ │ │ │ ├── mipmap/
│ │ │ │ ├── values/
├── build.gradle
├── settings.gradle
When you install a capacitor plugin you will probably need to manually update permission within the AndroidManifest.xml
file.
Note 2: The MainActivity.kt File (Entry Point)
This is the Kotlin (kt) language for Android...you might default in Java. Either will work.
Located at:
src-capacitor/android/app/src/main/java/com/example/app/MainActivity.kt
This file extends BridgeActivity, which is provided by Capacitor:
package com.example.app
import com.getcapacitor.BridgeActivity
class MainActivity : BridgeActivity() {
}
What The above Means:
Note 3: AndroidManifest.xml (Native Configuration)
Located at:
/src-capacitor/android/app/src/main/AndroidManifest.xml
This file configures important settings like:
Example snippet below (please excuse the tick mark escape characters):
Note again when adding plugins, you will probably need to update permissions:
`<uses-permission...>
`<manifest xmlns:android="http://schemas.android.com/apk/res/android">
`<package="com.example.app">`
`<uses-permission android:name="android.permission.INTERNET" />`
`<application
android:allowBackup="true"
android:theme="@style/AppTheme">
`<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:theme="@style/AppTheme.NoActionBar">
`<intent-filter>
`<action android:name="android.intent.action.MAIN" />
</intent-filter>
`</activity>
`</application>
`</manifest>`
My understanding of how Java is integrated into this architecture is sketchy at best. You do need to be sensitive to the versions of the JDK, JVM and Kotlin. Things can go wrong and you might be forced to fiddle directly with gradle files, which are way down inside the node modules. Do your own research!
Per some of my research:
If you install native plugins (e.g., Camera, Filesystem), Capacitor will automatically integrate them.
For example, if you install the capacitor camera plugin:
npm install @capacitor/camera
npx cap sync
It will register in Kotlin automatically. If needed, you can manually add them to MainActivity.kt:
import com.getcapacitor.BridgeActivity
import com.getcapacitor.Plugin
import com.getcapacitor.community.camera.CameraPlugin
class MainActivity : BridgeActivity() {
init {
registerPlugin(CameraPlugin::class.java)
}
}
Verify installation in the /src-capacitor
folder:
npm list @capacitor/android
ls android/ # Should show complete Android project structure
Your Quasar app runs inside a WebView on the Android.
Capacitor provides a JavaScript-to-Native bridge, allowing Quasar to interact with the native Android layer.
Note: some developers do not like WebView for various reasons, such as performance.
Kotlin is only used when you need to modify native functionality (e.g., adding custom plugins or tweaking the Android behavior).
Additionally, there is yet another step:
/dist
directoryTo build your Quasar app for production generate the /dist directory with terminal command in the root directory:
quasar build
This will create a new /dist directory:
your-project/
├── .quasar
├── dist/spa <- new dist directory
├── node_modules
├── src/
├── src-capacitor/
├── index.html
├── package-lock.json
├── package.json
└── quasar.config.js
Then Very Important!
Update the capacitor.config.json
file!!!
In your /src-capacitor
folder, it must to point to the correct web directory:
"webDir": "../dist/spa"
The capacitor.config.json
file should look something like this:
{
"appId": "com.yoururl.gmap",
"appName": "quasargooglemap",
"webDir": "../dist/spa"
}
Notes: per my research here's an explanation for the above step regarding dist/spa
:
When you scaffolded your project using quasar mode add capacitor
, it defaulted to "www"
instead of "dist/spa"
for historical and compatibility reasons.
The "www"
directory is a common default for many web-based mobile frameworks, including Cordova, which Capacitor was designed to be compatible with. This default setting allows for easier migration from Cordova projects and maintains consistency with other hybrid mobile development tools.
However, Quasar's build process typically outputs to the "dist/spa"
directory for Single Page Applications. This mismatch between Quasar's output and Capacitor's default expectation is why you need to manually update the webDir
in the capacitor.config.json
file.
To align Capacitor with Quasar's build output, you should change the webDir
setting in your capacitor.config.json
If you do not run "quasar build", and just launch a dev server locally, you can probably keep "webDir": "www"
in capacitor.config.json
file.
Now sync your project with Capacitor to ensure everything is up-to-date run command in the src-capacitor directory:
cd src-capacitor
npx cap sync
Run npx cap sync
in the /src-capacitor
folder to synchronize your web app with the Capacitor project.
This command does two things:
The npx cap sync command relies on the capacitor.config.json
file (in /src-capaitor
folder), which contains the following crucial piece of information:
`"webDir": "dist/spa"`
The npx cap sync
command is crucial because it:
Copies the latest web assets from your specified webDir to the native platform folders.
Updates Capacitor and Cordova plugins, ensuring all native dependencies are in place.
Do Not Run npx cap sync
In Project root.
Note that if you run npx cap sync in the project root
directory, you will get an error, because the root directory does not have a capacitor.config.json
file.
The error message seems rather confusing,
It should probably say something like:
"Yo dummy, I couldn't find the capacitor.config.json file so I couldn't do anything.
But if you read the error msg carefully it has a clue.
error Could not find the web assets directory: ./www. Please create it and make sure it has an index.html file. You can change the path of this directory in capacitor.config.json (webDir option). You may need to compile the web assets for your app (typically npm run build). More info: https://capacitorjs.com/docs/basics/workflow#sync-your-project
The clue in the above error is the command npx cap sync
looking for the webDir
(aka web assets directory) in the capacitor.config.json
file, which is only in the /src-capacitor
folder to create the web assets (for use in the WebView)
Per Research: More tedious details:
The command npx cap sync
is responsible for synchronizing your web app with the native platforms (Android/iOS). Specifically, it performs the following steps:
Copies Web Assets (dist/spa
) to Native Platforms
index.html
, CSS, JavaScript, etc.) into each native platform’s web runtime directory:
android/app/src/main/assets/public/
ios/App/public/
Updates Dependencies for Installed Plugins
package.json
to find any installed Capacitor plugins (e.g., @capacitor/camera
, @capacitor/geolocation
).Runs npx cap copy
Automatically
npx cap copy
manually, meaning it updates the web assets in the native platforms.Runs npx cap update
Automatically
Ensures Android/iOS Project Files are in Sync
- It updates native platform files, such as AndroidManifest.xml
and Info.plist
, with any configuration changes from your Capacitor plugins.
Optionally, you can run npx cap sync android
in the /src-capacitor
folder to specifically sync the Android platform.
**How capacitor.config.json
is Used
Your capacitor.config.json
file contains essential project settings:
appId
: "com.abcdefg.gmap"
appName
: "quasargooglemap"
webDir
: "dist/spa"
"dist/spa"
is the directory where Quasar compiles the production build of your app.Why is this important?
npx cap sync
relies on webDir
to copy files to the native platforms.dist/pwa
instead of dist/spa
), you'd need to update webDir
./src-capacitor
importanceRunning npx cap sync
in the root directory of your Quasar-Capacitor project doesn't work because Quasar manages the Capacitor integration differently from a standard Capacitor project. Here's why:
Quasar's project structure: Quasar isolates Capacitor-related files in the /src-capacitor
directory, including the relevant capacitor.config.json
file.
Capacitor configuration: The capacitor.config.json file in the /src-capacitor
folder is the one Capacitor uses directly when building and running our app.
Quasar CLI integration: Quasar CLI handles the Capacitor sync process when you run commands like quasar dev -m capacitor
or quasar build -m capacitor
.
Core Capacitor Commands
These are the main commands used for managing Capacitor in your project:
npx cap init [appName] [appId]
capacitor.config.ts/json
file.npx cap add [platform]
ios
, android
, web
) to your project.npx cap add android
npx cap update
npx cap sync
dist
folder) to the native platform directories and updates dependencies.
npx cap copy
npx cap open [platform]
npx cap open android # Opens Android Studio npx cap open ios # Opens Xcode
Development & Debugging Commands
These help with debugging and running your app:
npx cap doctor
npx cap run [platform]
npx cap run android
npx cap serve
capacitor://
or http://
debugging).Plugin & Configuration Management
Useful for managing Capacitor plugins and settings:
npx cap ls
npx cap plugin add [plugin-name]
npx cap plugin add @capacitor/geolocation
npx cap plugin rm [plugin-name]
npx cap migrate
Platform-Specific Commands
These commands apply to a specific platform:
npx cap copy [platform]
npx cap sync [platform]
npx cap sync android
npx cap open [platform]
Troubleshooting Tip
If you are facing issues with Capacitor commands, try:
npx cap doctor
This will scan for common misconfigurations.
At this point I highly recommend you inspect both package.json file, in project root
and in /src-capacitor
to insure the plugin is in fact installed.
They should look similar to what's below. (Note: a slight variation in capacitor versions between root
and /src-capacitor
didn't seem to cause issues).
Package.json in project root
:
Package.json in /src-capacitor
:
And finally, always after installing plugins or making other updates, be sure and remember run in your /src-capacitor
folder:
npx cap sync
For notes about the npx cap sync
command, reference Part 3F - Sync Your Project again for notes on "What npx cap sync
does".
Wasn't that a journey! And now, finally you might actually be able to do some actual development.
To finally launch the app in development, run:
quasar dev -m capacitor -T android
The above command translates/parses roughly as follows:
quasar
: Hey Quasar,dev
: please launch a development server,-m capacitor
: in mode capacitor,-T android
: targeting android.When you run the above command, a session of Android Studio should automagically launch.
You should be able to interact with your app in Android Studio, and on the test Android phone at the same time.
When setting up your development environment:
Also: HIGHLY RECOMMEND: use the chrome inspect devices tool!
Open a browser tab, put in:
chrome://inspect/#devices
When you launch the app you will be able to select your test Android phone and interact with it and show console log and review error messages from the WebView! This feature is so awesome!
But, just a note: the inspect tool can be a bit balky...and it sometimes lags up to a few minutes before it brings up the device list.
=The Chrome Inspect tool is crucial. =
Per research: Your Quasar + Capacitor app is basically a web app running inside a native WebView. Chrome inspect is the tool designed to inspect WebViews. It’s basically poking inside the WebView as if it were a regular browser tab.
Android Studio is great at debugging native Android code (Java/Kotlin). It can see the device, it can launch and deploy your app, and it gives you full access to Logcat, which catches:
Sometimes your JavaScript console.log messages do show up in Logcat — but not always clearly, and they can get buried in the noise.
And finally, now we can start adding Capacitor plugins that can work on a phone!
There are so many cool features that Capacitor has to offer. Here's a link: https://capacitorjs.com/docs/plugins
Each time you add/install a capacitor plugin:
npm install
in two places!/src-capacitor
, then again in the root
.package.json
files to confirm versions.npx cap sync
in the src-capacitor
directory/folder.Example: @capacitor/geolocation
Let's use the geolocation plugin as an example for how to go about installing a plugin into your scaffolded Quasar project (which again in Feb 2025: Quasar defaulted in cli and core at v6).
.
https://capacitorjs.com/docs/apis/geolocation
The Capacitor geolocation plugin does not explicitly provide any map rendering or visualization capabilities.
The plugin uses the native features on your phone, or on your desktop machine to determine lat-long location data.
Also per research: The Google Geolocation API is a completly separate web service (part of Maps Platform) used for:
Capacitor's plugin bypasses this Google Geolocation API by using direct device capabilities.
cd to your project root
, and run:
npm install @capacitor/geolocation@6.x
run in /src-capacitor
folder:
cd src-capacitor
npm install @capacitor/geolocation@6.x
.
The same pattern (appending @6.x) should work for all the capacitor plugins.
⚠️ Warning: Just blindly following the Capacitor documentation might get you into a versioning conflict.
Just running npm install @capacitor/geolocation
will default in v7 (as of Feb 2025).
This v7 will conflict with the capacitor core defaulted in with quasar mode add capacitor
command, which defaults in capacitor-core at v6 (as of Feb 2025).
Oh, and good luck trying to find a comprehensive guide to a proper versioning for the software stack of:
...Node,
.....Vite,
........Quasar,
................Vue,
....................Capacitor,
..................... Capacitor-Android
.........................Android-Studio
............................Android SDK
...............................Gradle
.................................JDK
.....................................Java & Jetbrains
......................................JVM
.........................................Kotlin
... there simply isn't any comprehensive guide as far as I could discern after many hours of flogging the internet.
It's mostly trial and error. The documentation IMO is lacking. Or it's just proof that I don't really know what I'm doing? More probable: All programming is stuck in this version dependency purgatory...and we just have to suffer, because that is after all, according to Buddha, what life is about.
This guide represents literally weeks of many, many scaffolding attempts to land a project that works (as of Feb 2025).
You're Welcome.
link to other rants about versioning dependencies:
P3C Step 1 Notes
P3D Step 1 Notes
Yes folks, yet more manual steps! Who said this would be easy?
For Android, you sometimes, but not always, have to manually update the AndroidManifest.xml
file.
Do your own research!
Example:
Per Capacitor Documentation at following link: https://capacitorjs.com/docs/apis/geolocation
Find your AndroidManifest.xml
file, which should be way down under:
/scr-capacitor
/android
/app
/src
/main
For the geolocation plugin, per capacitor, put the following into the AndroidManifest.xml
file:
<!-- Geolocation Plugin -->
<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" />
First let's just get a hello world MapPageGeoLocate.vue
wired in,
...we will replace the hello world with code that uses the geolocation plugin in the next step.
IndexPage.vue
Note that for dev & testing I often create several versions of any given component...some times a dozen. So to facilitate that I use the IndexPage.vue
as a default landing page, then use buttons to route to my actual pages. Don't judge...it's just for testing.
Lets create an initial Hello World page under /src/pages
folder
...just to make sure the basic page, router and button work first.
CapacitorGeoLocate.vue
- Hello WorldBelow is code for creating the CapacitorGeoLocate.vue
in the /src/pages
folder...again, we are just getting things wired up.
<script setup>
// No setup needed for this simple example
</script>
<template>
<div>
<h1>Hello, World!</h1>
</div>
</template>
<style scoped>
/* Add styles here if needed */
</style>
route.js
Add the following to the routes.js
under the /src/router
folder.
{
path: 'geolocation',
name: 'geolocation',
component: () => import('pages/CapacitorGeoLocate.vue'),
},
route.js
file should look like below:IndexPage.vue
Add following to IndexPage.vue
under /src/pages
folder
<q-btn
color="primary"
label="Go to just Geolocate Page"
@click="$router.push('/geolocation')"
/>
IndexPage.vue
file should look like below:Test as both a SPA web page and in Android Studio
SPA - In the root
directory run following terminal command.
npm run dev
You should see a web page with the button. The button should take you to the Hello World page.
Android Studio - In the root
directory run the following terminal command.
quasar dev -m capacitor -T android
You should be able to launch as an Android app in Android Studio. The button should take you to the Hello World page.
Now that we have:
MapPageGeoLocate.vue
page that properly routes (previous part 6), The @capacitor/geolocation
plugin is fairly basic so it easier to implement than lets say the google-maps plugin (subject of another blog...tbd).
Full disclosure: It's just a hack page created by Claude...don't hate me.
<template>
<div class="geolocation-demo">
<h1>@capacitor/geolocation Demo</h1>
<!-- Platform Check -->
<div class="feature-section">
<div class="feature-card">
<h3>Platform Check</h3>
<p>Check which platform the app is running on (Native or Web).</p>
<button @click="checkPlatform">Check Platform</button>
<div class="result-box">
<pre>{{ platformInfo }}</pre>
</div>
</div>
</div>
<!-- Permissions Section -->
<div class="feature-section">
<h2>Permissions</h2>
<div class="feature-card">
<h3>Check Permissions</h3>
<p>Check current location permissions status on the device.</p>
<button @click="checkPermissions">Check Permissions</button>
<div class="result-box">
<pre>{{ permissionsStatus }}</pre>
</div>
</div>
<div class="feature-card">
<h3>Request Permissions</h3>
<p>Request location permissions from the user. Not available on web.</p>
<button @click="requestPermissions">Request Permissions</button>
<div class="result-box">
<pre>{{ permissionsRequestResult }}</pre>
</div>
<div v-if="requestPermissionsError" class="error-box request-error">
<p><strong>Code:</strong> {{ requestPermissionsError.code }}</p>
<p><strong>Message:</strong> {{ requestPermissionsError.message }}</p>
</div>
</div>
</div>
<!-- Current Position Section -->
<div class="feature-section">
<h2>Get Current Position</h2>
<div class="feature-card">
<h3>Get Current Position</h3>
<p>Get the current GPS location of the device.</p>
<div class="options-form">
<div class="form-group">
<label>
<input
type="checkbox"
v-model="currentPosOptions.enableHighAccuracy"
/>
Enable High Accuracy
</label>
<p class="option-description">
Uses GPS if available (may consume more battery).
</p>
</div>
<div class="form-group">
<label
>Timeout (ms):
<input
type="number"
v-model.number="currentPosOptions.timeout"
min="0"
/>
</label>
<p class="option-description">
Maximum wait time for location data.
</p>
</div>
<div class="form-group">
<label
>Maximum Age (ms):
<input
type="number"
v-model.number="currentPosOptions.maximumAge"
min="0"
/>
</label>
<p class="option-description">
Maximum age of cached position that is acceptable.
</p>
</div>
</div>
<button @click="getCurrentPosition">Get Current Position</button>
<div class="result-box">
<pre>{{ currentPosition }}</pre>
</div>
</div>
</div>
<!-- Watch Position Section -->
<div class="feature-section">
<h2>Watch Position</h2>
<div class="feature-card">
<h3>Watch Position</h3>
<p>
Set up a watch for location changes. Note that watching for location
can consume significant energy.
</p>
<div class="options-form">
<div class="form-group">
<label>
<input
type="checkbox"
v-model="watchPosOptions.enableHighAccuracy"
/>
Enable High Accuracy
</label>
</div>
<div class="form-group">
<label
>Timeout (ms):
<input
type="number"
v-model.number="watchPosOptions.timeout"
min="0"
/>
</label>
</div>
<div class="form-group">
<label
>Maximum Age (ms):
<input
type="number"
v-model.number="watchPosOptions.maximumAge"
min="0"
/>
</label>
</div>
<div class="form-group">
<label
>Minimum Update Interval (ms):
<input
type="number"
v-model.number="watchPosOptions.minimumUpdateInterval"
min="0"
/>
</label>
<p class="option-description">
Android only: Minimum time between updates.
</p>
</div>
</div>
<button @click="startWatchPosition" :disabled="isWatching">
Start Watching
</button>
<button @click="stopWatchPosition" :disabled="!isWatching">
Stop Watching
</button>
<div class="result-box">
<p>Watch ID: {{ watchId || 'Not watching' }}</p>
<p>Updates received: {{ watchUpdatesCount }}</p>
<pre>{{ watchPosition }}</pre>
</div>
</div>
</div>
<!-- Error Display -->
<div v-if="error" class="error-section">
<h3>General Error</h3>
<div class="error-box">
<p><strong>Code:</strong> {{ error.code }}</p>
<p><strong>Message:</strong> {{ error.message }}</p>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { Geolocation } from '@capacitor/geolocation';
import { Capacitor } from '@capacitor/core';
// Platform info
const platformInfo = ref('');
// Permission states
const permissionsStatus = ref('');
const permissionsRequestResult = ref('');
const requestPermissionsError = ref(null);
// Current position
const currentPosition = ref('');
const currentPosOptions = reactive({
enableHighAccuracy: false,
timeout: 10000,
maximumAge: 0,
});
// Watch position
const watchPosition = ref('');
const watchPosOptions = reactive({
enableHighAccuracy: false,
timeout: 10000,
maximumAge: 0,
minimumUpdateInterval: 5000,
});
const isWatching = ref(false);
const watchId = ref('');
const watchUpdatesCount = ref(0);
// Error handling
const error = ref(null);
// Check platform
const checkPlatform = () => {
const isNative = Capacitor.isNativePlatform();
const platformName = Capacitor.getPlatform();
const platformData = {
isNativePlatform: isNative,
platform: platformName,
description: isNative
? `Running on native ${platformName} platform`
: 'Running as a web application',
};
platformInfo.value = JSON.stringify(platformData, null, 2);
console.log('Platform check:', platformData);
};
// Helper function to format position data for display
const formatPosition = (position) => {
if (!position) return 'No position data available';
const { coords, timestamp } = position;
return JSON.stringify(
{
timestamp,
coords: {
latitude: coords.latitude,
longitude: coords.longitude,
accuracy: coords.accuracy,
altitude: coords.altitude,
altitudeAccuracy: coords.altitudeAccuracy,
heading: coords.heading,
speed: coords.speed,
},
},
null,
2
);
};
// Check permissions
const checkPermissions = async () => {
try {
error.value = null;
console.log('Checking permissions...');
const status = await Geolocation.checkPermissions();
console.log('Permissions status:', status);
permissionsStatus.value = JSON.stringify(status, null, 2);
} catch (err) {
console.error('Error checking permissions:', err);
error.value = {
code: err.code || 'UNKNOWN',
message: err.message || 'An unknown error occurred',
};
permissionsStatus.value = 'Error checking permissions';
}
};
// Request permissions
const requestPermissions = async () => {
try {
error.value = null;
requestPermissionsError.value = null;
console.log('Requesting permissions...');
const status = await Geolocation.requestPermissions({
permissions: ['location'],
});
console.log('Permissions request result:', status);
permissionsRequestResult.value = JSON.stringify(status, null, 2);
} catch (err) {
console.error('Error requesting permissions:', err);
requestPermissionsError.value = {
code: err.code || 'UNKNOWN',
message: err.message || 'An unknown error occurred',
};
permissionsRequestResult.value = 'Error requesting permissions';
}
};
// Get current position
const getCurrentPosition = async () => {
try {
error.value = null;
currentPosition.value = 'Loading...';
console.log('Getting current position with options:', currentPosOptions);
const position = await Geolocation.getCurrentPosition(currentPosOptions);
console.log('Current position result:', position);
currentPosition.value = formatPosition(position);
} catch (err) {
console.error('Error getting current position:', err);
error.value = {
code: err.code || 'UNKNOWN',
message: err.message || 'An unknown error occurred',
};
currentPosition.value = 'Error getting current position';
}
};
// Watch position
const startWatchPosition = async () => {
try {
error.value = null;
if (isWatching.value) return;
watchPosition.value = 'Waiting for position updates...';
watchUpdatesCount.value = 0;
console.log('Starting position watch with options:', watchPosOptions);
watchId.value = await Geolocation.watchPosition(
watchPosOptions,
(position, err) => {
if (err) {
console.error('Error in watch callback:', err);
error.value = {
code: err.code || 'UNKNOWN',
message: err.message || 'An unknown error occurred during watch',
};
return;
}
console.log('Watch update received:', position);
watchUpdatesCount.value++;
watchPosition.value = formatPosition(position);
}
);
console.log('Watch started with ID:', watchId.value);
isWatching.value = true;
} catch (err) {
console.error('Error starting position watch:', err);
error.value = {
code: err.code || 'UNKNOWN',
message: err.message || 'An unknown error occurred',
};
watchPosition.value = 'Error starting position watch';
isWatching.value = false;
}
};
// Clear watch
const stopWatchPosition = async () => {
try {
error.value = null;
if (!isWatching.value || !watchId.value) return;
console.log('Stopping watch with ID:', watchId.value);
await Geolocation.clearWatch({
id: watchId.value,
});
console.log('Watch stopped successfully');
isWatching.value = false;
watchId.value = '';
watchPosition.value += '\n\nWatch stopped.';
} catch (err) {
console.error('Error stopping watch:', err);
error.value = {
code: err.code || 'UNKNOWN',
message: err.message || 'An unknown error occurred',
};
}
};
</script>
<style scoped>
.geolocation-demo {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
h1 {
text-align: center;
margin-bottom: 30px;
}
h2 {
margin-top: 30px;
border-bottom: 1px solid #ccc;
padding-bottom: 10px;
}
.feature-section {
margin-bottom: 30px;
}
.feature-card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
margin-bottom: 20px;
background-color: #f9f9f9;
}
.feature-card h3 {
margin-top: 0;
}
.options-form {
margin: 15px 0;
padding: 10px;
background-color: #f0f0f0;
border-radius: 5px;
}
.form-group {
margin-bottom: 10px;
}
.option-description {
margin: 0;
font-size: 0.8em;
color: #666;
}
button {
background-color: #4caf50;
color: white;
border: none;
padding: 10px 15px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
margin: 4px 2px;
cursor: pointer;
border-radius: 5px;
}
button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.result-box {
margin-top: 10px;
padding: 10px;
background-color: #f5f5f5;
border: 1px solid #ddd;
border-radius: 4px;
min-height: 50px;
max-height: 300px;
overflow: auto;
}
.result-box pre {
margin: 0;
white-space: pre-wrap;
}
.error-section {
margin-top: 30px;
padding: 15px;
background-color: #ffebee;
border: 1px solid #ffcdd2;
border-radius: 8px;
}
.error-box {
margin-top: 10px;
background-color: #ffebee;
border: 1px solid #ffcdd2;
border-radius: 8px;
padding: 10px;
}
.request-error {
margin-top: 15px;
}
</style>
After updating your code (and saving), test as both a SPA web page and in Android Studio
SPA - In the root
directory run following terminal command.
npm run dev
You should see a web page with the button,
...clicking the button should take you to the CapacitorGeoLocate.vue page:
Android Studio - In the root
directory run the following terminal command.
quasar dev -m capacitor -T android
You should be able to launch as an Android app in Android Studio.
...on Android you may probably see a permissions pop-up screen:
Let me thanks Vueschool.io (link: https://vueschool.io) for their excellent video tutorials. They have a great product that really helped getting ramped up on Vue.js.
Let me thank Luke Diebold in particular for his excellent video tutorials, as they gave a huge head start. Luke is just an outstanding educator and Quasar evangelist.
https://www.youtube.com/@LukeDiebold
Also a shout out goes to all my AI friends, especially Perplexity (which offer links to it's sources!) and Claude which can produce fairly decent code.
So, apologies to all the kind people of the internet who selflessly contribute to the technical zeitgeist. But without these AI's ability to distill their knowledge into specific answers, this project would have been absolutely impossible. Although the AI's are often frustratingly dead wrong, they also often nail the answers, and even the wrong answers sometimes offer important clues. In fact, I fully expect this blog too will be consumed into the AI blackhole.
Oh, but I found Copilot in VS Code kinda useless...just say'n. This is as of Feb 2025, so I'm sure things will improve.
And let's give a thanks to Obsidian!
https://obsidian.md/
I recently discovered this app, and it sure beats any of the other apps I've used over the years for taking notes.
Be sure and install the Obsidian webclipper extension to your browser! Wow...it is sooooo useful. When you find a great web resource, just clip into Obsidian and it's there for you to research and link (tags) into all your other notes. Also, in fact, this blog was produced in Obsidian. Obsidian is so useful, and it's free! Unbelievable.